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

afci_download.c

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

1. 文件职责

本文件是 AFCI(电弧故障断路器)云端固件下载流程的标志与标识适配层,本身不搬运任何固件字节。它把 g_stEMSInfo.stUpt[UPDT_AFCI] 这一升级表项包装成 5 个对本模块友好的查询接口:强制更新标志(IsDownloadAFCI)、已从服务器更新完成标志(is_afci_firm_download_finished)、下载百分比(GetPercentDownloadAFCI)、AFCI 机型字符串(get_afci_type)、AFCI 硬件版本号(get_afci_hard_version)。

数据流位置:云端下发特殊命令 → net/server.c:2346 handle_special_cmd_for_dev() 置 stUpt[UPDT_AFCI].bIsUpdateForce 与文件掩码 → 本文件的 IsDownloadAFCI() / GetPercentDownloadAFCI() 被 HMI 主界面轮询 → net/ems.c:2945 request_update_file_info() 通过 get_afci_hard_version() / get_afci_type() 把机型与原版本上报服务器 → net/server.c:3675 handle_fw_file_from_server() 逐包写入 g_u8_fw_sdram1 → net/upd_download.c:391 calculate_dev_FW_Flash_MD5() 比对 MD5 成功后 Set_Status_Is_Updated_From_Server(UPDT_AFCI, TRUE) → is_afci_firm_download_finished() 被逆变器通信层读取,决定是否停发常规数据帧。

驱动方是「云端指令 + 逆变器通信任务」:前者触发下载,后者消费“升级完成”标志。

2. 关键数据结构与宏

名称类型说明
STUpdateTab结构体定义于 net/server.h:216,固件升级表项。本文件主要读它的 bIsUpdateForce(强制更新)、bIsUpdatedFromServer(已完成)、u32LenFile(文件总长)、u32OffsetFile(已下载偏移)、as8FileMask[8]
ENUpdateType枚举定义于 net/server.h:186;本文件用其中的 UPDT_AFCI(值 7,排在 UPDT_Meter/UPDT_EVC 之后)作为 stUpt[] 下标
ST_EMS_INFO(g_stEMSInfo)全局结构体实例定义于 net/ems.h,本文件唯一的全局状态来源;stUpt[UPDT_MAX] 数组即升级表(net/ems.h:346)
FILE_MASK_AFCI宏net/server.h 中为 "00002000",AFCI 的文件掩码;本文件未直接引用,由 server.c / ems.c 用于匹配
FILE_MASK_DEFAULT宏net/server.h:82,值 "00000000";本文件在文件掩码为空串时作为兜底返回
VERSION_AFCI_HARD宏midware/afci/afci_comm.h:18,值 "V1.0";本文件把它作为 AFCI 硬件版本上报云端
AFCI_TYPE_BYTE_WATT_S宏midware/afci/afci_comm.h:19,值 "BYTE_AFCI_S"(贝瓦单相 AFCI 机型串)
AFCI_TYPE_BYTE_WATT_T宏midware/afci/afci_comm.h:20,值 "BYTE_AFCI_T"(贝瓦三相 AFCI 机型串)
INVERTER_CATEGORY_E枚举定义于 midware/inverter/inverter.h:403:INVERTER_TYPE_BYTE_WATT_S / INVERTER_TYPE_BYTE_WATT_T / INVERTER_TYPE_NON_BYTE_WATT;本文件用 get_inverter_type_category() 的返回值切换机型串

本文件不定义任何结构体、枚举、联合体、位域或宏常量,只有 include guard 由头文件提供。

3. 函数清单

函数名作用域说明
get_afci_Updt_File_Mask全局afci_download.c:41。返回 AFCI 升级文件掩码,空则回退 FILE_MASK_DEFAULT;但读的是 stUpt[UPDT_Meter] 下标
is_afci_firm_download_finished全局afci_download.c:59。返回 Get_Status_Is_Updated_From_Server(UPDT_AFCI),即 AFCI 固件已由服务器更新到位
IsDownloadAFCI全局afci_download.c:70。返回 get_flag_force_update(UPDT_AFCI),服务器下发的 AFCI 强制更新标志
GetPercentDownloadAFCI全局afci_download.c:81。返回 已下载偏移 * 100 / 文件总长
get_afci_type全局afci_download.c:93。按 get_inverter_type_category() 把逆变器机型映射为 AFCI 机型串,非贝瓦机型返回空串 ""
get_afci_hard_version全局afci_download.c:110。返回常量 VERSION_AFCI_HARD("V1.0")

