docs: RTU 模块 + Mongoose API 参考文档

- docs/system/RTU/API-RTU.md: RTU 完整文档(531行)
  X-Macro 框架/启动流程/数据结构/新增模块指南
- docs/protocol/libmongoose/API-libmongoose.md: mongoose 文档(347行)
  HTTP/WebSocket/定时器 API + 集成约束
- docs/README.md: 新增 system/ + protocol/libmongoose 索引
- COMPLETION.md: 更新 RTU + mongoose 完成状态
This commit is contained in:
ypc 2026-07-08 17:36:15 +08:00
parent d1569c92bb
commit db1ee1e979
4 changed files with 916 additions and 2 deletions

View File

@ -41,7 +41,8 @@
| Modbus 主站管理 | `libmodbus_m`(原工程自研模块,导入+适配) | ✅ |
| 通讯通道解码 | `libcom_decode` | ⬜ |
| Web 管理服务 | `libweb_server` | ⬜ |
| 主程序入口 | `RTU`(系统模块框架 + app_modules.c + main.c | ✅ |
| Mongoose 网络库 | `libmongoose`(开源库 v7.22,导入+适配) | ✅ |
| 主程序入口 | `RTU`X-Macro 框架 + app_config.json 启停控制 + 独立 config/ 目录) | ✅ |
## 阶段 3系统集成

View File

