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

afci_comm.c

源文件路径:midware/afci/afci_comm.c 所属模块:midware / afci(电弧故障断路器 AFCI 通信与日志) 代码行数:951

1. 文件职责

本文件是 EMS 与 AFCI 板(电弧故障检测模块)之间的常规通信层,负责 5 条业务:读 AFCI 软版本号并按机型重排为可读字符串、AFCI 通道自检(工厂模式进入/退出 + 通道使能与结果回读)、告警清除与故障日志的逐帧拉取、AFCI 软重启、以及清除 AFCI 故障记录。

它处在「逆变器通信任务 → USART2 总线 → AFCI 板」这一环:所有帧都经 alphaess_write_data() / alphaess_afci_recv_data() 走 USART2(与阿尔法逆变器主控共用同一条串口),被 midware/inverter/alphaess/alphaess_comm_usart.c 的 alphaess_afci_comm_function()(:5045)周期驱动。

拉取到的 AFCI 故障日志以 ASCII HEX 字符串形式滚动缓存到 SDRAM 定址全局量 g_t_afci_log_tab,再由 net/ems.c 的 fill_send_afci_log() 打包成 CMD_SEND_AFCI_LOG_DATA(0x62) JSON 上报云端,云端回复后由 net/server.c:7084 回调 set_afci_log_data_upload_send_status() 收尾 —— 因此本文件同时是 AFCI 日志上传链路的生产者。

2. 关键数据结构与宏