共 6 个函数,全部为全局作用域,无 static 函数、无函数指针、无回调。文件内无任何循环/阻塞逻辑,均为 O(1) 查询。

4. 核心逻辑解析

4.1 三个纯转发接口与百分比公式

三个标志/百分比接口都是对 net/upd_download.c 中通用访问器的直接转发,没有本地缓存:

本文件函数转发到底层字段
IsDownloadAFCI()get_flag_force_update(UPDT_AFCI)(upd_download.c:89)stUpt[UPDT_AFCI].bIsUpdateForce
is_afci_firm_download_finished()Get_Status_Is_Updated_From_Server(UPDT_AFCI)(upd_download.c:375)stUpt[UPDT_AFCI].bIsUpdatedFromServer
GetPercentDownloadAFCI()get_curr_offset_file_request(UPDT_AFCI)(upd_download.c:121)+ get_length_file_updating(UPDT_AFCI)(upd_download.c:327)u32OffsetFile * 100 / u32LenFile

百分比公式的关键取值来源:

由于分子分母都是 u32,而函数返回 u8,* 100 的计算在 32 位下完成后再截断为 8 位——正常流程里比值 ≤ 100,不触发截断。

4.2 AFCI 机型映射

get_afci_type()(afci_download.c:93)是一个 3 分支 switch:

get_inverter_type_category() 返回输出的 AFCI 机型串
INVERTER_TYPE_BYTE_WATT_S"BYTE_AFCI_S"
INVERTER_TYPE_BYTE_WATT_T"BYTE_AFCI_T"
INVERTER_TYPE_NON_BYTE_WATT(含 default)""(空串)

get_inverter_type_category() 定义于 midware/inverter/inverter.c:8003,返回值来自逆变器自身识别结果。返回空串是有意义的:非贝瓦机型不带 AFCI,云端比对机型串时不会命中。

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

本文件自身没有状态机,但它读写的两个布尔位构成一条外部迁移链:

[云端特殊命令到达]
   server.c:2346 handle_special_cmd_for_dev(..., isForceUpd, fileMask)
        ├─ server.c:2370  set_response_force_upd_status(updType, TRUE)   // 已应答
        ├─ server.c:2408  set_flag_force_update(UPDT_AFCI, TRUE)         // bIsUpdateForce=1
        └─ server.c:2418  set_updt_file_mask(UPDT_AFCI, FILE_MASK_AFCI)
                 ↓  IsDownloadAFCI()==TRUE  →  HMI 进入“AFCI 下载中”界面
[文件信息上报/下发]  ems.c:2945 → server.c:3318 u32LenFile 生效
                 ↓  server.c:3675 逐包写 g_u8_fw_sdram1,u32OffsetFile 递增
                 ↓  GetPercentDownloadAFCI() 在 HMI 上显示 0~100
[最后一包收妥]  server.c:3811 calculate_dev_FW_Flash_MD5(UPDT_AFCI, g_u8_fw_sdram1, AFCI_FIRM_DOWNLOAD)
        ├─ MD5 相同 → upd_download.c:412 Set_Status_Is_Updated_From_Server(UPDT_AFCI, TRUE)
        │              ↓ is_afci_firm_download_finished()==TRUE
        │              ↓ alphaess_comm_usart.c:5444 只传输固件,停发常规帧
        └─ MD5 不同 → upd_download.c:422 u16_upgrade_error.BIT.md5_error = 1

u8 返回值被直接当布尔用(if(...)),全工程一致,语义清晰。

4.4 通信协议帧格式与纠错

本文件不构造也不解析任何报文。与之相关的是它提供的两个字符串如何进入 EMS 云端协议:

超时与重试不在本文件,由 server.c 的包序校验(offset 必须与本地一致,server.c:3699)与云端超时重发实现。

4.5 与 uCOS-II 的配合

无任何 uCOS-II 调用:不创建任务、不申请信号量、不使用消息邮箱、不调用延时。所有函数都是对 g_stEMSInfo 的同步单次读写。

