wireless_driver.c
u8_wireless_uart_flag4.2 通讯棒型号探测:wireless_module_find()4.3 巡检状态机:wireless_status_detect()4.4 硬重启时序:wireless_restart()4.5 P1 抄表:wireless_read_P1_data()4.6 云端状态回写:wireless_status_refresh(char *buf)4.7 tick 字段与时间基准5. 对外接口6. 依赖关系7. 备注与风险点源文件路径:
midware/ethernt/wireless/wireless_driver.c所属模块:midware/ethernt/wireless(无线通讯棒驱动层) 代码行数:644
1. 文件职责
本文件是 EMS 主控与"无线通讯棒"(易联 E-LINKER WIFI / 4G 棒、Alpha 自研 WIFI 棒)之间的驱动适配层,向下把 UART5 上的 AT 指令收发(elink_parse.c)与具体模块状态解析(wifi/e_linker_wifi.c)封装起来,向上给 midware/ethernt/ethernet.c 的无线收发通道提供统一入口(wireless_send / wireless_recv / wireless_recv_flag)。
它处在数据流的"物理链路之上、TCP 协议栈之下"这一环:云端的 EMS 报文由 ethernet.c 组帧后经 wireless_send() 通过 AT 通道透传给通讯棒,通讯棒再走蜂窝网/路由上网;反向由 wireless_recv_flag() 触发 handle_tcp_recv_data(WIRELESS)。
本文件还是整个无线子系统的"状态机宿主":wireless_status_detect() 负责通讯棒型号探测、连接状态刷新、信号强度采集与异常重启,由 task_ethernet_monitor 任务每 500ms 调用一次(midware/ethernt/ethernet.c:1544)。
另外 wireless_read_P1_data() 走同一条 UART5 通道去读 P1 采集器电表数据,由 task_meter 任务每 300ms 调用一次(midware/meter/meter.c:5879),因此本文件同时承担"电表数据源"这一职责。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
WIRELESS_TAB_T | 结构体 | 无线运行时总表(定义在 wireless_driver.h),本文件定义其实例 g_t_wireless_info |
E_LINKER_ID_INFO | 结构体 | 通讯棒身份信息(SN / HW / SW / ICCID / 是否 4G),本文件定义实例 g_e_linker_info |
WIRELESS_TYPE_E | 枚举 | 通讯棒型号:NONE、ZLG、E_LINKER_WIFI、E_LINKER_4G、ALPHA_LINKER_WIFI、MAX_WIRELESS |
PROTOCOL_TYPE_E | 联合体 | 通讯棒上报的协议支持位(纯 TCP / TCP+TLS / MQTT / MQTTS),由 e_linker_wifi.c 填写、ethernet.c 读取 |
APP_TAB | 结构体 | 外部应用状态表类型,本文件引用外部实例 g_t_app_info(net/ems.h:351) |
METER_RUN_TABLE_T | 结构体 | 电表运行数据表(midware/meter/meter.h:310),wireless_read_P1_data() 用它承接 P1 数据 |
METER_DATA_T | 结构体 | METER_RUN_TABLE_T 内的实测数据子结构(midware/meter/meter.h:189),含 u16_volt[]/s16_current[]/s32_actpower[]/s32_reactpower[]/s16_factor[]/u16_frequent;该结构体处于 #pragma pack(1) 作用域内,无对齐填充 |
PHASE_A/PHASE_B/PHASE_C/PHASE_T/MAX_PHASE | 枚举 | 相位索引,MAX_PHASE = 4;PHASE_T 表示总值 |
SENCOND_30MS | 宏 | 30(net/ems.h:21)——因 OS_TICKS_PER_SEC = 1000,实为 30ms,用作串口静默间隔 |
SENCOND_10S | 宏 | 10000(net/ems.h:28),通讯棒探测周期 |
SENCOND_300S | 宏 | 300000(net/ems.h:36),无线状态周期体检间隔 |
SENCOND_800MS | 宏 | 800(net/ems.h:23),P1 抄表最小间隔 |
UPDT_STS_IDLE | 枚举值 | net/server.h:160,升级状态机的"空闲"态 |
RESUME_STS_NONE / RESUME_STS_Idle | 枚举值 | net/server.h:208/209,断点续传状态 |
SOCK_OK | 宏 | midware/ethernt/lan/socket.h:88,值 1,表示有线网 socket 正常 |
E_LINKER_COMM_DEBUG / E_LINKER_4G_COMM_DEBUG | 宏 | 调试打印开关;E_LINKER_COMM_DEBUG 定义在 e_Linker_wifi.h:8,E_LINKER_4G_COMM_DEBUG 全工程无定义(见备注) |
WIRELESS_DEBUG / WIRELESS_DEBUG_INFO | 宏 | 本文件调试打印开关,均默认 0 |
MAX_E_LINKER_SN_LEN / MAX_WIFI_4G_ICCID_LEN | 宏 | SN 16、ICCID 25(定义在 wireless_driver.h) |
cUPS | 枚举值 | 逆变器运行模式,用于 P1 掉线时不误报电表丢失 |
3. 函数清单
| 函数名 | 作用域 | 说明(一句话) |
|---|---|---|
void wireless_set_restart_flag(u8 flag) | 全局 | 置位通讯棒重启请求标志,供网络层异步请求重启 |
u8 wireless_query_restart_flag(void) | 全局 | 读取重启请求标志 |
u8 wireless_send(u8 *buf, u32 len, u16 timeout) | 全局 | 直接透传到 e_linker_send() 发数据给通讯棒 |
u8 wireless_recv_flag(void) | 全局 | 透传到 e_linker_recv_flag(),告知 UART5 是否有待读数据 |
u32 wireless_recv(u8 *buf, u32 len) | 全局 | 透传到 e_linker_recv(),从 UART5 环形缓冲取数据 |
void wireless_status_refresh(char *buf) | 全局 | 解析云端下发的 JSON "WiFi info" 字段,刷新无线状态/IP/SN 等 |
void wireless_status_detect(void) | 全局 | 无线子系统总巡检:型号探测、状态刷新、信号采集、异常重启 |
static u8 wireless_module_find(void) | static | 按 4G→AlphaLinker→ELinker 顺序尝试登录,识别通讯棒型号 |
void wireless_init(void) | 全局 | 清空无线运行状态与 tick,首次调用时给通讯棒上电 |
void wireless_restart(void) | 全局 | 断电/上电三段式硬重启通讯棒,全程 9s 阻塞延时 |
void wireless_read_P1_data(void) | 全局 | 通过 AT 通道读取 P1 采集器电表数据并写入电表模块 |
4. 核心逻辑解析
4.1 串口互斥:u8_wireless_uart_flag
UART5 是"AT 指令通道"与"无线 TCP 透传通道"共用的物理口,三条调用路径可能并发:
ethernet.c发送事件:置位 → 循环wireless_send()→ 清位(ethernet.c:804/856)ethernet.c接收事件:置位 →wireless_recv_flag()/handle_tcp_recv_data()→ 清位(ethernet.c:896/901)- 本文件
wireless_status_detect():入口判断 + 占用,函数末尾清位(wireless_driver.c:189~295) - 本文件
wireless_read_P1_data():入口判断 + 占用,出口清位(wireless_driver.c:484~608)
该字段在头文件里被声明为 volatile u8,是软互斥而非硬件锁:因为 task_meter(prio 9) 与 task_ethernet_monitor(prio 14) 都是可抢占的 uCOS-II 任务,占用期间若被更高优先级任务抢占并再次进入,靠的是先检查后置位的顺序判断(非原子),理论上存在竞态窗口(见第 7 节)。
4.2 通讯棒型号探测:wireless_module_find()
无独立状态机,而是一条"顺序试探"逻辑,探测周期由调用方控制(10s):
| 步骤 | 发送的 AT 指令 | 成功后的型号 |
|---|---|---|
| 1 | AT_GET_4G_COM("AT+4G_COM?\r\n") | E_LINKER_4G |
| 2 | AT_ALPHE_LOGIN_E("AT+LOGIN=ALPHA_LINKER\r\n") | ALPHA_LINKER_WIFI |
| 3 | AT_E_LOGIN_E("AT+LOGIN=E-LINTER\r\n") | E_LINKER_WIFI |
| 失败 | — | NONE,并 memset(&g_e_linker_info,0,...) |
- 入口快速返回:
u8_wireless_found为真直接返回TRUE(wireless_driver.c:312),已识别型号后不再每次试探。 - 每次试探前把
s8_wireless_eirp = -99、u8_4g_rssi = 99、u8_4g_ber = 99、u8_wireless_type = NONE复位(wireless_driver.c:331~334、362~364`)。 - 命中后调用
e_linker_wifi_init(),该函数内部会读协议支持位、写 AP SSID / 目标 IP / 端口 / 密码,必要时wireless_restart()。 - 探测顺序决定了"同一根棒既能答 4G 又能答 WIFI"时优先判为 4G。
4.3 巡检状态机:wireless_status_detect()
由 task_ethernet_monitor 每 500ms 调用。整体是"三条并行的时间片分支",不是显式 enum 状态机:
入口闸门(wireless_driver.c:189)
if ((g_t_wireless_info.u8_wireless_uart_flag == TRUE) ||
((OSTimeGet() - g_t_wireless_info.u32_WIFI_uart_tick) < SENCOND_30MS))
return;
即"串口被占用"或"距上次串口活动不足 30ms"时直接退出,避免与 AT 收发抢通道。通过后置位 u8_wireless_uart_flag = TRUE。
分支 A:型号探测(周期 10s)
条件(wireless_driver.c:196):
((tcp 未连 && app 未连) || u8_wireless_type == NONE) && (now - u32_dectect_tick >= SENCOND_10S)
- 命中:
u32_dectect_tick = now;l_u8_find_cnt++;调用wireless_module_find()。- 找到 →
l_u8_find_cnt = 0,按型号分派:E_LINKER_WIFI/ALPHA_LINKER_WIFI:仅当wireless_meter_is_all_lost() == 1(全部电表丢失)时才做get_e_linker_wifi_info()+e_linker_wifi_status_detect();注释意图是"电表都丢了才怀疑是棒子的问题,否则不要打扰它"。E_LINKER_4G:无条件get_e_linker_wifi_info()+e_linker_4g_status_detect()。default(含ZLG/NONE):u8_wireless_found = FALSE。
- 未找到 →
l_u8_find_cnt > 6时清零并置u8_wireless_rst_flag = TRUE,即连续 7 次(约 70s)探测不到就请求重启通讯棒。
- 找到 →
- 附加 tick 回绕纠正:
else if (u32_dectect_tick > OSTimeGet())时把 tick 拉回当前值(wireless_driver.c:234),防止 tick 被写坏导致 10s 周期永不满足。
分支 B:周期体检(周期 300s)
条件(wireless_driver.c:243~247):
get_updt_status_current() <= UPDT_STS_IDLE 且 IsSystemDownload() == FALSE 且 Get_Resume_Status_Current() == RESUME_STS_Idle 且 u8_wireless_type != NONE 且 now - u32_wireless_check_tick >= SENCOND_300S。
命中后:
u32_wireless_check_tick = now- 按型号调
e_linker_wifi_status_detect()(WIFI/AlphaLinker)或e_linker_4g_status_detect()(4G) - 信号强度:若
g_4g_state.state.u8_sta_state == TRUE或g_wifi_state.state.l_u8_route == TRUE,取e_linker_sta_eirp()(发AT+STA_EIRP?),否则固定-99 - 4G 信号质量:若
g_4g_state.state.u8_sim_pin_state == TRUE,取get_e_linker_4g_csq()(发AT+CSQ?,解析"CSQ:%d,%d"),否则u8_4g_rssi = u8_4g_ber = 99
分支 C:延迟重启(wireless_driver.c:289)
u8_wireless_rst_flag == TRUE → wireless_restart() → 清标志。注意这一步在释放 u8_wireless_uart_flag 之前,所以 9s 重启期间串口一直被占用。
出口:u32_WIFI_uart_tick = OSTimeGet(); u8_wireless_uart_flag = FALSE;
4.4 硬重启时序:wireless_restart()
IWDG_Feed() → OSTimeDlyHMSM(0,0,3,0) // 等 3s,让正在进行的串口收发自然结束
IWDG_Feed() → wifi_power_off() // 拉 GPIOH_PIN_7 掉电
IWDG_Feed() → OSTimeDlyHMSM(0,0,3,0) // 断电保持 3s
IWDG_Feed() → wifi_power_on() // 上电
IWDG_Feed() → OSTimeDlyHMSM(0,0,3,0) // 等待模块启动
IWDG_Feed()
共 9s 阻塞延时,全过程中穿插 4 次 IWDG_Feed() 喂狗,避免看门狗复位。OSTimeDlyHMSM 会让出 CPU,同优先级/低优先级任务仍能运行,但本任务自身 9s 不返回,期间 wireless_status_detect() 不再巡检。wireless_init() 里的 wifi_power_on() 用 static u8 s_u8_reset_flag 保证全程只上电一次。
4.5 P1 抄表:wireless_read_P1_data()
前置闸门(顺序判断,任一不满足即 return)
meter_get_meter_or_ct(GRID_METER) != P1_SAMPLING→meter_set_grid_wifi_P1_fault(0)(清告警)后返回
—— 非 P1 电表场景不做任何事。
u8_wifi_support_P1_falg != TRUE或型号不在{E_LINKER_WIFI, E_LINKER_4G}中 →meter_set_grid_wifi_P1_fault(1)后返回
—— 只有支持 18031 版协议的易联棒才支持 P1,Alpha 自研棒不参与;注释明确"再发 P1 的 AT 指令会影响设备上线"。
- 时间闸门:
(now - u32_P1_read_tick) < SENCOND_800MS或(now - u32_WIFI_uart_tick) < SENCOND_30MS或u8_wireless_uart_flag == TRUE→ 返回。
通过后置 u8_wireless_uart_flag = TRUE 占用串口。
采集主体(wireless_driver.c:495~607)
条件:型号为 E_LINKER_WIFI 且 !is_goto_get_update_file_status()(不在取升级文件)且 check_force_upgradable_flag() 且 Get_Resume_Status_Current() == RESUME_STS_NONE。
即"升级/断点续传期间不抄 P1"。
u32_P1_read_tick = OSTimeGet()- 调
e_linker_P1_data(l_u8_pdata)—— 内部发AT+P1E_DATA?\r\n,并要求返回串长度 >MAX_E_LINKER_P1_LEN(75) 才算成功 - 成功:
u32_WIFI_uart_tick = OSTimeGet(),随后按下面的格式解析 - 失败:
s_u8_timeout_count累加,超过 15 次才置meter_set_grid_wifi_P1_fault(1)
P1 数据格式(sscanf 格式串,wireless_driver.c:509)
"%d,%12[^,],%14[^,],%11[^,],%d,%d,%d,%d,%d,%d,%d,%d,%hu,%hu,%hu,%hd,%hd,%hd,%d,%d,%d,%d,%d,%d"
共 24 个转换项,逗号分隔:
| # | 目标字段 | 含义 |
|---|---|---|
| 1 | l_u8_p1_link_sta | 采集器链路状态,1 = 在线 |
| 2 | l_p1_data.u8_meter_sn | 电表 SN(≤12 字符) |
| 3 | l_u8_p1_hw_ver | P1 硬件版本(≤14) |
| 4 | l_u8_p1_sf_ver | P1 软件版本(≤11) |
| 5 | l_p1_data.u32_p1_cycle | 刷新周期 |
| 6 | l_u32_p1_type | 电表类型 |
| 7~10 | l_u32_energy_input_1/2、l_u32_energy_output_1/2 | 双向电能(买/卖各 2 相或 2 段) |
| 11~12 | l_u32_in_actpower、l_u32_out_actpower | 输入/输出有功功率 |
| 13~15 | t_data.u16_volt[PHASE_A/B/C] | 三相电压(0.1V) |
| 16~18 | t_data.s16_current[PHASE_A/B/C] | 三相电流(0.01A) |
| 19~21 | t_data.s32_actpower[PHASE_A/B/C] | 三相有功功率(0.001kW) |
| 22 | t_data.u16_frequent | 频率(格式项写成 %d,见第 7 节风险 2) |
| 23 | t_data.s16_factor[PHASE_T] | 总功率因数(格式项写成 %d,见第 7 节风险 2) |
| 24 | l_u32_cost | 电费(当前未使用) |
sscanf 返回值必须等于 24(比较结果存入 l_u8_res,为 1 时才进后处理)。
注意第 22/23 两项的转换说明符与目标字段宽度不匹配(
%d写u16/s16),且METER_DATA_T是#pragma pack(1)紧凑布局,两者会互相覆盖,详见第 7 节风险 2。
派生计算(wireless_driver.c:570~572)
t_data.u32_energy_input[PHASE_T] = (u32_energy_input_1 + u32_energy_input_2 ) / 10;
t_data.u32_energy_output[PHASE_T] = (u32_energy_output_1 + u32_energy_output_2) / 10;
t_data.s32_actpower[PHASE_T] = u32_in_actpower - u32_out_actpower; // 有符号差值
除以 10 是把 P1 的 0.001kWh 口径归一到电表模块约定的 0.01kWh 口径。
软件版本截取(防越界,wireless_driver.c:573~583)
P1 的软件版本号比电表原有版本号长,而目标 t_data.u8_software_version[9] 只能放 9 字节(8 字符 + NUL):
if (len < sizeof(u8_software_version)) index = 0;
else index = len - sizeof(...) + 1;
memcpy(u8_software_version, &p1_sf_ver[index], sizeof(u8_software_version));
即取后 8 位字符。
入库(wireless_driver.c:585~594)
l_u8_p1_link_sta == 1 时:meter_set_run_data(&l_p1_data) → meter_set_grid_hw_ver(l_u8_p1_hw_ver) → u32_P1_refresh_tick = OSTimeGet() → meter_set_P1_lose_flag(0)。
无论链路状态如何都执行 s_u8_timeout_count = 0 与 meter_set_grid_wifi_P1_fault(0)。
掉线判定(wireless_driver.c:612~633)
以 u32_P1_refresh_tick 为心跳基准:
(now - u32_P1_refresh_tick) > 3000(OSTimeGet为 ms 计数,即 3s)→ 判定 P1 掉线- 若处于升级取文件 / 强制升级 / 断点续传 /
inverter_read_run_mode() == cUPS,只置meter_set_P1_lose_flag(1),不改电表通信状态、不清数据(避免升级过程误报掉电) - 否则
meter_set_grid_com_sta(1)+meter_set_clear_grid_data(1)+meter_set_P1_lose_flag(1)
- 若处于升级取文件 / 强制升级 / 断点续传 /
- 否则
meter_set_grid_com_sta(0)清丢失告警
出口 u8_wireless_uart_flag = FALSE,注意此分支不受初始闸门 return 的影响,即使本次没抄表也会做掉线判定(这是有意设计:在 E_LINKER_WIFI 之外的型号上也能维持"P1 已离线"标志)。
4.6 云端状态回写:wireless_status_refresh(char *buf)
由 net/server.c:7054 在收到命令字 CMD_RXD_WIFI_INFO 时调用,buf 是 TCP 载荷偏移 7 字节后的 JSON 串。
json_get_value(buf, "WiFi info", str)取出内嵌字符串(长度上限MAX_LEN_JSON_CONNENT),失败直接返回;str为char[128]。- 复位
g_e_linker_info.u8_is4G = 0。 - 单次
sscanf解析 14 个字段(wireless_driver.c:116):
"%16[^,],%14[^,],%14[^,],%u,%u,%hhu,%hu.%hu.%hu.%hu,%hhu,%hhu,%hhu,%24[^,]"
字段顺序:SN, SW, HW, is_connect_router, is_connect_sta, tcpstatus, ip1.ip2.ip3.ip4, 4g_rssi, 4g_ber, is4G, ICCID。
- 返回项数校验放宽为
10 || 13 || 14(wireless_driver.c:126),以兼容旧固件:10 项 = 只到 IP;13 项 = 到 is4G;14 项 = 含 ICCID。 - 变更检测:
SN、SW、ICCID任一与g_e_linker_info中缓存不同 →strncpy更新并置is_need_report_status = 1。 - 状态落位:
g_wifi_state.state.l_u8_APP_login = is_connect_stag_wifi_state.state.l_u8_route = is_connect_routerg_t_wireless_info.u8linkstatus = g_wifi_state.state.l_u8_route
- IP 覆盖:仅当
g_stNetSysInfo.s8SocketOk != SOCK_OK(有线 LAN 未建链)时才把 4 个wIpAddress写进全局IP_Address;有线优先,注释"优先使用有线lan通讯,不覆盖有线lan的ip"。IP 变化也置is_need_report_status = 1。 - 连接标志:
g_t_app_info.u8_app_connect_flag == FALSE && u8tcpstatus == FALSE时,用l_u8_APP_login赋值并刷新u32_app_connect_tick(带 30 分钟超时语义的时间戳)。 is_need_report_status == 1→Set_Setup_Config_Status(FALSE)+meter_set_saveConfigFlag(),触发云端重新上报配置。
4.7 tick 字段与时间基准
OSTimeGet() 在 OS_TICKS_PER_SEC = 1000 下返回毫秒计数,全部超时判断都是 now - tick 的无符号回绕安全写法。
| 字段 | 作用 | 初值位置 |
|---|---|---|
u32_dectect_tick | 型号探测节流(10s) | wireless_init() |
u32_link_tick | 链路相关节流(本文件只初始化,未使用) | wireless_init() |
u32_tcp_tick | TCP 相关节流(本文件只初始化,未使用) | wireless_init() |
u32_wireless_check_tick | 300s 周期体检节流 | wireless_init() |
u32_P1_read_tick | P1 抄表节流(800ms) | wireless_init(),抄表时更新 |
u32_P1_refresh_tick | P1 数据心跳,>3s 判掉线 | 抄表成功且链路在线时更新 |
u32_WIFI_uart_tick | 上次串口活动时刻(30ms 静默) | wireless_init(),巡检出口、发送、抄表成功时更新 |
5. 对外接口
本文件导出(供外部调用)
| 名称 | 调用方 |
|---|---|
WIRELESS_TAB_T g_t_wireless_info | ethernet.c、net/ems.c、net/server.c、hmi/led.c、wifi/e_linker_wifi.c |
E_LINKER_ID_INFO g_e_linker_info | net/ems.c:1896(上报 SN/HW/SW/ICCID)、midware/interface/modbus/modbus.c:3244 起(SN 拆字节读寄存器) |
wireless_set_restart_flag() | ethernet.c:1114/1135/1366/1415、net/server.c:1455 |
wireless_query_restart_flag() | ethernet.c:936 |
wireless_send() | ethernet.c:810/835 |
wireless_recv_flag() | ethernet.c:897 |
wireless_recv() | net/server.c:6353/6381 |
wireless_status_refresh() | net/server.c:7054(CMD_RXD_WIFI_INFO) |
wireless_status_detect() | ethernet.c:1544(task_ethernet_monitor) |
wireless_init() | ethernet.c:941/973/993(异常恢复、任务启动) |
wireless_restart() | wifi/e_linker_wifi.c:463(e_linker_wifi_init() 内部失败重启) |
wireless_read_P1_data() | midware/meter/meter.c:5879(task_meter) |
本文件调用的外部函数/变量
| 来源模块 | 具体项 |
|---|---|
elink_parse.c | e_linker_send、e_linker_recv、e_linker_recv_flag |
wifi/e_linker_wifi.c | e_linker_wifi_login、e_linker_wifi_init、e_linker_wifi_status_detect、e_linker_4g_status_detect、get_e_linker_wifi_info、e_linker_sta_eirp、get_e_linker_4g_csq、e_linker_P1_data;全局量 g_wifi_state、g_4g_state |
midware/meter/meter.c | meter_get_meter_or_ct、meter_set_run_data、meter_set_grid_hw_ver、meter_set_grid_com_sta、meter_set_clear_grid_data、meter_set_grid_wifi_P1_fault、meter_set_P1_lose_flag、wireless_meter_is_all_lost、meter_set_saveConfigFlag |
midware/inverter/inverter.c | inverter_read_run_mode(cUPS) |
net/ems.c | Set_Setup_Config_Status、g_t_app_info |
net/server.c | get_updt_status_current、IsSystemDownload、Get_Resume_Status_Current、check_force_upgradable_flag、is_goto_get_update_file_status |
midware/ethernt/ethernet.c | g_stNetSysInfo.s8SocketOk、IP_Address |
hardware/gpio/gpio.c | wifi_power_on、wifi_power_off |
hardware/iwdg/iwdg.c | IWDG_Feed |
common/json.c | json_get_value |
| uCOS-II | OSTimeGet、OSTimeDlyHMSM |
| libc | sscanf、strcmp、strncpy、strlen、memcpy、memset、printf |
6. 依赖关系
依赖(include / 使用)
- 本文件 include:
wireless_driver.h、e_Linker_wifi.h、ems.h、elink_parse.h、ems_download.h、flash_data_store.h、iwdg.h、gpio.h、meter.h、inverter.h、json.h、socket.h - 间接依赖:
hardware/usart5(UART5 驱动)、uCOS-II 内核
被依赖
midware/ethernt/ethernet.c(转发无线数据、巡检入口)net/server.c(无线接收路径、云端 WiFi 信息解析)net/ems.c(上报无线型号、SN、信号强度、IP)hmi/led.c(LED 指示无线/路由状态)midware/interface/modbus/modbus.c(读通讯棒 SN)midware/ethernt/wireless/wifi/e_linker_wifi.c(反向调用wireless_restart())
7. 备注与风险点
wireless_init()不重置型号字段。 该函数复位了u8_wireless_found、信号强度、各类 tick,但没有清u8_wireless_type。若通讯棒已被判为E_LINKER_4G而实际换成 WIFI 棒,wireless_module_find()会在u8_wireless_found为真时直接返回且跳过试探,型号可能与实机不符。型号的实际清零点在wireless_module_find()的失败分支和e_linker_wifi.c的连续 6 次失败分支。
sscanf第 22/23 项长度不匹配(真实缺陷,会造成字段互相覆盖)。wireless_driver.c:532把u16_frequent写成%d配(int *),wireless_driver.c:533把s16_factor[PHASE_T]写成%d配(int *),两处都是 4 字节写 2 字节字段。METER_DATA_T声明在#pragma pack(1)下(midware/meter/meter.h:188),无对齐填充,字节偏移为:
| 字段 | 偏移 | 长度 |
|---|---|---|
u16_volt[4] | 0 | 8 |
s16_current[4] | 8 | 8 |
s32_actpower[4] | 16 | 16 |
s32_reactpower[4] | 32 | 16 |
s16_factor[4] | 48 | 8 |
u16_frequent | 56 | 2 |
u32_total_phase_energy_input | 58 | 4 |
于是按 sscanf 的写入顺序:第 22 项(应为频率)在偏移 56 写 4 字节,顺带把 u32_total_phase_energy_input 的低 16 位冲掉;紧接着第 23 项(应为功率因数)在偏移 54 写 4 字节,其高 16 位又覆盖偏移 56~57,即最终 u16_frequent 里存的是功率因数的高 16 位,而频率本身丢失。正确写法应为 %hu(频率)与 %hd(功率因数)。
(int *)&l_p1_data.t_data.u16_frequent, // 第 22 项,应为 %hu
(int *)&l_p1_data.t_data.s16_factor[PHASE_T] // 第 23 项,应为 %hd
recv_wifi_log()无边界写入(见elink_parse.c)。l_u8_pdata[170]由调用方传入,但解析器不校验长度,超长应答会溢出该栈数组;调用方注释也只写"数据长度 162",余量仅 8 字节。
u8_wireless_uart_flag是非原子软锁。 检查与置位之间可被任务切换打断(wireless_status_detect()在wireless_driver.c:189检查、194置位;wireless_read_P1_data()在484检查、493置位),ethernet.c:804/896亦同。当前靠"各调用点错开周期"规避,没有OSSemPend之类硬互斥。
wireless_restart()在持锁状态下阻塞 9s。 该调用位于wireless_status_detect()释放u8_wireless_uart_flag之前(wireless_driver.c:289~293 早于295),期间所有无线收发路径(含ethernet.c的上报)都会被 30ms 静默/占用判断挡回,最长约 9s 无法上云。另外该函数内有 4 次IWDG_Feed(),属于"用喂狗换长延时"的写法,一旦路径被改坏会掩盖看门狗保护。
E_LINKER_4G_COMM_DEBUG全工程无定义。elink_parse.c:230用#if (E_LINKER_4G_COMM_DEBUG == 1)控制打印,该宏既不在elink_parse.h也不在其它头文件定义;在 C 预处理下未定义标识符按 0 处理,语句被裁掉,属于永远关闭的死代码。e_linker_wifi.c:153/593同样如此。
- P1 掉线判定与
u32_P1_refresh_tick的初值耦合。 该字段在wireless_init()被设为当前 tick,之后只有"P1 在线且l_u8_p1_link_sta == 1"才更新。因此设备刚启动即处于非 P1 场景(第一个闸门 return)时,代码仍会走到 3s 判定分支;因为wireless_init()刚刷过 tick,前 3s 内不会误报,但u8_wifi_support_P1_falg == FALSE时同样会累积推进——逻辑上依赖wireless_init()被及时调用。
u32_link_tick/u32_tcp_tick疑似遗留。 两者在wireless_init()中赋值,本文件其余位置从未读写;实际链路/tcp 节流由wifi/e_linker_wifi.c内部的static计数器与e_linker_tcp_state()承担。
- 调试打印复制粘贴错误。
wireless_driver.c:550/551打印 B 相、C 相电压时仍使用PHASE_A作为数组下标,三行输出完全相同;属仅影响日志的瑕疵(该块由WIRELESS_DEBUG_INFO控制,默认 0)。
wireless_send()的超时是忙等。 最终落到usart5_send_data(),其内部用while(...)轮询 DMA 完成标志而非OSTimeDly,ethernet.c传入的timeout = 5000(ms) 一旦触发,将以忙等方式霸占 CPU 最长 5s。
is_need_report_status的 IP 比较在%hu截断下工作。wIpAddress1..4用%hu解析到u16,若云端给的是标准点分十进制(0~255)没有问题;但一旦某段超过 65535,%hu的溢出行为未定义。