@ -24,7 +24,20 @@
| libcmd | [API-libcmd.md](public/libcmd/API-libcmd.md) | C 接口+C++ 内部 | 命令注册/补全 + 内置 linenoise |
| libcomm | [API-libcomm.md](public/libcomm/API-libcomm.md) | C 接口+C++ 内部 | TCP/UDP/UART 通讯抽象层 |
### 通讯与协议库 (protocol/ — 阶段 2 计划)
### 通讯与协议库 (protocol/)
| 模块 | 文档 | 语言 | 说明 |
|------|------|------|------|
| libmodbus | [API-libmodbus.md](protocol/libmodbus/API-libmodbus.md) | C (开源库) | Modbus 协议栈 v3.1.12 |
| lib60870 | [API-lib60870.md](protocol/lib60870/API-lib60870.md) | C (自研) | IEC 60870-5-101/103/104 协议栈 |
| libmongoose | [API-libmongoose.md](protocol/libmongoose/API-libmongoose.md) | C (MIT 开源) | HTTP/WebSocket 嵌入式网络库 v7.22 |
### 系统模块 (system/)
| 模块 | 文档 | 语言 | 说明 |
|------|------|------|------|
| RTU | [API-RTU.md](system/RTU/API-RTU.md) | C + C++ | 主程序入口、X-Macro 框架、模块生命周期 |
| libmodbus_m | [API-libmodbus_m.md](system/libmodbus_m/API-libmodbus_m.md) | C++ | Modbus 主站管理(通道/点表/轮询/写入) |
```
┌──────────┐

View File

@ -0,0 +1,369 @@
# API-libmongoose — 嵌入式 HTTP/WebSocket 网络库
> 版本: v1.0
> 日期: 2026-07-08
> 来源: Mongoose v7.22 (MIT 许可https://github.com/cesanta/mongoose)
> 状态: ✅ 导入完成x86 + ARM 双平台编译通过(零警告)
---
## 1. 模块概述
libmongoose 是 Mongoose v7.22 开源库的封装模块。Mongoose 是一个**单文件、纯 C 实现的嵌入式网络库**,广泛用于 IoT 和嵌入式设备。本模块主要用于 RTU 的 Web 管理服务(`libweb_server`),提供 HTTP REST API 和 WebSocket 双向通信能力。
| 功能 | 说明 |
|------|------|
| HTTP 服务器 | 解析请求、路由匹配、JSON 响应,用于 REST API |
| WebSocket | 双向消息推送(实时遥测数据、告警通知) |
| 事件驱动 | 基于 epoll 的异步 IO单线程管理所有连接 |
| 定时器 | 毫秒级软定时器,无需额外线程 |
| 跨平台 | Linux / FreeRTOS / Zephyr / ESP32 等,本工程只用 Linux |
### 架构位置
```
libweb_server (system/) — REST API + WebSocket 管理
libmongoose (protocol/) — HTTP/WS 协议栈
Linux kernel socket + epoll
```
---
## 2. 文件结构
```
src/protocol/libmongoose/
├── inc/
│ ├── myMongoose.h # RTU 适配头(编译配置宏 + #include "mongoose.h"
│ └── mongoose.h # Mongoose v7.22 头文件5748 行,上游文件)
└── src/
└── mongoose.c # Mongoose v7.22 实现31786 行,上游文件)
release/
├── inc/
│ ├── myMongoose.h # 拷贝自 src供其他模块包含
│ └── mongoose.h # 拷贝自 src
└── x86/lib/
└── libmongoose.a # x86 编译产物462KB
└── arm/lib/
└── libmongoose.a # ARM 编译产物471KB
```
---
## 3. 编译配置
`myMongoose.h` 中定义以下宏(必须在 `#include "mongoose.h"` 之前):
| 宏 | 值 | 说明 |
|------|-----|------|
| `MG_ENABLE_LOG` | 1 | 启用内置日志printf 到 stderr |
| `MG_ENABLE_FILE` | 0 | 禁用文件系统RTU 不通过 mongoose 提供静态文件) |
| `MG_ENABLE_POSIX_FS` | 0 | 禁用 POSIX 文件 API |
| `MG_ENABLE_EPOLL` | 1 | 启用 epollLinux 高效 IO 多路复用) |
| `MG_ENABLE_POLL` | 1 | 启用 pollepoll 回退方案) |
| `MG_ENABLE_SOCKET` | 1 | 使用 Linux 内核 socket |
---
## 4. 核心数据结构
### 4.1 mg_mgr — 事件管理器
```c
struct mg_mgr
{
struct mg_connection *conns; /* 活动连接链表 */
struct mg_timer *timers; /* 定时器链表 */
// ... 内部字段
};
```
每个进程只需一个 `mg_mgr` 实例,管理所有连接和定时器。
### 4.2 mg_connection — 连接
```c
struct mg_connection
{
struct mg_connection *next; /* 链表指针 */
struct mg_mgr *mgr; /* 所属管理器 */
struct mg_addr peer; /* 对端地址 */
void *fd; /* socket 文件描述符 */
unsigned long id; /* 连接 ID */
unsigned is_websocket : 1; /* 是否为 WebSocket 连接 */
unsigned is_client : 1; /* 是否为客户端连接 */
// ...
};
```
### 4.3 事件类型
```c
enum
{
MG_EV_ERROR, /* 错误 */
MG_EV_OPEN, /* 连接建立(仅客户端出站连接) */
MG_EV_POLL, /* mg_mgr_poll() 每次迭代触发 */
MG_EV_RESOLVE, /* DNS 解析完成 */
MG_EV_CONNECT, /* TCP 连接完成 */
MG_EV_ACCEPT, /* TCP 新连接接受 */
MG_EV_TLS_HS, /* TLS 握手完成 */
MG_EV_READ, /* 数据可读 */
MG_EV_WRITE, /* 数据可写 */
MG_EV_CLOSE, /* 连接关闭 */
MG_EV_HTTP_MSG, /* HTTP 请求/响应解析完成 */
MG_EV_HTTP_CHUNK, /* HTTP 分块数据 */
MG_EV_WS_OPEN, /* WebSocket 握手完成 */
MG_EV_WS_MSG, /* WebSocket 消息到达 */
MG_EV_WS_CTL, /* WebSocket 控制帧 */
MG_EV_MQTT_CMD, /* MQTT 命令 */
MG_EV_MQTT_MSG, /* MQTT 消息 */
MG_EV_MQTT_OPEN, /* MQTT 连接建立 */
MG_EV_SNTP_TIME, /* SNTP 时间 */
MG_EV_USER, /* 用户自定义事件起点 */
};
```
---
## 5. 接口函数
### 5.1 生命周期
```c
/** 初始化事件管理器 */
void mg_mgr_init(struct mg_mgr *mgr);
/** 事件循环(每次调用处理一批事件,阻塞不超过 ms 毫秒) */
void mg_mgr_poll(struct mg_mgr *mgr, int ms);
/** 销毁事件管理器(关闭所有连接,释放所有内存) */
void mg_mgr_free(struct mg_mgr *mgr);
```
**典型用法**:
```c
struct mg_mgr mgr;
mg_mgr_init(&mgr);
/* 注册 HTTP/WS 监听 + 定时器 */
// ...
while (running)
{
mg_mgr_poll(&mgr, 50); /* 50ms 超时 */
}
mg_mgr_free(&mgr);
```
### 5.2 HTTP 服务器
```c
/** 创建 HTTP 监听连接 */
struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data);
/** 获取 HTTP 请求/响应消息 */
int mg_http_get_request_len(const unsigned char *buf, size_t buf_len);
struct mg_http_message *mg_http_parse(const char *buf, size_t len);
struct mg_http_message *mg_http_parse2(const char *buf, size_t len);
/** 响应辅助 */
void mg_http_reply(struct mg_connection *c, int status_code,
const char *headers, const char *body_fmt, ...);
void mg_http_serve_dir(struct mg_connection *c, struct mg_http_message *hm,
const char *root);
/** 路由匹配 */
bool mg_match(struct mg_str str, struct mg_str pattern, struct mg_str *caps);
bool mg_http_match_uri(const struct mg_http_message *hm, const char *pattern);
```
**REST API 示例**:
```c
static void fn(struct mg_connection *c, int ev, void *ev_data)
{
if (ev == MG_EV_HTTP_MSG)
{
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
if (mg_http_match_uri(hm, "/api/status"))
{
mg_http_reply(c, 200, "Content-Type: application/json\r\n",
"{\"status\":\"ok\"}");
}
}
}
mg_http_listen(&mgr, "http://0.0.0.0:8080", fn, NULL);
```
### 5.3 WebSocket
```c
/** 升级 HTTP 连接到 WebSocket */
void mg_ws_upgrade(struct mg_connection *c, struct mg_http_message *hm,
const char *fmt, ...);
/** 发送 WebSocket 消息 */
size_t mg_ws_send(struct mg_connection *c, const void *buf, size_t len, int op);
/** 格式化发送 WebSocket 消息 */
size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...);
/** 封装非 WS socket 为 WS 帧(用于代理) */
size_t mg_ws_wrap(struct mg_connection *c, size_t len, int op,
const void *buf, size_t buf_len);
/** 主动连接 WebSocket 服务器(客户端模式) */
struct mg_connection *mg_ws_connect(struct mg_mgr *mgr, const char *url,
mg_event_handler_t fn, void *fn_data,
const char *fmt, ...);
```
**WebSocket 帧操作码 (op)**:
```c
#define WEBSOCKET_OP_CONTINUE 0 /* 继续帧 */
#define WEBSOCKET_OP_TEXT 1 /* 文本消息 */
#define WEBSOCKET_OP_BINARY 2 /* 二进制消息 */
#define WEBSOCKET_OP_CLOSE 8 /* 关闭握手 */
#define WEBSOCKET_OP_PING 9 /* Ping */
#define WEBSOCKET_OP_PONG 10 /* Pong */
```
**WebSocket 服务端示例**:
```c
static void fn(struct mg_connection *c, int ev, void *ev_data)
{
if (ev == MG_EV_HTTP_MSG)
{
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
if (mg_match(hm->uri, mg_str("/ws"), NULL))
{
mg_ws_upgrade(c, hm, NULL);
}
}
else if (ev == MG_EV_WS_MSG)
{
struct mg_ws_message *wm = (struct mg_ws_message *)ev_data;
/* 回显消息 */
mg_ws_send(c, wm->data.buf, wm->data.len, WEBSOCKET_OP_TEXT);
}
}
```
### 5.4 定时器
```c
/** 添加一次性定时器 */
struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
unsigned flags, void (*fn)(void *), void *arg);
/** 定时器标志 */
#define MG_TIMER_REPEAT 1 /* 周期性定时器 */
#define MG_TIMER_RUN_NOW 2 /* 立即运行一次 */
```
### 5.5 通用收发
```c
/** 发送原始数据 */
bool mg_send(struct mg_connection *c, const void *buf, size_t len);
/** 格式化发送 */
size_t mg_printf(struct mg_connection *c, const char *fmt, ...);
size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap);
/** 关闭连接 */
void mg_close_conn(struct mg_connection *c);
```
---
## 6. 使用约束与注意事项
### 6.1 线程安全
- `mg_mgr_poll()` 必须在**单线程**中调用
- 如需要多线程,通过 `mg_wakeup()` 向事件循环投递消息
### 6.2 内存管理
- 所有通过 `mg_http_listen()` 创建的连接在 `mg_mgr_free()` 时自动关闭释放
- `mg_http_message` 中的 `hm->body`、`hm->query` 等字段为协议栈内部缓冲区,**不可手动 free**
### 6.3 与 RTU 的集成方式
- `libweb_server` 作为 RTU 的独立线程模块,在线程内创建自己的 `mg_mgr`
- 通过 X-Macro 框架的定时器触发 `mg_mgr_poll()`
- HTTP 路由中使用 `dc_get_signal_val()` 获取实时数据,`dc_set_out_signal_val()` 发布前端写入的数据
### 6.4 日志说明
mongoose 内部使用 `printf` 向 stderr 输出日志(`MG_ENABLE_LOG=1`)。在 RTU 装置上 stderr 通常重定向到 `/dev/null` 或 syslog。如需捕获 mongoose 日志,可定义 `MG_ENABLE_CUSTOM_LOG=1` 并提供自定义 `MG_LOG()` 宏。
---
## 7. 依赖关系
### 7.1 本模块依赖
- **无**mongoose 是纯 C、零依赖的单文件库直接使用 Linux socket API
### 7.2 依赖本模块的模块
| 模块 | 用途 |
|------|------|
| `libweb_server` (system/) | HTTP REST API + WebSocket 通信 |
### 7.3 模块依赖图
```
┌──────────────────┐
│ libweb_server │ (RTU 线程模块)
│ REST API + WS │
└────────┬─────────┘
│ myMongoose.h
┌──────────────────┐
│ libmongoose │ (纯 C 协议栈)
│ HTTP + WebSocket │
└────────┬─────────┘
Linux Socket API + epoll
```
---
## 8. 编译与构建
```bash
# 编译 libmongoose.a
cd release/src/protocol/libmongoose
make -f makefile all # x86
make -f makefile CROSS=arm all # ARM
# 参与全量构建
cd release && ./build.sh # x86
cd release && ./build.sh arm # ARM
```
---
## 9. 许可证
Mongoose 使用 **MIT 许可证**(商业友好)。完整许可文本见 `mongoose.h` 头部注释。
---
## 10. 参考链接
- [Mongoose 官方文档](https://mongoose.ws/documentation/)
- [Mongoose GitHub](https://github.com/cesanta/mongoose)
- [WebSocket RFC 6455](https://datatracker.ietf.org/doc/html/rfc6455)
- [HTTP/1.1 RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230)

531
docs/system/RTU/API-RTU.md Normal file
View File

@ -0,0 +1,531 @@
# 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](../../../src/system/inc/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 生成,无需手动定义:
```c
/* 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` 自动创建和管理。
```c
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 事件定义
```c
#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()
```c
int app_sys_init(void);
```
**功能**: 初始化所有 X-Macro 注册的模块。包括加载 `app_config.json`、执行各模块 init1/init2、创建事件 + 定时器 + 启动线程。
**参数**: 无
**返回值**:
| 值 | 说明 |
|----|------|
| 0 | 初始化成功 |
| -1 | 初始化失败(配置文件解析/模块 init/线程创建) |
**调用位置**: `main.c``dc_init()` 之后、主循环之前。
### 5.2 app_sys_stop()
```c
void app_sys_stop(void);
```
**功能**: 停止所有模块。先向每个模块发送 `EV_STOP` 信号通知其退出主循环,然后 `pthread_join` 等待所有线程安全退出。
**调用位置**: `main.c` 中收到 SIGINT/SIGTERM 或 `Ctrl+D` 后、`dc_cleanup()` 之前。
### 5.3 app_get_ptr()
```c
stru_app *app_get_ptr(uint32_t app_id);
```
**功能**: 根据模块 ID 获取 `stru_app` 指针。供模块内部或外部代码访问其他模块数据。
**参数**:
| 参数 | 说明 |
|------|------|
| app_id | 模块 ID`enum_app` 枚举值) |
**返回值**: 有效模块指针,超出范围返回 `NULL`
---
## 6. 配置文件
### 6.1 app_config.json
位置:`config/SYSTEM/app_config.json`
```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` 追加一行
```c
/* 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/` 下实现四个函数:
```c
/* 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` 中注册:
```makefile
SUBDIRS := ./new_module ./libmodbus_m ./RTU
```
### Step 4: 更新配置文件
`config/SYSTEM/app_config.json` 中添加模块条目:
```json
{"name": "app_new_module", "enable": true}
```
---
## 8. 模块编写规范
### 8.1 主循环模板
```c
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.cpp``get_base_path()`
```c
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 可执行文件
```bash
# 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` |