g_stEMSInfo 被 EMS 网络任务(net/server.c)写、被 HMI 任务(hmi/ui/ui_main.c:898)与逆变器通信任务(midware/inverter/alphaess/alphaess_comm_usart.c:5337)读,属于跨任务共享的普通全局变量,未加临界区。当前依赖 u32 读写的自然原子性和布尔位的单字节写入来避免撕裂。

5. 对外接口

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

导出名调用方
IsDownloadAFCIhmi/ui/ui_main.c:898、net/ems_download.c:261(IsSystemDownload())
GetPercentDownloadAFCIhmi/ui/ui_main.c:904
is_afci_firm_download_finishedmidware/inverter/alphaess/alphaess_comm_usart.c:5337、:5444
get_afci_typenet/ems.c:3025、:3105;net/server.c:3314、:3711
get_afci_hard_versionnet/ems.c:2989;net/server.c:3314
get_afci_Updt_File_Mask无任何调用点,且未在 afci_download.h 中声明

本文件不导出全局变量。

本文件调用的外部符号:

名称来源
g_stEMSInfonet/ems.h(全局 EMS 信息结构)
Get_Status_Is_Updated_From_Server / get_flag_force_update / get_curr_offset_file_request / get_length_file_updatingnet/upd_download.c(声明于 upd_download.h:26/28/37/40)
get_inverter_type_categorymidware/inverter/inverter.c:8003(声明于 inverter.h:2255)
strlenC 标准库(经 string.h 间接引入)
FILE_MASK_DEFAULTnet/server.h:82
VERSION_AFCI_HARD / AFCI_TYPE_BYTE_WATT_*midware/afci/afci_comm.h:18-20

6. 依赖关系

依赖(第 13-21 行 include):

被依赖(include afci_download.h 的文件):

7. 备注与风险点

  1. get_afci_Updt_File_Mask() 使用了错误的下标(疑似复制粘贴缺陷):afci_download.c:43-45 操作的是 g_stEMSInfo.stUpt[UPDT_Meter].as8FileMask,即读的是电表的升级掩码,而不是 UPDT_AFCI。对照 meter_download.c:40 可见两者代码完全一致。所幸该函数全工程无调用点、也未在头文件声明,目前不影响运行,但一旦被启用就是隐藏 bug。
  2. as8FileMask[8] 可能没有结束符,strlen 存在越界读:set_updt_file_mask()(upd_download.c:253)用 strncpy(dst, fileMask, 8) 写入,而掩码串字面量恰好是 8 字符(如 "00002000"),因此末尾 '\0' 会被截掉;afci_download.c:43 与 meter_download.c:42 随后对它取 strlen,会继续向后读到结构体的下一成员 as8FWType[10]。当前靠该成员恰好为 0 才得到正确结果,属未定义行为,重构结构体布局即可能出错。
  3. 百分比函数存在除零可能:GetPercentDownloadAFCI() 的除数是 u32LenFile。bIsUpdateForce 在 server.c:2408 被置位时,文件长度通常还没解析出来(u32LenFile 仍为 0),而 HMI 是「先判 IsDownloadAFCI() 再算百分比」(ui_main.c:898、:904),存在同一轮内分母为 0 的窗口。ARM 平台上 32 位无符号除法除零不会触发硬件异常(Cortex-M4 的 UDIV 指令或库函数 __aeabi_uidiv 均返回 0),因此表现为百分比显示 0% 而非死机,但语义上并不正确,属于依赖“除零得 0”这一平台行为的隐式假设。
  4. 函数头注释张冠李戴:afci_download.c:64-79 的注释写的是 IsDownloadMeter / GetPercentDownloadMeter,显然是复制 meter_download.c 后未改注释。
  5. 作者/文件名注释不一致:.c 文件头 @author: Alpha EMS Team,.h 文件头 @author: Alpha g_stEMSInfo Team。后者与 meter_download.h / evc_download.h 一致,推测是历史上把标识符 EMS 全局替换为 g_stEMSInfo 时误改了注释。
  6. 硬版本号硬编码:get_afci_hard_version() 返回 afci_comm.h 的宏 VERSION_AFCI_HARD = "V1.0",一旦硬件改版必须同步改宏,没有与实物 AFCI 上报版本做一致性校验的路径。
  7. 冗余 include:MD5.h / sdram.h / iwdg.h 在本文件未被使用(见 6. 依赖),可移除;当前保留会扩大编译依赖面。