RTU_ALL_AI/docs/system/RTU/API-RTU.md

16 KiB
Raw Permalink Blame History

API-RTU — RTU 主程序模块

版本: v3.0
日期: 2026-07-08
来源: 基于原工程 e173631 重构,升级为 X-Macro 框架
状态: 已实现x86 + ARM 双平台编译通过


1. 模块概述

RTU 模块是 RTU_ALL_AI 项目的主程序入口和系统管理框架,负责:

功能 说明
模块生命周期管理 X-Macro 驱动的线程模块注册、初始化init1→init2→start→stop
配置文件启停控制 通过 config/SYSTEM/app_config.json 按需启用/禁用模块
三级定时器 为每个模块自动创建 10ms / 100ms / 1000ms 三级周期性定时器
事件驱动循环 每个模块通过 stru_task_event_t 等待定时器事件和自己业务事件
优雅关闭 EV_STOP 信号 + pthread_join 确保所有线程安全退出
命令行交互 内置 version / uptime 命令,各模块可注册自定义命令

核心设计理念

新增模块只需修改 app_modules.h 中一行宏,无需改动框架代码。模块的枚举值、extern 声明、g_vec_app 初始化列表全部由 X-Macro 自动展开生成,消除了传统运行时注册的样板代码。

与原始框架e173631对比

方面 原始(运行时注册) 升级后X-Macro
模块注册 app_module_register() 运行时调用 APP_MODULE() 编译时宏,零运行时开销
启停控制 app_config.json 按需启用
定时器 无(模块自行实现) 自动三级定时器
停止 app_modules_stop/join 独立函数 app_sys_stop() 一体化
新增模块 修改 main.c + app_modules.c 仅修改 app_modules.h 一行

2. 文件结构

src/system/
├── inc/
│   ├── app_modules.h          # 模块注册表X-Macro 中心列表)
│   └── mySystem.h             # 公共定义stru_app / enum_app / API 声明)
└── RTU/
    └── src/
        ├── main.c             # 主程序入口(信号处理 → 初始化 → 主循环 → 关闭)
        └── app_sys.cpp        # 系统管理实现(配置解析 / 模块初始化 / 停止)

config/
└── SYSTEM/
    └── app_config.json        # 运行时模块启停配置(部署到 RK 装置)

3. 架构

app_config.json → cJSON 解析
       │
       ▼
  g_enabled_apps (std::set)
       │
       ▼
  app_modules.h ──X-Macro──▶ g_vec_app (std::vector<stru_app>)
       │                              │
       │                    ┌─────────┼─────────┐
       │                    ▼         ▼         ▼
       │               app_init1  app_init2  创建定时器
       │                    │         │     (10/100/1000ms)
       │                    │         │         │
       │                    ▼         ▼         ▼
       │              ┌────────────────────────────┐
       └── is_app_enabled( ) ──▶  pthread_create()  │
                              │  独立线程运行 fun_cb │
                              └──────────┬─────────┘
                                         │
                              ┌──────────▼──────────┐
                              │  task_event_wait()   │
                              │  ← EV_TIMER1/2/3     │
                              │  ← EV_STOP           │
                              └──────────────────────┘

启动流程

main()
  │
  ├── signal(SIGINT/SIGTERM) → sig_handler()
  │
  ├── log_init() / dc_init()
  │
  ├── app_sys_init()
  │     ├── [1] app_config_load()
  │     │       ├── get_system_config_path()
  │     │       │     ├── WORK_PATH 环境变量RK 装置)
  │     │       │     └── func_proc_self_dir()(本地调试)
  │     │       └── cJSON_Parse(app_config.json)
  │     │            → g_enabled_apps
  │     │
  │     ├── [2] app_init()
  │     │     ├── init1: 遍历 g_vec_app → 调用各模块 init1()
  │     │     ├── init2: 遍历 g_vec_app → 调用各模块 init2()
  │     │     └── start: 遍历 g_vec_app
  │     │           ├── task_event_create()
  │     │           ├── app_timer_create() × 3
  │     │           └── pthread_create() → fun_cb
  │     │
  │     └── return 0
  │
  ├── while(g_running) → 命令行输入循环
  │
  └── app_sys_stop()              ← Ctrl+C
        ├── EV_STOP → 各模块
        └── pthread_join → 各线程

4. 核心数据结构

4.1 模块枚举enum_app

app_modules.h X-Macro 生成,无需手动定义:

/* app_modules.h */
APP_MODULE(MODBUS_M,  modbus_m,  app_modbus_m_init1,  app_modbus_m_init2,  app_modbus_m)
// 新增模块只需追加一行

/* mySystem.h 自动展开为 */
typedef enum
{
    ENUM_APP_MODBUS_M,    // ← 自动生成
    // ENUM_APP_XXX,      // ← 新增模块的枚举值
    ENUM_APP_MAX
} enum_app;

4.2 模块上下文stru_app

每个线程模块一个实例,由 app_sys.cpp 自动创建和管理。

