EMS 知识库
首页 / knowledge/代码解析/midware/debug

shell_usmart.h

源文件路径:midware/debug/shell_usmart.h 所属模块:midware/debug(调试支撑 — USMART 串口命令行外壳) 代码行数:21

1. 文件职责

本文件是 USMART 调试外壳(源自正点原子的 usmart 组件)在本工程中的胶水头文件,只有两个作用:定义一个总开关宏 DEBUG_SUMART,并把 USMART 外壳任务的入口函数 task_usmart() 声明出来供外部创建任务使用。

它处在调试链路的启动环节:user/main.c 在 DEBUG_SUMART 为真时于 main.c:322 用 OSTaskCreateExt() 创建 task_usmart 任务(优先级 TASK_USMART_PRIO,任务名 "task_usmart_parse",栈 TASK_USMART_STK),该任务体在 midware/debug/shell_usmart.c:54 实现,循环里调 usmart_scan() 解析串口 0 收到的命令行。

它同时被另外两个 USMART 底层文件引用:common/usmart/usmart.c 与 common/usmart/usmart_str.c 都 include 本文件,并统一用 #if DEBUG_SUMART 包裹整份实现。因此本文件是"三份 USMART 源码 + main.c 任务创建"这四处共用的唯一开关与声明入口。

2. 关键数据结构与宏