名称类型说明
ALPHAESS_AFCI_STATE_E枚举afci_comm.h:59。自检状态机三态:AFCI_START_STATE(0)、AFCI_SELF_CHECK_STATE(1)、AFCI_FAULT_STATE(2)
AFCI_LOG_UPDATA_STATE_E枚举afci_comm.h:66。日志上传状态:AFCI_DATA_NONE(0x00)、AFCI_DATA_UPDATA(0x01)、AFCI_UPDATA_COMPLETE(0x02);后两者直接作为 JSON UploadStatus 字段上报
AFCI_QRY_RET_E枚举afci_comm.h:73。日志帧查询返回值:AFCI_QRY_OK、AFCI_QRY_FAIL、AFCI_QRY_END(本帧无有效数据 = 拉完)、AFCI_QRY_BUF_FULL
AFCI_LOG_DATA_TABLE结构体afci_comm.h:80。AFCI 日志上传的全局唯一状态块,见下方字段说明
g_t_afci_log_tab全局变量afci_comm.c:27。AFCI_LOG_DATA_TABLE 的唯一定义,用 __attribute__((at(SDRAM_AFCI_FAULT_LOG_ADDR))) 定址到 SDRAM(sdram.h:56,保留 2 KB);被 extern 于 afci_comm.h:95
AFCI_SLAVR_ADDRESS宏afci_comm.h:22,值 0x01。AFCI 常规 Modbus 从站地址。注意与逆变器从站地址 ALPHAESS_SLAVR_ADDRESS(0x03) 不同,靠首字节区分报文归属
SELF_CHECK_CHANNEL宏afci_comm.h:23,值 0x3F。4 路 AFCI 检测通道全使能位图(bit0~bit5)
AFCI_ADDR_REG_WARNING_MESSAGE / AFCI_NUM_WARNING_MESSAGE宏afci_comm.h:25-26,寄存器 0x0002,1 个寄存器。读出的 16 位值即“无告警”判别码
AFCI_ADDR_REG_QUERY_SOFT_VERSION2 / AFCI_NUM_QUERY_SOFT_VERSION2宏afci_comm.h:28-29,寄存器 0x0010,11 个寄存器(22 字节)软版本区
AFCI_ADDR_REG_SELF_CHECK_FUNCTION_ENABLE / AFCI_NUM_SELF_CHECK_FUNCTION_ENABLE宏afci_comm.h:31-32,寄存器 0x0024,1 个寄存器。写 = 使能自检通道,读 = 回读自检状态
AFCI_ADDR_REG_SET_SOFT_REBOOT / ALPHAESS_NUM_SET_SOFT_REBOOT宏afci_comm.h:34-35,寄存器 0x0025,写 1 触发软重启(注意第二个宏沿用了 ALPHAESS_ 前缀,命名不一致)
AFCI_ADDR_REG_SEND_FAC_MODE_CMD / AFCI_NUM_SEND_FAC_MODE_CMD宏afci_comm.h:37-38,寄存器 0x0026,1 = 进入工厂模式,0 = 退出
AFCI_ADDR_REG_SEND_CLEAR_INFO_CMD / AFCI_NUM_SEND_CLEAR_INFO_CMD宏afci_comm.h:40-41,寄存器 0x00E0,写 0 清除信息
AFCI_FUNC_REG_SEND_CLEAR_DATA_CMD / AFCI_NUM_SEND_CLEAR_DTA_CMD宏afci_comm.h:43-44,功能码 0xE0(拼写 DTA 为笔误),用于 8 字节裸帧清故障记录
AFCI_ADDR_REG_GET_LOG_DATA_CMD / AFCI_ADDR_REG_REPEAT_LOG_DATA_CMD宏afci_comm.h:46-50,功能码 0xE1(取新日志)/ 0xE2(重发当前帧),只占 1 字节
AFCI_GET_MAX_LOG_DATA_LEN宏afci_comm.h:52,值 64。单帧最多拉取 64 字节日志数据
AFCI_LOG_MAX_FRAME_NUM / AFCI_LOG_TOTAL_MAX_LEN宏afci_comm.h:54-55。17 帧 × 64 字节 = 1088 字节,即 afci_log_buff 的容量(注意存的是 HEX 文本,实际承载 544 字节原始数据)
AFCI_LOG_GROUP_SIZE宏afci_comm.h:57,值 8。每凑满 8 帧日志就打成一个上传包
DEBUG_ALPHAESS_AFCI宏afci_comm.h:16,值 0。本文件与 alphaess_comm_usart.c:403 的调试打印总开关,当前关闭
AFCI_LOG_DATA_TABLE 字段—u32_afci_log_send_len(已拼接长度,单位字节=2×字符数)、u32_afci_log_send_net_len(发往云端长度)、u16_afci_log_seq(当前帧序号,实际未被本文件使用)、u8_afci_log_status、u8_afci_log_send_flag(待发标志)、u8_afci_log_rev_ok_flag(云端已应答标志)、afci_log_pack_flag[32](包标识/时间戳)、u32_afci_log_send_offset(发送次数)、afci_log_buff[1088]

本文件不定义任何结构体/枚举/宏,全部来自 afci_comm.h;唯一的文件级变量是 s_u8_afci_recv_buf。

3. 函数清单

