Files
TAIXIN/project/network.c

227 lines
10 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file network.c
* @brief 网络栈初始化与 DHCP 管理
*
* 本文件是 TXW82x FPV SDK 的网络子系统初始化模块,负责:
* - 初始化 LwIP TCP/IP 协议栈
* - 注册 WiFi / 以太网网络接口
* - 启动 DHCP 服务器AP 模式下为客户端分配 IP
* - 周期性检查 DHCP 客户端状态并处理超时重试
*/
/* ========================= 头文件包含 ========================= */
/* 系统配置与平台基础头文件 */
#include "sys_config.h" // 系统总体配置宏定义(外设使能、功能开关等)
#include "basic_include.h" // 基础类型和宏定义uint8 等)
#include "hal/adc.h" // ADC 硬件抽象层(可能用于电源监测等)
#include "lib/rpc/cpurpc.h" // CPU 间 RPC 通信库(多核通信)
#include "lib/atcmd/libatcmd.h" // AT 指令解析库
#include "lib/common/atcmd.h" // AT 指令公共定义
#include "lib/umac/ieee80211.h" // IEEE 802.11 协议定义WiFi 上层 MAC
#include "lib/lmac/lmac.h" // 低层 MAC 驱动WiFi 下层 MAC
#include "lib/bluetooth/uble/ble_demo.h" // BLE 蓝牙低功耗演示接口
/* LwIP 协议栈相关头文件 */
#include "lwip/err.h" // LwIP 错误码定义
#include "lwip/sockets.h" // LwIP POSIX socket 兼容层
#include "lwip/netdb.h" // LwIP 网络主机数据库DNS 解析等)
#include "lwip/sys.h" // LwIP 系统抽象层OS 适配)
#include "lwip/ip_addr.h" // LwIP IP 地址操作工具
#include "lwip/tcpip.h" // LwIP TCP/IP 核心初始化接口
#include "netif/ethernetif.h" // 以太网网络接口适配层
/* 自定义网络工具与服务 */
#include "lib/net/dhcpd/dhcpd.h" // DHCP 服务器实现
#include "lib/net/utils.h" // 网络通用工具函数
#include "lib/net/skmonitor/skmonitor.h" // Socket 监控器(检测 socket 状态/异常)
#include "syscfg.h" // 用户可配置参数结构体sys_cfgs
#include "app/user_app.h" // 用户应用层接口sys_status 等)
/* ========================= 函数实现 ========================= */
/**
* @brief 添加一个网络接口并注册到 LwIP 协议栈
*
* 根据 devid 获取对应的网络设备,设置静态 IP 或启用 DHCP 客户端,
* 然后将该网络接口注册到 LwIP 中,使其可以收发 IP 报文。
*
* @param devid 设备 ID例如 HG_WIFI0_DEVIDWiFi或 HG_GMAC_DEVID以太网
* @param name 接口名称字符串,如 "w0"WiFi、"e0"(以太网)
* @param dhcpc 是否启用 DHCP 客户端1 = 启用0 = 使用静态 IP
* @param setip 是否使用配置的静态 IP 地址1 = 使用0 = 使用默认0.0.0.0
*
* @note 该函数用 __init 修饰,表示仅在系统初始化阶段调用,
* 运行完后其代码空间可被回收以节省 RAM。
*/
__init static void sys_network_add_netif(uint8 devid, char *name, uint8 dhcpc, uint8 setip)
{
/* 定义 IP 地址、子网掩码、默认网关三个地址变量 */
ip_addr_t ipaddr, netmask, gw;
/* 根据 devid 从设备管理器中获取对应的 netdev 结构体指针 */
struct netdev *ndev = (struct netdev *)dev_get(devid);
if (ndev) {
/* 从全局配置 sys_cfgs 中读取预设的静态 IP 地址参数 */
ipaddr.addr = sys_cfgs.ipaddr; // 本机 IP 地址
netmask.addr = sys_cfgs.netmask; // 子网掩码
gw.addr = sys_cfgs.gw_ip; // 默认网关地址
/* 打印接口名称和配置的 IP/掩码/网关信息,方便调试 */
os_printf(KERN_INFO"netif %s setttings: "IPSTR"/"IPSTR"/"IPSTR"!\r\n", name, IP2STR_N(ipaddr.addr), IP2STR_N(netmask.addr), IP2STR_N(gw.addr));
/**
* 将该网络接口添加到 LwIP 协议栈:
* - 若 setip=1传入 IP/掩码/网关指针,使用静态地址
* - 若 setip=0三个参数传 NULL接口地址默认为 0.0.0.0
* (后续通过 DHCP 获取)
*/
lwip_netif_add(ndev, name, (setip ? &ipaddr : NULL), (setip ? &netmask : NULL), (setip ? &gw : NULL));
if (dhcpc) {
/* 标记 DHCP 客户端尚未完成,供 sys_dhcpc_check() 使用 */
sys_status.dhcpc_done = 0; // 0 表示 DHCP 还未获取到地址
/* 启动该接口的 DHCP 客户端,向 DHCP 服务器请求 IP 地址 */
lwip_netif_set_dhcp(ndev, 1); // 参数 1 表示开启 DHCP
/* 打印日志提示 DHCP 客户端已启动 */
os_printf(KERN_INFO"netif %s start dhcp client!\r\n", name);
}
} else {
/* 设备 ID 无效或对应设备未注册,打印错误信息 */
os_printf(KERN_ERR"No Netdev: %d\r\n", devid);
}
}
/**
* @brief 系统网络初始化总入口
*
* 依次完成以下工作:
* 1. 初始化 LwIP TCP/IP 协议栈
* 2. 初始化 socket 监控器
* 3. 注册 WiFi 接口 (w0),可选启用 DHCP 客户端
* 4. 若以太网 (GMAC) 使能,注册以太网接口 (e0)
* 5. 将 DHCP 客户端结果的初始值设为静态配置(作为 DHCP 失败时的回退)
*
* @note 由 main.c 在系统启动阶段调用__init 修饰表示仅执行一次。
*/
__init void sys_network_init(void)
{
/* 初始化 LwIP TCP/IP 协议栈核心,传入 NULL 表示不使用回调通知 */
tcpip_init(NULL, NULL);
/* 初始化 socket 监控器,用于检测和管理 socket 连接状态 */
sock_monitor_init();
/* 注册 WiFi 接口 "w0",根据 sys_cfgs.dhcpc_en 决定是否启用 DHCP 客户端,
setip=1 表示同时设置静态 IP 作为回退地址 */
sys_network_add_netif(HG_WIFI0_DEVID, "w0", sys_cfgs.dhcpc_en, 1);
/* 将 "w0" 设为 LwIP 的默认网络接口(用于路由选择) */
lwip_netif_set_default2("w0");
#if GMAC_EN // 如果以太网 GMAC 功能在编译配置中启用
/* 定义 6 字节数组用于存储 MAC 地址 */
uint8_t mac[6];
/* 从 eFuse 中读取并计算 MAC 地址(每个芯片有唯一值) */
sysctrl_efuse_mac_addr_calc(mac);
/**
* 将 MAC 地址最后一字节最低两位置 1
* - bit0 = 1 表示本地管理地址locally administered
* - bit1 = 1 使地址与 WiFi 接口的 MAC 区分开
*/
mac[5] |= 3;
/* 为以太网设备设置修改后的 MAC 地址 */
netdev_set_macaddr((struct netdev *)dev_get(HG_GMAC_DEVID), mac);
/* 注册以太网接口 "e0"DHCP 设置与 WiFi 接口一致 */
sys_network_add_netif(HG_GMAC_DEVID, "e0", sys_cfgs.dhcpc_en, 1);
/**
* 将 "e0" 设为默认网络接口,覆盖之前 "w0" 的设置。
* 这样做是因为有线连接通常比 WiFi 更稳定可靠,
* 当两者同时存在时优先使用以太网。
*/
lwip_netif_set_default2("e0");
#endif
/**
* 将 DHCP 客户端结果的初始值设为静态配置中的 IP 参数。
* 这在 DHCP 尚未完成或失败时,确保 sys_status 中有有效的 IP 信息可用。
*/
sys_status.dhcpc_result.ipaddr = sys_cfgs.ipaddr; // 默认 IP = 静态配置
sys_status.dhcpc_result.netmask = sys_cfgs.netmask; // 默认掩码 = 静态配置
sys_status.dhcpc_result.router = sys_cfgs.gw_ip; // 默认网关 = 静态配置
}
/**
* @brief 启动 DHCP 服务器
*
* 在 WiFi AP接入点模式下启动 DHCP 服务器,为连接到本设备的
* 客户端(如手机、图传接收端)自动分配 IP 地址。
*
* @note 仅当配置中同时满足 dhcpd_en=1 且 wifi_mode=AP 时才启动。
* 服务器运行在 "w0"WiFi接口上。
*/
//启动DHCP服务器 // Start DHCP server中文启动 DHCP 服务器)
void sys_dhcpd_start()
{
/* DHCP 服务器参数结构体 */
struct dhcpd_param param;
/* 仅在 DHCP 服务器已启用 且 WiFi 工作在 AP 模式时才执行 */
if (sys_cfgs.dhcpd_en && sys_cfgs.wifi_mode == WIFI_MODE_AP) {
/* 清零参数结构体,确保所有字段有确定的初始值 */
os_memset(&param, 0, sizeof(param));
/* 从全局配置中逐一读取 DHCP 服务器参数 */
param.start_ip = sys_cfgs.dhcpd_startip; // DHCP 分配的起始 IP 地址
param.end_ip = sys_cfgs.dhcpd_endip; // DHCP 分配的结束 IP 地址
param.netmask = sys_cfgs.netmask; // 子网掩码
param.lease_time = sys_cfgs.dhcpd_lease_time; // IP 租约时间(秒)
param.dns1 = sys_cfgs.dhcpd_dns1; // 主 DNS 服务器地址
param.dns2 = sys_cfgs.dhcpd_dns2; // 备用 DNS 服务器地址
param.router = sys_cfgs.dhcpd_router; // 下发給客户端的默认网关地址
/* 在 "w0"WiFi AP接口上启动 DHCP 服务器,失败则打印错误 */
if (dhcpd_start("w0", &param)) {
os_printf("dhcpd start error\r\n"); // DHCP 服务器启动失败
}
}
}
/**
* @brief 周期性检查 DHCP 客户端状态
*
* 该函数应在主循环或定时器中被周期性调用。
* 当 DHCP 客户端已启用但尚未获取到 IP 地址时,每调用约 7 次
* (约 7 个周期)后重新发起 DHCP 请求,防止因网络抖动导致
* DHCP 流程卡死。
*
* @note 使用 static 局部变量 __loop 计数,无需外部传入计数器。
*/
void sys_dhcpc_check(void)
{
/* 静态计数器,记录连续检查到 DHCP 未完成的次数 */
static uint8 __loop;
/* 仅在 DHCP 客户端已启用 且 尚未成功获取 IP 时进入检查逻辑 */
if (sys_cfgs.dhcpc_en && !sys_status.dhcpc_done) {
if (__loop++ > 6) {
/**
* 连续超过 6 次检查仍未完成 DHCP认为当前 DHCP 流程可能卡死,
* 重新在 "w0" 接口上发起 DHCP 请求。
*/
lwip_netif_set_dhcp2("w0", 1); // 重新触发 DHCP 发现流程
/* 重置计数器,开始下一轮超时检测 */
__loop = 0;
}
}
}