名称类型说明
__SHELL_USMART_H宏头文件保护宏,防止重复 include(第 9-10 行定义,第 20 行 #endif)
DEBUG_SUMART宏值为 0(第 13 行)——本工程默认关闭 USMART。作为编译总开关,被 midware/debug/shell_usmart.c:6、common/usmart/usmart.c:27、common/usmart/usmart_str.c:24、user/main.c:50 与 user/main.c:321 共 5 处引用
task_usmart函数声明(全局)void task_usmart(void *p_arg);(第 18 行),USMART 外壳任务体,符合 uCOS-II 任务原型

本文件不定义任何结构体、枚举或联合体。USMART 表格结构 struct _m_usmart_nametab(common/usmart/usmart.h:39)、设备结构 struct _m_usmart_dev(common/usmart/usmart.h:45)定义在 common/usmart/usmart.h 中,命令表数组实例 usmart_nametab[]、设备实例 usmart_dev 定义在 midware/debug/shell_usmart.c:18、:36。

任务相关参数不在本文件内:TASK_USMART_PRIO(第 22 号优先级,注释标"任务间隔 100ms")与 TASK_USMART_STK_SIZE(512 字)定义在 UCOSII/uCOS-CONFIG/app_cfg.h:73、:100。

3. 函数清单

函数名作用域说明
task_usmart全局(本文件中仅为声明,定义在 midware/debug/shell_usmart.c:54)USMART 外壳任务:usmart_init(SystemCoreClock) 初始化后进入死循环,每轮 usmart_scan() 再 OSTimeDlyHMSM(0,0,0,100),即以 100 ms 周期轮询串口 0 的命令行

本文件自身没有任何函数定义,只有一个函数原型。

4. 核心逻辑解析

本文件是无逻辑的纯声明头,可讲的"逻辑"只有开关语义与编译期取舍。

4.1 DEBUG_SUMART 的编译期作用范围

DEBUG_SUMART 为 0 表示常量假,因此下面 5 处条件编译体全部不参与编译:

引用位置被裁掉的内容
midware/debug/shell_usmart.c:6整个文件体(usmart_nametab[]、usmart_dev、task_usmart() 定义)——即 shell_usmart.c 编译成空目标文件
common/usmart/usmart.c:27TIMER3_IRQHandler()、usmart_init()、usmart_scan() 等全部 USMART 内核实现
common/usmart/usmart_str.c:24usmart_strcmp()、usmart_strcopy() 等全部字符串工具
user/main.c:50OS_STK TASK_USMART_STK[TASK_USMART_STK_SIZE]; 任务栈数组——不占 RAM
user/main.c:321OSTaskCreateExt(task_usmart, ...) 与 OSTaskNameSet(...)——不创建任务

由此推出一个重要结论:关闭状态下 task_usmart 在整个工程中没有任何引用者,本文件的声明实际上处于"悬空但合法"的状态(声明未使用不会报错,只有定义了却未使用的 static 函数才会有告警)。反过来,若把 DEBUG_SUMART 改成 1,必须确认 midware/debug/shell_usmart.c、common/usmart/usmart.c、common/usmart/usmart_str.c 三份实现都存在且能通过编译,且 TASK_USMART_PRIO/TASK_USMART_STK_SIZE(在 UCOSII/uCOS-CONFIG/app_cfg.h:73、:100)与 main.c 中的 TASK_USMART_STK 声明能同时生效。

4.2 任务调度时序(启用时)

main() 启动阶段
   └─ OSTaskCreateExt(task_usmart, ..., TASK_USMART_PRIO, ...)      main.c:322
        └─ OSTaskNameSet(TASK_USMART_PRIO, "task_usmart_parse", ...) main.c:331
                                    │
                                    ▼
                      task_usmart(p_arg)                            shell_usmart.c:54
                        ├─ (void)p_arg;
                        ├─ usmart_init(SystemCoreClock);    // 传主频给 USMART 做延时换算
                        └─ for(;;) {
                               usmart_scan();               // 从 USART0 收命令、查表、执行
                               OSTimeDlyHMSM(0,0,0,100);    // 让出 100 ms
                           }

任务本身不持有信号量、不申请消息邮箱、不等待事件,是纯轮询式设计:usmart_scan() 内部按 usmart_dev 里配置的超时参数判断一条命令是否收齐,收齐后经 usmart_exe() 查 usmart_nametab[] 表并调用对应函数指针。任务优先级由 TASK_USMART_PRIO 决定,100 ms 的周期让出决定了它不会成为 CPU 时间的主要竞争者——这也是它作为"调试壳"可以常驻的代价。

4.3 关键全局变量的读写

变量位置本文件的关系
usmart_nametab[]shell_usmart.c:18可被调试调用的函数表:read_addr/write_addr(仅 USMART_USE_WRFUNS == 1 时;本工程 common/usmart/usmart.h:26 把它设为 0,故这两条未注册)、usmart_test(usmart.h:77)、get_e_linker_sn、e_linker_protocol_support_state —— 其中后两个来自无线模块(e_linker_wifi.h),说明这套调试壳在本工程里的实用价值主要是"现场读 W5500 无线模组序列号与协议支持状态"
usmart_devshell_usmart.c:36关联函数指针(usmart_init/usmart_cmd_rec/usmart_exe/usmart_scan,声明于 common/usmart/usmart.h:69-72)、函数条目数、显示进制(1 = 十六进制)、参数缓冲(parm[PARM_LEN],usmart.h:19 定义 PARM_LEN = 200)与索引
SystemCoreClocksystem/(CMSIS 提供)task_usmart 用它做 USMART 的延时/超时基准
TASK_USMART_PRIO / TASK_USMART_STK_SIZEUCOSII/uCOS-CONFIG/app_cfg.h:73、:100任务创建参数(22 号优先级、512 字栈)
TASK_USMART_STKuser/main.c:50任务栈数组,由 DEBUG_SUMART 门控

5. 对外接口

本文件导出

导出项供谁使用
宏 DEBUG_SUMARTmidware/debug/shell_usmart.c:6、common/usmart/usmart.c:27、common/usmart/usmart_str.c:24、user/main.c:50、user/main.c:321 —— 共 5 处 #if 门控
函数声明 void task_usmart(void *p_arg);user/main.c:322 的 OSTaskCreateExt(task_usmart, ...)(仅当 DEBUG_SUMART 为真时编译)

本文件不导出任何全局变量。

本文件(间接)依赖的外部符号

shell_usmart.h 本身不 include 任何东西(第 9-20 行之间没有任何 #include),因此它不引入任何外部依赖;真正的依赖都在引用它的 .c 文件里:shell_usmart.c 依赖 common/usmart/usmart.h(usmart_init/usmart_cmd_rec/usmart_exe/usmart_scan、usmart_dev/usmart_nametab 的 extern 声明、USMART_USE_WRFUNS)、user/main.h(任务优先级与栈长的再导出)、midware/ethernt/wireless/e_linker_wifi.h(get_e_linker_sn、e_linker_protocol_support_state)。

6. 依赖关系

依赖

无。本文件是一个零 include 的自包含头(仅用 #ifndef/#define/#endif 保护与一条函数原型),这是它与同目录 debug.h、ate.h 等头文件最大的区别——那些头会链式引入 includes.h。

被依赖(4 个文件)

三者构成"声明(本文件)+ 内核(common/usmart/)+ 应用绑定(midware/debug/)+ 任务创建(user/main.c)"的四层结构。common/usmart 属于通用工具库,midware/debug 属于调试支撑,两边靠本文件解耦:common/usmart 不依赖 midware/debug 的任何实现,只依赖这一个宏与一条声明。

7. 备注与风险点

  1. 文件头 @brief 与 @version/@date 全为空(shell_usmart.h:5-6):只有文件名与作者,没有任何版本、日期或职责描述。对比同目录 debug.h、ate.h 都有基本说明,本文件在"这个宏干什么用"上没有留下任何线索——只能靠 5 处引用点反推。
  1. 开关宏放在头文件里且值为 0(shell_usmart.h:13):这带来一个容易被忽视的后果——DEBUG_SUMART 是"全局常量 0",因此 #if DEBUG_SUMART 保护下的代码永远不会被编译器语法检查。也就是说 shell_usmart.c、usmart.c、usmart_str.c 三份实现长期处于"未编译状态",一旦有人把宏改成 1,很可能直接编译不过(例如它们引用的 usmart_test()、USMART_USE_WRFUNS、PARM_LEN 等符号若已从 usmart.h 中移除,只有到那时才会暴露)。这是典型的"调试开关腐化"风险,建议定期以 DEBUG_SUMART=1 做一次编译验证。
  1. DEBUG_SUMART 命名与 DEBUG_* 家族不一致:同目录下 shell_usmart.c 用的是 DEBUG_SUMART,而 evc_upgrade.h 用 DEBUG_EVC_UPGRADE、evc_ii.h 用 DEBUG_EVC_II,evc.h/evc_ii.h 用 (x == 1) 形式判别。本工程对"调试开关"没有统一约定,本文件是"裸宏 + #if"这一种。
  1. task_usmart 的字面命名与任务名不符:main.c:331 把任务命名为 "task_usmart_parse",而函数名是 task_usmart。uCOS-II 的 OSTaskNameSet() 只影响 OSTaskNameGet() 与调试工具显示,不影响功能,但检索日志时会误导。
  1. 本文件没有 extern "C" 保护:工程是纯 C(Keil MDK),无影响;若将来有 C++ 单元参与链接,这条原型会被名字修饰,故记录为潜在约束。
  1. task_usmart 未在本文件中声明为 static/extern:原型默认是 extern。配合第 2 点,当 DEBUG_SUMART == 0 时 shell_usmart.c 不提供该符号,链接期不会有任何提示(因为没有引用者)。这属于"声明与定义同时被开关裁掉"的安全情形,但如果 main.c 的 #if 被误写(例如只包了任务创建、没包栈数组),就会出现"栈溢出/未定义符号"这类连锁问题——第 4.1 节表格中标出的 5 处必须同时修改。