函数名作用域说明
send_query_data_to_afcistatic:51。组 0x03 读保持寄存器请求帧(8 字节)并发送
ems_send_ctrl_data_to_afci全局:77。组 0x06 写单寄存器 / 0x10 写多寄存器帧并发送,带长度合法性校验
alphaess_afci_recv_data全局:119。从 USART2 同步收一帧 AFCI 应答,校验从站地址与 Modbus CRC,成功回填长度
afci_log_init全局:200。清零 g_t_afci_log_tab 并复位 u8_ems_set_inv_afci_log_flag
get_version_sort_mapstatic:213。按逆变器机型类别返回“版本字节重排表”及其长度
parse_afci_version_datastatic:242。校验版本帧头、按重排表抽取版本字符、置 u8_support_afci_flag
query_afci_software_version全局:292。查询 AFCI 软版本(唯一上电/升级后识别 AFCI 是否存在的入口)
inverter_read_ver_afci全局:339。返回版本字符串指针,先强制末字节为 0 保证可当 C 串用
send_afci_clear_info全局:352。向寄存器 0x00E0 写 0,清除 AFCI 信息(全工程无调用点)
set_afci_fac_mode全局:402。向寄存器 0x0026 写 fac_mode,1 进工厂模式 / 0 退出
send_afci_clear_warning_message全局:442。向寄存器 0x0002 写 0 清除告警报文
send_afci_self_check_enablestatic:482。向寄存器 0x0024 写 SELF_CHECK_CHANNEL(0x3F) 使能全部自检通道,成功后打自检计时戳
query_afci_self_check_statusstatic:523。读寄存器 0x0024,取应答第 5 字节低 4 位,为 0 判定自检“已完成”
query_afci_warning_messagestatic:568。读寄存器 0x0002,与机型对应基准码(S 相 0x2100 / T 相 0x2700)比对判定“无告警”
set_afci_soft_reboot全局:623。向寄存器 0x0025 写 1 软重启 AFCI
afci_self_check_handle全局:663。AFCI 自检状态机(3 态),成功清 bit27、失败置 bit27 并要求停机
send_clear_afci_log_data全局(未在头文件声明):747。发 8 字节裸帧 [01][E0][00][00][00][00][CRC] 清除 AFCI 故障记录
query_afci_log_datastatic:773。按功能码 + 帧序号拉一帧日志,HEX 化后追加进 afci_log_buff
afci_fault_log_data_handle全局:827。日志分帧拉取主状态推进器,凑 8 帧成组、连续 3 次失败收尾
set_afci_log_data_upload_send_status全局:926。云端应答后的回调:解锁发送、累加 u32_afci_log_send_offset,整包传完则清零并清 AFCI 报错
get_afci_soft_version全局:947。返回 g_t_inv_info.t_afci_info.u8_afci_soft_version 指针(全工程无调用点)

共 21 个函数:14 个全局 + 7 个 static。无函数指针、无回调、无递归。

4. 核心逻辑解析

4.1 通信协议:两种帧格式共用一条 USART2

本文件所有报文都通过 alphaess_write_data()(alphaess_comm_usart.c:262)下发、alphaess_afci_recv_data() 收取,物理层是 USART2(hardware/usart2/usart2.c)。接收侧由 USART2_IRQHandler 的 IDLE 空闲中断 OSSemPost(g_t_uart2_rcv_sem) 触发(usart2.c:94),alphaess_afci_recv_data 里的 usart2_is_recv_async_data() 实际就是 OSSemPend(..., 500) ——500 ms 就是本模块的应答超时。

帧格式 A:标准 Modbus RTU(功能码 0x03 / 0x06 / 0x10)

读请求 (send_query_data_to_afci, 8B)
[0x01][0x03][addr_H][addr_L][num_H][num_L][CRC_L][CRC_H]
              ↑ 起始寄存器           ↑ 寄存器个数

写单寄存器 0x06 (ems_send_ctrl_data_to_afci, 8B)
[0x01][0x06][addr_H][addr_L][val_H][val_L][CRC_L][CRC_H]

写多寄存器 0x10 (ems_send_ctrl_data_to_afci, 7+n B)
[0x01][0x10][addr_H][addr_L][num_H][num_L][byte_cnt][data...][CRC_L][CRC_H]

读应答
[0x01][0x03][byte_cnt][data...][CRC_L][CRC_H]
校验:CRC16-Modbus,低字节在前;GetCrcCode_Modbus()(common/crc.c)

ems_send_ctrl_data_to_afci()(:87)在组帧前做三重长度校验:register_num <= ALPHAESS_MAX_REGISTER_NUM(100)、len_buff <= 200、且 len_buff == register_num * 2;只有全部满足才填寄存器个数与数据域。0x06 分支用 memcpy(l_u8_tx_buf + 4, tx_buff, 2)(:100)直接覆盖刚写好的“寄存器个数”字段,这是 Modbus 0x06 “地址+值”语义的正确写法,但也意味着 0x06 分支里 l_u8_tx_buf[4][5] 的写入是多余的。

