EMS 知识库
首页 / knowledge/代码解析/common/usmart

usmart.h

源文件路径:common/usmart/usmart.h 所属模块:common / usmart(串口调试交互组件) 代码行数:80

1. 文件职责

本文件是 USMART 串口调试组件的公共接口头文件,定义了该组件的两个核心结构体(函数注册表项 _m_usmart_nametab、设备实例 _m_usmart_dev)、一整套行为开关宏(MAX_FNAME_LEN / MAX_PARM / PARM_LEN / USMART_ENTIMX_SCAN / USMART_USE_WRFUNS)、错误码与显示类型常量,以及 9 个对外函数的原型。它处在 EMS 固件调试基础设施的接口层:common/usmart/usmart.c、common/usmart/usmart_str.c、midware/debug/shell_usmart.c 三方都依赖它来共享同一份结构体布局,usmart_dev 与 usmart_nametab[] 这两个单例则由 midware/debug/shell_usmart.c 按本文件的布局实例化。文件本身没有可执行代码、不定义变量、不参与任务调度;它被 DEBUG_SUMART(定义在 midware/debug/shell_usmart.h:13,值为 0)间接决定是否真正参与编译。注意 struct 定义与宏常量的组合决定了「参数打包进 parm[]」这一 ABI,任何字段顺序或 MAX_PARM / PARM_LEN 的改动都会同时影响三个 .c 文件。

2. 关键数据结构与宏

名称类型(结构体/枚举/宏/联合体)说明
__USMART_H宏(include guard)防重包含开关,usmart.h:9-10
MAX_FNAME_LEN宏usmart.h:17,值 30,函数名最大长度,注释要求「不小于最长函数名的长度」;用于 usmart.c 的 rfname / sfname / cmdname 栈数组
MAX_PARM宏usmart.h:18,值 10,单函数最大参数个数;注释明确「修改此参数,必须修改 usmart_exe 与之对应」——因为 usmart.c:350-390 是手写的 0~10 分支 switch
PARM_LEN宏usmart.h:19,值 200,所有参数合并后的总字节上限;注释提醒串口接收部分要与之对应
USMART_ENTIMX_SCAN宏usmart.h:22,值 1,声明「使用 TIM 定时中断扫描 SCAN 函数」;注释强调 runtime 统计功能必须置 1
USMART_USE_WRFUNS宏usmart.h:26,值 0,读写任意地址功能开关;控制 usmart.c:461 是否编译 read_addr / write_addr,也控制 shell_usmart.c:15 是否把它们注册进函数表
USMART_OK宏usmart.h:29,值 0,无错误
USMART_FUNCERR宏usmart.h:30,值 1,函数错误(命令词无法识别 / 括号不配对)
USMART_PARMERR宏usmart.h:31,值 2,参数错误(格式非法或实参比形参少)
USMART_PARMOVER宏usmart.h:32,值 3,参数溢出(实参个数超过 MAX_PARM)
USMART_NOFUNCFIND宏usmart.h:33,值 4,未在 usmart_nametab[] 中匹配到函数
SP_TYPE_DEC宏usmart.h:35,值 0,参数按十进制显示
SP_TYPE_HEX宏usmart.h:36,值 1,参数按十六进制显示
struct _m_usmart_nametab结构体usmart.h:39-43。字段:void* func(函数指针)、const u8* name(声明串,如 "void usmart_test(void)")。表项数组由 midware/debug/shell_usmart.c:14 定义
struct _m_usmart_dev结构体usmart.h:45-62。字段:funs(表指针)、init/cmd_rec/exe/scan 四个函数指针、fnum(函数数量)、pnum(本次调用的参数数量)、id(命中函数下标)、sptype(显示进制)、parmtype(u16 位图,bit i = 参数 i 是字符串)、plentbl[MAX_PARM](各参数长度前缀表)、parm[PARM_LEN](参数打包缓冲)、runtimeflag、runtime(0.1ms 为单位的耗时)
usmart_nametab[]全局变量(extern 声明)usmart.h:65,实际定义在 midware/debug/shell_usmart.c:14,本工程注册了 usmart_test、get_e_linker_sn、e_linker_protocol_support_state 三项
usmart_dev全局变量(extern 声明)usmart.h:66,实际定义在 midware/debug/shell_usmart.c:32,USMART 单例

