From 3bf70c5b6dcfe1ca9d9e461cb05478447c444dad Mon Sep 17 00:00:00 2001 From: ypc <15051963820@163.com> Date: Fri, 12 Jun 2026 15:24:58 +0800 Subject: [PATCH] =?UTF-8?q?<=E4=BF=AE=E6=94=B9>=201=E3=80=81=E8=B0=83?= =?UTF-8?q?=E6=95=B4claude=E7=9A=84=E9=83=A8=E5=88=86=E8=A7=84=E5=88=99?= =?UTF-8?q?=E8=AE=B0=E5=BF=86=E6=96=87=E4=BB=B6=EF=BC=9B2=E3=80=81?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=87=AA=E5=AE=9A=E4=B9=89=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E9=83=A8=E5=88=86=E7=BC=BA=E9=99=B7=EF=BC=8C=E6=97=A7=E7=89=88?= =?UTF-8?q?=E6=9C=ACcpu=E4=BD=BF=E7=94=A8=E7=8E=87=E8=B6=85=E9=AB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/memory/MEMORY.md | 3 + .claude/memory/code-style.md | 79 +++++++++++++++++++ .claude/memory/project-rules.md | 24 ++++++ .claude/memory/user_language.md | 10 +++ claude/mid/Tab命令补全功能.md | 82 +++++++++++++++++++ claude/mid/app_cmd_CPU108问题修复.md | 60 ++++++++++++++ claude/问题处理文档.md | 43 ++++++++++ release/inc/myCmd.h | 8 +- src/public/libcmd/src/my_cmd.cpp | 91 ++++++++++++++++++++-- src/system/RTU/src/app_cmd.cpp | 36 +++++---- src/system/libdatacenter/src/dc_signal.cpp | 8 +- src/system/libiec/src/iec.cpp | 25 +++++- src/system/libiec61850m/src/iec61850m.cpp | 8 +- src/system/libself_ptl/src/method.cpp | 7 +- 14 files changed, 456 insertions(+), 28 deletions(-) create mode 100644 .claude/memory/MEMORY.md create mode 100644 .claude/memory/code-style.md create mode 100644 .claude/memory/project-rules.md create mode 100644 .claude/memory/user_language.md create mode 100644 claude/mid/Tab命令补全功能.md create mode 100644 claude/mid/app_cmd_CPU108问题修复.md diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md new file mode 100644 index 0000000..b80da06 --- /dev/null +++ b/.claude/memory/MEMORY.md @@ -0,0 +1,3 @@ +- [user-language](user_language.md) — 用户要求所有对话和思考过程使用中文显示 +- [project-rules](project-rules.md) — 项目开发规范:编译/运行路径、排查流程、文档管理、plan归档到mid目录 +- [code-style](code-style.md) — C/C++代码格式规范:Tab缩进、Allman括号、Yoda条件、空行规则 diff --git a/.claude/memory/code-style.md b/.claude/memory/code-style.md new file mode 100644 index 0000000..2f05c97 --- /dev/null +++ b/.claude/memory/code-style.md @@ -0,0 +1,79 @@ +--- +name: code-style +description: 项目 C/C++ 代码格式规范 — 缩进、括号、空格、空行、条件写法 +metadata: + type: feedback +--- + +## 缩进 + +使用 **Tab 字符**缩进(显示宽度 4),不使用空格缩进。 + +## 括号风格(Allman 风格) + +所有大括号 **独占一行**,包括函数、if、for、while、struct: + +```cpp +LOCAL void check_sg_zone_change() +{ + if(g_sg_zone_saddr.empty()) + { + return; + } + + for(auto &setting : g_vec_setting) + { + if(strcmp(setting.base.saddr, zone_saddr) == 0) + { + break; + } + } +} +``` + +单条语句也保留大括号,不省略。 + +## 空格规则 + +- 关键字与括号之间 **不加空格**:`if(`, `for(`, `while(`, `switch(` +- 函数名与括号之间 **不加空格**:`func(args)` +- 指针声明:`type *name`(`*` 前有空格,后无空格) +- 引用声明:`type &name` + +## Yoda 条件 + +常量写在比较运算符左侧: + +```cpp +if(NULL == ptr) // ✓ 正确 +if(0 != ret) // ✓ 正确 +if(ptr == NULL) // ✗ 不符合项目风格 +``` + +## 空行 + +- 函数之间:两行空行 +- 逻辑块之间:一行空行 +- `#include` 区块末尾:一行空行 + +## typedef struct + +```cpp +typedef struct +{ + uint32_t field1; + uint8_t field2; +}stru_type_name; +``` + +结构体成员无缩进额外层级(与 `{` 对齐)。 + +## 变量声明 + +- 局部静态变量用 `LOCAL` 宏(= `static`) +- 全局变量用 `g_` 前缀 +- 结构体用 `stru_` 前缀 +- 枚举用 `enum_` 前缀,枚举值用 `ENUM_` 前缀 + +**Why:** 从项目中多个核心源文件(iec61850s.cpp、self_ptl.cpp、ws_method.cpp、dc_signal.cpp)提取的共识格式规范 +**How to apply:** 新增代码和修改现有代码时必须遵守此格式。本次仅统一缩进/括号/空格/空行,命名问题暂不处理。 diff --git a/.claude/memory/project-rules.md b/.claude/memory/project-rules.md new file mode 100644 index 0000000..4789f8c --- /dev/null +++ b/.claude/memory/project-rules.md @@ -0,0 +1,24 @@ +--- +name: project-rules +description: 项目开发规范 — 编译/运行路径、排查流程、文档管理、plan归档要求 +metadata: + node_type: memory + type: feedback + originSessionId: 5e65af11-b197-479e-a82f-c2e5b475a8c3 +--- + +## 核心规则 + +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/` 目录 + +**Why:** 用户明确要求的项目开发规范和工作流程 +**How to apply:** 每次操作前检查这些规则,特别是编译/运行路径和问题排查流程。问题解决后必须追加到问题处理文档,同时将 plan 归档到 mid 目录。 diff --git a/.claude/memory/user_language.md b/.claude/memory/user_language.md new file mode 100644 index 0000000..e1598f1 --- /dev/null +++ b/.claude/memory/user_language.md @@ -0,0 +1,10 @@ +--- +name: user-language +description: 用户要求所有对话、思考过程和中间输出均使用中文显示 +metadata: + node_type: memory + type: user + originSessionId: 5e65af11-b197-479e-a82f-c2e5b475a8c3 +--- + +用户要求所有对话内容、思考过程(thinking)、以及所有用户能看到的中间过程都使用中文显示。包括但不限于:回复内容、代码注释、任务列表、提交信息等。代码本身(变量名、函数名等)保持英文不变。 diff --git a/claude/mid/Tab命令补全功能.md b/claude/mid/Tab命令补全功能.md new file mode 100644 index 0000000..c9f53e9 --- /dev/null +++ b/claude/mid/Tab命令补全功能.md @@ -0,0 +1,82 @@ +# Tab 命令补全功能实现 + +## 日期 + +2026-06-12 + +## 概述 + +为 CLI 交互实现多级 Tab 命令补全:第一个词补全命令名,后续词根据命令上下文补全子功能。 + +## 实现内容 + +### 1. 数据结构扩展(myCmd.h) + +`stru_cmd` 增加 `complete` 回调字段: + +```c +typedef struct +{ + const char *name; + void (*func)(int argc, char *argv[]); + const char *desc; + void (*complete)(const char *buf, char ***completions, int *ncomp); +}stru_cmd; +``` + +`CMD_REGISTER` 宏改为支持可变参数,`cmd_manager_add_command` 增加默认参数 `complete = NULL`。 + +### 2. 上下文感知补全(my_cmd.cpp) + +`cmd_complete` 逻辑: +- 无空格 → 命令名前缀匹配(原行为) +- 有空格 → 提取第一个词查找命令,调用其 `complete` 回调获取子补全 + +`cmd_sub_complete` 辅助函数:给定子命令列表和前缀,返回匹配项。 + +### 3. 前缀保留修复(my_cmd.cpp) + +`linenoiseEdit` 中 Tab 键处理原本用补全结果**覆盖整行**,导致子命令补全时命令名前缀丢失。改为找到最后一个空格,只替换空格之后的当前词: + +```c +// 修复前:strncpy(buf, completions[0], ...); // 整行覆盖 +// 修复后: +char *last_space = strrchr_manual(buf, pos); +if (NULL != last_space) + strncpy(last_space + 1, completions[0], ...); // 只替换当前词 +else + strncpy(buf, completions[0], ...); // 第一个词仍覆盖整行 +``` + +### 4. 各模块子补全注册 + +| 命令 | 子命令 | +|------|--------| +| `datacenter` | `out`, `in`, `yk`, `ao`, `param`, `all` | +| `iec` | `run_cnt` | +| `iec61850m` | `info`, `yk`, `set` | +| `self_ptl` | `1`, `3`, `5`, `6`, `9`, `11` | + +### 5. 构建系统修复 + +[release/src/system/makefile](release/src/system/makefile) 中 8 个子模块 SUBDIRS 被注释导致增量编译失效,已取消注释。 + +## 影响文件 + +| 文件 | 改动 | +|------|------| +| [myCmd.h](release/inc/myCmd.h) | stru_cmd 增加 complete 字段;CMD_REGISTER 可变参数;cmd_sub_complete 声明 | +| [my_cmd.cpp](src/public/libcmd/src/my_cmd.cpp) | cmd_complete 上下文感知;cmd_sub_complete;Tab 替换前缀保留 | +| [dc_signal.cpp](src/system/libdatacenter/src/dc_signal.cpp) | datacenter 子补全 | +| [iec.cpp](src/system/libiec/src/iec.cpp) | iec 子补全 | +| [iec61850m.cpp](src/system/libiec61850m/src/iec61850m.cpp) | iec61850m 子补全 | +| [method.cpp](src/system/libself_ptl/src/method.cpp) | self_ptl 子补全 | +| [release/src/system/makefile](release/src/system/makefile) | 取消 SUBDIRS 注释 | + +## 使用效果 + +``` +cmd > d + Tab → datacenter +cmd > datacenter + p + Tab → datacenter param +cmd > iec + r + Tab → iec run_cnt +``` diff --git a/claude/mid/app_cmd_CPU108问题修复.md b/claude/mid/app_cmd_CPU108问题修复.md new file mode 100644 index 0000000..0cf85e7 --- /dev/null +++ b/claude/mid/app_cmd_CPU108问题修复.md @@ -0,0 +1,60 @@ +# app_cmd 线程 CPU 108% 问题修复 + +## 日期 + +2026-06-12 + +## 背景 + +`app_cmd` 线程是 CLI 命令行处理线程,属于 9 个应用线程之一。其主循环采用定时器驱动的事件模型(EV_TIMER1=10ms、EV_TIMER2=100ms、EV_TIMER3=1000ms)。原本 `cmd_recv()` 在 EV_TIMER1 中每次被调用,但该调用已被注释掉,原因是启用后 CPU 占用飙升至 108%。 + +## 根因 + +### 直接原因:`read()` 返回 EOF 未处理 + +`linenoiseEdit()`([my_cmd.cpp:107](src/public/libcmd/src/my_cmd.cpp#L107))中读取 stdin 的代码: + +```c +if (read(STDIN_FILENO, &c, 1) == -1) return -1; +``` + +只检查了 `-1`(错误),未处理返回 `0`(EOF)。当进程无真正控制终端时(RTU 嵌入式部署环境常见),stdin 处于 EOF 状态,`read()` 立即返回 0。代码不匹配 `-1`,继续执行,`c` 为未定义值,后落入 `buf[len++] = c` 分支,循环回 `read()` — 死循环,CPU 100%+。 + +### 架构层面问题 + +| 问题 | 说明 | +|------|------| +| 阻塞 I/O 在定时器线程中 | `linenoise()` 是同步阻塞调用,放在 10ms 定时器中导致线程被阻塞 | +| 无 stdin 就绪检查 | 没有用 `select()`/`poll()` 先检查 stdin 是否有数据 | +| 终端模式反复切换 | 每次 `linenoise()` 调用都 `tcgetattr`+`tcsetattr`,频率过高 | +| `tcsetattr` 返回值未检查 | `linenoise()` 中调用 `enableRawMode()` 未检查返回值 | + +### 定时器机制 + +定时器使用 POSIX `timer_create(CLOCK_REALTIME, SIGEV_THREAD, ...)`,每次超时内核创建新线程执行回调 → `task_event_send` → `pthread_cond_signal` 唤醒 app 线程。 + +## 修复内容 + +### 1. my_cmd.cpp — 修复 EOF 处理和返回值检查 + +- `read()` 返回值判断从 `== -1` 改为 `<= 0`,覆盖 EOF 场景 +- `linenoise()` 中检查 `enableRawMode()` 返回值,失败直接返回 NULL,避免在有问题的终端上执行读取循环 + +### 2. app_cmd.cpp — 重构为非阻塞模式 + +- 新增 `isatty(STDIN_FILENO)` 前置检查,非终端环境直接跳过 +- 用 `select()` 零超时检测 stdin 可读性,仅在数据就绪时才调用 `linenoise()` +- 从 EV_TIMER1(10ms)移至 EV_TIMER2(100ms),降低终端模式切换频率 + +## 验证 + +- 编译:零错误零警告 +- 测试:`./test/RTU < /dev/null` 运行 3 秒,CPU 占用 0.0%(修复前为 108%) + +## 影响文件 + +| 文件 | 改动 | +|------|------| +| [my_cmd.cpp](src/public/libcmd/src/my_cmd.cpp) | `read()` EOF 处理;`enableRawMode()` 返回值检查 | +| [app_cmd.cpp](src/system/RTU/src/app_cmd.cpp) | 非阻塞 `cmd_recv_nonblock()`;`isatty` + `select`;移至 EV_TIMER2 | +| [CLAUDE.md](CLAUDE.md) | 全文翻译为中文 | diff --git a/claude/问题处理文档.md b/claude/问题处理文档.md index c42da85..db56cf6 100644 --- a/claude/问题处理文档.md +++ b/claude/问题处理文档.md @@ -2,6 +2,49 @@ --- +## 2026-06-12 + +### #6 Tab 补全子命令前缀丢失 + +**问题**:输入 `datacenter ` + `p` + Tab 后,`datacenter ` 前缀被 `param` 覆盖,整行只剩 `param`。 + +**根因**:`linenoiseEdit` 中 Tab 键处理用 `strncpy(buf, completions[0])` 整行覆盖。 + +**修复**:改为找到最后一个空格,只替换空格之后的当前词,保留前缀。 + +--- + +### #5 app_cmd 交互卡顿与 Tab 补全失效 + +**问题**:上一轮将 `cmd_recv` 改为 select 非阻塞 + EV_TIMER2(100ms) 后: +1. 回车后 `cmd>` 回显不及时,有明显卡顿感 +2. 输入 `d` 后按 Tab,不会弹出命令补全 + +**根因**:`select()` 方案与 `linenoise()` 交互式行编辑器根本性不兼容——select 时终端处于规范模式(行缓冲),Tab 不是行终止符不会触发 select;100ms 定时器引入最多 100ms 延迟。 + +**修复**:将 `app_cmd` 线程从定时器事件驱动改为简单阻塞循环 `while(1) { cmd_recv(); }`。`linenoise()` 自管理终端模式切换和 Tab 补全,线程阻塞在 stdin 上零延迟响应。 + +**验证**:编译通过。 + +--- + +### #4 app_cmd 线程启用后 CPU 飙升至 108% + +**问题**:`app_cmd` 线程中 `cmd_recv()` 启用后,CPU 占用 108%,导致该入口被暂时屏蔽([app_cmd.cpp:117](src/system/RTU/src/app_cmd.cpp#L117) 被注释)。 + +**根因**: +1. **死循环层面**:`linenoiseEdit()`([my_cmd.cpp:107](src/public/libcmd/src/my_cmd.cpp#L107))中 `read()` 只检查了返回 `-1`,未处理返回 `0`(EOF)。当进程无真正控制终端时(RTU 嵌入式环境常见),`read()` 立即返回 0 形成死循环。 +2. **架构层面**:`linenoise()` 是同步阻塞调用,却被放在 10ms 定时器 EVI_TIMER1 中执行,与其他定时器事件循环模型不兼容。 + +**修复内容**: +1. `my_cmd.cpp`:`read()` 返回值判断改为 `<= 0`(含 EOF 处理);`enableRawMode()` 返回值在 `linenoise()` 中检查,失败直接返回 NULL +2. `app_cmd.cpp`:重构 `cmd_recv` 为 `cmd_recv_nonblock()`,用 `select()` 实现非阻塞 stdin 检查 + `isatty()` 过滤非终端环境,移至 EV_TIMER2(100ms)调用 +3. `CLAUDE.md`:全文翻译为中文 + +**验证**:编译通过(零错误零警告),`./test/RTU < /dev/null` 运行 3 秒 CPU 占用 0.0%。 + +--- + ## 2026-06-10 ### #1 libmms_m RCB 订阅编号硬编码 diff --git a/release/inc/myCmd.h b/release/inc/myCmd.h index 2b40e09..a14dbe9 100644 --- a/release/inc/myCmd.h +++ b/release/inc/myCmd.h @@ -7,15 +7,16 @@ typedef struct const char *name; void (*func)(int argc, char *argv[]); const char *desc; + void (*complete)(const char *buf, char ***completions, int *ncomp); }stru_cmd; -#define CMD_REGISTER(cmd_name, func_ptr, cmd_desc) \ +#define CMD_REGISTER(cmd_name, func_ptr, cmd_desc, ...) \ __attribute__((constructor)) static void register_##func_ptr(void) { \ - cmd_manager_add_command(cmd_name, func_ptr, cmd_desc); \ + cmd_manager_add_command(cmd_name, func_ptr, cmd_desc, ##__VA_ARGS__); \ } -void cmd_manager_add_command(const char *name, void (*func)(int argc, char *argv[]), const char *desc); +void cmd_manager_add_command(const char *name, void (*func)(int argc, char *argv[]), const char *desc, void (*complete)(const char *, char ***, int *) = NULL); stru_cmd *cmd_manager_get_commands(unsigned int *out_count); @@ -23,6 +24,7 @@ stru_cmd *cmd_manager_get_commands(unsigned int *out_count); void cmd_help(int argc, char *argv[]); stru_cmd *cmd_find(const char *name); void cmd_complete(const char *buf, char ***completions, int *ncomp); +void cmd_sub_complete(const char *buf, char ***completions, int *ncomp, const char **subs, int sub_count); char *linenoise(const char *prompt); diff --git a/src/public/libcmd/src/my_cmd.cpp b/src/public/libcmd/src/my_cmd.cpp index a50aeae..add01a3 100644 --- a/src/public/libcmd/src/my_cmd.cpp +++ b/src/public/libcmd/src/my_cmd.cpp @@ -22,7 +22,7 @@ static std::vector& get_cmd_list() return s_cmd_list; } -void cmd_manager_add_command(const char *name, void (*func)(int argc, char *argv[]), const char *desc) +void cmd_manager_add_command(const char *name, void (*func)(int argc, char *argv[]), const char *desc, void (*complete)(const char *, char ***, int *)) { if(NULL == name || NULL == func || NULL == desc) { @@ -34,6 +34,7 @@ void cmd_manager_add_command(const char *name, void (*func)(int argc, char *argv .name = name, .func = func, .desc = desc, + .complete = complete, }); } @@ -104,7 +105,8 @@ static int linenoiseEdit(char *buf, int bufsize, const char *prompt) { int history_idx = linenoiseHistoryLen; while (1) { - if (read(STDIN_FILENO, &c, 1) == -1) return -1; + ssize_t n = read(STDIN_FILENO, &c, 1); + if (n <= 0) return -1; if (c == '\n' || c == '\r') { buf[len] = 0; @@ -164,7 +166,28 @@ static int linenoiseEdit(char *buf, int bufsize, const char *prompt) { if (completionCallback) { completionCallback(buf, &completions, &ncomp); if (ncomp > 0) { - strncpy(buf, completions[0], bufsize - 1); + /* 找到最后一个空格,只替换当前词,保留前缀 */ + char *last_space = NULL; + for (int i = pos - 1; i >= 0; i--) + { + if (' ' == buf[i]) + { + last_space = &buf[i]; + break; + } + } + + if (NULL != last_space) + { + int keep_len = last_space - buf + 1; + strncpy(last_space + 1, completions[0], bufsize - keep_len - 1); + buf[bufsize - 1] = '\0'; + } + else + { + strncpy(buf, completions[0], bufsize - 1); + } + len = pos = strlen(buf); SAFE_WRITE(STDOUT_FILENO, "\r\033[K", 4); SAFE_WRITE(STDOUT_FILENO, prompt, strlen(prompt)); @@ -189,7 +212,7 @@ static int linenoiseEdit(char *buf, int bufsize, const char *prompt) { char *linenoise(const char *prompt) { char buf[1024]; - enableRawMode(); + if (enableRawMode() != 0) return NULL; int n = linenoiseEdit(buf, sizeof(buf), prompt); disableRawMode(); if (n <= 0) return NULL; @@ -236,9 +259,35 @@ stru_cmd *cmd_find(const char *name) void cmd_complete(const char *buf, char ***completions, int *ncomp) { + auto& s_cmd_list = get_cmd_list(); + + /* 判断是否有空格 —— 有空格则进入子命令补全 */ + const char *space = strchr(buf, ' '); + if(NULL != space) + { + size_t cmd_len = space - buf; + + for(auto &cmd : s_cmd_list) + { + if(0 == strncmp(cmd.name, buf, cmd_len) && '\0' == cmd.name[cmd_len]) + { + if(NULL != cmd.complete) + { + cmd.complete(buf, completions, ncomp); + return; + } + break; + } + } + + *ncomp = 0; + *completions = NULL; + return; + } + + /* 无空格:命令名前缀匹配(原有逻辑) */ int cnt = 0; char **c = NULL; - auto& s_cmd_list = get_cmd_list(); for(auto &cmd : s_cmd_list) { @@ -266,6 +315,38 @@ void cmd_complete(const char *buf, char ***completions, int *ncomp) } } +void cmd_sub_complete(const char *buf, char ***completions, int *ncomp, const char **subs, int sub_count) +{ + const char *prefix = strrchr(buf, ' '); + if(NULL == prefix) + { + *ncomp = 0; + *completions = NULL; + return; + } + prefix++; + + int cnt = 0; + char **c = NULL; + size_t prefix_len = strlen(prefix); + + for(int i = 0; i < sub_count; i++) + { + if(0 == strncmp(subs[i], prefix, prefix_len)) + { + if(NULL == c) + { + c = (char **)malloc(sizeof(char *) * (sub_count + 1)); + } + c[cnt] = strdup(subs[i]); + cnt++; + } + } + + *completions = c; + *ncomp = cnt; +} + void cmd_help(int argc, char *argv[]) { auto& s_cmd_list = get_cmd_list(); diff --git a/src/system/RTU/src/app_cmd.cpp b/src/system/RTU/src/app_cmd.cpp index e831df4..ab52f93 100644 --- a/src/system/RTU/src/app_cmd.cpp +++ b/src/system/RTU/src/app_cmd.cpp @@ -12,13 +12,18 @@ LOCAL void cmd_recv() { - char *line = linenoise("cmd > "); - if(line == NULL) + if(!isatty(STDIN_FILENO)) { return; } - if(strlen(line) == 0) + char *line = linenoise("cmd > "); + if(NULL == line) + { + return; + } + + if(0 == strlen(line)) { free(line); return; @@ -28,7 +33,7 @@ LOCAL void cmd_recv() char *orig_line = strdup(line); - if(orig_line == NULL) + if(NULL == orig_line) { free(line); return; @@ -37,13 +42,13 @@ LOCAL void cmd_recv() char *argv[MAX_ARGC]; int argc = 0; char *p = strtok(line, " \t"); - while(p != NULL && argc < MAX_ARGC) + while(NULL != p && argc < MAX_ARGC) { argv[argc++] = p; p = strtok(NULL, " \t"); } - if(argc == 0) + if(0 == argc) { free(orig_line); free(line); @@ -53,10 +58,10 @@ LOCAL void cmd_recv() stru_cmd *p_cmd = cmd_find(argv[0]); if(NULL == p_cmd) { - if(strcmp(argv[0], "cd") == 0) + if(0 == strcmp(argv[0], "cd")) { const char *path = (argc >= 2) ? argv[1] : getenv("HOME"); - if(path == NULL || chdir(path) != 0) + if(NULL == path || 0 != chdir(path)) { LOG_E("cd failed: %s", path ? path : "(null)"); } @@ -65,8 +70,7 @@ LOCAL void cmd_recv() return; } - // 如果不是内部命令,则尝试执行 Linux shell 命令 - if(system(orig_line) != 0) + if(0 != system(orig_line)) { LOG_E("shell command failed: %s", orig_line); } @@ -82,7 +86,7 @@ LOCAL void cmd_recv() int app_cmd_init1(void *arg) { - // lineniseSetCompletionCallback(cmd_complete); + lineniseSetCompletionCallback(cmd_complete); return 0; } @@ -106,15 +110,15 @@ void *app_cmd(void *arg) while(1) { - task_event_recv(p_app->p_event, - EV_TIMER1 | EV_TIMER2 | EV_TIMER3, - TASK_EVENT_FLAG_OR | TASK_EVENT_FLAG_CLEAR, - TASK_EVENT_WAIT_FOREVER, + task_event_recv(p_app->p_event, + EV_TIMER1 | EV_TIMER2 | EV_TIMER3, + TASK_EVENT_FLAG_OR | TASK_EVENT_FLAG_CLEAR, + TASK_EVENT_WAIT_FOREVER, &event); if(event & EV_TIMER1) { - // cmd_recv(); + cmd_recv(); } if(event & EV_TIMER2) diff --git a/src/system/libdatacenter/src/dc_signal.cpp b/src/system/libdatacenter/src/dc_signal.cpp index da3bcfb..139ff0a 100644 --- a/src/system/libdatacenter/src/dc_signal.cpp +++ b/src/system/libdatacenter/src/dc_signal.cpp @@ -2432,6 +2432,12 @@ LOCAL void cmd_dc(int argc, char *argv[]) } } -CMD_REGISTER("datacenter", cmd_dc, "数据中心的控制命令"); +LOCAL void cmd_dc_complete(const char *buf, char ***completions, int *ncomp) +{ + static const char *subs[] = {"out", "in", "yk", "ao", "param", "all"}; + cmd_sub_complete(buf, completions, ncomp, subs, sizeof(subs)/sizeof(subs[0])); +} + +CMD_REGISTER("datacenter", cmd_dc, "数据中心的控制命令", cmd_dc_complete); diff --git a/src/system/libiec/src/iec.cpp b/src/system/libiec/src/iec.cpp index 6d9b1b7..0110c7b 100644 --- a/src/system/libiec/src/iec.cpp +++ b/src/system/libiec/src/iec.cpp @@ -514,4 +514,27 @@ LOCAL void cmd_iec(int argc, char *argv[]) } } -CMD_REGISTER("iec", cmd_iec, "iec线程的控制命令"); \ No newline at end of file +LOCAL void cmd_iec_complete(const char *buf, char ***completions, int *ncomp) +{ + int spaces = 0; + for(const char *p = buf; *p; p++) + { + if(' ' == *p) + { + spaces++; + } + } + + if(1 == spaces) + { + static const char *subs[] = {"run_cnt"}; + cmd_sub_complete(buf, completions, ncomp, subs, sizeof(subs)/sizeof(subs[0])); + } + else if(2 == spaces) + { + static const char *subs[] = {"get", "reset"}; + cmd_sub_complete(buf, completions, ncomp, subs, sizeof(subs)/sizeof(subs[0])); + } +} + +CMD_REGISTER("iec", cmd_iec, "iec线程的控制命令", cmd_iec_complete); \ No newline at end of file diff --git a/src/system/libiec61850m/src/iec61850m.cpp b/src/system/libiec61850m/src/iec61850m.cpp index b0e7970..2ab3021 100644 --- a/src/system/libiec61850m/src/iec61850m.cpp +++ b/src/system/libiec61850m/src/iec61850m.cpp @@ -875,4 +875,10 @@ LOCAL void cmd_iec61850m(int argc, char *argv[]) } } -CMD_REGISTER(MODULE_IEC61850M, cmd_iec61850m, "iec61850客户端线程的控制命令"); \ No newline at end of file +LOCAL void cmd_iec61850m_complete(const char *buf, char ***completions, int *ncomp) +{ + static const char *subs[] = {"info", "yk", "set"}; + cmd_sub_complete(buf, completions, ncomp, subs, sizeof(subs)/sizeof(subs[0])); +} + +CMD_REGISTER(MODULE_IEC61850M, cmd_iec61850m, "iec61850客户端线程的控制命令", cmd_iec61850m_complete); \ No newline at end of file diff --git a/src/system/libself_ptl/src/method.cpp b/src/system/libself_ptl/src/method.cpp index 4fb2185..d0dbe8e 100644 --- a/src/system/libself_ptl/src/method.cpp +++ b/src/system/libself_ptl/src/method.cpp @@ -1207,8 +1207,13 @@ LOCAL void cmd_self_ptl(int argc, char *argv[]) } +LOCAL void cmd_self_ptl_complete(const char *buf, char ***completions, int *ncomp) +{ + static const char *subs[] = {"1", "3", "5", "6", "9", "11"}; + cmd_sub_complete(buf, completions, ncomp, subs, sizeof(subs)/sizeof(subs[0])); +} -CMD_REGISTER("self_ptl", cmd_self_ptl, "私有规约的控制命令"); +CMD_REGISTER("self_ptl", cmd_self_ptl, "私有规约的控制命令", cmd_self_ptl_complete);