122 lines
7.9 KiB
Markdown
122 lines
7.9 KiB
Markdown
# Project memory
|
||
_Durable project-level knowledge. Persists across all sessions in this project. Edit only content under italic instructions._
|
||
|
||
## Project context
|
||
_What is this project? What's its goal? High-level identity._
|
||
|
||
**RTU (Remote Terminal Unit)** — 基于 IEC 61850 的智能通信网关,用于电力系统自动化。
|
||
|
||
- **核心协议**: IEC 61850 MMS(服务端/客户端)、IEC 101/104(通过 ICP67 协议)
|
||
- **通信方式**: TCP/UART/UDP 多通道、MQTT(mosquitto)、WebSocket
|
||
- **数据模型**: 信号数据中心(遥测/遥信/遥控/遥调/参数),支持 XXH128 哈希索引
|
||
- **技术栈**: C/C++(GCC/Linux ARM 交叉编译)、Mongoose 嵌入式 Web 服务器、linenoise CLI
|
||
- **编译**: `./release/build.sh`(x86)或 `./release/build.sh arm`(ARM 交叉编译)
|
||
- **运行**: `./test/RTU`
|
||
|
||
### 模块架构
|
||
|
||
```
|
||
src/
|
||
├── system/RTU/ # 主程序入口、CLI、自点表配置、应用系统调度
|
||
├── system/libdatacenter/ # 数据中心(信号注册/变更检测/SBO控制/事件队列)
|
||
├── system/libcom_channel/ # 通信通道管理(TCP服务端/客户端、串口)
|
||
├── protocol/libmms_s/ # IEC 61850 MMS 服务端(ICD解析、模型创建、控制/定值/文件)
|
||
├── protocol/libmms_m/ # IEC 61850 MMS 客户端(总召/读写/报告订阅)
|
||
├── protocol/libicp67/ # ICP67 协议(IEC 101/104 帧编解码)
|
||
├── protocol/libmongoose/ # Mongoose HTTP/WebSocket 嵌入式服务器
|
||
├── public/libmy_mosquitto/ # MQTT 客户端库(mosquitto 2.x)
|
||
├── public/libcJSON/ # JSON 解析
|
||
└── public/libcomm/ # 统一通信抽象层(TCP/UART/UDP)
|
||
```
|
||
|
||
9 个应用线程: `app_sys`, `app_cmd`, `app_comm_channel`, `app_com_scan`, `app_iec`, `app_self_ptl`, `app_web_server`, `app_iec61850m`, `app_iec61850s`
|
||
|
||
## Rules
|
||
_Hard constraints from user that every session must respect._
|
||
|
||
### 工作流程规则
|
||
1. **对话语言**: 全程使用中文显示
|
||
2. **编译路径**: `./release/build.sh`(x86)或 `./release/build.sh arm`(ARM交叉编译)
|
||
3. **执行路径**: `./test/RTU`
|
||
4. **排查问题流程**: 先重新读取对应位置的源码,再对照问题或打印信息排查,不要依赖记忆中的旧代码
|
||
5. **问题记录**: 每次解决的问题都追加到 `claude/问题处理文档.md`
|
||
6. **文档目录**:
|
||
- `claude/mid/` — 存放中间文档、plan 文档
|
||
- `claude/工程/` — 存放按模块记录的项目工程文档
|
||
7. **每次读取项目工程时**: 把读到的东西按模块生成文档记录到 `claude/工程/` 文件夹
|
||
8. **解决问题的 plan**: 每次制定并执行 plan 解决问题后,将 plan 内容整理为文档存入 `claude/mid/` 目录
|
||
9. **Claude→Mimo 记忆转换规则** (2026-06-12, plan 1781250239159-brave-harbor):
|
||
- `.claude/memory/MEMORY.md` → Mimo `memory/projects/global/MEMORY.md`
|
||
- `.claude/memory/code-style.md` + `project-rules.md` → MEMORY.md §Rules
|
||
- `.claude/memory/user_language.md` → Mimo `memory/global/MEMORY.md`
|
||
- `claude/mid/*.md` → 提取核心知识 → MEMORY.md §Discovered durable knowledge
|
||
- `claude/工程/*.md` → 提取核心知识 → MEMORY.md §Architecture decisions
|
||
- 原始 claude 文件保留不动,仅新增 Mimo 记忆文件
|
||
|
||
### C/C++ 代码格式规范
|
||
- **缩进**: 使用 **Tab 字符**缩进(显示宽度 4),不使用空格缩进
|
||
- **括号风格**: Allman 风格 — 所有大括号独占一行(函数、if、for、while、struct),单条语句也保留大括号
|
||
- **空格**:
|
||
- 关键字与括号之间不加空格: `if(`, `for(`, `while(`, `switch(`
|
||
- 函数名与括号之间不加空格: `func(args)`
|
||
- 指针声明: `type *name`(`*` 前有空格,后无空格)
|
||
- 引用声明: `type &name`
|
||
- **Yoda 条件**: 常量写在比较运算符左侧,`if(NULL == ptr)` 而非 `if(ptr == NULL)`
|
||
- **空行**: 函数之间两行空行,逻辑块之间一行空行,`#include` 区块末尾一行空行
|
||
- **typedef struct**: 结构体成员无缩进额外层级(与 `{` 对齐)
|
||
- **命名约定**: 局部静态变量用 `LOCAL` 宏(= `static`),全局变量用 `g_` 前缀,结构体用 `stru_` 前缀,枚举用 `enum_` 前缀/`ENUM_` 值前缀
|
||
|
||
## Architecture decisions
|
||
_Major design choices with rationale. The "why" matters more than the "what" for future sessions._
|
||
|
||
### 1. 数据中心信号管理
|
||
`dc_signal.cpp` 使用 XXH128 哈希对信号快速索引(`signal_out`, `signal_in`, `signal_yk`, `signal_ao`, `signal_param` 五张表,每表独立互斥锁)。输出信号变更通过脏队列 + 去重 + 比对 + 回调实现增量推送(仅变更时发送),`last_caller_module` 防止同模块回调自循环。SBO(Select Before Operate)控制流程:SELECT 暂存值 → DIRECT 校验与 SELECT 值一致 → 写入信号。事件队列(扰动/SOE/故障)使用 swap 模式低锁竞争 pop。
|
||
|
||
### 2. 参数配置双文件机制
|
||
`param.xml` 为参数模板(min/max/step/unit/default),不随运行修改。`self_param.xml` 由 datacenter 在运行时自动生成,存储当前信号值。初始化时值优先级:self_param.xml > param.xml value > param.xml default。`dc_param_cfg_check` 每 1000ms 检测变更标志,将 Ao/Param 信号值序列化写入 self_param.xml。
|
||
|
||
### 3. WebSocket 多连接隔离
|
||
每个 WebSocket 连接拥有独立的信号资源 session(per-connection),连接建立时开辟、断开时释放。全局共享方案会导致一个客户端的 add/del 操作影响其他客户端。
|
||
|
||
### 4. MMS 客户端事件驱动模型
|
||
`mms_m.cpp` 使用事件队列 + 状态机模式,定时器驱动周期性操作(T0=120s all-call, T1=60s GI, T2=30s CO, T3=20s param)。RCB 订阅支持可配置化编号过滤。
|
||
|
||
### 5. IEC 61850 服务器模型
|
||
`mms_s_icd.cpp` 解析 SCL XML ICD 文件构建完整数据模型。`mms_s_model.cpp` 动态创建 IedModel(LD/LN/DO/SDO/DA 树)。定值组管理通过 SGCB + SG/SE 镜像 DA 实现编辑区/运行区隔离。
|
||
|
||
### 6. 通信通道统一抽象
|
||
`com_channel.cpp` 管理所有通信通道配置。`libcomm` 提供统一连接/发送/接收/断开接口,按类型分发到 TCP/UART/UDP 实现。ICP66 帧转换为 ICP67 格式。
|
||
|
||
### 7. MQTT 通信
|
||
使用自编译 mosquitto 2.x 客户端库(`libmy_mosquitto`),支持 MQTT v5 特性。
|
||
|
||
## Discovered durable knowledge
|
||
_Cross-task facts that survive across sessions. Promoted from session checkpoints' §7 when proven durable._
|
||
|
||
### 已修复的关键问题
|
||
|
||
#### #1 RCB 订阅编号可配置化(2026-06-10)
|
||
- **问题**: `mms_m_icd_report_init()` 硬编码只订阅编号 `"01"` 的 RCB
|
||
- **修复**: 新增 `mms_m_out_set_rcb_numbers()` API,支持逗号分隔的多编号和通配符 `"*"`
|
||
- **文件**: `myMms_m.h`, `mms_m.h`, `mms_m.cpp`, `iec61850m.cpp`
|
||
|
||
#### #2 libweb_server 多连接支持(2026-06-10)
|
||
- **问题**: 原 WebSocket 服务端仅支持单客户端,存在多线程竞态、悬空指针等 10 个缺陷
|
||
- **修复**: 改为多连接,每个连接独立信号资源 session,断开自动释放
|
||
- **文件**: `web_server.cpp`, `ws_method.h`, `ws_method.cpp`
|
||
|
||
#### #3 app_cmd CPU 108% 问题(2026-06-12)
|
||
- **根因**: `linenoiseEdit()` 中 `read()` 仅检查 `-1` 未处理 EOF(返回 0),非终端环境下形成死循环
|
||
- **修复**: 改为 `<= 0` 判断 + `enableRawMode()` 返回值检查 + `select()` 非阻塞方案
|
||
- **文件**: `my_cmd.cpp`, `app_cmd.cpp`
|
||
|
||
#### #4 Tab 命令补全前缀丢失(2026-06-12)
|
||
- **问题**: 子命令 Tab 补全时命令名前缀被覆盖(如 `datacenter param` 变 `param`)
|
||
- **修复**: Tab 键处理改为找到最后一个空格,只替换空格之后的当前词
|
||
- **文件**: `my_cmd.cpp`
|
||
|
||
#### #5 app_cmd 交互卡顿(2026-06-12)
|
||
- **问题**: select 非阻塞 + 100ms 定时器导致回车后回显有卡顿感
|
||
- **修复**: 改为简单阻塞循环 `while(1) { cmd_recv(); }`,linenoise 自管理终端模式
|
||
- **文件**: `app_cmd.cpp`
|