alphaess_afci_recv_data()(:119)的校验链:usart2_is_recv_async_data() 拿信号量 → 轮询 usart2_get_data_len() ≥ 2(最多等 500 ms)→ 逐字节搬进调用者缓冲 → 判 buf[0] == AFCI_SLAVR_ADDRESS(0x01) → 用末两字节与 GetCrcCode_Modbus(buf, len-2) 比对。任一步失败 *len = 0。它不做长度上限检查,只按 l_u16_len 全量拷贝。

帧格式 B:AFCI 日志命令帧(功能码 0xE0 / 0xE1 / 0xE2)

取日志请求 (query_afci_log_data → send_query_data_to_afci)
[0x01][0xE1或0xE2][seq_H][seq_L][0x00][0x40][CRC_L][CRC_H]
                    ↑ 帧序号占用了“起始寄存器地址”字段   ↑ 64

日志应答
[0x01][func][b2][b3][b4][b5][data...][CRC_L][CRC_H]
             └── 4 字节长度/状态,全 0 表示本帧无数据(取完)
有效数据下标 = 6 .. (recv_len-3),即长度 = recv_len - 8

清故障记录裸帧 (send_clear_afci_log_data, 8B)
[0x01][0xE0][0x00][0x00][0x00][0x00][CRC_L][CRC_H]

注意 0x00E0 在本文件有两种身份:send_afci_clear_info() 把它当寄存器地址(配 0x06 功能码),send_clear_afci_log_data() 把它当功能码(裸帧)。

超时与重试:本文件不做自动重发,重试由上层状态机完成 —— 自检失败靠 s_u8_err_cnt(阈值 3,:720),日志靠 l_u8_err_cnt(阈值 3,:884)+ 功能码 0xE2 重发当前帧(:849),升级靠 afci_upgrade.c 的 s_u8_rev_err_cnt。

4.2 版本号解析:机型相关的字节重排

AFCI 板返回的 22 字节版本区不是顺序的版本字符,不同机型(贝瓦单相 S5 / 贝瓦三相 T10)的排布不同,因此用重排表映射(get_version_sort_map,:213):

机型(get_inverter_type_category())重排表长度
INVERTER_TYPE_BYTE_WATT_S(贝瓦单相)s_map_s5 = {4,3,6,5,8,7,9,10,12,14}10
INVERTER_TYPE_BYTE_WATT_T(贝瓦三相)s_map_t10 = {4,3,6,5,8,7,9,10,11}9
INVERTER_TYPE_NON_BYTE_WATT / defaultNULL0

parse_afci_version_data()(:242)的执行顺序:

  1. 长度守卫 min_required_len = 3 + map_len;
  2. 帧头三连判:从站地址 0x01、功能码 0x03、字节数必须精确等于 AFCI_NUM_QUERY_SOFT_VERSION2 * 2 = 22;
  3. u8_afci_soft_version[0] = 'V',随后按 map[i] 取字节逐个填入 [i+1],每个下标再做一次 map[i] >= recv_len 越界守卫(:264);
  4. 以 [map_len + 1] = '\0' 收尾;
  5. AFCI 存在性判定:version[1] != '\0' && version[1] != 0xFF → u8_support_afci_flag = TRUE,否则 FALSE。

第 5 步是本模块的“探针”:整机是否具备 AFCI,完全由这一次读版本的成败决定。query_afci_software_version()(:292)无论成功失败都会把 u8_query_afci_device_info_flag 清为 FALSE(:314 / :325),因此该查询每次请求只尝试一次;成功时额外刷新 u32_ems_inv_comm_tick(逆变器通信心跳)。

