set_upgrade_s5.c
senergys5_fill_dsp_upgrade_data,:384-416)4.4 块循环的终止条件4.5 收尾与版本回读(SENERGYS5_UPGRADE_END,:670-717)4.6 与 uCOS-II 任务/时序的配合4.7 关键全局变量的读写关系5. 对外接口5.1 本文件导出5.2 本文件调用或引用的外部符号6. 依赖关系7. 备注与风险点源文件路径:
midware/inverter/set/set_upgrade_s5.c所属模块:midware/inverter/set(盛能杰 S5 / S5-II / M10 逆变器通信) 代码行数:727
1. 文件职责
本文件实现盛能杰 Smile5 系列(SUB_S5 / SUB_S5_II / SUB_M10)逆变器主控 DSP、从机 DSP 与 DCDC(ARM) 模块的串口 Bootloader 固件升级。它处在"云端下发固件 → UART2 逐块搬进 SDRAM(g_u8_fw_sdram1/2)→ 本文件通过 UART2 把固件写入逆变器"这条链路的末端,是整个过程唯一真正与逆变器 Bootloader 对话的代码。
它由 midware/inverter/inverter.c:1090 的 task_inverter(uCOS-II 任务,周期 80 ms,inverter.c:1188)→ set_comm_usart_s5.c:6199 的 senergys5_inverter_comm() 周期调用:一旦发现固件已下载完成就把正常遥测通信让位给升级流程。状态机的每一次进入只推进"一步"(发一帧或发一个 2 KB 数据块),靠 s_senergys5_upgrade_info.upgrade_status 在多次调用之间保持进度。
进度与标志通过 inverter.c 的 inverter_read_upgrade_flag_* / inverter_read_upgrade_percent_* 聚合后上报云端与 HMI(inverter.c:3812/3847/3882/3917/3976/4003)。
2. 关键数据结构与宏
2.1 本文件定义/持有的对象
| 名称 | 类型 | 说明 |
|---|---|---|
s_senergys5_upgrade_info | 全局结构体变量(SENERGYS5_UPGRADE_INFO_T,__attribute__((at(SDRAM_SENERGYS5_UPGRADE_INFO_ADDR))),:25) | 升级上下文,被强制定位到 SDRAM 固定地址(hardware/sdram/sdram.h:67 标注 Len:3k)。上电不清零、跨软复位保留,是本文件唯一的状态载体 |
s_temp_buf[4] | static u8 数组(:27) | 每块的 4 字节累加校验和暂存区(大端)。非持久化,掉电即失 |
senergys5_query_inv_update_versions_info | extern 函数声明(:28) | 冗余声明:set_comm_usart_s5.h:829 已有同签名声明;定义在 set_comm_usart_s5.c:1949,升级结束后回读主机版本寄存器 |
SENERGYS5_UPGRADE_INFO_T | 结构体(#pragma pack(1),定义于 set_upgrade_s5.h:45-62) | 升级上下文字段表(对象/状态/地址/偏移/长度/块计数/校验和/2048 字节数据缓冲/u8_set_dcdc_upgrade_on_flag),详见 set_upgrade_s5.h.md |
SENERGYS5_UPGRADE_STATUS_E | 枚举(set_upgrade_s5.h:34-41) | 状态机五态:ENTER_BOOT=0、SHAKE_HANDS、SEND_FILE_PROPERTIES、SEND_UPGRADE_FILE、UPGRADE_END |
SENERGYS5_UPGRADE_OBJECT_E | 枚举(set_upgrade_s5.h:26-32) | 升级对象:NONE=0、MASTER=1、SLAVE、DCDC |
2.2 本文件主要使用的宏
| 名称 | 类型 | 说明 |
|---|---|---|
SENERGYS5_UPGRADE_DEBUG | 宏 0(set_upgrade_s5.h:15) | 全文件 printf 总开关,量产关闭 |
SENERGYS5_INV_REPLY_CODE | 宏 0xA5 | Bootloader 通用应答码;握手/块长度/块校验和/文件属性四个阶段都等它 |
SENERGYS5_INV_REPLY_CODE1 | 宏 0x55 | 本文件不使用(仅被 set_comm_usart_s5.c:428 用于通信探测) |
SENERGYS5_INV_BLOCK_SIZE | 宏 2048 | 每块数据字节数,同时是 u8_upgrade_buf 容量与每轮循环的偏移步长 |
SENERGYS5_ADDR_INV_UPADTE_VERSIONS_INFO | 宏 0x1A1C | 升级后回读版本的寄存器起始地址 |
SENERGYS5_NUM_INV_UPADTE_VERSIONS_INFO | 宏 0x0D | 回读寄存器个数 13(应答 26 字节) |
SDRAM_SENERGYS5_UPGRADE_INFO_ADDR | 宏(hardware/sdram/sdram.h:67) | 升级上下文的固定 SDRAM 地址 |
UPDT_INV1 / UPDT_INV2 / UPDT_INV3 | 枚举值(net/server.h:190-192,ENUpdateType,值为 2/3/4) | 分别对应主机固件、从机固件、ARM(DCDC) 固件 |
SUB_S5_II / SUB_M10 | 枚举值(midware/inverter/inverter.h:332-333) | 决定数据块前是否追加 2 字节长度命令 |
2.3 逆向出的协议字段(本文件以内联常量形式写死,无宏)
| 名称 | 值 | 说明 |
|---|---|---|
| ENTER_BOOT 命令头 | 0x01 0xA0 | u8_upgrade_buf[0..1] |
| ENTER_BOOT 对象码 | 0x01(主机) / 0x02(从机) / 0x05(DCDC) | u8_upgrade_buf[2] |
| ENTER_BOOT 固定引导字 | 0x33 0x77 0x99 | u8_upgrade_buf[3..5],三对象一致 |
| ENTER_BOOT 口令对 | 0x97 0xBA(主机) / 0x97 0xFE(从机) / 0x96 0x8A(DCDC) | u8_upgrade_buf[6..7],随对象变化 |
| 期望应答码 | 0x55(主机) / 0x56(从机) / 0x62(DCDC) | 存在 u8_upgrade_buf[8],不进 ENTER_BOOT 帧,在 SHAKE_HANDS 阶段单独发出 |
| 块长度命令 | 0x08 0x00 | 大端 0x0800=2048,仅 S5-II / M10 发送 |
3. 函数清单
| 函数名 | 作用域 | 说明 |
|---|---|---|
senergys5_data_recv_flag(void) | static(:43) | 转发 usart2_is_recv_async_data(),判断 UART2 异步接收缓冲是否有字节 |
senergys5_send_data(u8 *data_buf, u16 data_len, u16 timeout) | static(:63) | 先清 UART2 接收缓冲再发数据,避免上一帧残留回显污染本次应答判断 |
senergys5_upgrade_send_mdsp(const u8 *upgrade_buf, const u16 upgrade_len) | static(:83) | 升级专用发送封装,固定 4000 ms 超时,调试模式下逐字节打印 |
senergys5_upgrade_recv_mdsp(const u8 reply_code, const u32 timeout) | 全局(:116) | 阻塞轮询等待指定应答码,超时返回 FALSE;被头文件导出供通信探测复用 |
senergys5_get_inv_upgrade_flag(void) | 全局(:160) | 查询主/从机固件是否已下载完成,并带副作用地置位 master/slave 待升级标志 |
senergys5_get_dcdc_start_upgrade_flag(void) | 全局(:184) | 查询 ARM(DCDC) 固件是否已下载完成,并置位 dcdc 待升级标志 |
senergys5_get_master_upgrade_flag(void) | 全局(:206) | master_flag && object==MASTER,供上层切换运行模式 |
senergys5_read_upgrade_percent_master(void) | 全局(:220) | 主机进度百分比 = offset*100/file_len,对象不匹配返回 0 |
senergys5_get_slave_upgrade_flag(void) | 全局(:238) | slave_flag && object==SLAVE |
senergys5_read_upgrade_percent_slave(void) | 全局(:252) | 从机进度百分比 |
senergys5_get_dcdc_upgrade_flag(void) | 全局(:270) | dcdc_flag && object==DCDC |
senergys5_read_upgrade_percent_arm(void) | 全局(:284) | DCDC 进度百分比 |
senergys5_upgrade_code_handle(const u8* buf, const u16 len, const u8 relpy) | static(:308) | "发一帧 + 等一个应答码"的原子动作,2000 ms 超时 |
senergys5_upgrade_send_file_properties(SENERGYS5_UPGRADE_INFO_T *upgrade_info) | static(:339) | 从固件头部取 8 字节,拆成两次 4 字节写,并解析文件长度/总块数 |
senergys5_fill_dsp_upgrade_data(void) | static(:384) | 按偏移读 2048 字节(末块取余数)并逐字节累加出 32 位校验和 |
senergys5_inv_upgrade_handle(void) | 全局(:429) | 升级状态机主体,单次调用只推进一个状态的一步 |
4. 核心逻辑解析
4.1 状态机总览与迁移条件
switch (s_senergys5_upgrade_info.upgrade_status) 位于 :439:
ENTER_BOOT ──成功──► SHAKE_HANDS ──成功──► SEND_FILE_PROPERTIES ──成功──► SEND_UPGRADE_FILE
│ 失败×5 │ 失败×5 │ 失败×5 │
└──重试(SHAKE_HANDS) └──► END └──► END │
▲ │
(对象=MASTER 且版本回读成功)│ 块数用尽/失败×5
└────────── UPGRADE_END ◄──┘
SENERGYS5_ENTER_BOOT(:441-516):清零版本查询计数器,按优先级master → slave → dcdc选定对象,填u8_upgrade_addr(主机/ DCDC 用g_u8_fw_sdram1,从机用g_u8_fw_sdram2)、u32_upgrade_file_len(get_length_file_updating(UPDT_INV1/2/3))以及 9 字节命令字段。三个 flag 都为 FALSE 时直接置UPGRADE_END返回(空闲态,:491-498)。
成功(收到期望应答码)→ SHAKE_HANDS;失败 err_count++,累计到 5 次时不清 END 而是回到 SHAKE_HANDS(:509-514,这是唯一"越级前进"的分支,见 7.3)。
SENERGYS5_SHAKE_HANDS(:518-541):把u8_upgrade_buf[8](0x55/0x56/0x62)单字节发出,等0xA5。成功 →SEND_FILE_PROPERTIES;失败 5 次 →UPGRADE_END(放弃)。SENERGYS5_SEND_FILE_PROPERTIES(:543-567):见 4.3。成功 →u32_upgrade_file_offset = 8并进入SEND_UPGRADE_FILE;失败 5 次 →UPGRADE_END。SENERGYS5_SEND_UPGRADE_FILE(:569-668):见 4.4。SENERGYS5_UPGRADE_END(:670-717):见 4.5。default(:719-724)把未知状态强制收敛到UPGRADE_END。
4.2 帧格式与收发时序
阶段一 ENTER_BOOT(8 字节,无校验字段)
偏移 0 1 2 3 4 5 6 7
0x01 0xA0 对象码 0x33 0x77 0x99 口令H 口令L
主机: 0x01 0x97 0xBA 期望应答 0x55
从机: 0x02 0x97 0xFE 期望应答 0x56
DCDC: 0x05 0x96 0x8A 期望应答 0x62
发送长度 8(:500),应答码取 u8_upgrade_buf[8]。帧内无长度域、无 CRC,靠固定引导字 + 口令对做合法性判断。
阶段二 SHAKE_HANDS(1 字节):仅发 u8_upgrade_buf[8],即把阶段一"预留"的应答码作为握手字节真正发出(:522),等待 0xA5。
阶段三 SEND_FILE_PROPERTIES(4 + 4 字节,两段之间有 200 ms 静默)
:344-349 从 u8_upgrade_addr 起读 8 字节到 u8_upgrade_buf[0..7](固件头,含义未文档化);:351 以大端解析 buf[4..7] 为 u32_upgradr_file_size;:352 得 u32_upgradr_block_count = file_size / 2048(整除)。随后 :354 发 buf[0..3]、OSTimeDlyHMSM(0,0,0,200)、:362 发 buf[4..7](即文件长度),最后等 0xA5,超时 105000 ms(:368,注释"将 15s 超时,改成 105S",说明逆变器写 Flash 元信息耗时很长)。
阶段四 SEND_UPGRADE_FILE(每块 0/2 + 2048 + 4 字节)
senergys5_fill_dsp_upgrade_data()(:588)准备 2 KB 数据与校验和。- 仅当
get_inverter_sub()为SUB_S5_II或SUB_M10(:596),先发 2 字节0x08 0x00(=2048,大端)并等0xA5——这是"本块长度"命令;SUB_S5不发。 - 发 2048 字节原始数据(
:618,不经senergys5_upgrade_code_handle,即发完不等应答)。 - 发 4 字节大端累加校验和并等
0xA5(:637)。 - 三步全部成功(
err_count == 0)才OSTimeDlyHMSM(0,0,0,200)、offset += 2048、send_block_count++(:662-667)。
超时/重试:发送层 usart2_send_data(..., 4000) 为 4000 ms(:95);senergys5_upgrade_code_handle 的等待为 2000 ms(:317);每阶段连续失败 5 次即放弃并置 UPGRADE_END。注意 u8_upgradr_err_count 是跨阶段共用的一个计数器,只有成功路径才清零,失败路径保留累加。
4.3 校验和计算(senergys5_fill_dsp_upgrade_data,:384-416)
l_u16_data_len = (offset + 2048 >= file_len) ? (file_len - offset) : 2048 // :392-399
l_addr_temp = u8_upgrade_addr + offset // :403
u32_check_code = Σ buf[i] (i = 0..data_len-1,字节无符号累加进 u32) // :410-414
结果按大端拆成 4 字节存 s_temp_buf(:591-594)。关键点:u32_check_code 只累加从 SDRAM 真实读到的 data_len 个字节,0xFF 填充部分不参与求和。
4.4 块循环的终止条件
:574 的判断是 u32_send_block_count == u32_upgradr_block_count。因为 u32_upgradr_block_count 是整除结果,当文件长度不是 2048 的整数倍时,最后一个不满 2048 的块永远不会被发送(send_block_count 只能取到整除值)。终止时 :576-584 清零 offset 与 send_block_count、状态置 UPGRADE_END,并记录 s_u32_query_inv_ver_tick = OSTimeGet() 作为版本回读的起算点。
4.5 收尾与版本回读(SENERGYS5_UPGRADE_END,:670-717)
| 对象 | 处理 |
|---|---|
MASTER(:674-698) | 距 s_u32_query_inv_ver_tick 超过 10 s 且重试计数 < 12 时,调 senergys5_query_inv_update_versions_info(0x1A1C, 0x0D)。失败则计数 +1、重置 10 s 起算点(重试周期 10 s,最多 12 次 ≈ 120 s);成功则 master_flag = FALSE 且状态回到 ENTER_BOOT,从而接着升级从机。计数 ≥ 12 时同时放弃主、从两机标志 |
SLAVE(:699-702) | 直接 slave_flag = FALSE(状态保持 UPGRADE_END) |
DCDC(:703-709) | Set_Status_Is_Updated_From_Server(UPDT_INV3, FALSE)、dcdc_flag = FALSE、整体 memset 清零,然后置 u8_set_dcdc_upgrade_on_flag = TRUE |
公共尾部(:711-716) | 主、从标志都为 FALSE 时清 UPDT_INV2/UPDT_INV1 的"服务器已就绪"状态并整体 memset |
memset 后 upgrade_status 归 0 = ENTER_BOOT,因此所有复位路径都自动回到状态机入口;下一次 ENTER_BOOT 发现三 flag 全 FALSE 就置 UPGRADE_END 返回,形成稳定空闲态。
4.6 与 uCOS-II 任务/时序的配合
- 驱动者:
task_inverter(inverter.c:1045,周期 80 ms,inverter.c:1188)。同一循环内先OSFlagPend(g_t_fast_dispatch_flag, PEND_LOGIC_CALCULATE_DONE, ..., 20, &err),再调senergys5_inverter_comm()(set_comm_usart_s5.c:6199)。因此升级流程与 EMS 主调度共享 80 ms 节拍。 - 升级期间旁路正常通信:
set_comm_usart_s5.c:6201一旦senergys5_get_inv_upgrade_flag()或senergys5_get_dcdc_start_upgrade_flag()为真,就只跑升级状态机,并把运行模式置cUpdateMaster/cUpdateSlave/cUpdateArm(:6213-6227),同时清故障/告警位与通信失联标志(:6204-6209)。 - 无信号量/消息邮箱:本文件不与 uCOS-II 同步对象交互,全部靠
OSTimeGet()比较 (:123、:676) 与OSTimeDlyHMSM(0,0,0,50/200)(:139/146/360/664)做阻塞等待——即同步式串口轮询。senergys5_upgrade_recv_mdsp内部是死循环 + tick 超时,单次最长可阻塞timeout毫秒(文件属性阶段实测可达 105 s),期间task_inverter整体被占用。 - tick 即毫秒(
OSTimeGet()差值直接与10*1000、2000、4000等毫秒常量比较)。
4.7 关键全局变量的读写关系
| 变量 | 读 | 写 |
|---|---|---|
s_senergys5_upgrade_info.upgrade_status | 每次进入 senergys5_inv_upgrade_handle 的 switch | 各状态迁移点;memset 归 0 等价于回 ENTER_BOOT |
u8_upgrade_master_flag / u8_upgrade_slave_flag | ENTER_BOOT 选对象、get_*_upgrade_flag、:711 | senergys5_get_inv_upgrade_flag() 置位;UPGRADE_END 清除 |
u8_upgrade_dcdc_flag | 同上 | senergys5_get_dcdc_start_upgrade_flag() 置位;:706 清除 |
u8_upgrade_object | 三个 get_*_upgrade_flag、百分比函数 | ENTER_BOOT 按 flag 设定;memset 归 0 |
u8_upgrade_addr | send_file_properties、fill_dsp_upgrade_data | ENTER_BOOT 设为 g_u8_fw_sdram1/2 |
u32_upgrade_file_offset / u32_send_block_count | 百分比、块循环 | :551 置 8;:665-666 递增;:579-580 清零 |
u8_set_dcdc_upgrade_on_flag | set_comm_usart_s5.c:2831(触发逆变器强制下电) | :708 置 TRUE;set_comm_usart_s5.c:502/510 初始化;memset 清零 |
g_u8_fw_sdram1 / g_u8_fw_sdram2 | 只读(固件源) | 由 net/server.c:69-70 与下载流程写入 |
5. 对外接口
5.1 本文件导出
| 名称 | 类型 | 使用者(真实搜索结果) |
|---|---|---|
senergys5_inv_upgrade_handle() | 函数 | midware/inverter/set/set_comm_usart_s5.c:6211 |
senergys5_get_inv_upgrade_flag() | 函数 | set_comm_usart_s5.c:6201 |
senergys5_get_dcdc_start_upgrade_flag() | 函数 | set_comm_usart_s5.c:6201 |
senergys5_get_master_upgrade_flag() | 函数 | set_comm_usart_s5.c:6213、midware/inverter/inverter.c:3812 |
senergys5_get_slave_upgrade_flag() | 函数 | set_comm_usart_s5.c:6218、inverter.c:3882 |
senergys5_get_dcdc_upgrade_flag() | 函数 | set_comm_usart_s5.c:6223、inverter.c:3976 |
senergys5_read_upgrade_percent_master() | 函数 | inverter.c:3847 |
senergys5_read_upgrade_percent_slave() | 函数 | inverter.c:3917 |
senergys5_read_upgrade_percent_arm() | 函数 | inverter.c:4003 |
senergys5_upgrade_recv_mdsp() | 函数 | set_comm_usart_s5.c:428(senergy_comm_status_check 通信探测) |
s_senergys5_upgrade_info | 全局变量 | set_comm_usart_s5.c:502/510/2831/2833(初始化清零、置/读 DCDC 下电标记) |
5.2 本文件调用或引用的外部符号
| 名称 | 来源模块 |
|---|---|
usart2_clear_buffer、usart2_send_data、usart2_is_recv_async_data、usart2_read_data_async | hardware/usart2/usart2.h:9-13(hardware/usart2/usart2.c) |
OSTimeGet、OSTimeDlyHMSM | uCOS-II(UCOSII/) |
is_inverter_firm_download_finished | net/inv_download.c:182(声明 inv_download.h:34) |
Get_Status_Is_Updated_From_Server、Set_Status_Is_Updated_From_Server、get_length_file_updating | net/upd_download.c:375/359/327(声明 upd_download.h:37-40) |
g_u8_fw_sdram1、g_u8_fw_sdram2 | net/server.c:69-70(声明 server.h:258-259,各 3 MB) |
senergys5_query_inv_update_versions_info | midware/inverter/set/set_comm_usart_s5.c:1949 |
get_inverter_sub、SUB_S5_II、SUB_M10 | midware/inverter/inverter.c:1369、inverter.h:332-333 |
SDRAM_SENERGYS5_UPGRADE_INFO_ADDR | hardware/sdram/sdram.h:67 |
memset / printf / NULL / TRUE / FALSE / u8/u16/u32 | 标准库与 includes.h |
6. 依赖关系
依赖(本文件 :13-21 的 include)
inverter.h(get_inverter_sub、SUB_S5_II、SUB_M10、类型定义)set_upgrade_s5.h(本文件的接口与上下文结构体)upd_download.h(get_length_file_updating、Set/Get_Status_Is_Updated_From_Server)inv_download.h(is_inverter_firm_download_finished)server.h(ENUpdateType与UPDT_INV1/2/3、g_u8_fw_sdram1/2)sdram.h(SDRAM_SENERGYS5_UPGRADE_INFO_ADDR)usart2.h(UART2 收发)hex_file_parse.h、set_comm_can.h:已 include 但本文件未出现其任何符号(残留 include,见 7.6)
被依赖
midware/inverter/set/set_comm_usart_s5.c(升级触发、单步驱动、模式切换、DCDC 下电标记)midware/inverter/inverter.c(inverter_read_upgrade_flag_master/slave/arm、inverter_read_upgrade_percent_master/slave/arm六个聚合出口,:3812/3847/3882/3917/3976/4003)- 再往上是
hmi/net通过inverter.h的上述接口消费进度(本文件不直接对外)
7. 备注与风险点
memset(s_senergys5_upgrade_info.u8_upgrade_buf, 0xFF, sizeof(SENERGYS5_INV_BLOCK_SIZE));(:409)填错长度。SENERGYS5_INV_BLOCK_SIZE是整型常量2048,sizeof(int) == 4,所以这条语句只把前 4 个字节填成0xFF,而不是 2048 字节(应写sizeof(u8_upgrade_buf)或直接SENERGYS5_INV_BLOCK_SIZE)。后果:末块不足 2048 字节时,剩余字节是上一块遗留的旧数据而非 0xFF 填充,而校验和又只累加真实读到的字节,因此填充区内容与校验和不一致,逆变器端收到的尾部数据是脏的。本文件其它地方(:576)用的是sizeof(s_temp_buf),写法不统一。- 末块可能被整体丢弃:
u32_upgradr_block_count = file_size / 2048(:352)为整除,而循环终止条件是块计数相等(:574)。文件长度非 2048 整数倍时,最后那不足 2048 字节的一段永远不会发出,只依赖逆变器端容忍缺尾。 ENTER_BOOT失败 5 次后"越级"进入SHAKE_HANDS(:509-514)。此时阶段一并未成功、对象口令也没有被逆变器确认,但仍然跳过重试直接握手;与其它三个阶段的"失败 5 次即UPGRADE_END"策略不一致。若保留意图是"有些固件进 Boot 后不回 0x55 而直接能握手",应在注释中说明。SEND_FILE_PROPERTIES失败 5 次进入UPGRADE_END时没有复位u32_upgrade_file_offset/u32_send_block_count(:556-565)。这些残值会留在被固定地址放置的s_senergys5_upgrade_info里;主机升级失败后UPGRADE_END若回读版本成功会回到ENTER_BOOT接着升从机,而进入SEND_UPGRADE_FILE时只重置了offset(:551)、没有重置send_block_count。当从机文件块数与残值巧合相等时(:574)会直接判定"已发完",把从机当成升级成功——这是一个静默失败路径。- 百分比函数存在除零风险:
senergys5_read_upgrade_percent_master/slave/arm(:228/260/292)都用offset*100 / u32_upgrade_file_len,而u32_upgrade_file_len来自get_length_file_updating()(服务器下发值)。若对象已选中但长度仍为 0(服务器未给出长度或下载流程未更新),就是整数除零。 hex_file_parse.h、set_comm_can.h两个 include(:17、:21)在本文件中完全未使用:无hex_parse、无任何 CAN 符号引用,属复制自同类文件的残留。:577有一行被注释掉的收尾命令// l_u8_res = senergys5_upgrade_code_handle(s_temp_buf,2,SENERGYS5_INV_REPLY_CODE);,而:576仍在memset(s_temp_buf, ...),说明"发完块后的 2 字节结束命令"被中途去掉,是版本遗留痕迹。- 大量魔法数字内联在函数体里(
:451-489的引导字与口令、:434-435的0x08/0x00、:317的 2000、:368的 105000、:676的10*1000、:691的 12 次),协议字典没有以宏形式沉淀在set_upgrade_s5.h;头文件里反而留着零引用的SENERGYS5_INV_UPDATE_SIZE(set_upgrade_s5.h:19)。 u8_upgrade_addr是非 const 裸指针且被写进固定 SDRAM 地址的结构体:指针值跨软复位保留,若固件版本变化导致 SDRAM 分区调整,复位后会指向错误区域;结构体本身也没有 magic/version 字段做布局校验(见set_upgrade_s5.h.md第 7 节)。- 阻塞式等待与任务实时性:
senergys5_upgrade_recv_mdsp(:116)是纯轮询死循环,task_inverter在其返回前无法做任何事(文件属性阶段最长 105 s)。OSTimeDlyHMSM(...,50)只提供 50 ms 粒度的让步,期间usart2_read_data_async()会丢弃任何不等于reply_code的字节——若逆变器应答含多字节或先发干扰字节,会直接误判为超时。 DCDC分支的u8_set_dcdc_upgrade_on_flag = TRUE(:708)实际会被立即清掉:紧随其后的公共尾部判断(:711)读的是刚被memset清零的主/从标志,因此恒成立,:715的第二次memset把刚置的标记又清零。也就是说"ARM 升级完成后强制逆变器下电"这一标记在 DCDC 路径下从未真正保持为 TRUE(该标记的消费点在set_comm_usart_s5.c:2831)。疑似漏把该标记移到公共尾部之后。extern声明重复::28又声明了一遍senergys5_query_inv_update_versions_info,而set_comm_usart_s5.h:829已有声明;若两处签名将来不同步会引发隐蔽错误。