inovance_upgrade.c
SEND_FILE)4.4 与 uCOS-II 任务/时序的配合4.5 关键全局变量读写5. 对外接口本文件导出本文件调用6. 依赖关系7. 备注与风险点源文件路径:
midware/inverter/inovance/inovance_upgrade.c所属模块:midware/inverter/inovance(汇川逆变器通信与固件升级) 代码行数:852
1. 文件职责
本文件实现汇川(Inovance)逆变器主机 MCU1 / 从机 MCU2 / FPGA(ARM) 三颗芯片的固件在线升级流程,是逆变器固件下发链路的最后一环。上游由云端 EMS 把固件包下载进 SDRAM(g_u8_fw_sdram1 / g_u8_fw_sdram2)并置位 UPDT_INV1/INV2/INV3 更新标记,本文件负责把这些镜像按 264 字节定长分包,通过 USART2 以「Modbus-RTU 私有扩展帧」写入逆变器 bootloader。
本文件不创建任务、不使用信号量或消息邮箱,全部逻辑是在调用者任务上下文中同步轮询执行的状态机:每次被调用推进一个状态(部分状态内含 OSTimeDlyHMSM 阻塞延时)。驱动者是 inovance_comm_usart.c:2571 的 inovance_inverter_comm(),它在 inovance_comm_usart.c:2592 调用 inovance_upgrade_handle()。
对外另外导出 6 个只读查询函数(主/从/FPGA 的「升级中标志」与「升级百分比」),由 inverter.c 与 HMI 侧读取用于显示。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
INOVANCE_UPGRDADE_T | 结构体 | 升级上下文。字段:u8_upgrade_addr(SDRAM 镜像基址)、u8_upgrade_obj(升级对象)、u8_upgrade_state(本文件未使用,实际状态放在函数内 static 变量)、u8_upgrade_buf[264](单包数据暂存)、u32_file_offset(已发送偏移)、u32_file_length(镜像总长)。文件内以 s_t_inovance_upgrade(inovance_upgrade.c:24)单例存在 |
INOVANCE_UPGRADE_RETURN_E | 枚举 | 设备返回码 / 设备运行状态的混合枚举,同时容纳三组含义不同的取值(详见第 7 节风险点) |
INOVANCE_UPGRADE_OBJ_E | 枚举 | 升级对象:INOVANCE_NONE=0、INOVANCE_MCU1、INOVANCE_MCU2、INOVANCE_FPGA、INOVANCE_INIT、INOVANCE_MAX |
INOVANCE_UPGRADE_STATE_E | 枚举 | 主状态机状态:INIT / QUERY_STATUS / JUMP_BOOT / SET_DOWNLOAD_MODE / SEND_FILE / START_PROGRAM / END |
INOVANCE_UPGRADE_DEBUG | 宏 | 调试开关,默认 0。置 1 后每个状态进入/退出都打印大量 printf,并额外定义 state_name[]/obj_name[]/STATE_NAME/OBJ_NAME |
INOVANCE_UPGRADE_ADDR_READ_DEV_STATUS | 宏 | 0x04,APP_OPERATE 命令读取的设备状态寄存器地址 |
INOVANCE_UPGRADE_ADDR_JUMP_BOOT | 宏 | 0x05,APP_OPERATE 命令跳转 boot 的寄存器地址 |
INOVANCE_UPGRADE_CMD_APP_OPERATE | 宏 | 0x45,APP 操作命令字(查状态 / 跳 boot) |
INOVANCE_UPGRADE_CMD_SET_DOWNLOAD_MODE | 宏 | 0x64,进入下载模式命令字 |
INOVANCE_UPGRADE_CMD_SEND_FILE | 宏 | 0x69,下发固件数据包命令字 |
INOVANCE_UPGRADE_CMD_START_PROGRAM | 宏 | 0x70,启动新程序命令字 |
INOVANCE_UPGRADE_FILE_LENGTH | 宏 | 264,单包固件数据长度,同时是 u8_upgrade_buf 的容量与总长整除校验的模数 |
INOVANCE_UPGRADE_DELAY | 宏 | 200,QUERY_STATUS 无回复时的时间片延时(ms) |
INOVANCE_SLAVE_ADDRESS | 宏(外部) | 0x01,来自 inovance_comm_usart.h:40,是全部下发帧的从机地址 |
INOVANCE_DAT_PCK_INTERVAL_INV | 宏(外部) | 100,来自 inovance_comm_usart.h:25,用作命令帧的发送节流窗口与发送超时(ms) |
INOVANCE_OPERATE_STOP / INOVANCE_OPERATE_START | 枚举(外部) | 来自 inovance_comm_usart.h:173-176(INOVANCE_OPERATE_CODE_E),值分别为 1 / 2 |
3. 函数清单
| 函数名 | 作用域 | 说明 |
|---|---|---|
inovance_read_upgrade_flag_master | 全局 | 返回「当前升级对象 == INOVANCE_MCU1」,供上层判断主机是否在升级 |
inovance_read_upgrade_percent_master | 全局 | 主机升级百分比 = u32_file_offset * 100 / get_length_file_updating(UPDT_INV1),对象不匹配时返回 0 |
inovance_read_upgrade_flag_slave | 全局 | 返回「当前升级对象 == INOVANCE_MCU2」 |
inovance_read_upgrade_percent_slave | 全局 | 从机升级百分比(分母为 UPDT_INV2 文件长度) |
inovance_read_upgrade_flag_fpga | 全局 | 返回「当前升级对象 == INOVANCE_FPGA」 |
inovance_read_upgrade_percent_fpga | 全局 | FPGA 升级百分比(分母为 UPDT_INV3 文件长度) |
inovance_upgrade_write_data | static | 串口发包封装:做 timeout 节流、清空接收缓冲、调用 usart2_send_data,返回发送结果 |
inovance_upgrade_recv_data | static | 串口收包与解析:搬出异步接收数据、校验 Modbus CRC16、按命令字区分提取 code/ret/len |
inovance_upgrade_read_dev_status | static | 组 01 45 00 04 00 01 CRC 帧,查询逆变器当前运行状态 |
inovance_upgrade_set_jump_boot | static | 组 01 45 00 05 00 01 CRC 帧,令 APP 跳转到 bootloader |
inovance_upgrade_set_download_mode | static | 组 01 64 F6 0F 00 08 CRC 帧,令 boot 进入下载模式 |
inovance_upgrade_start_program | static | 组 01 70 00 00 00 00 CRC 帧,令 boot 校验并启动新程序 |
inovance_upgrade_send_file_content | static | 组 01 69 <264B> CRC 帧(共 268 字节)下发一个固件数据包 |
inovance_upgrade_handle | 全局 | 升级主状态机,每次调用推进一个状态;含 3 次失败退出、超时重发、分对象串行升级逻辑 |
4. 核心逻辑解析
4.1 主状态机与迁移条件
状态变量为函数内 static u8 s_u8_upgrade_state(inovance_upgrade.c:364),初值 0 即 INOVANCE_UPGRADE_INIT。另有一组跨调用保持的 static 标志(inovance_upgrade.c:365-370):
s_u8_recv_err_cnt:当前状态内的连续应答异常计数,超阈值(3)触发退出或重试s_u8_boot_recv_cnt:INIT阶段连续「无回复」次数,>10 判定逆变器已在 boot 中s_u8_upgrade_mcu1_flag/s_u8_upgrade_mcu2_flag/s_u8_upgrade_fpga_flag:本轮还需升级哪些对象的待办标志s_u8_upgrade_fail_cnt:整轮升级失败次数,>3 直接放弃
函数入口的全局急停(inovance_upgrade.c:396-405):s_u8_upgrade_fail_cnt > 3 时强制回到 INIT、清零 s_t_inovance_upgrade、把 UPDT_INV1/2/3 三个服务端更新标记全部清掉并 return(本次不再推进状态机)。
各状态迁移:
| 当前状态 | 条件 | 下一状态 | 附带动作 |
|---|---|---|---|
INIT | is_inverter_firm_download_finished()(即 UPDT_INV1 && UPDT_INV2 均置位)且 MCU1 待办 | QUERY_STATUS | 装载 g_u8_fw_sdram1,obj = INOVANCE_MCU1,长度取 UPDT_INV1 |
INIT | 同上但仅 MCU2 待办 | QUERY_STATUS | 装载 g_u8_fw_sdram2,obj = INOVANCE_MCU2,长度取 UPDT_INV2 |
INIT | !is_inverter_firm_download_finished() 且 Get_Status_Is_Updated_From_Server(UPDT_INV3) 且 FPGA 首次 | QUERY_STATUS | 装载 g_u8_fw_sdram1,obj = INOVANCE_FPGA,长度取 UPDT_INV3 |
INIT | 三个来源都不成立 / 对象已全部处理完 | END | addr=NULL、obj=INOVANCE_NONE、length=0 |
INIT | file_length == 0 或 file_length % 264 != 0 | END | 三个待办标志全部清 FALSE |
INIT | inovance_set_inv_start_stop(INOVANCE_OPERATE_STOP) 返回 TRUE | QUERY_STATUS | recv_err_cnt = 0(APP 正常停机应答) |
INIT | 返回值 == 2(无回复) | 停留 INIT | boot_recv_cnt++;一旦 >10 直接转 QUERY_STATUS(认定已在 boot 中,无需停机) |
INIT | 返回值 == FALSE(l_u16_inv_recv_num == 5,APP 异常回复) | 停留 INIT | recv_err_cnt++;>3 转 END 并清三个待办标志 |
QUERY_STATUS | 收到 code == 0x45 且 (ret >> 8) == INOVANCE_UPGRADE_SAFE(3) | JUMP_BOOT | recv_err_cnt = 0(APP 处于安全状态,允许跳 boot) |
QUERY_STATUS | 收到 code == 0x45 但状态非 SAFE | END | 清当前对象的待办标志(本对象放弃,不影响其它对象) |
QUERY_STATUS | 收到 code == 0xC5(0x45+0x80 异常回复)且帧长 == 8 | SET_DOWNLOAD_MODE | 判定 APP 已被擦除、设备已在 boot 中,跳过 JUMP_BOOT |
QUERY_STATUS | 收不到 或 帧长 != 8 | 停留 | recv_err_cnt++,无回复时额外 OSTimeDlyHMSM(...,200);>3 清标志转 END |
JUMP_BOOT | 无条件(接收数据被丢弃) | SET_DOWNLOAD_MODE | 发跳转帧后固定延时 500 ms |
SET_DOWNLOAD_MODE | ret == INOVANCE_UPGRADE_NO_ERROR(0) 且 code == 0x64 | SEND_FILE | recv_err_cnt = 0 |
SET_DOWNLOAD_MODE | 其它 | 停留;连续 3 次失败后 | recv_err_cnt++,>3 时清当前对象标志并转 START_PROGRAM(跳过数据下发,走收尾) |
SEND_FILE | u32_file_offset >= u32_file_length 或 length <= 0 | START_PROGRAM | 数据已发完 |
SEND_FILE | 收到 code == 0x69 且 ret == 0 | 停留 | recv_err_cnt = 0,u32_file_offset += 264 |
SEND_FILE | 收到 code == 0xE9(0x69+0x80)且 ret == INOVANCE_UPGRADE_ID_ERROR(0x08) | START_PROGRAM | 设备侧认为镜像已收全(ID 校验结束) |
SEND_FILE | 其它应答 | 停留 | recv_err_cnt++,延时 300 ms;>3 时 fail_cnt++、u32_file_offset = 0、回到 QUERY_STATUS 从头发起 |
START_PROGRAM | ret == 0 且 code == 0x70 | END | 清当前对象待办标志、fail_cnt = 0、固定延时 15 s |
START_PROGRAM | 其它 | 停留 | recv_err_cnt++,延时 1000 ms;>= 3 时清当前对象标志并转 END |
END | 无条件 | INIT | 清零上下文、inovance_set_inv_start_stop(INOVANCE_OPERATE_START) 恢复逆变器运行、按待办标志清除服务端更新标记 |
4.2 通信协议帧格式
底层是 USART2(115200bps,见 inovance_comm_usart.c:2322 的 usart2_init(115200)),帧结构为「从机地址 + 命令字 + 数据域 + Modbus CRC16(低字节在前)」,与标准 Modbus 不同之处是命令字直接复用功能码位置。
下发命令帧(INOVANCE_SLAVE_ADDRESS = 0x01):
| 帧用途 | 字节序列 | 长度 |
|---|---|---|
| 查设备状态 | 01 45 00 04 00 01 CRC_L CRC_H | 8 |
| 跳转 boot | 01 45 00 05 00 01 CRC_L CRC_H | 8 |
| 进下载模式 | 01 64 F6 0F 00 08 CRC_L CRC_H | 8 |
| 启动新程序 | 01 70 00 00 00 00 CRC_L CRC_H | 8 |
| 下发固件包 | 01 69 <264 字节固件> CRC_L CRC_H | 268 |
45 帧的 00 04 / 00 05 是 16 位寄存器地址,00 01 是寄存器个数;校验使用 GetCrcCode_Modbus()(common/crc.c:144),计算结果低字节先发(见 inovance_upgrade.c:237-238 等)。
接收解析(inovance_upgrade_recv_data,inovance_upgrade.c:147-215):
usart2_is_recv_async_data()判断有无整帧到达;无则code = ret = 0、len保持 0 返回(调用方据此走「无回复」分支)。usart2_get_data_len()取帧长,< 2直接返回。- 逐字节
usart2_read_data_async()搬入调用者 buffer。 - CRC 取自帧尾两字节并按小端拼装:
crc_temp = (buf[len-1] << 8) | buf[len-2];与GetCrcCode_Modbus(buf, len - 2)比对。 - 仅在 CRC 匹配时才解析命令字与返回码:
code == 0x45:ret = (buf[3] << 8) | buf[4],即 16 位寄存器值(这里ret >> 8是运行状态,ret & 0xFF是低字节)。code ∈ {0xC5, 0x64, 0x69, 0x70, 0xE4, 0xE9, 0xF0}:ret = buf[2],即单字节错误码(正常命令字或其+0x80异常形态)。
- 结果通过指针出参
*code/*ret/*len回传。
超时与重试:没有协议级超时定时器,重试依赖状态机 + 计数。发送侧由 inovance_upgrade_write_data(inovance_upgrade.c:115-139)做发送节流:若距上次发送不足 timeout ms 则 OSTimeDlyHMSM 补足,然后 s_u32_send_pack_tick = OSTimeGet()、usart2_clear_buffer()、usart2_send_data(buf, len, timeout)。接收侧由各状态自己的 s_u8_recv_err_cnt(阈值 3)与 SEND_FILE 的 s_u8_upgrade_fail_cnt(阈值 3,整轮重来)构成两级重试。
4.3 固件分包下发时序(SEND_FILE)
memcpy(s_t_inovance_upgrade.u8_upgrade_buf,
s_t_inovance_upgrade.u8_upgrade_addr + s_t_inovance_upgrade.u32_file_offset,
INOVANCE_UPGRADE_FILE_LENGTH); // inovance_upgrade.c:697
inovance_upgrade_send_file_content(s_t_inovance_upgrade.u8_upgrade_buf); // :698
- 偏移
u32_file_offset从 0 开始,每收到一个0x69正常应答就+= 264(:720)。 - 首包后的 20 s 延时:
u32_file_offset == INOVANCE_UPGRADE_FILE_LENGTH(:707,此时刚发出第 1 包)会OSTimeDlyHMSM(0,0,20,0),用于等待设备端擦除 APP 区。 - 末包的 5 s 延时:
u32_file_offset == u32_file_length - 264(:699)时OSTimeDlyHMSM(0,0,5,0),等待设备端把 Flash 写入缓存落盘。 - 因此镜像长度必须是 264 的整数倍,这个前提在
INIT中用% INOVANCE_UPGRADE_FILE_LENGTH强校验(:471-472),不满足则整轮放弃。 - 单包失败 >3 次:
fail_cnt++、偏移归零、回QUERY_STATUS重新走「停 APP → 跳 boot → 进下载模式」全流程(:749-752)。
4.4 与 uCOS-II 任务/时序的配合
- 本文件不创建任何任务、不申请信号量或消息邮箱,所有同步都靠
OSTimeDlyHMSM忙等。 - 唯一驱动源是汇川逆变器通信任务里的
inovance_inverter_comm()(inovance_comm_usart.c:2571)。升级期间该函数的正常抄表分支被完全旁路(inovance_comm_usart.c:2575-2593),并在每次进入时刷新g_t_inovance_comm_info.u32_ems_inv_comm_tick,以免触发INOVANCE_EMS_INV_COMM_LOST_TIME(30 s,inovance_comm_usart.h:26)的通信丢失判定。 inovance_upgrade_init()(inovance_comm_usart.c:2304)在升级首次被触发时调用一次:初始化 USART2 与 CAN、清运行信息,并把u8_run_mode交给上层置为cUpdateMaster/cUpdateSlave/cUpdateArm(inovance_comm_usart.c:2585-2590)。- 因为状态机是一次调用推进一个状态,且内部含最长 20 s 的阻塞延时,所以升级期间该任务的实际调度周期会被拉长到秒级;这属于设计取舍,需注意其它依赖该任务的看门狗/丢失计数。
4.5 关键全局变量读写
| 变量 | 读/写 | 触发条件 |
|---|---|---|
s_t_inovance_upgrade | 读+写 | 全流程;INIT 装载地址/对象/长度,SEND_FILE 维护 u32_file_offset,END 与失败急停时 memset 清零 |
s_u8_upgrade_mcu1_flag / mcu2 / fpga | 读+写 | INIT 首次置 TRUE 并按 TRUE 选择对象;任一对象成功、或该对象在任何状态被判失败时置 FALSE |
g_u8_fw_sdram1 / g_u8_fw_sdram2 | 只读 | 固件源地址,INIT 中赋给 u8_upgrade_addr(MCU1/FPGA 用 sdram1,MCU2 用 sdram2) |
Get_Status_Is_Updated_From_Server(UPDT_INV1/2/3) | 只读 | INIT 判断是否进入升级、以及走 MCU1/MCU2 还是 FPGA 分支 |
Set_Status_Is_Updated_From_Server(UPDT_INV1/2/3, FALSE) | 只写 | 失败超限急停、END 状态收尾 |
get_length_file_updating(UPDT_INV1/2/3) | 只读 | INIT 取镜像总长;三个百分比查询函数取分母 |
g_t_inv_info.t_run_info.u8_run_mode | 间接写 | 由调用者 inovance_comm_usart.c:2585-2590 依据本文件的三个 flag 查询函数设置 |
g_t_inovance_comm_info.u32_ems_inv_comm_tick | 间接写 | INIT/END 调用 inovance_set_inv_start_stop() 成功应答时被其内部刷新 |
5. 对外接口
本文件导出
| 符号 | 类型 | 调用方 |
|---|---|---|
inovance_upgrade_handle | 函数 | inovance_comm_usart.c:2592(inovance_inverter_comm()) |
inovance_read_upgrade_flag_master | 函数 | inverter.c:3828、inovance_comm_usart.c:2585 |
inovance_read_upgrade_percent_master | 函数 | inverter.c:3863 |
inovance_read_upgrade_flag_slave | 函数 | inverter.c:3898、inovance_comm_usart.c:2587 |
inovance_read_upgrade_percent_slave | 函数 | inverter.c:3933 |
inovance_read_upgrade_flag_fpga | 函数 | inverter.c:3984、inovance_comm_usart.c:2589 |
inovance_read_upgrade_percent_fpga | 函数 | inverter.c:4011 |
无导出全局变量:s_t_inovance_upgrade 是 static,所有宏/枚举/结构体定义在 inovance_upgrade.h 中向外暴露。
本文件调用
| 外部符号 | 来源模块 |
|---|---|
usart2_init / usart2_clear_buffer / usart2_send_data / usart2_is_recv_async_data / usart2_get_data_len / usart2_read_data_async | hardware/usart2/usart2.h |
GetCrcCode_Modbus | common/crc.h:17 |
is_inverter_firm_download_finished | net/inv_download.h:34 |
get_length_file_updating / Set_Status_Is_Updated_From_Server / Get_Status_Is_Updated_From_Server | net/upd_download.h:37,39,40 |
ENUpdateType / UPDT_INV1/2/3 | net/server.h:190-192 |
g_u8_fw_sdram1 / g_u8_fw_sdram2 | net/server.h:258-259(__attribute__((at(...))) 定位于 SDRAM 固件区) |
inovance_set_inv_start_stop / INOVANCE_SLAVE_ADDRESS / INOVANCE_DAT_PCK_INTERVAL_INV / INOVANCE_OPERATE_STOP / INOVANCE_OPERATE_START | midware/inverter/inovance/inovance_comm_usart.h |
g_t_inovance_comm_info / g_t_inv_info | midware/inverter/inovance/inovance_comm_usart.h、midware/inverter/inverter.h |
OSTimeGet / OSTimeDlyHMSM | UCOSII(经 includes.h) |
6. 依赖关系
依赖(本文件 include):inovance_upgrade.h、upd_download.h、inv_download.h、server.h、sdram.h、usart2.h、inovance_comm_usart.h、inovance_comm_can.h、crc.h、inverter.h(inovance_upgrade.c:13-22)。其中 inovance_comm_can.h 在本文件中实际未被直接使用(CAN 相关操作在 inovance_upgrade_init() 里完成)。
被依赖:
midware/inverter/inovance/inovance_comm_usart.c:调用inovance_upgrade_handle()(:2592)与三个 flag 查询函数(:2585/2587/2589)midware/inverter/inverter.c:调用全部 6 个查询函数(:3828/3863/3898/3933/3984/4011),把汇川升级状态映射为上层统一的「逆变器升级中/百分比」接口
7. 备注与风险点
- 潜在栈越界(较严重):
inovance_upgrade_handle里的接收缓冲是u8 l_u8_recv_buf[20](inovance_upgrade.c:372),而inovance_upgrade_recv_data按usart2_get_data_len()的实际长度逐字节写入*(buf + l_u16_index)(:173),完全没有上限检查。正常协议应答不超过 8 字节,但一旦 USART2 收到异常长帧(噪声、波特率不匹配、串到其它帧),就会冲掉该任务的栈。 - 除零风险:
inovance_read_upgrade_percent_master/slave/fpga的分母是get_length_file_updating(UPDT_INV*)(:52/:77/:104),只判断了u8_upgrade_obj,未判断分母是否为 0。INIT中检测到长度为 0 时先退出到END、上下文要到下一次调用才memset清零(:827),中间窗口内被其它任务读取百分比就会整数除零(Cortex-M4 上触发 UsageFault)。 - 无符号恒假比较:
(s_t_inovance_upgrade.u32_file_length <= 0)(:688)对u32永远为假,属冗余写法,编译器会给警告;真正起作用的是u32_file_offset >= u32_file_length。 - 失败超限急停未清待办标志:
s_u8_upgrade_fail_cnt > 3分支(:396-405)只清了服务端更新标记和上下文,没有把s_u8_upgrade_mcu1_flag/mcu2_flag/fpga_flag复位。这些 static 标志会跨「整轮失败」保留为 TRUE,下一次升级请求到来时INIT仍会按旧标志选择对象,行为与「全新一轮」不一致。 abs()用于u32:inovance_upgrade_write_data中abs(OSTimeGet() - s_u32_send_pack_tick)与abs(timeout - abs(...))(:120、:122)把无符号差值传给int版abs,在 tick 回绕或差值超过INT_MAX时结果未定义;节流逻辑本身也只是「补足到 timeout」,没有减法下限保护。- 状态枚举三域混用:
INOVANCE_UPGRADE_RETURN_E把「设备运行状态」(RUNNING=1/REVERSE=2/SAFE=3)、「APP 侧响应错误」(CMD_ERROR=1/ADDR_ERROR=2/LENGTH_ERROR=3/CRC_CHECK_ERROR=4/JUMPER_DISCONNECT=5)、「boot 侧响应错误」(NO_ERROR=0/DATA_CRC16_ERROR=1/.../ID_ERROR=0x08/CRC32_INCOMPATIBLE_ERROR=0x11/...)塞进同一个枚举,多组取值重叠。代码里用(ret >> 8) == INOVANCE_UPGRADE_SAFE(:542)这种「高字节是状态、低字节是错误码」的隐式约定,可读性差且极易误用。
另注:枚举首项 INOVANCE_UPGRADE_RUNNING = 0x01 与 INOVANCE_UPGRADE_CMD_ERROR = 0x01 同值;INOVANCE_UPGRADE_NO_ERROR 出现在中间位置(=0x00),故 DATA_CRC32_ERROR 后显式写成 = 0x07 以复位计数,ID_ERROR 顺延为 0x08。修改此枚举顺序会静默改变协议语义。
- 魔法数字:
set_download_mode帧里的0xF6 0x0F(:287-288)与0x00 0x08(:289-290)没有宏/注释说明含义(推测为固定握手口令与长度),jump_boot的0x00 0x01、start_program的全零数据域同理。协议侧一改就要翻代码找字面量。 - 硬编码长延时阻塞任务:500 ms / 300 ms / 1000 ms / 5 s / 15 s / 20 s 全部以字面量出现在
OSTimeDlyHMSM中(:630/704/712/741/786/795),其中 20 s 的「首包后擦除等待」是任务级阻塞。虽然升级分支每次调用会刷新通信丢失 tick,但这段时间整个汇川任务无法处理其它报文(含 CAN 侧),若上层对逆变器心跳有更严的时限会出问题。 - 重复/错误的函数头注释:多个函数的 Doxygen 注释
@Name都写成不存在的inovance_send_upgrade_cmd(:110、:218、:246、:274、:302、:330),@Brief一律是「逆变器升级串口发送函数」,与实际的收包/查询函数不符(如inovance_upgrade_recv_data标成了发送);inovance_upgrade_read_dev_status等函数没有自己的@Name块。属历史拷贝残留,排查时容易误导。 INOVANCE_UPGRDADE_T.u8_upgrade_state死字段:结构体里定义了u8_upgrade_state,但状态机真正用的是函数内static u8 s_u8_upgrade_state,该字段全文件从未读写。- 接收缓冲残留:
inovance_upgrade_recv_data在len < 2时直接return(:160-163),既不清空 USART2 接收 FIFO 也没置位出参;此时*code/*ret/*len保持调用者栈上的旧值,调用方可能把上一轮的应答误当作本轮结果。 JUMP_BOOT忽略应答:JUMP_BOOT状态发完跳转帧后只是读一次串口就丢弃(:628),随后无条件延时 500 ms 前进。若设备实际未跳转,问题要到SET_DOWNLOAD_MODE连续 3 次失败才暴露。