typedef struct
{
    const char         *name;           /**< 模块名称,如 "app_modbus_m" */
    uint32_t            app_id;         /**< 模块 ID枚举值 */
    app_init_fn         app_init1;      /**< 阶段 1 初始化(信号注册前) */
    app_init_fn         app_init2;      /**< 阶段 2 初始化(信号注册后) */
    app_func_fn         fun_cb;         /**< 主循环入口(独立线程) */
    void               *arg;            /**< 线程参数(指向自身) */
    stru_task_event_t   p_event;        /**< 事件句柄(定时器 + 停止信号) */
    stru_rtx_data       rtx;            /**< 收发数据缓冲区 */
    uint32_t            timer_arg[TIMER_NUM]; /**< 定时器参数([app_id:8, idx:8] */
    stru_task_timer_t   p_timer[TIMER_NUM];  /**< 三级定时器句柄 */
    uint32_t            run_cnt;        /**< 运行计数 */
} stru_app;

4.3 事件定义

#define TIMER_NUM  3               /* 定时器级数 */
#define EV_TIMER1  (0x01 << 0)     /* 10ms 定时器事件 */
#define EV_TIMER2  (0x01 << 1)     /* 100ms 定时器事件 */
#define EV_TIMER3  (0x01 << 2)     /* 1000ms 定时器事件 */
#define EV_STOP    (0x80)          /* 模块停止信号 */
#define MSG_SIZE   2048            /* 收发缓冲区大小 */

5. 接口函数

5.1 app_sys_init()

int app_sys_init(void);

功能: 初始化所有 X-Macro 注册的模块。包括加载 app_config.json、执行各模块 init1/init2、创建事件 + 定时器 + 启动线程。

参数: 无

返回值:

说明
0 初始化成功
-1 初始化失败(配置文件解析/模块 init/线程创建)

调用位置: main.cdc_init() 之后、主循环之前。

5.2 app_sys_stop()

void app_sys_stop(void);

功能: 停止所有模块。先向每个模块发送 EV_STOP 信号通知其退出主循环,然后 pthread_join 等待所有线程安全退出。

调用位置: main.c 中收到 SIGINT/SIGTERM 或 Ctrl+D 后、dc_cleanup() 之前。

5.3 app_get_ptr()

stru_app *app_get_ptr(uint32_t app_id);

功能: 根据模块 ID 获取 stru_app 指针。供模块内部或外部代码访问其他模块数据。

参数:

参数 说明
app_id 模块 IDenum_app 枚举值)

返回值: 有效模块指针,超出范围返回 NULL


6. 配置文件

6.1 app_config.json

位置:config/SYSTEM/app_config.json

{
    "apps": [
        {"name": "app_modbus_m", "enable": true}
    ]
}

字段说明:

字段 类型 说明
apps Array 模块配置列表
name String 模块名称,格式为 app_<配置名>,与 app_modules.h 中 cfg_name 对应
enable Boolean true=启用,false=禁用

配置路径优先级:

  1. WORK_PATH 环境变量 → $WORK_PATH/config/SYSTEM/RK3568 装置运行时由启动脚本设定)
  2. 可执行文件所在目录 → <exe_dir>/config/SYSTEM/x86 本地调试用 fallback

部署约定: config/ 整个目录直接同步到 RK 装置可执行文件的同级目录下。

6.2 配置文件缺失

app_config.json 未找到,框架默认启用所有模块,不视为错误。日志输出:

app_config.json not found, enabling all modules by default

7. 新增模块步骤

只需三步:

Step 1: 在 app_modules.h 追加一行

/* src/system/inc/app_modules.h */
APP_MODULE(NEW_MODULE, new_module, app_new_module_init1, app_new_module_init2, app_new_module)

宏参数说明:

参数 示例 说明
name NEW_MODULE 枚举后缀,生成 ENUM_APP_NEW_MODULE
cfg_name new_module 配置名,生成名称 "app_new_module"
init1 app_new_module_init1 阶段 1 初始化函数(信号注册前)
init2 app_new_module_init2 阶段 2 初始化函数(信号注册后),可为 NULL
func app_new_module 主循环入口函数(独立线程)

Step 2: 实现模块代码

src/system/<模块名>/src/ 下实现四个函数:

/* init1: 信号注册前(可解析配置文件) */
int app_new_module_init1(void *arg)
{
    stru_app *p_app = (stru_app *)arg;
    // 1. 注册输出信号到 datacenter
    // 2. 解析模块配置文件XML/JSON
    return 0;
}

/* init2: 信号注册后(注册遥控/遥调信号及回调) */
int app_new_module_init2(void *arg)
{
    // 注册 yk/ao 信号及其回调函数
    return 0;
}

/* 主循环: 事件驱动 */
void *app_new_module(void *arg)
{
    stru_app *p_app = (stru_app *)arg;
    uint32_t event;

    while (1)
    {
        task_event_wait(p_app->p_event, &event, 0);

        if (event & EV_STOP)
        {
            break;  /* 退出循环 */
        }

        if (event & EV_TIMER1)
        {
            /* 10ms 周期任务 */
            p_app->run_cnt++;
        }

        /* ... 其他事件处理 ... */
    }

    return NULL;
}

