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

s19.h

源文件路径:common/s19.h 所属模块:common(通用工具库) 代码行数:44

1. 文件职责

本文件是 common/s19.c 的对外接口头文件,定义 Motorola S-Record(.s19)固件文本的解析状态枚举 S19_FILE_PASRE_STATUS_E、解析结果结构体 S19_FILE_PASRE_PCK,并声明单行解析函数 parsing_upgrade_file()。它是 BMS 电池固件升级链路的解析层:EMS 从云端下载 .s19 固件文本、存入 SDRAM 后,由 midware/bms/alpha/battery_upgrade.c 的状态机逐行调用本接口,把每行拆成「数据地址 + 数据长度 + 数据内容」,再按 BMS 的 CAN 升级协议(send_addr_code/send_data_code)逐 8 字节下发。文件本身不含实现与状态,只提供类型与原型。

2. 关键数据结构与宏

名称类型说明
__S19_H__宏include guard
S19_DEBUG宏(= 0)调试打印总开关。置 1 后 s19.c 内所有 printf 才参与编译;生产版本为 0,printf 语句被条件编译整体移除
S19_FILE_PASRE_STATUS_E枚举(typedef 匿名枚举)解析结果状态集,从 0 起编号,共 9 个成员(名称里 PASRE 是 PARSE 的拼写错误,已固化到接口)
BUF_ADDR_ERR枚举成员(= 0)入参为空:file_addr == NULL 或 file_pack->u8_burn_data == NULL
S_ADDR_ERR枚举成员(= 1)在文本中找不到 'S',或记录类型不被支持(既不是 S0/S1/S2/S3,也不是结束记录 S7/S8/S9)
END_ADDR_ERR枚举成员(= 2)在文本中找不到换行符 '\n'(即这一行没有正常结束)
LEN_ERR枚举成员(= 3)sscanf 读长度失败,或长度字段与实际字符数不符
DATA_ERR枚举成员(= 4)数据域某个字节的 sscanf 解析失败
CHECK_SUM_ERR枚举成员(= 5)校验和字段读取失败或与计算值不匹配
HEAD_OK枚举成员(= 6)S0 头记录(公司/文件名等元信息)校验通过,不含烧写数据
PARSE_OK枚举成员(= 7)S1/S2/S3 数据记录校验通过,file_pack 已被填好
PARSE_END枚举成员(= 8)遇到 S7/S8/S9 结束记录,文件传输完毕
S19_FILE_PASRE_PCK结构体单行解析结果,字段见下(名称同样含 PASRE 拼写错误)
S19_FILE_PASRE_PCK.u8_s_addru8 *指向本行 'S' 字符的指针(指向 SDRAM 固件映像内部,不是拷贝)
S19_FILE_PASRE_PCK.u8_end_addru8 *指向本行结尾 '\n' 的指针,调用方用它算出下一行的偏移
S19_FILE_PASRE_PCK.u8_burn_datau8 *输入字段:调用方预先指向自己的接收缓冲(battery_upgrade.c 传的是 s_bat_upgrade_tab.u8_burn_data),解析成功时被写入本行数据
S19_FILE_PASRE_PCK.u8_burn_lenu8输出字段:本行有效数据字节数(S1 为 count-3,S2 为 count-4,S3 为 count-5)
S19_FILE_PASRE_PCK.u32_burn_addru32输出字段:本行的装载地址,按记录类型分别由 2/3/4 个地址字节拼成

本文件不定义位域,除 include guard 与 S19_DEBUG 外没有其它宏常量。注意 u8_burn_data 是唯一的「入参字段」,其余是出参。

3. 函数清单

函数名作用域说明
parsing_upgrade_file全局(原型声明,写为 extern u8)解析一行 S-Record 到 S19_FILE_PASRE_PCK,返回 S19_FILE_PASRE_STATUS_E 中的取值;定义于 s19.c:35

共 1 个原型声明(s19.h:41),对应 s19.c 中的唯一全局定义。本头文件无 static 函数、无函数指针、无回调。

4. 核心逻辑解析

本文件是纯声明文件,不含可执行逻辑。接口契约要点(实现细节见 s19.c.md):

4.1 返回值不是「状态」而是「本行类型 + 是否成功」的混合体

S19_FILE_PASRE_STATUS_E 把两类语义塞进同一个枚举:

类别成员值的分布
错误码(0~5)BUF_ADDR_ERR、S_ADDR_ERR、END_ADDR_ERR、LEN_ERR、DATA_ERR、CHECK_SUM_ERR0 ~ 5
成功码(6~8)HEAD_OK、PARSE_OK、PARSE_END6 ~ 8

