4. 添加网卡移植的最后一步就是编写网卡驱动然后将网卡添加到协议栈 。网卡驱动其本质上完成的是数据链路层的工作,在整个通讯链路上处于通讯枢纽位置,通讯报文的发送和接收均由其实际完成 。针对网卡部分的移植工作共三步:
1)编写网卡驱动;
2)注册网卡到协议栈;
3)对接网卡数据收发接口;
协议栈目前支持两种网卡类型:ethernet和ppp 。两种网卡的移植工作虽然步骤一样,但具体移植细节还是有很大区别的,需要分开单独进行 。
4.1 ethernet网卡从移植的角度看,ethernet网卡驱动要提供三个接口函数并完成与协议栈的对接:
1)网卡初始化函数,完成网卡初始及启动工作,并将其添加到协议栈;
2)网卡发送函数,发送上层协议传递的通讯报文到对端;
3)网卡接收函数,接收到达的通讯报文并传递给上层协议;
对于网卡初始化函数,其要做的工作用一句话总结就是:参照网卡数据手册对其进行配置,然后将其注册到协议栈:
#define DHCP_REQ_ADDR_EN 1 //* dhcp请求ip地址使能宏static PST_NETIF l_pstNetifEth = NULL; //* 协议栈返回的netif结构int ethernet_init(void){/* 进行初始配置,比如引脚配置、使能时钟、相关工作参数配置等工作 *///* 在这里添加能够完成上述工作的相关代码,请参照目标网卡的技术手册编写…………/* 到这里网卡配置工作完成,但还未启动 *///* 添加网卡到协议栈,一定要注意启动以太网卡之前一定要先将其添加到协议栈EN_ONPSERR enErr;ST_IPV4 stIPv4;#if !DHCP_REQ_ADDR_EN//* 分配一个静态地址,请根据自己的具体网络情形设置地址stIPv4.unAddr = inet_addr_small("192.168.0.4");stIPv4.unSubnetMask = inet_addr_small("255.255.255.0");stIPv4.unGateway = inet_addr_small("192.168.0.1");stIPv4.unPrimaryDNS = inet_addr_small("1.2.4.8");stIPv4.unSecondaryDNS = inet_addr_small("8.8.8.8");stIPv4.unBroadcast = inet_addr_small("192.168.0.255");#else//* 地址清零,为dhcp客户端申请动态地址做好准备memset(&stIPv4, 0, sizeof(stIPv4));#endif//* 注册网卡,也就是将网卡添加到协议栈l_pstNetifEth = ethernet_add(……);if(!l_pstNetifEth){#if SUPPORT_PRINTFprintf("ethernet_add() failed, %s\r\n", onps_error(enErr));#endifreturn -1;}//* 启动网卡,开始工作,在这里添加与目标网卡启动相关的代码……#if DHCP_REQ_ADDR_EN//* 启动一个dhcp客户端,从dhcp服务器申请一个动态地址if(dhcp_req_addr(l_pstNetifEth, &enErr)){#if SUPPORT_PRINTFprintf("dhcp request ip address successfully.\r\n");#endif}else{#if SUPPORT_PRINTFprintf("dhcp request ip address failed, %s\r\n", onps_error(enErr));#endif}#endifreturn 0;}
上面给出的样例代码中,省略的部分是与目标系统相关的网卡初始配置代码,其余则是与协议栈有关的网卡注册代码 。这部分代码主要是完成了两块工作:一,注册网卡到协议栈;二,指定或申请一个静态/动态地址 。注册网卡的工作是由协议栈提供的ethernet_add()函数完成的,其详细说明如下:
//* 注册ethernet网卡到协议栈,只有如此协议栈才能正常使用该网卡进行数据通讯 。//*pszIfName:网卡名称//*ubaMacAddr:网卡mac地址//*pstIPv4:指向ST_IPV4结构体的指针(include/netif/netif.h),这个结构体保存用户指定的ip地址、网关、dns、子网掩码等配置信息//*//*pfunEmacSend:函数指针,指向发送函数,函数原型为INT(* PFUN_EMAC_SEND)(SHORT sBufListHead, UCHAR *pubErr),这个指针指向的其实//*就是网卡发送函数//*//* pfunStartTHEmacRecv:函数指针,协议栈使用该函数启动网卡接收线程,该线程为协议栈内部工作线程,用户移植时只需提供启动该线程的接口函数即可//*//*ppstNetif:二维指针,协议栈成功注册网卡后ethernet_add()函数会返回一个PST_NETIF指针给调用者,这个参数指向这个指针,其最终会被//*协议栈通过pvParam参数传递给pfunStartTHEmacRecv指向的函数//*//*penErr:如果注册失败,ethernet_add()函数会返回一个错误码,这个参数用于接收这个错误码//*//* 注册成功,返回一个PST_NETIF类型的指针,后续的报文收发均用到这个指针;注册失败则返回NULL 。具体错误信息参见penErr参数携带的错误码 。PST_NETIF ethernet_add(const CHAR *pszIfName, const UCHAR ubaMacAddr[ETH_MAC_ADDR_LEN], PST_IPV4 pstIPv4, PFUN_EMAC_SEND pfunEmacSend,void (*pfunStartTHEmacRecv)(void *pvParam), PST_NETIF *ppstNetif, EN_ONPSERR *penErr);
经验总结扩展阅读
- 2 onps栈移植说明——编译器及os适配层移植
- 1 onps栈移植说明——onps栈的配置及裁剪
- 亲爱的客栈杨紫乔欣是哪期?
- <一>从指令角度了解函数堆栈调用过程
- stm32h750移植lvgl
- 3 Python全栈工程师之从网页搭建入门到Flask全栈项目实战 - 入门Flask微框架
- 都卷Java,你看看你得学多少技术栈才能工作!
- flutter系列之:flutter中可以建索引的栈布局IndexedStack
- 官栈花胶多久吃一次 官栈即食花胶要加热吗
- 官栈即食花胶是不是真的 官栈即食花胶有激素吗