/** * @file events.c * @brief 系统事件处理模块 —— WiFi / 网络 / LTE 事件分发与处理 * * 本文件是 TXW82x FPV SDK 的核心事件处理单元,主要包含: * - sys_event_hdl() : 全局系统事件处理分发函数(任务上下文,可执行耗时操作) * - sys_event_hdl_dhcp() : DHCP 客户端生命周期管理(WiFi 连接后启动 DHCP,DHCP 完成后记录 IP) * - sys_event_hdl_lte() : LTE/4G 网卡与 WiFi 之间的网络切换逻辑 * - sys_wifi_event_cb() : WiFi 协议栈事件回调(在协议栈任务/中断上下文中执行,禁止耗时操作) * - sys_wifi_event_hdl_default() : 更新 sys_status 结构体中的 WiFi 状态信息 */ #include "sys_config.h" // 系统总配置头文件,包含各功能模块的宏开关 #include "basic_include.h" // 基础头文件集合(os_printf、os_memcpy 等基础 API) #include "lib/net/skmonitor/skmonitor.h" // socket 监控库,用于网络连接状态监控 #include "lib/net/dhcpd/dhcpd.h" // DHCP 服务器端库(本文件未直接使用,但头文件引用保留以备扩展) #include "lib/net/uhttpd/uhttpd.h" // 超轻量 HTTP 服务器库(本文件未直接使用,保留以备扩展) #include "lib/umac/ieee80211.h" // IEEE 802.11 协议定义(WiFi 事件枚举、模式宏等) #include "lib/net/utils.h" // 网络工具函数(如 lwip_netif_set_dhcp2 等) #include "lwip/err.h" // LwIP 错误码定义 #include "lwip/sockets.h" // LwIP BSD socket 兼容层 #include "lwip/netdb.h" // LwIP 网络数据库函数(gethostbyname 等) #include "lwip/sys.h" // LwIP 系统抽象层(线程、信号量等) #include "lwip/ip_addr.h" // LwIP IP 地址操作宏(IPSTR、IP2STR_N 等) #include "lwip/tcpip.h" // LwIP TCP/IP 协议栈核心接口 #include "lwip/dns.h" // LwIP DNS 解析接口(dns_getserver 等) #include "netif/ethernetif.h" // 以太网网络接口驱动层 #include "lwip/apps/netbiosns.h" // LwIP NetBIOS 名称服务(本文件未直接使用,保留以备扩展) #include "lwip/dns.h" // LwIP DNS 头文件(重复包含,无副作用,保留原始代码不变) #include "syscfg.h" // 系统配置持久化存储接口(syscfg_save 等) #include "lib/bluetooth/uble/ble_demo.h" // BLE 蓝牙低功耗演示模块(用于蓝牙配网功能) #include "sysevt_usb/sysevt_usb.h" // USB 主机事件处理(视频 USB 设备相关) /** * @brief WiFi 配对模块的事件处理函数(外部定义) * 处理 WiFi 配对(pair)相关的协议栈事件 */ extern int32 sys_wifi_event_hdl_wifi_pair(uint8 ifidx, uint16 evt, uint32 param1, uint32 param2); /** * @brief 配对指示灯模块的事件处理函数(外部定义) * 根据 WiFi 配对状态控制 LED 指示灯 */ extern int32 sys_wifi_event_hdl_pairled(uint8 ifidx, uint16 evt, uint32 param1, uint32 param2); /** * @brief 配对指示灯模块的事件处理函数(重复声明,保留原始代码不变) */ extern int32 sys_wifi_event_hdl_pairled(uint8 ifidx, uint16 evt, uint32 param1, uint32 param2); /** * @brief 对讲机模块的事件处理函数(外部定义) * 处理 WiFi 对讲机(walkie-talkie)相关的协议栈事件 */ extern int32 sys_wifi_event_hdl_walkietalkie(uint8 ifidx, uint16 evt, uint32 param1, uint32 param2); /** * @brief WiFi 配对的系统事件处理函数(外部定义) * 在 sys_event_hdl() 任务上下文中处理配对相关逻辑(可执行耗时操作) */ extern void sys_event_hdl_wifi_pair(uint32 event_id, uint32 data, uint32 priv); /** * @brief 对讲机模块的系统事件处理函数(外部定义) * 在 sys_event_hdl() 任务上下文中处理对讲机相关逻辑(可执行耗时操作) */ extern void sys_event_hdl_walkie_talkie(uint32 event_id, uint32 data, uint32 priv); /** * @brief 处理 DHCP 相关系统事件(WiFi 连接后启动 DHCP 客户端,DHCP 完成后保存 IP 信息) * * 该函数由 sys_event_hdl() 调用,运行在系统事件任务上下文中,可以执行耗时操作。 * 主要处理两个事件: * 1. WiFi 连接成功 → 启动 DHCP 客户端获取 IP 地址 * 2. DHCP 客户端完成 → 将获取到的 IP/掩码/网关/DNS 保存到 sys_status * * @param event_id 系统事件 ID,由 SYS_EVENT(模块, 子事件) 宏组合而成 * @param data 事件附带的数据(本函数未使用) * @param priv 事件附带的私有数据(本函数未使用) */ //更新 sys_status 信息 // Update sys_status information static void sys_event_hdl_dhcp(uint32 event_id, uint32 data, uint32 priv) { switch (event_id) { /* WiFi 连接成功事件 */ case SYS_EVENT(SYS_EVENT_WIFI, SYSEVT_WIFI_CONNECTTED): /* 如果配置中启用了 DHCP 客户端,则启动 DHCP 流程获取 IP 地址 */ if (sys_cfgs.dhcpc_en) { sys_status.dhcpc_done = 0; // 清零 DHCP 完成标志,表示正在进行 DHCP lwip_netif_set_dhcp2("w0", 1); // 在 "w0"(WiFi 接口)上启动 LwIP DHCP 客户端 os_printf(KERN_NOTICE"wifi connected, start dhcp client ...\r\n"); // 打印日志:WiFi 已连接,启动 DHCP } /* 如果当前工作在 STA(Station 站点)模式,则保存当前连接的 AP 信息到持久化配置 */ if(sys_cfgs.wifi_mode == WIFI_MODE_STA) { ieee80211_conf_get_ssid(sys_cfgs.wifi_mode, sys_cfgs.ssid); // 获取当前连接的 SSID 并存入配置 ieee80211_conf_get_psk(sys_cfgs.wifi_mode, sys_cfgs.psk); // 获取当前连接的 PSK 密码并存入配置 sys_cfgs.key_mgmt = ieee80211_conf_get_keymgmt(sys_cfgs.wifi_mode); // 获取当前密钥管理方式(WPA/WPA2/Open) syscfg_save(); // 将配置持久化保存到 Flash,下次开机自动连接 } break; /* DHCP 客户端完成事件(成功获取到 IP 地址) */ case SYS_EVENT(SYS_EVENT_NETWORK, SYSEVT_LWIP_DHCPC_DONE): { struct netif *nif = netif_find("w0"); // 通过名称 "w0" 查找 WiFi 网络接口的 netif 结构体 sys_status.dhcpc_done = 1; // 标记 DHCP 过程已完成 sys_status.dhcpc_result.ipaddr = nif->ip_addr.addr; // 保存 DHCP 分配的 IP 地址 sys_status.dhcpc_result.netmask = nif->netmask.addr; // 保存 DHCP 分配的子网掩码 sys_status.dhcpc_result.svrip = 0; // DHCP 服务器 IP 未使用,置零保留 sys_status.dhcpc_result.router = nif->gw.addr; // 保存 DHCP 分配的默认网关地址 sys_status.dhcpc_result.dns1 = (dns_getserver(0))->addr; // 保存主 DNS 服务器地址(索引0) sys_status.dhcpc_result.dns2 = (dns_getserver(1))->addr; // 保存备用 DNS 服务器地址(索引1) os_printf(KERN_NOTICE"dhcp done, ip:"IPSTR", mask:"IPSTR", gw:"IPSTR"\r\n", // 打印获取到的 IP 信息 IP2STR_N(nif->ip_addr.addr), IP2STR_N(nif->netmask.addr), IP2STR_N(nif->gw.addr)); } break; } } /** * @brief 处理 LTE/4G 网卡与 WiFi 之间的网络切换事件 * * 当系统同时具备 WiFi 和 LTE(通过 USB RNDIS 网卡)两种网络通路时, * 本函数实现优先级切换策略:WiFi 优先,WiFi 断开时回退到 LTE。 * * 切换逻辑: * - LTE 连接且 WiFi 未连接 → 使用 LTE 作为默认网口,启动 LTE 上的 DHCP * - WiFi 连接成功 → 关闭 LTE 网口,切换默认网口为 WiFi(WiFi 优先) * - WiFi 断开 → 重新启用 LTE 网口,回退到 LTE 网络 * * @param event_id 系统事件 ID * @param data 事件附带的数据(本函数未使用) * @param priv 事件附带的私有数据(本函数未使用) */ void sys_event_hdl_lte(uint32 event_id, uint32 data, uint32 priv) { #if defined(RT_USBH_WIRELESS_RNDIS) && !defined(STATIC_RNDIS_NETDEV) // 只在启用了RNDIS功能且是动态申请网口时才需要事件进行切换 // Only when RNDIS feature is enabled and netdev is dynamically allocated, event-based switching is needed switch (event_id) { /* LTE 网卡连接事件(USB RNDIS 网卡已就绪) */ case SYS_EVENT(SYS_EVENT_LTE, SYSEVT_LTE_CONNECTED): os_printf("lte connected\r\n"); // 打印日志:LTE 已连接 if (sys_status.wifi_connected == 0) { // 如果 WiFi 当前未连接,则使用 LTE 作为默认网络 lwip_netif_set_default2("l0"); // 将 "l0"(LTE 网口)设置为 LwIP 默认路由接口 lwip_netif_set_dhcp2("l0", 1); // 在 LTE 网口上启动 DHCP 客户端获取 IP os_printf("start dhcp client on l0 ...\r\n"); // 打印日志:在 LTE 接口启动 DHCP } break; /* WiFi 连接成功事件 —— WiFi 优先级高于 LTE,关闭 LTE 网口 */ case SYS_EVENT(SYS_EVENT_WIFI, SYSEVT_WIFI_CONNECTTED): lwip_netif_updown2("l0", 0); // 关闭 "l0"(LTE 网口),参数0表示 down lwip_netif_set_default2("w0"); // 将 "w0"(WiFi 网口)设为默认路由接口 os_printf("wifi connected, down lte netif ...\r\n"); // 打印日志:WiFi 已连接,关闭 LTE break; /* WiFi 断开事件 —— 回退到 LTE 网络 */ case SYS_EVENT(SYS_EVENT_WIFI, SYSEVT_WIFI_DISCONNECT): lwip_netif_updown2("l0", 1); // 重新启用 "l0"(LTE 网口),参数1表示 up lwip_netif_set_default2("l0"); // 将默认路由切回 LTE 网口 os_printf("wifi disconnected, up lte netif ...\r\n"); // 打印日志:WiFi 已断开,启用 LTE break; } #endif } /** * @brief 全局系统事件处理分发函数(系统事件任务上下文入口) * * 该函数是系统事件处理的核心分发器,由系统事件任务循环调用。 * 它依次调用各功能模块的事件处理函数,实现事件的广播式分发。 * * 重要特性: * - 运行在独立的系统事件任务上下文中,可以执行耗时操作(如 DHCP、Flash 读写) * - 返回 SYSEVT_CONTINUE 表示事件继续传递给后续处理函数(不截断事件) * - 简单功能可直接在此函数中调用处理 API,复杂功能建议通过 sys_event_take() 注册独立处理函数 * * @param event_id 系统事件 ID,由 SYS_EVENT(模块, 子事件) 宏组合而成 * @param data 事件附带的数据 * @param priv 事件附带的私有数据 * @return sysevt_hdl_res 返回 SYSEVT_CONTINUE 表示事件继续传递 */ sysevt_hdl_res sys_event_hdl(uint32 event_id, uint32 data, uint32 priv) { #if SYS_WIFI_PAIR sys_event_hdl_wifi_pair(event_id, data, priv); // WiFi 配对功能的事件处理 #endif #ifdef SYS_APP_WALKIE_TALKIE sys_event_hdl_walkie_talkie(event_id, data, priv); // 对讲机功能的事件处理 #endif /* * 继续添加其他模块的处理函数 ... * Continue adding other module handlers ... * 一些小功能的事件处理没必要使用 sys_event_take,在此添加API调用即可。 * Small features can simply add API calls here without using sys_event_take. * 复杂功能的事件处理,可以使用 sys_event_take API 注册事件处理函数。 * Complex features can use sys_event_take API to register event handlers. * 使用 sys_event_take 注册,每次会消耗16byte heap memory * Each sys_event_take registration consumes 16 bytes of heap memory */ #if SYS_APP_BLENC sys_event_ble_netconfig(event_id, data, priv); // BLE 蓝牙配网功能的事件处理 #endif sys_event_hdl_dhcp(event_id, data, priv); // DHCP 客户端生命周期管理 sys_event_hdl_lte(event_id, data, priv); // LTE/WiFi 网络切换处理 system_event_usbh_video_hdl(event_id, data, priv); // USB 主机视频设备事件处理 return SYSEVT_CONTINUE; // 返回"继续传递",不截断事件,让后续处理函数也能收到该事件 } /** * @brief WiFi 协议栈事件默认处理函数 —— 更新 sys_status 结构体中的 WiFi 状态 * * 该函数在 sys_wifi_event_cb() 中被调用,负责将 WiFi 协议栈上报的事件 * 转换为 sys_status 结构体中的状态字段更新,供应用层查询当前 WiFi 状态。 * * @param ifidx WiFi 接口索引(0=w0, 1=w1) * @param evt WiFi 协议栈事件类型(IEEE80211_EVENT_xxx) * @param param1 事件参数1(具体含义取决于事件类型) * @param param2 事件参数2(具体含义取决于事件类型) * @return int32 固定返回 0 */ //更新 sys_status 信息 // Update sys_status information static int32 sys_wifi_event_hdl_default(uint8 ifidx, uint16 evt, uint32 param1, uint32 param2) { switch (evt) { /* WiFi 连接成功事件 */ case IEEE80211_EVENT_CONNECTED: sys_status.wifi_connected = 1; // 标记 WiFi 已连接 sys_status.wifi_status_code = 0; // 连接状态码清零(0 = 成功) sys_status.channel = ieee80211_conf_get_channel(WIFI_MODE_STA); // 获取当前工作信道号 os_memcpy(sys_status.bssid, param1, 6); // 拷贝 AP 的 MAC 地址(BSSID,6字节)到状态结构体 break; /* RSSI(接收信号强度指示)更新事件 */ case IEEE80211_EVENT_RSSI: sys_status.rssi = (int8)param1; // 将最新的 RSSI 值(有符号8位,单位 dBm)保存到状态 break; /* EVM(误差向量幅度)更新事件,反映信号调制质量 */ case IEEE80211_EVENT_EVM: sys_status.evm = (int8)param1; // 将最新的 EVM 值保存到状态,值越小信号质量越好 break; /* WiFi 连接失败事件 */ case IEEE80211_EVENT_CONNECT_FAIL: sys_status.wifi_connected = 0; // 标记 WiFi 未连接 sys_status.wifi_status_code = param2; // 保存失败原因状态码,用于诊断连接失败原因 break; /* WiFi 断开连接事件 */ case IEEE80211_EVENT_DISCONNECTED: sys_status.wifi_connected = 0; // 标记 WiFi 未连接 sys_status.wifi_reason_code = param2; // 保存断开原因码(如 beacon 超时、AP 主动断开等) break; /* WiFi 接口使能(启用)事件 */ case IEEE80211_EVENT_INTERFACE_ENABLE: sys_status.wifi_mode = param1; // 记录当前 WiFi 工作模式(STA/AP/MONITOR 等) break; /* 信道切换事件(可能由 DFS 雷达检测触发,或手动切换信道) */ case IEEE80211_EVENT_CHANNEL_CHANGE: sys_status.channel = param2; // 更新当前工作信道号到状态结构体 sys_cfgs.channel = param2; // 同步更新配置中的信道号(可能是 DFS 信道切换) break; default: break; // 未处理的事件类型,忽略 } return 0; // 返回 0,表示处理完成 } /** * @brief WiFi 协议栈事件回调函数 —— 在协议栈任务上下文中执行的入口 * * 该函数由 WiFi 协议栈在事件发生时直接调用,运行在协议栈任务(或中断)上下文中。 * * 【重要约束】由于运行在协议栈任务上下文: * - 禁止执行耗时操作(如 DHCP 流程、Flash 读写、长循环等) * - 只能做轻量级操作(更新状态变量、设置标志位、发送信号量等) * - 需要执行耗时逻辑时,应通过 sys_event_post() 将事件转发到 sys_event_hdl() 处理 * * 各子处理函数的返回值通过位或(|=)合并,用于向协议栈返回处理结果。 * * @param ifidx WiFi 接口索引(0=w0, 1=w1) * @param evt WiFi 协议栈事件类型(IEEE80211_EVENT_xxx) * @param param1 事件参数1(如 BSSID 指针、RSSI 值等) * @param param2 事件参数2(如原因码、状态码等) * @return int32 各子处理函数返回值的位或结果 */ //WiFi协议栈的事件回调函数 // WiFi protocol stack event callback function // 该callback是在WiFi协议栈的Task中执行,因此该callback中不能执行耗时的代码 // This callback executes in the WiFi protocol stack Task, so time-consuming code is not allowed // 耗时的代码逻辑,可以使用sys_event_hdl来执行 // Time-consuming logic should be dispatched to sys_event_hdl for execution int32 sys_wifi_event_cb(uint8 ifidx, uint16 evt, uint32 param1, uint32 param2) { int32 ret = 0; // 初始化返回值为 0,后续通过位或累加各子处理函数的结果 #if SYS_WIFI_PAIR ret |= sys_wifi_event_hdl_wifi_pair(ifidx, evt, param1, param2); // WiFi 配对功能处理 #endif #if SYS_WIFI_PAIRLED ret |= sys_wifi_event_hdl_pairled(ifidx, evt, param1, param2); // 配对指示灯功能处理 #endif #ifdef SYS_APP_WALKIE_TALKIE ret |= sys_wifi_event_hdl_walkietalkie(ifidx, evt, param1, param2); // 对讲机功能处理 #endif /* * 继续添加其他模块的处理函数 ... * Continue adding other module handlers ... */ ret |= sys_wifi_event_hdl_default(ifidx, evt, param1, param2); // 默认处理:更新 sys_status 状态 return ret; // 返回合并后的处理结果 }