4.3 自检状态机(afci_self_check_handle,:663)

        ┌──────────────── AFCI_START_STATE ────────────────┐
        │ 若 !s_u8_afci_self_check_sent:                   │
        │   set_afci_fac_mode(1)        进工厂模式           │
        │   send_afci_clear_warning_message()                │
        │   send_afci_self_check_enable()  写 0x3F 并打时间戳 │
        │   → sent=TRUE, state=SELF_CHECK                   │
        └──────────────────────┬───────────────────────────┘
                               ▼
                   AFCI_SELF_CHECK_STATE
        条件:(OSTimeGet() - u32_ems_afci_self_check_tick) > 8000
                ├─ query_afci_self_check_status() == TRUE
                │      └─ query_afci_warning_message() == TRUE
                │            → ems_set_fault_bit(27, FALSE)        // 清 AFCI 自检故障
                │              u8_afci_self_check_flag  = FALSE
                │              u8_afci_self_check_result = TRUE
                │              u8_afci_heart_flag        = TRUE
                │              send_afci_clear_warning_message()
                │              set_afci_fac_mode(0)                // 退出工厂模式
                │              set_info_status(AFCI_SELFCHECK_STATUS)
                │              → AFCI_START_STATE
                │      └─ 否则 err_cnt++, → AFCI_FAULT_STATE
                └─ 否则 err_cnt++, → AFCI_FAULT_STATE

                   AFCI_FAULT_STATE
        sent = FALSE;send_afci_clear_warning_message();重打自检时间戳
        若 err_cnt > 3:u8_afci_self_check_flag  = FALSE
                        u8_afci_self_check_result = FALSE
                        u8_afci_self_result_shut_down = TRUE   // 要求停机
                        err_cnt = 0
                        set_info_status(AFCI_SELFCHECK_STATUS)
                        ems_set_fault_bit(27, TRUE)             // 置 AFCI 自检故障
                        否则 → AFCI_START_STATE(重来一轮)

关键点:

4.4 日志分帧拉取与成组(afci_fault_log_data_handle,:827)

函数用 3 个 static 变量保存跨调用进度:l_u16_frame_seq(初值 1,注释明确“从第 0 包查不上来”)、l_u16_logic_cnt、l_u8_err_cnt。

单帧逻辑 query_afci_log_data(func, seq, &valid_len)(:773):

  1. 发 [0x01][func][seq][0x00][0x40] 请求;
  2. 应答校验四连:长度 > 0、buf[0]==0x01、buf[1]==func、buf[2..5] 不全为 0;
  3. log_end = recv_len - 3(去掉 2 字节 CRC 与 1 字节索引修正),valid_len = log_end - 6 + 1;
  4. valid_len == 0 → AFCI_QRY_END;
  5. 缓冲上界守卫:u32_afci_log_send_len + valid_len*2 >= sizeof(afci_log_buff) → AFCI_QRY_BUF_FULL;
  6. 逐字节 sprintf(&buff[send_len + i*2], "%02X", raw[6 + i]) 追加(:804),send_len += valid_len*2。

主函数流程:

if (u8_afci_log_send_flag) return;                     // 上一包还没被网络任务发走,防重入
ret = query(0xE1 取新日志, seq)
if OK      → seq++, logic_cnt++, err_cnt = 0
else       ret = query(0xE2 重发当前帧, seq)             // 0xE1 失败立即换 0xE2
             if OK → seq++, logic_cnt++, err_cnt = 0
             else  → err_cnt++

若 (logic_cnt >= 8) 或 (ret == AFCI_QRY_BUF_FULL):      // 8 帧成组 或 缓冲将满
    buff[send_len] = '\0'
    u32_afci_log_send_net_len = u32_afci_log_send_len
    u8_afci_log_send_flag  = TRUE                       // 交给网络任务
    u8_afci_log_rev_ok_flag = TRUE
    u32_afci_log_send_len  = 0                          // 本组结束,缓冲复位复用
    u8_afci_log_status = AFCI_DATA_UPDATA(1)
    logic_cnt = 0