函数返回 u8(而非枚举类型),调用方必须同时判断「是否 ≥ 6」与「具体是哪一种成功」。工程内 midware/bms/alpha/battery_upgrade.c 正是这么用的:l_u8_pasre_status == HEAD_OK(:641)→ 只推进偏移不烧写;== PARSE_OK(:646)→ 真正烧写本行;== PARSE_END(:711)→ 进入升级结束流程;其余(:716 的 else)→ u8_file_parse_cnt++,连续 3 次失败就 UPGRADE_INFO_INIT 重来。

4.2 指针字段与缓冲的所有权约定

4.3 记录类型与地址宽度的对应

记录类型地址字节数有效数据长度返回码
S0无(元信息)无HEAD_OK
S12count - 3PARSE_OK
S23count - 4PARSE_OK
S34count - 5PARSE_OK
S7/S8/S9——PARSE_END
S4/S5/S6 或其它——S_ADDR_ERR

(count 即记录里紧跟在 S+类型字符之后的那个长度字节,覆盖「地址 + 数据 + 校验和」三部分。)

4.4 通信协议 / 定时 / uCOS-II 配合

5. 对外接口

导出(供外部使用):

名称使用方
parsing_upgrade_file()midware/bms/alpha/battery_upgrade.c:635(在 SEND_UPGRADE_DATA 分支中每包调用一次)
S19_FILE_PASRE_PCKmidware/bms/alpha/battery_upgrade.c:555(S19_FILE_PASRE_PCK l_pasre_pck = {0};)
S19_FILE_PASRE_STATUS_E 成员(HEAD_OK/PARSE_OK/PARSE_END)midware/bms/alpha/battery_upgrade.c:641、:646、:711

被调用(本文件引用的外部符号):

名称来源
chip.hsystem/sys/chip.h(s19.h:13),提供 u8 / u16 / u32
stdio.hC 标准库(s19.h:14),供 s19.c 里被 #if S19_DEBUG 包住的 printf 使用
string.hC 标准库(s19.h:15),供 strstr / memset / memcpy 使用

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

6. 依赖关系

依赖:

被依赖(include 本头文件的文件):

7. 备注与风险点

  1. 枚举成员名与 common/hex_file_parse.h 冲突(高危):两个头文件的枚举都定义了 PARSE_OK、PARSE_END、DATA_ERR,且取值完全不同:
名称s19.hhex_file_parse.h
PARSE_OK70
PARSE_END82
DATA_ERR43

任何同时 include 两者的编译单元都会因枚举常量重定义而编译失败(或在不严格的编译器下产生静默的数值比较错误)。当前工程恰好没有这样的文件(s19.h 只被 battery_upgrade.c 使用),但两套「固件行解析器」的接口命名撞车是明确的隐患。

  1. PASRE 拼写错误已污染整个接口:S19_FILE_PASRE_STATUS_E 与 S19_FILE_PASRE_PCK 两个类型名把 PARSE 拼成了 PASRE,调用方 battery_upgrade.c:555 的变量名 l_pasre_pck 又跟着错了一遍。修正名称需要跨文件同步修改。
  2. extern u8 返回值与枚举不匹配:parsing_upgrade_file() 逻辑上返回 S19_FILE_PASRE_STATUS_E,但声明与定义都用 u8。调用方若把返回值赋给有符号变量或直接参与比较,编译器无法帮忙检查;同时 extern 写在头文件里是冗余的(函数声明默认就是外部链接)。
  3. 结构体三个「地址指针」字段类型与命名不一致:字段名用 u8 * 前缀却指向字符缓冲(u8_s_addr / u8_end_addr 实际是 char * 转换而来,见 s19.c:37~:38 与 s19.c:145~:146),命名暗示「8 位地址」而不是「8 位宽的类型别名 + 指针」,容易误读;u32_burn_addr 才是真正的地址值。
  4. u8_burn_len 是 u8:一行最多 252 字节数据,恰好放得下;但这也意味着无法表达超过 255 字节的行,接口没有注释说明这个上限,一旦将来改用长行 S19(例如 250+ 字节载荷)会静默截断。
  5. S19_DEBUG 是二进制开关:置 1 时会启用十余处 printf(s19.c:47~:409 之间的 #if S19_DEBUG 块),其中包含打印整行数据与每个字节的循环(s19.c:75~:80),在实时任务里会造成明显阻塞,只适合离线排查。
  6. stdio.h/string.h 由头文件包含:与工程内其它 common/ 头文件(crc.h 只 include chip.h、convert.h 只 include includes.h)风格不一致,且会扩大包含者的编译依赖面。
  7. 头文件说明不足:S19_FILE_PASRE_PCK 里哪个字段是入参(u8_burn_data)、哪些是出参、指针指向谁的内存、缓冲容量要求,都没有注释;结构体成员的注释(“开始地址/结束地址/数据/数据长度/数据地址”,s19.h:34~:38)只复述了字段名,没有提供上述关键约定。