文件内无枚举、无联合体定义。

3. 函数清单

本文件是头文件,不含函数定义,仅含 9 个函数原型声明:

函数名作用域(static/全局)说明(一句话)
usmart_init全局(声明,usmart.h:69)初始化 USMART:配置 TIMER3 时基与默认显示进制,prototype 参数为系统时钟
usmart_cmd_rec全局(声明,usmart.h:70)识别串口字符串中的函数名与参数,写入 usmart_dev.id / pnum,返回 USMART_* 错误码
usmart_exe全局(声明,usmart.h:71)执行已识别的函数并回显返回值与执行耗时
usmart_scan全局(声明,usmart.h:72)从 UART0 取异步接收数据并驱动「识别 → 执行」流程
read_addr全局(声明,usmart.h:73)按绝对地址读 32 位值,默认因 USMART_USE_WRFUNS==0 不编译
write_addr全局(声明,usmart.h:74)按绝对地址写 32 位值,默认因 USMART_USE_WRFUNS==0 不编译
usmart_get_runtime全局(声明,usmart.h:75)返回 TIMER3 折算后的函数执行耗时(单位 0.1ms)
usmart_reset_runtime全局(声明,usmart.h:76)把耗时计时归零并放宽计数周期
usmart_test全局(声明,usmart.h:77)调试自测函数,打印 TIMER3 的 CNT 与 ARR

实现于 usmart.c 但本文件未声明的符号(头文件与实现不同步):

usmart_str.h 中的 11 个字符串工具函数由 usmart.h:15 的 #include "usmart_str.h" 间接引入。

4. 核心逻辑解析

本文件无过程代码,其「逻辑」体现在结构体布局与宏共同约定的参数打包 ABI上,这是理解 usmart.c / usmart_str.c 的前提。

4.1 参数打包 ABI

struct _m_usmart_dev 用两个平行数组描述一次函数调用的实参:

这套布局有一个隐含约束:parmtype 的位宽(16)必须 ≥ MAX_PARM,且 plentbl 的元素数必须等于 MAX_PARM。usmart.h:18 的注释已经提醒「修改此参数必须修改 usmart_exe」,但没提 parmtype 的位宽限制。

4.2 状态变量的语义与生命周期

usmart_dev 是一份跨调用累积的状态,不是每帧重置:

4.3 宏开关的联动关系

宏影响面
USMART_ENTIMX_SCAN = 1声明「由 TIM 中断扫描」。在 usmart.c 里并没有引用该宏,中断入口是硬编码的 TIMER3_IRQHandler(usmart.c:35),所以置 0 也无法真正关掉中断扫描,只会关掉这份声明语义
USMART_USE_WRFUNS = 0同时控制 usmart.c:461(read_addr/write_addr 的定义)与 shell_usmart.c:15(函数表注册)。两处都依赖同一个宏,开关一致
PARM_LEN = 200决定 parm[] 容量,也决定 usmart_str.c:413 的 u8 tstr[PARM_LEN+1] 局部缓冲大小。而 usmart_scan 从 UART0 取数据用的却是固定 50 字节数组(usmart.c:415),两者不联动
MAX_FNAME_LEN = 30决定 usmart.c:140/285/286/322 四处栈数组大小,也是 usmart_get_cmdname(..., MAX_FNAME_LEN) 的截断阈值

4.4 与任务/调度的配合

本文件本身不创建任何 uCOS-II 对象,但它声明了 4 个函数指针槽位(init / cmd_rec / exe / scan,usmart.h:49-52),使 usmart_dev 成为一个「接口表」。shell_usmart.c:32-52 用它把 usmart_init / usmart_cmd_rec / usmart_exe / usmart_scan 绑成虚函数表;实际执行流中只有 usmart_dev.scan() 是被间接调用的(usmart.c:43 与 shell_usmart.c:task_usmart),cmd_rec 与 exe 则分别在 usmart.c:431、usmart.c:432 通过函数指针调用。这层间接调用在 uCOS-II 任务上下文中增加了少量开销,但对调试组件而言可接受。

5. 对外接口

导出(供外部调用)