若 err_cnt >= 3:
    if logic_cnt > 0 :                                  // 尾部残包,作为最后一组发出
        buff[send_len] = '\0';net_len = send_len;send_len = 0
        u8_afci_log_status = AFCI_DATA_UPDATA;logic_cnt = 0
    else :                                              // 已无新帧 → 本次传输结束
        u8_afci_log_status = AFCI_UPDATA_COMPLETE(2)
        l_u16_frame_seq = 1;err_cnt = 0
        u8_ems_set_inv_afci_log_flag = FALSE
        send_len = 0;net_len = 0
        memset(afci_log_buff, 0, 1088)
    send_flag = TRUE;rev_ok_flag = TRUE

设计要点:

4.5 上传握手:与网络任务的协作(跨任务共享 g_t_afci_log_tab)

[逆变器任务]                                  [网络任务]
afci_fault_log_data_handle()
  send_flag = TRUE ─────────────────────────► net/ems.c:4966 判定条件成立
                                              (send_flag && rev_ok_flag &&
                                               !is_goto_get_update_file_status() &&
                                               check_force_upgradable_flag() &&
                                               Get_Resume_Status_Current()==NONE)
                                              → STATUS_SEND_AFCI_LOG_DATA
                                              net/ems.c:6207 fill_send_afci_log()
                                                打包 JSON:UploadDataTime / SN /
                                                PackFlag / UploadStatus(=u8_afci_log_status) /
                                                FileOffset(=u32_afci_log_send_offset) /
                                                FileLen(=u32_afci_log_send_net_len) /
                                                FileData(=afci_log_buff)
                                              net/ems.c:6211 rev_ok_flag = FALSE
   ↑ 云端回复 CMD_SEND_AFCI_LOG_DATA(0x62)
   └──────────────────────────────────────────  net/server.c:7084
                                                set_afci_log_data_upload_send_status()
                                                  send_flag = FALSE   → 允许拉下一组
                                                  rev_ok_flag = TRUE
                                                  send_offset++
                                                  若 status == COMPLETE:
                                                     memset(整个 g_t_afci_log_tab)
                                                     send_clear_afci_log_data()   // 清 AFCI 记录
                                                     send_afci_clear_warning_message()

fill_send_afci_log() 只在 u32_afci_log_send_offset == 0 时刷新 afci_log_pack_flag 时间戳(net/ems.c:2677-2688),所以 PackFlag 是“本次日志传输开始时刻”,而不是每包时间。

4.6 与 uCOS-II 的配合

本文件不创建任务、不创建信号量/邮箱,只消费 g_t_uart2_rcv_sem(由 USART2 IDLE 中断 post):

5. 对外接口

本文件导出(供谁调用)

导出名调用方
query_afci_software_versionalphaess_comm_usart.c:5076(升级完成后 50 s)、:5411(u8_query_afci_device_info_flag 为 TRUE 时,标志在 :1205 置位)
afci_self_check_handlealphaess_comm_usart.c:5060(alphaess_afci_comm_function(),受 :4996 afci_self_check_condition() 门控)
afci_fault_log_data_handlealphaess_comm_usart.c:5071(u8_ems_set_inv_afci_log_flag 为 TRUE 时;该标志在 :5513 由逆变器 AFCI 故障位置位)
set_afci_fac_mode本文件 :675/:698;alphaess_comm_usart.c:5209(心跳置位后持续退出工厂模式)
send_afci_clear_warning_message本文件 :677/:696/:718/:935;alphaess_comm_usart.c:5065(u8_afci_clear_warning_info_flag)
set_afci_log_data_upload_send_statusnet/server.c:7084(收到 CMD_SEND_AFCI_LOG_DATA(0x62) 应答)
inverter_read_ver_afcinet/ems.c:2270(信息上报 JSON 的 AfciVersion 字段)
afci_log_initalphaess_comm_usart.c:5412
ems_send_ctrl_data_to_afciafci_upgrade.c:55
alphaess_afci_recv_dataafci_upgrade.c:56
set_afci_soft_rebootafci_upgrade.c:432(升级首轮失败时软重启 AFCI)
g_t_afci_log_tabnet/ems.c:2672-2713(fill_send_afci_log)、:4966-4973(发送条件)、:6211(清 rev_ok_flag);net/server.c:7084
send_afci_clear_info无调用点(仅 afci_comm.h:107 声明)
get_afci_soft_version无调用点(仅 afci_comm.h:105 声明)

