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

inv_download.c

源文件路径:net/inv_download.c 所属模块:net(网络应用层 / 设备固件升级下载) 代码行数:195

1. 文件职责

本文件是逆变器(INV)与其配套设备云端固件下载流程的适配层,覆盖三个升级目标:UPDT_INV1(主机 / INVC(M))、UPDT_INV2(从机 / INVC(S))、UPDT_INV3(ARM 协处理器 / INVC(ARM))。它提供三类能力:查询“云端是否强制下载”(IsDownloadINV / IsDownloadCHG / IsDownloadInv3)、查询下载百分比(GetPercentDownloadINV / GetPercentDownloadCHG / GetPercentDownloadInv3)、查询“整机固件是否已从服务器更新完成”(is_inverter_firm_download_finished、is_bwinv_firm_download_finished)。

它还包含一个唯一的数据写入函数 Save_Data_To_Inv3_FW_Area(),把服务器下发的 INV3 固件块直接写进 SDRAM 外挂的固件缓冲区 g_u8_fw_sdram1(带 3 次重试),以及 Set_Inv2_Ver_From_Server() 把服务器版本串写进 stUpt[UPDT_INV2].as8SoftVer(带长度截断保护)。

数据流位置:云端特殊命令 → net/server.c:2346 handle_special_cmd_for_dev() 置位 → 本文件的状态查询被 HMI(hmi/ui/ui_main.c:791-813)与升级流程轮询 → net/server.c:3675 handle_fw_file_from_server() 把包数据分发到 save_fw_to_sdram()(INV1/INV3 用 g_u8_fw_sdram1,INV2 用 g_u8_fw_sdram2,见 net/server.c:3648-3657)→ net/upd_download.c:391 calculate_dev_FW_Flash_MD5() 校验 MD5 → 完成后由各厂商升级模块(midware/inverter/*/xxx_upgrade.c)读取本文件的完成标志决定何时开始刷写逆变器。

驱动方有三类:云端(触发下载)、HMI(显示进度)、逆变器通信/升级任务(消费完成标志)。

2. 关键数据结构与宏

名称类型说明
STUpdateTab结构体定义于 net/server.h:216;本文件读写其中的 bIsForceUpdtResponse(已应答强制升级)、as8SoftVer[16](服务器版本串)、bIsUpdateForce、bIsUpdatedFromServer、u32LenFile、u32OffsetFile
ENUpdateType枚举定义于 net/server.h:186;本文件使用 UPDT_INV1(2)、UPDT_INV2(3)、UPDT_INV3(4) 三个下标
ST_EMS_INFO(g_stEMSInfo)全局结构体实例定义于 net/ems.h;stUpt[UPDT_MAX] 是升级表(net/ems.h:346)
g_u8_fw_sdram1全局数组u8 g_u8_fw_sdram1[SDRAM_3M] __attribute__((at(SDRAM_FIRM1_START_ADDR))),声明于 net/server.h:258;INV1/INV3/BMS/Meter/EVC/AFCI 共用的 3 MB SDRAM 固件暂存区
MAX_LEN_SOFT_VER宏net/server.h:146,值 (16);软版本串最大长度,对应 as8SoftVer[16];本文件用它做 Set_Inv2_Ver_From_Server() 的截断判据
BOOLEAN类型uCOS/uC-LIB 定义;Get_Response_For_Inv3_Force_Update() 的返回类型
BOARD_EMS3_6_3_E枚举值system/board_init/board_init.h:21 的板型之一;is_bwinv_firm_download_finished() 用它判断是否为单核 CPU 逆变器(贝瓦机型)板
DEBUG_TCP_CLIENT_STATE宏调试开关,控制 Save_Data_To_Inv3_FW_Area() 与 Set_Inv2_Ver_From_Server() 中的 printf
SIZE_KB_500宏定义于 inv_download.h:21,值 (1024*500);全工程无任何引用(死宏),且未在本文件使用

本文件不定义任何结构体、枚举、联合体、位域。

3. 函数清单

函数名作用域说明
Get_Response_For_Inv3_Force_Update全局inv_download.c:39。返回 stUpt[UPDT_INV3].bIsForceUpdtResponse,表示 EMS 是否已对云端 INV3 强制升级命令作出应答
Save_Data_To_Inv3_FW_Area全局inv_download.c:55。把一包 INV3 固件写入 g_u8_fw_sdram1 + u32OffsetFile,最多重试 3 次,成功返回 0、失败返回 1
Set_Inv2_Ver_From_Server全局inv_download.c:88。把服务器版本串写入 stUpt[UPDT_INV2].as8SoftVer,带 NULL/长度 0 提前返回与 MAX_LEN_SOFT_VER 截断保护
IsDownloadINV全局inv_download.c:116。返回 get_flag_force_update(UPDT_INV1),主机强制下载标志
GetPercentDownloadINV全局inv_download.c:127。UPDT_INV1 的下载百分比
IsDownloadCHG全局inv_download.c:138。返回 get_flag_force_update(UPDT_INV2),从机(充电机 CHG)强制下载标志
GetPercentDownloadCHG全局inv_download.c:149。UPDT_INV2 的下载百分比
IsDownloadInv3全局inv_download.c:160。返回 get_flag_force_update(UPDT_INV3),ARM 侧强制下载标志
GetPercentDownloadInv3全局inv_download.c:171。UPDT_INV3 的下载百分比
is_inverter_firm_download_finished全局inv_download.c:182。返回 Get_Status_Is_Updated_From_Server(UPDT_INV1) && Get_Status_Is_Updated_From_Server(UPDT_INV2),即主/从机固件都已就绪
is_bwinv_firm_download_finished全局inv_download.c:192。返回 get_board_type() == BOARD_EMS3_6_3_E,单核 CPU 逆变器板的特判

共 11 个函数,全部为全局作用域,无 static 函数、无函数指针、无回调。其中 Get_Response_For_Inv3_Force_Update、Save_Data_To_Inv3_FW_Area、Set_Inv2_Ver_From_Server 三个全工程无调用点(详见第 7 节备注 1)。

4. 核心逻辑解析

4.1 三种逆变器升级目标的编号与显示映射

ENUpdateType 中的三个逆变器槽位与 HMI 显示文案、SDRAM 缓冲区、机型串来源的对应关系如下(数据来源:net/server.h:186-198、net/server.c:3642-3662、hmi/ui/ui_main.c:791-813):

枚举值HMI 文案文件掩码SDRAM 缓冲区固件类型串来源
UPDT_INV12INVC(M)FILE_MASK_INV1 = "00000004"g_u8_fw_sdram1inverter_read_inv_type()
UPDT_INV23INVC(S)FILE_MASK_INV2 = "00000008"g_u8_fw_sdram2inverter_read_inv_type()
UPDT_INV34INVC(ARM)FILE_MASK_INV3 = "00000400"g_u8_fw_sdram1inverter_read_inv_type()

注意 INV2 是唯一使用 g_u8_fw_sdram2 的类型,因此 INV1/INV3 的下载不能与其它共用 g_u8_fw_sdram1 的设备(BMS/Meter/EVC/AFCI)并发,这是云端调度必须遵守的隐含约束。

4.2 Save_Data_To_Inv3_FW_Area() —— 唯一的写路径

char Save_Data_To_Inv3_FW_Area(u8 *fw_Bin, u32 Len)          // inv_download.c:55
{
    l_u32AddrOffset = get_curr_offset_file_request(UPDT_INV3);
    l_u32WrAddr = (u32)(g_u8_fw_sdram1 + l_u32AddrOffset);
    ...
    for(u8 i = 0;i < 3;i ++)
    {
        l_u8Res = FMC_SDRAM_WriteBuffer_02(fw_Bin, l_u32WrAddr, Len);
        if(l_u8Res == Len)
            return 0;
    }
    return 1;
}

要点:

4.3 Set_Inv2_Ver_From_Server() —— 带截断保护的字符串复制

void Set_Inv2_Ver_From_Server(char * ver,u8 len)             // inv_download.c:88
{
    if(ver == NULL ||  len == 0 )  { ... return ; }           // 参数保护
    if( len  >=   MAX_LEN_SOFT_VER)                            // len >= 16
    {
        memcpy(..., ver, (MAX_LEN_SOFT_VER-1));                // 拷 15 字节
        ...as8SoftVer[MAX_LEN_SOFT_VER-1] = '\0';              // 强补结束符
    }
    else
    {
        memcpy(..., ver, len);                                 // 拷 len 字节
        ...as8SoftVer[len] =  '\0';                            // 补结束符(len<=15,不越界)
    }
}

契约是「最多保留 15 个可见字符 + 1 个 '\0'」,对应 as8SoftVer[16](net/server.h:226)。len 参数由调用方传入;本文件没有调用点,功能上已被 net/upd_download.c:269 的通用版 set_ver_from_server(ENUpdateType, char*, u8) 完全覆盖(net/server.c:2422 调用的是通用版)。

4.4 两个“完成”判据的语义差异

接口判据语义
is_inverter_firm_download_finished()UPDT_INV1 && UPDT_INV2 的 bIsUpdatedFromServer主机与从机固件都已收妥并通过 MD5 校验
is_bwinv_firm_download_finished()get_board_type() == BOARD_EMS3_6_3_E不查任何升级状态,纯板型判据

is_bwinv_firm_download_finished() 的实现与命名严重不符(注释称“获取单核 cpu 逆变器升级标记”):它只是问“本机是不是 3.6.3_E 板”。唯一调用点 midware/inverter/alphaess/alphaess_upgrade.c:410 的写法是:

else if(is_bwinv_firm_download_finished() && get_board_type() != BOARD_EMS3_6_4_E)

即 get_board_type()==BOARD_EMS3_6_3_E && get_board_type()!=BOARD_EMS3_6_4_E,后半段恒为真——这实际上就是在筛选 3.6.3_E 板。可以认为该函数是“板型判据”的包装,而不是“升级状态”查询。

is_inverter_firm_download_finished() 的调用点很多(至少 14 处),典型用法是“固件已就绪 → 逆变器通信层只传固件不传常规数据帧”:

4.5 状态迁移(外部状态机,本文件提供读点)

[云端特殊命令] server.c:2346 handle_special_cmd_for_dev
      ├─ 强制: server.c:2408  set_flag_force_update(UPDT_INV1/2/3, TRUE)
      ├─ 非强制: server.c:2410-2412  INV3 被显式清零(与 BMS/EVC 同组)
      └─ server.c:2418  set_updt_file_mask(...)
             ↓  IsDownloadINV()/IsDownloadCHG()/IsDownloadInv3() == 1
             ↓  HMI ui_main.c:791-813 进入 “Download INV/CHG FW” 界面,显示百分比
      ↓  server.c:3453-3464 set_file_updating_info_for_dev(UPDT_INV1/2/3, 5K, SDRAM_3M)
      ↓  server.c:3748-3758 save_fw_to_spi_flash → save_fw_to_sdram(INV1/INV3→sdram1, INV2→sdram2)
      ↓  server.c:3787-3798 calculate_dev_FW_Flash_MD5(UPDT_INV1/2/3, ...)
      ├─ MD5 一致 → upd_download.c:412 Set_Status_Is_Updated_From_Server(..., TRUE)
      │             ↓ is_inverter_firm_download_finished() == 1
      │             ↓ 各厂商 upgrade 模块开始刷写逆变器
      └─ MD5 不一致 → upd_download.c:422 u16_upgrade_error.BIT.md5_error = 1

另有强制升级应答链:net/server.c:2370/:2382 置 bIsForceUpdtResponse,Get_Response_For_Inv3_Force_Update() 是它的读点(当前无人调用);net/ems.c:2882 与 net/server.c:151 会把它清回 FALSE。

4.6 通信协议帧格式与重试机制

本文件不构造/解析任何报文,也没有超时参数。相关外部契约:

4.7 与 uCOS-II 的配合

本文件不涉及任何 uCOS-II API:无任务创建/挂起/延时,无信号量,无消息邮箱,无事件标志组。所有函数都是同步、非阻塞、O(1)(Save_Data_To_Inv3_FW_Area 的 3 次重试是忙等循环,但每次只是一次 SDRAM 写,不调用 OSTimeDly)。

g_stEMSInfo.stUpt[] 由 EMS 网络任务(net/server.c、net/ems.c)写,被 HMI 任务与多个逆变器通信任务读,全程无临界区。is_inverter_firm_download_finished() 连续读两个 u8 字段(inv_download.c:184)而未做原子快照,理论上可能出现“读到 INV1 已置位、INV2 尚未置位”的中间态;由于该函数只用于放宽数据帧发送限制,中间态只会导致延迟一轮生效,无功能风险。

5. 对外接口

本文件导出(供谁调用):

导出名调用方
IsDownloadINVhmi/ui/ui_main.c:791、:795;net/ems_download.c:255
IsDownloadCHGhmi/ui/ui_main.c:791、:802;net/ems_download.c:256
IsDownloadInv3hmi/ui/ui_main.c:791;net/ems_download.c:257
GetPercentDownloadINVhmi/ui/ui_main.c:799
GetPercentDownloadCHGhmi/ui/ui_main.c:806
GetPercentDownloadInv3hmi/ui/ui_main.c:813
is_inverter_firm_download_finishedmidware/inverter/alphaess/alphaess_comm_can.c:1189、alphaess_comm_usart.c:5337/:5434、ginlong/ginlong_comm_can.c:301、ginlong_comm_usart.c:4863、goodwe/goodwe_comm.c:2448、inovance/inovance_comm_can.c:599、inovance_comm_usart.c:2575、inovance_upgrade.c:414、kelong/kelong_comm.c:1365、set/set_comm_can.c:685、set_upgrade_s5.c:164;net/ems.c:6681
is_bwinv_firm_download_finishedmidware/inverter/alphaess/alphaess_upgrade.c:410
Get_Response_For_Inv3_Force_Update无调用点
Save_Data_To_Inv3_FW_Area无调用点
Set_Inv2_Ver_From_Server无调用点

本文件不导出全局变量。

本文件调用的外部符号:

名称来源
g_stEMSInfonet/ems.h
get_flag_force_update / Get_Status_Is_Updated_From_Server / get_curr_offset_file_request / get_length_file_updatingnet/upd_download.c(声明于 upd_download.h:26/28/37/40)
FMC_SDRAM_WriteBuffer_02hardware/sdram/sdram.c:242(声明于 sdram.h:107)
g_u8_fw_sdram1net/server.h:258
get_board_typesystem/board_init/board_init.h:30 / board_init.c
MAX_LEN_SOFT_VER、DEBUG_TCP_CLIENT_STATEnet/server.h:146 / 调试开关
memcpy、printf、__FUNCTION__、__LINE__C 标准库(string.h / stdio.h)

6. 依赖关系

依赖(第 13-23 行 include):

被依赖(include inv_download.h 的文件,共 18 处):

7. 备注与风险点

  1. 3 个函数定义后无任何调用点(死代码):Get_Response_For_Inv3_Force_Update(:39)、Save_Data_To_Inv3_FW_Area(:55)、Set_Inv2_Ver_From_Server(:88)在全工程 .c/.h 中除本文件外无第二次出现(已用 grep -rn 确认)。功能分别被 get_response_force_upd_status(UPDT_INV3)、Save_Data_To_FW_Area_InSdram(UPDT_INV3, ..., g_u8_fw_sdram1)、set_ver_from_server(UPDT_INV2, ...) 取代。保留的三份重复实现会随版本演化与通用版产生行为漂移。
  2. Save_Data_To_Inv3_FW_Area 返回值语义反直觉且未做边界检查:return 0 表示成功、return 1 表示失败(与 net/upd_download.c:137 一致),且不校验 offset + Len ≤ SDRAM_3M。越界防护完全依赖云端上报的 u32LenFile 落在 (5 KB, 3 MB) 区间内(net/server.c:3463)。若云端上报的包长与偏移不一致(例如重复包导致 u32OffsetFile 累加超限),会写穿 g_u8_fw_sdram1 的 3 MB 上界,覆盖到 SDRAM_FIRM2_START_ADDR(INV2 固件区)。
  3. is_bwinv_firm_download_finished() 名实不符:函数名与注释都是“固件下载完成标记”,实现却是 get_board_type() == BOARD_EMS3_6_3_E(inv_download.c:194),完全不查升级状态。唯一调用点 alphaess_upgrade.c:410 又叠加了 && get_board_type() != BOARD_EMS3_6_4_E,构成冗余条件。这是明确的命名/语义风险,改动板型定义时极易误伤。
  4. u8 截断与除零:三个百分比函数(:129、:151、:173)的除数是 u32LenFile,在文件信息到达前为 0;HMI 是「先判 IsDownload*() 再算百分比」,存在除零窗口(ARM 平台的 32 位无符号除法除零返回 0、不触发硬件异常,故不死机)。返回类型 u8 与 u32 中间值之间没有上限保护。
  5. is_inverter_firm_download_finished() 的两次读非原子:inv_download.c:184 在一行内连续读两个 u8 字段并做 &&,中间可能被网络任务打断,读到不一致快照。影响仅为延迟一轮生效,无功能风险,但属于典型竞态写法。
  6. SIZE_KB_500 是死宏:定义于 inv_download.h:21,全工程无引用(grep -rn 仅命中定义行)。INV 固件长度上限实际由 SDRAM_3M(net/server.c:3455-3463)决定,该宏已过期。
  7. inv_download.h 声明的 5 个函数无定义:set/get_flag_inv1_force_update、set/get_flag_inv3_force_update、Clear_Inv2_Update_Info 在本文件及全工程都没有实现;同时本文件定义的 Get_Response_For_Inv3_Force_Update 又没有在头文件中声明(缺原型,C99 下会有告警)。声明集合与实现集合双向不匹配。
  8. #include "md5.h" 大小写与其它文件不一致:同族文件用 "MD5.h"。Windows/Keil 不敏感,跨平台工具链会失败(见 6. 依赖)。
  9. 注释与实现不一致:inv_download.c:186-190 的函数头注释写 u8 is_inverter_firm_download_finished(void),但下面定义的是 is_bwinv_firm_download_finished()(注释标题重复);:44-53 的注释签名写 char Save_Data_To_Inv3_FW_Area(const u8 *fw_Bin, u32 Len),实现是 u8 *fw_Bin(去掉了 const)。
  10. 冗余 include:iwdg.h、stdlib.h、md5.h 在本文件无使用,midware/debug/ate.c 引入本头文件后也未使用任何符号。