RTU_ALL_AI/SPEC.md

457 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# RTU_ALL_AI 模块功能规范(基于 RTU 原工程分析)
> 生成时间: 2026-07-07
> 原则: 每条功能点均来自 RTU 原工程对应模块的完整分析,不遗漏不编造
---
## 1. myBase.h
### 功能点
| 序号 | 功能 | 说明 |
|------|------|------|
| B01 | 颜色宏 | COLOR_RESET/RED/GREEN/YELLOW/BLUE/MAGENTA/CYAN/WHITE |
| B02 | 文件名缩写宏 | `__SHORT_FILE__` 去除路径前缀 |
| B03 | 基础日志宏 | `MY_LOG(color,level,fmt,...)` / `MY_LOG_I` / `MY_LOG_E` |
| B04 | LOCAL 宏 | `#define LOCAL static` |
| B05 | 字符串类型 | `S_STR[64]` / `L_STR[128]` |
| B06 | uint16 大小端转换 | `MY_GET/SET_SHORT_BIGEND/LITTLEEND` |
| B07 | int32 大小端转换 | `MY_GET/SET_INT_BIGEND/LITTLEEND` |
| B08 | uint64 大小端转换 | `MY_GET/SET_LONG_BIGEND/LITTLEEND` |
| B09 | 类型级存/取宏 | `MY_GET/SET_DATA_WITH_TYPE` |
| B10 | 数据类型常量 | DATA_TYPE_B/S8/U8/.../STR (22种) |
---
## 2. liblist 侵入式链表
### 功能点Linux 内核标准 list.h 精简版)
| 序号 | 功能 | API |
|------|------|------|
| L01 | 链表初始化 | `LIST_HEAD` / `INIT_LIST_HEAD` |
| L02 | 头插 | `list_add` |
| L03 | 尾插 | `list_add_tail` |
| L04 | 删除 | `list_del` / `list_del_init` |
| L05 | 移动 | `list_move` / `list_move_tail` |
| L06 | 替换 | `list_replace` / `list_replace_init` |
| L07 | 判空 | `list_empty` / `list_is_linked` |
| L08 | 节点→宿主转换 | `list_entry` |
| L09 | 取首/尾元素 | `list_first_entry` / `list_last_entry` / `list_first_entry_or_null` |
| L10 | 遍历(安全) | `list_for_each` / `list_for_each_entry` / `*_safe` |
| L11 | 拼接 | `list_splice_init` |
### 关键约束
- 纯头文件,无运行时依赖
- 所有 API 必须兼容 C 和 C++(变量名不用 `new`/`class``typeof`→`__typeof__`
---
## 3. liblog 异步日志系统
### 功能点636 行,完整复刻 RTU 原实现)
| 序号 | 功能 | 说明 |
|------|------|------|
| G01 | 异步日志线程 | `log_worker_thread` 独立线程处理日志写入 |
| G02 | 懒初始化 | `pthread_once` 实现首次调用自动初始化 |
| G03 | 消息池预分配 | `calloc(LOG_QUEUE_SIZE)` 预分配消息池,避免频繁 malloc/free |
| G04 | 消息池取还 | `get_message_from_pool` / `return_message_to_pool` |
| G05 | 队列满阻塞 | `pthread_cond_wait` 等待 not_full不丢弃日志 |
| G06 | 批量消费 | 一次最多取 `LOG_BATCH_SIZE`=100 条,批量写入 |
| G07 | 控制台输出 | 带颜色 ANSI 码输出 |
| G08 | 文件输出 | 带时间戳写入日志文件 |
| G09 | 文件自动创建 | `init_log_directory` 自动创建 logs/ 目录 |
| G10 | 文件按大小轮转 | 超过 10MB 自动轮转,保留 5 个历史文件 |
| G11 | 文件 setlinebuf | 行缓冲模式 |
| G12 | 时间戳格式化 | 精确到毫秒 `YYYY-MM-DD HH:MM:SS.mmm` |
| G13 | 文件信息格式化 | `文件名/函数名:行号` 格式 |
| G14 | LOG_I/LOG_E 宏 | 便捷宏 |
| G15 | 开关控制 | `log_set_file_enabled` / `log_set_console_enabled` |
| G16 | flush | 等待队列清空 |
| G17 | cleanup | 停止线程、关闭文件、释放消息池 |
### 程序运行流程
```
首次 log_prt() 调用
→ pthread_once → log_global_init
→ init_message_pool (预分配 LOG_QUEUE_SIZE 个消息结构)
→ logger.running = 1
→ pthread_create(&log_worker_thread)
每次 log_prt()
→ get_message_from_pool()
→ 填充 level/timestamp/file_info/content
→ enqueue_log()
→ 队列满则 pthread_cond_wait(&not_full) 阻塞等待
→ 尾插队列
→ pthread_cond_signal(&not_empty)
log_worker_thread 主循环
→ 批量取消息 (最多 LOG_BATCH_SIZE)
→ write_log_batch_array()
→ 控制台: printf 带颜色
→ 文件: fopen/fprintf, 超过 10MB 触发 rotate_log_files
→ return_message_to_pool() 归还每个消息
```
---
## 4. libfunc 基础工具函数
### 功能点1783 行,完整复刻 RTU 原实现)
#### 4.1 校验计算 (6 个函数)
| 序号 | 函数 | 说明 |
|------|------|------|
| F01 | `func_cal_sum_byte` | 8位校验和 |
| F02 | `func_cal_sum_word` | 16位校验和 |
| F03 | `func_cal_crc16` | CRC16(Modbus 多项式) |
| F04 | `func_cal_crc32` | CRC32(标准多项式) |
| F05 | `func_cal_file_crc16` | 文件 CRC16 (4K 缓冲区) |
| F06 | `func_cal_file_crc32` | 文件 CRC32 (4K 缓冲区) |
#### 4.2 字符串转换 (10 个函数)
| 序号 | 函数 | 说明 |
|------|------|------|
| F07 | `func_get_hex_from_ASCLL` | 单字符hex→数值 |
| F08 | `func_get_dec_from_ASCLL` | 单字符dec→数值 |
| F09 | `func_string_hex_to_dec` | hex字符串→int |
| F10 | `func_string_dec_to_dec` | dec字符串→int |
| F11 | `func_string_hex_to_buf` | hex字符串→字节缓冲 |
| F12 | `func_dec_to_string` | int→dec字符串(支持宽度填充) |
| F13 | `func_hex_to_string` | int→hex字符串(支持宽度填充) |
| F14 | `func_float_to_string` | float→字符串(支持宽度) |
| F15 | `func_buf_to_string` | 字节缓冲→hex字符串 |
| F16 | `func_string_to_argv` | 字符串→argc/argv分割 |
#### 4.3 时间处理 (6 个函数)
| 序号 | 函数 | 说明 |
|------|------|------|
| F17 | `func_sys_time_to_string` | 系统时间结构体→字符串 |
| F18 | `func_string_to_sys_time` | 字符串→系统时间结构体 |
| F19 | `func_get_time` | 获取系统时间(支持 sys/cal 两种) |
| F20 | `func_set_time` | 设置系统时间 |
| F21 | `func_time_sys_to_cal` | 系统时间→日历时间 |
| F22 | `func_time_cal_to_sys` | 日历时间→系统时间 |
#### 4.4 文件目录操作 (11 个函数)
| 序号 | 函数 | 说明 |
|------|------|------|
| F23 | `func_dir_exist` | 目录是否存在 |
| F24 | `func_make_dirs` | 创建目录(递归) |
| F25 | `func_del_dirs` | 删除目录(递归) |
| F26 | `func_del_dirs_by_cmd` | 删除目录(系统命令) |
| F27 | `func_file_exist` | 文件是否存在 |
| F28 | `func_get_file_size` | 获取文件大小 |
| F29 | `func_read_file_to_buf` | 读文件到预分配buf |
| F30 | `func_read_file_alloc_buf` | 读文件到动态分配buf |
| F31 | `func_write_buf_to_file` | 写buf到文件 |
| F32 | `func_read_file_tip_info` | 读结构体格式文件信息(含CRC校验) |
| F33 | `func_make_dir`(内部) | 内部单级目录创建 |
#### 4.5 进程管理 (9 个函数)
| 序号 | 函数 | 说明 |
|------|------|------|
| F34 | `func_get_process_self_name` | 获取本进程名 |
| F35 | `func_get_process_name_by_pid` | PID→进程名 |
| F36 | `func_get_process_pid` | 获取本进程PID |
| F37 | `func_get_process_pid_by_name` | 进程名→PID |
| F38 | `func_process_exist_by_name` | 按名判断进程存在 |
| F39 | `func_process_exist_by_pid` | 按PID判断进程存在 |
| F40 | `func_get_process_path_by_pid` | PID→进程路径 |
| F41 | `func_get_process_self_path` | 本进程路径 |
| F42 | `func_get_process_self_dir` | 本进程目录 |
#### 4.6 环境变量路径 (12 个函数)
| 序号 | 函数 | 说明 |
|------|------|------|
| F43 | `func_get_env_value`(内部) | 读环境变量 |
| F44 | `func_get_env_path`(内部) | 读环境变量路径 |
| F45 | `func_get_work_path` | WORK_PATH |
| F46 | `func_get_sys_cfg_path` | SYS_CFG_PATH |
| F47 | `func_get_app_root_path` | APP_ROOT_PATH |
| F48 | `func_get_his_root_path` | HIS_ROOT_PATH |
| F49 | `func_get_log_root_path` | LOG_ROOT_PATH |
| F50 | `func_get_dbc_root_path` | DBC_ROOT_PATH |
| F51 | `func_get_shell_path` | SHELL_PATH |
| F52 | `func_get_update_path` | UPDATE_PATH |
| F53 | `func_get_app_path` | 应用路径(拼接后) |
| F54 | `func_get_app_cfg_path` | 应用配置路径 |
| F55 | `func_get_app_his_path` | 应用历史路径 |
| F56 | `func_get_app_log_path` | 应用日志路径 |
#### 4.7 IPC 消息队列 (9 个函数)
| 序号 | 函数 | 说明 |
|------|------|------|
| F57 | `func_create_ipc_msg_queue_by_name` | 按名称创建 |
| F58 | `func_create_ipc_msg_queue_by_pid` | 按PID创建 |
| F59 | `func_get_ipc_msg_queue_by_name` | 按名称获取 |
| F60 | `func_get_ipc_msg_queue_by_pid` | 按PID获取 |
| F61 | `func_ipc_msg_send_buf` | 发送原始buf |
| F62 | `func_ipc_msg_recv_buf` | 接收原始buf |
| F63 | `func_ipc_msg_send_struct` | 发送结构体 |
| F64 | `func_ipc_msg_recv_struct` | 接收结构体 |
| F65 | `func_delete_ipc_msg_queue` | 删除队列 |
| — | `func_process_exist_by_name` | (见4.5) |
---
## 5. 构建系统
### 层次结构 (与 RTU 完全一致)
```
release/
makefile ← 顶层入口 (SUBDIRS=./src)
linux.mk ← 公共编译选项 (CC/CXX/AR, x86/arm切换)
build.sh ← 一键编译脚本
src/
makefile ← 第二层 (SUBDIRS=public protocol system)
public/
makefile ← 第三层 (SUBDIRS=liblist libfunc liblog ...)
liblist/makefile
libfunc/makefile
...
protocol/
makefile
system/
makefile
```
### linux.mk 关键变量
- `CC`/`CXX`/`LD`/`AR` — 工具链
- `CROSS=arm` 切换 ARM 交叉编译
- `ROOT_DIR`/`SRC_ROOT_DIR`/`REL_INC`/`LIB_REL`/`EXE_REL` — 路径
- `C_FLAGS`/`CXX_FLAGS` — 编译选项(.c 用 gcc.cpp 用 g++
---
## 6. 模块分类:自研 vs 开源/项目库
> **重要**:以下分类决定模块是"自主从零实现"还是"直接使用现有开源库"
### 6.1 自研模块(需要从零实现)
| 模块 | 位置 | 语言 | 说明 |
|------|------|------|------|
| `libmd5` | public/ | 纯C | RFC 1321 MD5 摘要,需自主实现 |
| `libtask` | public/ | C/C++ | 事件/定时器/消息队列综合调度框架 |
| `libdatacenter` | public/ | C++ | 信号数据中心signal_in/out/ao/yk/param |
| `libcmd` | public/ | C++ | 命令注册/分发/linenoise交互框架 |
| `libcomm` | public/ | C++ | TCP/UDP/UART 通讯抽象层 |
### 6.2 开源/项目库(不需要重写,直接使用)
| 模块 | 位置 | 来源 | 说明 |
|------|------|------|------|
| `libcJSON` | public/ | cJSON | JSON 解析/生成,开源 MIT 许可证 |
| `libmy_xxhash` | public/ | xxHash | 极速哈希BSD 2-Clause 许可证 |
| `libxml` | public/ | tinyxml2 | XML 解析Zlib 许可证 |
| `libmy_mosquitto` | public/ | mosquitto | MQTT 客户端 |
| `libmongoose` | protocol/ | mongoose | 嵌入式 HTTP/WebSocket |
| `libmodbus` | protocol/ | libmodbus | Modbus RTU/TCP 协议栈 |
| `lib60870` | protocol/ | lib60870 | IEC 60870-5-101/103/104 协议栈 |
---
## 7. libmd5 自研模块详细功能
### 功能点(来自 RTU 原工程 `md5.c` 分析)
| 序号 | 函数 | 说明 |
|------|------|------|
| M01 | `StartMD5(ctx)` | 初始化上下文:设置魔数 A=0x67452301 等 |
| M02 | `EncodeMD5(ctx, input, len)` | 输入待计算数据,分块处理 64 字节块 |
| M03 | `GetMD5(ctx, result)` | 获取 16 字节 MD5 摘要 |
| M04 | `GetMD5String(ctx, output, mode)` | 格式化 hex 字符串mode=0 大写, 1 小写) |
| M05 | `MD5Transform`(内部) | 4 轮 × 16 步的 MD5 核心变换 |
| M06 | `Encode`(内部) | uint32 数组 → LE 字节序列 |
| M07 | `Decode`(内部) | LE 字节序列 → uint32 数组 |
### 数据结构
```c
typedef struct {
uint32_t state[4]; /* A, B, C, D */
uint32_t count[2]; /* 位计数 (low, high) */
unsigned char buffer[64]; /* 待处理数据缓冲 */
} MD5_CTX;
```
---
## 8. libtask 自研模块详细功能
### 功能点(来自 RTU 原工程 `myTask.c` + `myTask.h` 分析)
#### 8.1 定时器子系统
| 序号 | 函数 | 说明 |
|------|------|------|
| T01 | `task_timer_create(name, cb, arg, timeout_ms, flags)` | 创建定时器, flags=单次/周期 |
| T02 | `task_timer_start(ptimer)` | 启动定时器 |
| T03 | `task_timer_stop(ptimer)` | 停止定时器 |
| T04 | `task_timer_restart(ptimer, timeout_ms)` | 重启定时器(修改周期) |
| T05 | `task_timer_destroy(ptimer)` | 销毁定时器 |
| T06 | `task_timer_is_active(ptimer)` | 查询是否运行中 |
| T07 | `timer_manager_thread`(内部) | 独立线程轮询所有定时器到期 |
#### 8.2 事件子系统
| 序号 | 函数 | 说明 |
|------|------|------|
| T08 | `task_event_create(name)` | 创建事件对象 |
| T09 | `task_event_destroy(pevent)` | 销毁事件对象 |
| T10 | `task_event_send(pevent, event)` | 发送事件位 |
| T11 | `task_event_recv(pevent, set, opt, timeout_ms, recved)` | 等待事件, opt=AND/OR |
| T12 | `task_event_clear(pevent, event)` | 清除事件位 |
| T13 | `task_event_query(pevent)` | 查询当前事件位 |
#### 8.3 消息队列子系统
| 序号 | 函数 | 说明 |
|------|------|------|
| T14 | `task_msg_queue_create(name, msg_size, msg_num)` | 创建定长消息队列 |
| T15 | `task_msg_queue_destroy(pqueue)` | 销毁消息队列 |
| T16 | `task_msg_queue_send(pqueue, msg, size)` | 发送消息(阻塞) |
| T17 | `task_msg_queue_send_timeout(pqueue, msg, size, timeout_ms)` | 发送消息(超时) |
| T18 | `task_msg_queue_recv(pqueue, msg, size, timeout_ms)` | 接收消息(超时) |
| T19 | `task_msg_queue_try_recv(pqueue, msg, size)` | 尝试接收(非阻塞) |
| T20 | `task_msg_queue_get_count(pqueue)` | 获取队列当前消息数 |
| T21 | `task_msg_queue_space(pqueue)` | 获取队列剩余空间 |
#### 8.4 程序运行流程
```
定时器: timer_manager_thread 每 10ms 轮询所有活跃定时器 → 到期则回调
事件: 内部位图 + pthread_cond, send 置位+唤醒, recv 等待+清零
消息队列: 环形缓冲区 + pthread_mutex + pthread_cond
```
---
## 9. libcmd 自研模块详细功能
### 功能点(来自 RTU 原工程 `myCmd.h` + `my_cmd.cpp` 分析)
| 序号 | 函数/宏 | 说明 |
|------|---------|------|
| C01 | `cmd_manager_add_command(name, func, desc, complete)` | 注册命令 |
| C02 | `cmd_manager_get_commands(out_count)` | 获取所有已注册命令列表 |
| C03 | `cmd_help(argc, argv)` | 打印帮助信息 |
| C04 | `cmd_find(name)` | 按名称查找命令 |
| C05 | `cmd_complete(buf, completions, ncomp)` | Tab 自动补全回调 |
| C06 | `cmd_sub_complete(buf, completions, ncomp, subs, sub_count)` | 子命令补全 |
| C07 | `linenoise(prompt)` | 行编辑+历史交互式输入 |
| C08 | `linenoiseFree(ptr)` | 释放 linenoise 返回的内存 |
| C09 | `linenoiseHistoryAdd(line)` | 添加历史记录 |
| C10 | `linenoiseHistoryFree()` | 释放历史 |
| C11 | `CMD_REGISTER(name, func, desc)` | 宏:注册无补全的命令 |
| C12 | `CMD_REGISTER_C(name, func, desc, complete)` | 宏:注册带补全的命令 |
### 数据结构
```c
typedef struct {
const char *name; /* 命令名 */
void (*func)(int argc, char *argv[]); /* 回调 */
const char *desc; /* 描述 */
void (*complete)(...); /* 补全回调 */
} stru_cmd;
```
### 程序运行流程
```
命令注册 → cmd_manager_add_command → 存入全局命令哈希表
交互式Shell → linenoise(提示符) → 用户输入 → 查找命令 → 回调执行
Tab补全 → cmd_complete/cmd_sub_complete → linenoiseSetCompletionCallback
```
---
## 10. libcomm 自研模块详细功能
### 功能点(来自 RTU 原工程 myComm.h + comm/*.cpp 分析)
| 序号 | 函数 | 说明 |
|------|------|------|
| N01 | `comm_create(type, debug, para)` | 创建通讯实例(TCP/UDP/UART) |
| N02 | `comm_connect(id)` | 建立连接 |
| N03 | `comm_disconnect(id)` | 断开连接 |
| N04 | `comm_send(id, fd, data, len)` | 发送数据 |
| N05 | `comm_recv_register(id, cb)` | 注册接收回调 |
| N06 | `comm_state_register(id, cb)` | 注册状态变化回调 |
| N07 | `comm_destroy(id)` | 销毁实例 |
### 通讯类型枚举
```c
COMM_TYPE_TCP_SERVER, COMM_TYPE_TCP_CLIENT,
COMM_TYPE_UDP_SERVER, COMM_TYPE_UDP_CLIENT,
COMM_TYPE_UART
```
### 参数结构体
```c
stru_tcp_para { local_ip, local_port, remote_ip, remote_port }
stru_udp_para { local_ip, local_port, remote_ip, remote_port }
stru_uart_para { device, baudrate, data_bits, stop_bits, parity }
```
### 程序运行流程
```
comm_create → 按类型创建 TCP/UDP/UART 实例 → 返回 id
comm_connect → TCP 三次握手 / UDP bind / UART open
comm_send → 投递到对应 fd
接收线程 → 读 fd → 调用 comm_recv_cb 回调
状态变化 → 调用 comm_state_cb 回调(CONNECTED/DISCONNECTED)
```
---
## 11. libdatacenter 自研模块详细功能
### 功能点(来自 RTU 原工程 myDatacenter.h + datacenter/*.cpp 分析)
#### 11.1 信号注册5 种信号类型)
| 序号 | 函数 | 说明 |
|------|------|------|
| D01 | `dc_signal_out(saddr, desc, data_type, p_data)` | 注册输出信号(遥测/遥信) |
| D02 | `dc_signal_out_with_callback(...)` | 输出信号+变化回调 |
| D03 | `dc_signal_in(saddr, desc, link_saddr, p_data)` | 注册输入信号(关联输出信号) |
| D04 | `dc_signal_in_with_callback(...)` | 输入信号+变化回调 |
| D05 | `dc_signal_ao(saddr, desc, data_type, ctrl_type, p_data, cb, mod)` | 注册模拟输出(遥控) |
| D06 | `dc_signal_param(saddr, desc, data_type, ctrl_type, p_data, num, cb, mod)` | 注册参数(定值) |
| D07 | `dc_signal_yk(saddr, desc, data_type, ctrl_type, p_data, cb, mod)` | 注册遥控信号 |
#### 11.2 信号控制
| 序号 | 函数 | 说明 |
|------|------|------|
| D08 | `dc_signal_ao_set_val(saddr, step, ctrl, p_data, mod)` | 设置 AO 值(SBO/直接) |
| D09 | `dc_signal_param_set_val(saddr, step, ctrl, zone, p_data, mod)` | 设置定值(带区号) |
| D10 | `dc_signal_yk_set_status(saddr, step, ctrl, p_data, mod)` | 设置遥控状态 |
#### 11.3 信号查询
| 序号 | 函数 | 说明 |
|------|------|------|
| D11 | `dc_get_out_signal_info(saddr, desc, data_type, p_data)` | 查询输出信号信息 |
| D12 | `dc_get_in_signal_info(...)` | 查询输入信号 |
| D13 | `dc_get_ao_signal_info(...)` | 查询 AO 信号 |
| D14 | `dc_get_param_signal_info(...)` | 查询参数信号 |
| D15 | `dc_get_yk_signal_info(...)` | 查询遥控信号 |
| D16 | `dc_get_signal_val(p_data, data_type)` | 信号值转字符串 |
| D17 | `dc_set_out_signal_val(saddr, set_data, mod)` | 设置输出信号值 |
| D18 | `dc_get_signal_count(type)` | 按类型统计信号数 |
#### 11.4 事件/扰动/故障队列
| 序号 | 函数 | 说明 |
|------|------|------|
| D19 | `dc_event_queue_push(soe)` | SOE 事件入队 |
| D20 | `dc_event_register_queue_pop(cb)` | 注册事件消费回调 |
| D21 | `dc_disturb_dd_queue_push(dd)` | 扰动数据入队 |
| D22 | `dc_disturb_dd_register_queue_pop(cb)` | 注册扰动消费回调 |
| D23 | `dc_fault_queue_push(fault)` | 故障数据入队 |
| D24 | `dc_fault_register_queue_pop(cb)` | 注册故障消费回调 |
#### 11.5 控制步骤枚举
```c
SIGNAL_CTRL_STEP { READY, SELECT, DIRECT, CANCEL } // SBO 控制步骤
SIGNAL_CTRL_TYPE { NONE, DIRECT_NORMAL, SBO_NORMAL } // 控制类型
```
### 源文件组成15 个 .cpp 文件)
```
datacenter.cpp dc_cfg_check.cpp dc_event.cpp
dc_param.cpp dc_signal.cpp dc_signal_compare.cpp
dc_signal_core.cpp dc_signal_ctrl.cpp dc_signal_find.cpp
dc_signal_query.cpp dc_signal_show.cpp dc_signal_util.cpp
```