本文件调用的外部函数/变量

名称来源
g_t_inv_info(t_afci_info / t_config_data / t_run_info)midware/inverter/inverter.h:1914(AFCI_TABLE_T 定义于 :1887)
g_t_alphaess_comm_infoalphaess_comm_usart.h:715(ALPHAESS_TABLE_T)
alphaess_write_data / ALPHAESS_DATA_RCV_TIMEOUT(500) / ALPHAESS_FUNC_READ_HOLDING_REGISTER(0x03) / ALPHAESS_FUNC_WRITE_SIGNAL_HOLDING_REGISTER(0x06) / ALPHAESS_FUNC_WRITE_MULTIPLE_HOLDING_REGISTER(0x10) / ALPHAESS_MAX_REGISTER_NUM(100) / ALPHAESS_INV_RECV_BUFFER_SIZE(256)midware/inverter/alphaess/alphaess_comm_usart.{c,h}
usart2_is_recv_async_data / usart2_get_data_len / usart2_read_data_asynchardware/usart2/usart2.h
GetCrcCode_Modbuscommon/crc.h
OSTimeGet / OSTimeDlyHMSMuCOS-II
ems_set_fault_bitdata/data.c:338(声明 data.h:128)
set_info_status / AFCI_SELFCHECK_STATUSnet/ems.c:2722 / net/ems.h:269
get_inverter_type_category / INVERTER_TYPE_BYTE_WATT_*midware/inverter/inverter.c:8003 / inverter.h:403
SDRAM_AFCI_FAULT_LOG_ADDRhardware/sdram/sdram.h:56
memset / memcpy / sprintf / absC 标准库

6. 依赖关系

依赖(本文件 include):inverter.h、alphaess_comm_usart.h、afci_comm.h、ems.h、usart2.h、data.h、sdram.h、crc.h(:13-20)。其中 ems.h 只为 set_info_status / AFCI_SELFCHECK_STATUS,sdram.h 只为 SDRAM 定址宏。

被依赖:

7. 备注与风险点

  1. USART2 与逆变器主控共享总线,AFCI 帧会阻塞逆变器通信:alphaess_write_data() / alphaess_recv_data() 与 AFCI 用的是同一个 g_t_uart2_rcv_sem 和同一 RX 缓冲。alphaess_write_data() 每次都调 usart2_clear_buffer() 把信号量与缓冲清零,如果 AFCI 帧与逆变器帧在同一轮内靠近发出,先发的应答会被后发的清缓冲动作丢掉。当前靠同一任务串行 + 每帧 500 ms 超时兜底,没有优先级或仲裁机制。
  2. g_t_afci_log_tab 是跨任务无保护共享:逆变器任务在 afci_fault_log_data_handle() 里持续写 afci_log_buff / send_len / send_flag,网络任务在 set_afci_log_data_upload_send_status() 里对整个结构体 memset(:933)。二者只靠 u8_afci_log_send_flag 做粗粒度握手,memset 与逆变器侧正在进行的 sprintf 追加之间没有临界区,存在数据撕裂与长度错乱的可能。
  3. alphaess_afci_recv_data() 不做缓冲上界检查::143-150 按 usart2_get_data_len() 的长度全量写入调用者缓冲。本文件内调用者给的是 256 字节(ALPHAESS_INV_RECV_BUFFER_SIZE),但 afci_upgrade.c:28 给的是 11 字节(见该文件风险点)。该函数是公共导出,安全性取决于调用者自觉。
  4. alphaess_afci_recv_data() 只校验从站地址不校验功能码,send_afci_clear_info / set_afci_fac_mode / send_afci_clear_warning_message 等写操作在 *len > 0 时把应答当成成功(只判 buf[0]、buf[1],不校验寄存器地址与长度),因此只要 AFCI 回一个同功能码的帧就算成功,无法发现“写错寄存器”的应答异常。
  5. query_afci_self_check_status() 只取低 4 位::546 (s_u8_afci_recv_buf[4] & 0x0f),且 l_u16_afci_check_status 声明为 u16 却用 u16 = u8 & 0x0f,高字节 recv_buf[3] 被完全忽略。若 AFCI 把状态放在寄存器高字节,本判定恒为 0(恒判“完成”)。
  6. query_afci_warning_message() 对非贝瓦机型会误判::574-581,只有 S/T 两类机型才赋 0x2100 / 0x2700,INVERTER_TYPE_NON_BYTE_WATT 时 l_u16_afci_sub 保持 0,于是“寄存器读回 0”会被判为告警已清(TRUE)。虽然调用链上门控了机型,但函数自身无守卫。
  7. ems_send_ctrl_data_to_afci() 长度校验失败时会发 0 字节帧::87 的 if 不成立时 l_u8_len 保持 0,:109 仍调用 alphaess_write_data(l_u8_tx_buf, 0, ...) —— 实际效果是只清空接收缓冲和信号量,调用者随后等 500 ms 超时。属于静默失败。
  8. send_query_data_to_afci() 用“起始寄存器地址”字段承载日志帧序号(:79 + send_query_data_to_afci(log_func_code, l_u16_frame_seq, 64)):语义上是复用,功能码 0xE1/0xE2 并非标准 Modbus,读代码时容易误判为非法寄存器地址。
  9. 0x00E0 双重语义:既是寄存器地址(AFCI_ADDR_REG_SEND_CLEAR_INFO_CMD,配 0x06)也是功能码(AFCI_FUNC_REG_SEND_CLEAR_DATA_CMD,裸帧)。两个常量值与命名高度相似,是易错点。
  10. send_clear_afci_log_data() 是全局函数但未在 afci_comm.h 声明:外部无法正常调用(-Wmissing-prototypes 会告警),当前只有本文件 :934 使用。同理 get_afci_soft_version() 与 send_afci_clear_info() 已声明却全工程无调用点,属死代码。
  11. u16_afci_log_seq 字段从未被本文件读写:AFCI_LOG_DATA_TABLE 里的 u16_afci_log_seq(afci_comm.h:84)注释为“当前帧序号”,但实际帧序号是 afci_fault_log_data_handle 的 static l_u16_frame_seq,结构体字段成为遗留。
  12. l_u16_frame_seq 只在“整轮结束”分支复位为 1(:901):若传输在中途被 u8_ems_set_inv_afci_log_flag 清零打断(如故障位恢复),static 帧序号会停在中途值,下一轮会从中间帧开始拉,而非从头。
  13. abs() 用于 u32 差值::135 abs(OSTimeGet() - l_u32_recv_tick) > 500,参数为无符号,abs 接收 int。OSTimeGet() 约 49.7 天回绕一次,回绕瞬间该判断可能失效(与工程内其余同类写法一致,非本文件独有)。
  14. sprintf 逐字节写 HEX 的效率与安全::804 每字节一次 sprintf,且 %02X 输出到 send_len + i*2。上界守卫生效时安全,但 3 帧/秒的调用频率下 64 次 sprintf 明显低效,可换成查表写入。
  15. 注释与实现不符::617-621 的函数头注释写的是 set_afci_fac_mode(u8 fac_mode),但实际函数是 set_afci_soft_reboot();:766-771 注释名写 afci_fault_log_data_handle,实际是 query_afci_log_data()。均为复制粘贴遗留。
  16. ALPHAESS_NUM_SET_SOFT_REBOOT 命名前缀不一致:软重启是 AFCI 的寄存器,却用 ALPHAESS_ 前缀(afci_comm.h:35),与同文件其余 AFCI_* 常量风格不符。