符号类型使用者
MAX_FNAME_LEN / MAX_PARM / PARM_LEN / USMART_ENTIMX_SCAN / USMART_USE_WRFUNS宏common/usmart/usmart.c、common/usmart/usmart_str.c、midware/debug/shell_usmart.c
USMART_OK / USMART_FUNCERR / USMART_PARMERR / USMART_PARMOVER / USMART_NOFUNCFIND宏usmart.c(usmart.c:147,205,216,233,243,262,265,270,288,297,303,306,419,433,436,443-454 等)、usmart_str.c(usmart_str.c:259,269,419,433,438,448,451)
SP_TYPE_DEC / SP_TYPE_HEX宏usmart.c(usmart.c:210,238,340,343,394,397)
struct _m_usmart_nametab结构体类型midware/debug/shell_usmart.c:14 定义表数组
struct _m_usmart_dev结构体类型midware/debug/shell_usmart.c:32 定义 usmart_dev 实例
usmart_nametab[]全局变量(extern)usmart.c 通过 usmart_dev.funs 间接访问;shell_usmart.c:14 为唯一定义处
usmart_dev全局变量(extern)usmart.c(大量)、usmart_str.c(usmart_str.c:397,414,434-445)
usmart_init / usmart_cmd_rec / usmart_exe / usmart_scan / read_addr / write_addr / usmart_get_runtime / usmart_reset_runtime / usmart_test函数原型common/usmart/usmart.c 实现;midware/debug/shell_usmart.c 绑定/注册;common/usmart/usmart_str.c 调用 usmart_get_runtime 之外无直接引用
usmart_str.h 中 11 个字符串工具函数原型经 usmart.h:15 的 #include 传递

被本文件调用(外部依赖)

本文件唯一的外部依赖是 usmart_str.h(usmart.h:15 的 #include)。结构体与原型使用的 u8 / u16 / u32 类型由调用方通过 usmart_str.h → gd32f4xx.h / chip.h(usmart_str.h:14-15)间接获得。

6. 依赖关系

7. 备注与风险点

  1. 注释与实际定义位置不符:usmart.h:65-66 的注释写「在 usmart_config.c 里面定义」,但本工程中这两个符号实际定义在 midware/debug/shell_usmart.c:14 / shell_usmart.c:32,没有 usmart_config.c 这个文件。移植时留下的错误注释。
  2. usmart.h 未声明 usmart_sys_cmd_exe 与 sys_cmd_tab[]:二者在 common/usmart/usmart.c:121 / usmart.c:137 定义且未加 static,属「有实现无契约」的导出符号,存在与其他模块重名冲突的风险。
  3. parmtype 位宽与 MAX_PARM 未做静态断言:parmtype 是 u16(usmart.h:57),代码用 1<<n 置位(usmart_str.c:444)。若将来把 MAX_PARM 提高到 16 以上,移位会溢出且无编译期告警。
  4. MAX_PARM 的上限被 usmart_exe 硬编码:usmart.h:18 的注释已承认这一点——usmart.c:350-390 是手写的 0~10 分支 switch,改 MAX_PARM 必须同步改 usmart_exe,却没有任何机制强制两者一致;若只改宏,pnum == 10 的调用仍可工作但 11 个参数会静默不执行(switch 无 default)。
  5. PARM_LEN 与实际收包缓冲不联动:注释(usmart.h:19)要求「串口接收部分要与之对应(不小于 PARM_LEN)」,但收包侧 usmart.c:415 用的是固定 u8 data[50],远小于 200,注释给出的约束并未被满足。
  6. USMART_ENTIMX_SCAN 是失效开关:usmart.c 里没有任何地方引用它,扫描入口被硬编码为 TIMER3_IRQHandler(usmart.c:35)。把该宏置 0 不会关闭中断扫描,只会与注释产生矛盾。
  7. read_addr / write_addr 的原型无条件暴露:usmart.h:73-74 始终声明这两个危险函数,即便 USMART_USE_WRFUNS == 0 时不编译实现。某些编译器对「有声明无定义但无人引用」不会报错,但若被其他模块误引用会在链接期失败。该功能一旦开启即可任意改写寄存器/内存,属高危调试后门,务必保持关闭状态。
  8. 结构体字段无填充对齐说明:struct _m_usmart_dev 是全局单例,按本文件字段顺序静态初始化(shell_usmart.c:33-52),字段顺序或新增字段会静默改变初始化值的对应关系,且不会有类型检查帮忙。
  9. 其余:暂无。