Step 3: 更新构建系统

release/src/system/ 下创建模块子目录和 makefile并在 release/src/system/makefile 中注册:

SUBDIRS := ./new_module ./libmodbus_m ./RTU

Step 4: 更新配置文件

config/SYSTEM/app_config.json 中添加模块条目:

{"name": "app_new_module", "enable": true}

8. 模块编写规范

8.1 主循环模板

void *app_xxx(void *arg)
{
    stru_app *p_app = (stru_app *)arg;
    if (!p_app || !p_app->p_event)
    {
        LOG_E("app_xxx arg null");
        return NULL;
    }

    uint32_t event;
    uint32_t cnt_10ms  = 0;
    uint32_t cnt_100ms = 0;
    uint32_t cnt_1s    = 0;

    while (1)
    {
        task_event_wait(p_app->p_event, &event, 0);

        if (event & EV_STOP)
        {
            LOG_I("app_xxx stopping, total runs: 10ms=%u 100ms=%u 1s=%u",
                  cnt_10ms, cnt_100ms, cnt_1s);
            break;
        }

        if (event & EV_TIMER1)
        {
            cnt_10ms++;
            /* 10ms 周期处理 */
        }

        if (event & EV_TIMER2)
        {
            cnt_100ms++;
            /* 100ms 周期处理 */
        }

        if (event & EV_TIMER3)
        {
            cnt_1s++;
            /* 1000ms 周期处理 */
            p_app->run_cnt++;
        }
    }

    return NULL;
}

8.2 事件处理顺序

事件处理遵循 先停止后业务 原则:EV_STOP 检查放在最前面,确保收到停止信号后立刻退出。

8.3 配置路径约定

模块内部读取配置文件时,遵循与框架一致的路径约定(参考 modbus_m.cppget_base_path()

LOCAL std::string get_base_path()
{
    char buf[512] = {0};
    if (0 == func_get_work_path(buf, sizeof(buf))) /* 优先 WORK_PATH */
    {
        return std::string(buf) + "/";
    }
    if (0 != func_proc_self_dir(buf, sizeof(buf))) /* fallback 可执行文件目录 */
    {
        LOG_E("get_base_path failed");
        return "";
    }
    return std::string(buf) + "/";
}

9. 编译与构建

9.1 编译 RTU 可执行文件

# x86 本地编译
cd release && ./build.sh

# ARM 交叉编译RK3568
cd release && ./build.sh arm

9.2 产物

平台 路径 说明
x86 release/x86/exe/RTU ELF 64-bit x86-64, with debug_info
ARM release/arm/exe/RTU ELF 64-bit ARM aarch64, with debug_info

9.3 链接依赖

RTU 可执行文件链接以下库:

libmodbus_m  libmodbus  lib60870
libdatacenter  libxml  libcmd  libtask
liblog  libfunc  libmy_xxhash  libcJSON  libmd5  libcomm
libpthread  libstdc++

10. 依赖关系

10.1 依赖的库模块

模块 用途
liblog 日志输出
libfunc 文件操作、环境变量路径、字符串处理
libdatacenter 信号数据中心dc_init/dc_cleanup
libtask 事件机制、定时器、延迟
libcmd 命令行注册与交互
libcJSON app_config.json 解析
libmodbus 版本号显示
libmodbus_m Modbus 主站线程模块

10.2 被依赖

RTU 是最顶层模块,不被其他模块依赖。

10.3 模块间依赖图

┌─────────────────────────────────────────────────┐
│                     RTU                         │
│        (main.c + app_sys.cpp)                    │
│                                                  │
│  信号 → libtask (事件/定时器)                      │
│  日志 → liblog                                    │
│  配置 → libcJSON + libfunc (文件/路径)             │
│  命令 → libcmd (linenoise)                       │
└──────┬──────────────────────────────────────────┘
       │ app_modules.h X-Macro
       │
       ▼
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ libmodbus_m  │  │  libcom_decode│  │ libweb_server│
│ (已实现)     │  │  (预留)       │  │  (预留)       │
└──────┬───────┘  └──────────────┘  └──────────────┘
       │
       ▼
┌──────────────┐
│ libdatacenter│
│ libmodbus    │
│ lib60870     │
└──────────────┘

11. 命令行参考

命令 说明
help 显示所有已注册命令libcmd 内置)
version 显示固件版本 + libmodbus 版本
uptime 显示运行状态
modbus_m info 显示 Modbus 主站通道和点表信息
datacenter stat 显示数据中心统计libdatacenter 内置)

12. 变更历史

日期 版本 变更
2026-07-08 v3.0 配置文件独立化(config/ 目录)、添加 app_sys_stop()、代码风格统一
2026-07-08 v2.0 X-Macro 框架重构 + app_config.json 启停控制 + 三级定时器
2026-07-08 v1.0 原始运行时注册框架(app_modules.c + main.c