TXSDK_网络应用开发指南
Chinese only责任与版权
责任限制
本文档内容仅供参考。珠海泰芯半导体有限公司(以下简称“泰芯”)未对本文档信息的准确性或完整性作出任何明示或暗示的陈述或保证,且不对使用本文件信息所产生的后果承担任何责任。
泰芯保留在不另行通知对本文件进行修改、改进或其他变更的权利。
泰芯没有为客户产品的应用、设计验证提供协助的义务。客户应自行对其应用的设计、验证和测试负责,并确保其应用符合所有法律、法规及安全相关的要求。
如因客户未遵守本协议导致任何损害、费用、损失及/或责任,泰芯不承担任何责任;同时,客户应全额赔偿因客户未遵守本协议而给泰芯造成的任何损害、费用、损失及/或责任。
版权声明
未经泰芯书面同意,任何一方不得为商业目的修改、改编、变更、翻译或基于本文件创建衍生作品。
未经泰芯书面同意,任何一方不得向第三方披露或分发本文件中提及的任何部分或全部源代码、SDK、二进制文件和目标代码。
任何一方不得修改、反向工程、反汇编、反编译或以其他方式试图发掘任何非源代码部分的SDK,包括但不限于预编译的二进制文件和目标代码。
此外,任何可能侵犯泰芯或其他知识产权所有者权利的行为也均被严格禁止。
对于实施上述侵权行为的主体,泰芯有权依据中华人民共和国法律或其他可能适用的法律、国际条约采取必要的法律措施,包括但不限于对侵权人提起诉讼或仲裁,或申请法律强制措施。
珠海泰芯半导体有限公司
2024年09月24日
修订记录
日期 | 版本 | 描 述 | 修订人 |
2025-8-7 | V1.0 | TX | |
1. 概述
TXSDK 是泰芯半导体发布的 WiFi/音视频系列芯片开发 SDK。
本文档是TXSDK 网络功能开发的指南文档,介绍了SDK网络初始化,常用网络协议模块,以及网络开发示例代码,适用于所有的泰芯WiFi芯片SDK。
TXSDK使用了开源的lwip协议栈。lwip支持BSD socket API,使用方法参考常规BSD socket API使用方法即可。需要注意的是lwip的API默认是非多线程安全的,也就是说不能出现多个thread访问同一个socket。
2. SDK网络架构
TXSDK的网络功能架构如下图所示:
SDK的网络功能由lwip提供,lwip的运作依赖于SDK网络抽象层设备netdev。SDK系统中存在2种网络接口:netif和netdev,需要理解清楚2者之间的区别:
- netif: lwip的网络接口,由lwip创建维护,提供了IP地址,网络协议功能。netif可以认为是虚拟接口,需要netdev提供支撑才能正常运作。可以根据方案需求创建多个netif。
- netdev: SDK的网络设备,系统初始化时创建。对应了具体的硬件接口,提供链路层的通信功能。例如 HG_GMAC_DEVID 对应的是GMAC接口,提供以太网链路层通信功能;HG_WIFI0_DEVID对应的是WiFi模块,提供了IEEE80211链路层通信功能。
可以使用HG_GMAC_DEVID创建netif0,使用HG_WIFI0_DEVID创建netif1,这样设备将拥有2个网络:以太网和WiFi网络。
3. 网络初始化
SDK已经提供了网络初始化代码,具体实现代码在main.c文件中。
网络初始化之前需要先确认lwip的资源配置和功能开关。lwip的配置文件lwipopts.h文件提供了各个宏定义的默认值,如果需要调整宏定义的值,建议在 project_config.h 或 sys_config.h 里面进行重定义。 通常需要调整的配置是发送/接收buffer的大小以及各类socket的最大个数。
main.c中的sys_network_init函数执行了网络初始化,可以根据方案的网络需求创建不同的lwip netif接口。
- 终端模式:设备作为网络终端,仅处理自己的数据收发,不涉及数据的转发,创建一个netif即可。
- 桥接模式:设备作为网络的桥接设备,通常具备多个网络接口,需要处理多个接口之间的数据转发。例如无线网桥设备处理WiFi网络和有线网络之间的数据转发。
- 路由模式:设备具备初级的路由功能,拥有自己的子网,并对子网设备提供NAT功能。
3.1. 终端模式
终端模式通常是设备作为无线终端,网络初始化时使用wifi device创建一个netif接口。
示例代码使用wifi device创建了一个netif接口:w0.
3.2. 桥接模式
桥接模式通常是把以太网gmac和wifi device桥接起来,实现无线网桥的功能。SDK没有使用lwip的桥接功能,而是重新实现了桥接功能,只需要创建一个netif接口,lwip对桥接功能无感知。
- 对于v2.5及以下的SDK,开启桥接功能需要使用宏定义:WIFI_BRIDGE_DEVLIST。
该宏定义是一组net device的ID列表,表示需要把这些设备和WiFi桥接在一起,如下图示:
该宏定义表示需要把 GMAC,FMAC device与WiFi桥接起来。
- 从v2.7版本开始,SDK实现了软件交换机模块sswitch,模拟了常见的交换机使用方法:把需要桥接的net device插在交换机端口上即可。在网络初始化时需要先对该模块进行初始化,执行sswitch_init API。
int32 sswitch_init(uint8 port_cnt, uint32 mactbl_max, SSWITCH_FLAGS flags)
- 参数port_cnt [in]:支持的port数量,根据实际需求定义。
- 参数mactbl_max [in]:缓存mac地址的最大数量,超过最大数量时会对mac信息进行快速老化。
- 参数flags [in]:模块控制标识,定义如下:
typedef enum {
SSWITCH_FLAGS_STATIC_ONLY = BIT(0), // Only use static MAC table, do not dynamically update MAC table
SSWITCH_FLAGS_FORWARD_UCAST = BIT(1), // Allow forwarding of unicast packets with unknown destinations
SSWITCH_FLAGS_FORWARD_MCAST = BIT(2), // Allow forwarding of multicast packets
} SSWITCH_FLAGS;
示例代码如下:
示例代码中定义了sswitch模块支持2个端口,端口1是WiFi device,端口2是gmac device。WiFi device和GMAC device设备将会桥接在一起,并使用sswitch device创建netif接口(sswitch模块在初始化时创建了虚拟的net device,使用它的net device来创建netif接口)。
3.3. 路由模式
路由模式时设备拥有自己的子网,并对子网设备提供NAT服务。此时设备具有多个网络接口,选择其中一个接口作为上行接口,连接上行网络,例如通过有线或无线连接路由器,其他接口则作为下行网络。下行网络和上行网络是2个不同的网段,下行网络的设备需要NAT服务才能访问上行网络。
路由模式时设备需要创建2个netif接口:一个是上行接口,一个是下行接口。
示例代码:
示例代码中分别使用wifi device和gmac device创建了2个netif接口: w0 和 e0。同时将e0接口作为上行接口,w0接口作为下行接口,也就是上行是有线网络,下行是无线网络。
路由模式时设备还需要提供DHCP服务,为子网设备提供IP地址分配服务,使用 sys_dhcpd_start API开启DHCP服务器。
4. 网络参数
在网络初始化之后需要设置正确的网络参数才能使用网络功能。网络参数主要是IP地址和DHCP服务参数。IP地址可以是动态分配,也可以是静态分配。SDK的系统参数struct sys_config中有以下几个字段和网络参数有关:
- dhcpc_en: 是否开启dhcp client动态获取地址
- dhcpd_en: 是否开启dhcp server
- ipaddr: 静态参数的IP地址
- netmask: 静态参数的IP掩码
- gw_ip: 静态参数的网关IP地址
- dhcpd_startip: DHPC server参数:IP地址池的起始IP
- dhcpd_endip: DHPC server参数:IP地址池的结束IP
- dhcpd_lease_time: DHPC server参数:IP地址租约时间
- dhcpd_dns1: DHPC server参数:DNS服务器地址
- dhcpd_dns2: DHPC server参数:DNS服务器地址
- dhcpd_router: DHPC server参数:网关IP地址
4.1. 静态IP
使用静态IP时,设置dhcpc_en=0, 将ipaddr,netmask,gw_ip字段赋值即可。
4.2. 动态IP
使用动态IP时设置dhcpc_en=1即可,SDK在初始化时会先使用ipaddr,netmask,gw_ip的值,然后启动dhcp client。当dhcp client申请成功后,原来的IP地址信息将会被更新覆盖。
4.3. API列表
在sdk/lib/net/lwip/src/netif/ethernetif.c文件,提供了一些访问netif的API。用于创建netif,设置/获取IP地址,MAC地址,开启dhcp client等功能访问。
为了代码使用方便,大部分API都提供2种参数形式:ndev参数 和 name参数。
//删除netif接口
err_t lwip_netif_remove(struct netdev *ndev);
//创建添加netif接口
err_t lwip_netif_add(struct netdev *ndev, char *name, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw);
//设置指定ndev对应的netif为 默认netif
err_t lwip_netif_set_default(struct netdev *ndev);
//设置指定ndev对应的netif 开启/关闭 dhcp client功能
err_t lwip_netif_set_dhcp(struct netdev *ndev, uint8 enable);
//设置指定名称的netif 开启/关闭 dhcp client功能
err_t lwip_netif_set_dhcp2(char *name, uint8 enable);
//设置指定ndev对应的netif的IP地址
int32 lwip_netif_set_ip(struct netdev *ndev, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw);
//设置指定名称的netif的IP地址
int32 lwip_netif_set_ip2(char *name, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw);
//读取指定ndev对应的netif的IP地址
ip_addr_t lwip_netif_get_ip(struct netdev *ndev);
//读取指定名称的netif的IP地址
ip_addr_t lwip_netif_get_ip2(const char *name);
//读取指定ndev对应的netif的网络掩码地址
ip_addr_t lwip_netif_get_netmask(struct netdev *ndev);
//读取指定名称的netif的网络掩码地址
ip_addr_t lwip_netif_get_netmask2(const char *name);
//读取指定ndev对应的netif的网关地址
ip_addr_t lwip_netif_get_gw(struct netdev *ndev);
//读取指定名称的netif的网关地址
ip_addr_t lwip_netif_get_gw2(const char *name);
//读取指定ndev对应的netif的MAC地址
uint8 *lwip_netif_get_mac(struct netdev *ndev);
//读取指定名称的netif的MAC地址
uint8 *lwip_netif_get_mac2(const char *name);
//控制指定ndev对应的netif接口up/down操作
void lwip_netif_updown(struct netdev *ndev, uint8 up);
//控制指定名字的netif接口up/down操作
void lwip_netif_updown2(char *ifname, uint8 up);
5. 网络事件
SDK定义的与网络相关的事件如下:
enum SYSEVT_NETWORK_SUBEVT { /* uint16 */
SYSEVT_GMAC_LINK_UP = 1, //GMAC link up,通常是插入网线
SYSEVT_GMAC_LINK_DOWN, //GMAC link down,通常是拔掉网线
SYSEVT_LWIP_DHCPC_START, //dhcp client 启动
SYSEVT_LWIP_DHCPC_DONE, //dhcp client 获取IP成功
SYSEVT_WIFI_DHCPC_START,
SYSEVT_WIFI_DHCPC_DONE,
SYSEVT_DHCPD_NEW_IP, //DHCP server为子网设备分配了一个新IP
SYSEVT_DHCPD_IPPOOL_FULL, //DHCP server的IP地址池已满
SYSEVT_NTP_UPDATE, //网络时间更新成功
};
SDK事件的使用方法,请参阅《TXSDK_开发入门指南》第9章节。
6. SDK网络模块
TXSDK移植或开发了一些网络模块,可用于网络应用程序开发。
6.1. skmonitor
skmonitor模块是socket监测模块,用于监测socket是否可读/可写。skmonitor模块适合对小数据量通信的socket进行集中监测。当skmonitor监测到某个socket可读/可写时通过callback回调执行指定的函数。不需要为每个socket创建一个task用于数据收发,减少系统中创建task产生的内存资源消耗。SDK内置的dhcp server,http server,sntp模块均使用了skmonitor模块。
由于lwip的API默认不支持多线程访问同一个socket,所以使用skmonitor监测socket之后,其他代码不应再使用该socket。
【对于定义LWIP_NETCONN_SEM_PER_THREAD 为1的SDK,表示该版本SDK是可以支持多线程访问socket的】
skmonitor API如下:
- int32 sock_monitor_init(void); //skmonitor初始化,在网络初始化时执行
- int32 sock_monitor_add(uint16 sock, skmonitor_flags flags, skmonitor_cb cb, uint32 priv);
sock_monitor_add API用于向skmonitor注册一个socket。需要先创建socket,然后再注册到skmonitor模块。
注意:使用skmonitor监测的socket通常应设置为nonblock模式,除非应用代码明确可以避免被socket API阻塞。
- 参数sock [in] :socket句柄
- 参数flags [in] :监测标识:读,写,Error
- 参数cb [in] :回调函数,监测到socketde 读/写/error事件后执行此回调函数。
- 参数priv [in] :私有数据,执行回调函数时会传递此私有数据
- void sock_monitor_del(uint16 sock); //从skmonitor删除指定的socket
- void sock_monitor_disable(uint16 sock, uint8 disable); //停止或开启对socket的监测
6.2. sswitch
sswitch模块是TXSDK实现的软件交换机模块,模拟了常见的交换机行为,使用方法也类似。同时支持对输入输出的数据进行过滤处理,可实现防火墙效果。
SSWITCH_RULE_CHECK是sswitch模块定义的数据检查规则,支持添加扩展代码参与数据的收发控制,实现防火墙功能。
每1个rule表示了数据流的check点,如果需要使用此功能,则需要将weak.c文件中的weak函数sswitch_dev_rule_check实现为具体功能。sswitch_dev_rule_check函数中显示了数据流和check点的示意图,以便于理解。
typedef enum {
SSWITCH_RULE_CHECK_PORT_INPUT, //表示从某个端口接收到数据
SSWITCH_RULE_CHECK_LOCAL_INPUT, //表示接收的数据输入到本地系统
SSWITCH_RULE_CHECK_FORWARD, //表示接收的数据转发到某个端口
SSWITCH_RULE_CHECK_LOCAL_OUTPUT, //表示本地系统输出数据
SSWITCH_RULE_CHECK_LOCAL_OUTPUT_SCATTER, //表示本地系统输出数据(scatter格式)
} SSWITCH_RULE_CHECK;
API定义如下:
- void sswitch_dev_status(void); //打印sswitch模块的配置状态
- void sswitch_dev_mactbl_dump(void); //打印sswitch模块的mac table信息
- void sswitch_dev_mactbl_delete(uint8 *addr); //删除指定的MAC地址信息
- void sswitch_dev_mactbl_update(uint8 sport, uint8 *src_mac, uint8 is_static); //添加一条MAC信息(非主动学习),通常是添加静态MAC信息
- int32 sswitch_dev_port_enable(uint8 port_id, uint8 enable); //启用或关闭某个端口
- int32 sswitch_dev_port_config(uint8 port_id, struct netdev *ndev, uint8 mac);//配置端口,将某个net device插在某个端口上
- 参数 port_id [in]:端口号(从0开始)。
- 参数 ndev [in]:需要插入的net device(可使用dev_get获取)。
- 参数 mac [in]:是否使用该net device的MAC地址作为sswitch的MAC地址,取值 1 或 0。通常是使用WiFi device的MAC地址作为sswitch的MAC地址。
- int32 sswitch_init(uint8 port_cnt, uint32 mactbl_max, SSWITCH_FLAGS flags); //sswitch模块初始化
- 参数port_cnt [in]:支持的port数量,根据实际需求定义。
- 参数mactbl_max [in]:缓存mac地址的最大数量,超过最大数量时会对mac信息进行快速老化。
- 参数flags [in]:模块控制标识,定义如下:
typedef enum {
SSWITCH_FLAGS_STATIC_ONLY = BIT(0), // Only use static MAC table, do not dynamically update MAC table
SSWITCH_FLAGS_FORWARD_UCAST = BIT(1), // Allow forwarding of unicast packets with unknown destinations
SSWITCH_FLAGS_FORWARD_MCAST = BIT(2), // Allow forwarding of multicast packets
} SSWITCH_FLAGS;
6.3. SNTP
SNTP模块是TXSDK内置的网络时间(ntp)同步模块,API定义如下:
- int32 sntp_client_init(char *ntp_server, uint16 update_interval);
sntp模块初始化API,需要指定ntp server地址和更新周期。
- 参数ntp_server [in] :ntp服务器地址,可以是IP地址 或 域名。
- 参数update_interval [in] :更新周期:sntp模块会周期性更新时间。
- void sntp_client_fresh(void); //强制刷新时间
- void sntp_set_server(char *ntp_server); //重新设置NTP服务器地址
- void sntp_set_interval(uint16 interval); //重新设置NTP更新周期
- void sntp_client_disable(int8 disable); //停用或启用 NTP更新功能
- void sntp_set_sport(uint16 server_port); //设置NTP服务器的端口(非默认端口时需要使用此API)
SNTP模块更新网络时间后,应用程序可以直接使用gettimeofday API获取系统时间示例代码如下,使用时需要考虑时区因素。
6.4. PING
SDK添加了ping功能,通常是用于网络调试。代码实现在sdk/lib/net/lwip/src/api/ping.c文件。
void lwip_ping(char *ip_domain, int pktsize, unsigned int send_times)
- 参数 ip_domain [in] : 需要ping的 目的IP或域名
- 参数 pktsize [in]: ping包的大小
- 参数 send_times [i]: 发送ping包的次数,该API为阻塞式执行,直到完成指定发包次数。
6.5. Libcurl
TXSDK移植了开源的协议库libcurl,应用程序可以直接使用libcurl进行功能开发。libcurl的使用方法,请自行查询资料。
6.6. DHCP Server
TXSDK开发了DHCP server模块,用于提供IP地址分配服务。需要使用DHCP服务时启动该模块即可。
API定义如下:
int32 dhcpd_get_lease_list(struct dhcpd_leaseinfo *leaseslist, int32 list_size);//获取已分配的IP地址列表
uint32 dhcpd_get_lease_ip(uint8 *mac); //根据MAC地址获取其分配的IP地址
void dhcpd_ip_inactive(uint8 *mac);//设置指定MAC的分配IP为无效状态
int32 dhcpd_start(char *ifname, struct dhcpd_param *param); //启动DHCP服务器
void dhcpd_stop(void); //停止DHCP服务功能
void dhcpd_flush(void); //清空DHCP服务器的IP地址分配记录信息
void dhcpd_set_dns(uint32 dns1, uint32 dns2); //修改DHPC服务器的DNS参数
6.7. Http Server
TXSDK开发了http server,用于实现网页服务。TXSDK的网页服务,需要网页设计配合http server的交互方式,以实现用最小资源实现网页服务。
开发网页功能时需要将设计好的网页压缩后转换为字节数组,SDK提供了工具html2bin.bat工具用于生成字节数组文件。
html2bin.bat工具会将当前目录下的网页压缩文件转换为数组文件:html_bytes.c。然后需要修改 uhttpd_html.c文件,将新的网页数据添加到html列表中,并为每个html数据指定名称,浏览器访问网页时http server会按名称查找对应的网页数据。
开发网页功能时需要关注以下3个文件:
- html_bytes.c: 网页压缩包转换后的字节数组文件,可以支持多个网页压缩包。
- uhttpd_html.c: html文件列表,将转换后的网页数据添加到列表中,用于支持浏览器请求网页数据。
- uhttpd_values.c:定义了网页与http server之间的交互方式。http server内置了常用的数据类型,将系统参数添加到uhttpd_values数组中,网页便可以读取或修改该参数,http server不需要再额外开发代码。