其中buddy_alloc()函数在功能上与c语言的标准库函数malloc()完全相同,都是动态分配一块指定大小的内存给调用者使用,使用完毕后再由用户通过buddy_free()函数释放 。这两个函数由协议栈的内存管理(mmu)模块提供 。ethernet_put_packet()函数需要重点解释一下 。这个函数由协议栈提供 。它完成的工作非常重要,它在网卡接收函数与协议栈以太网接收线程thread_ethernet_ii_recv()之间搭建了一个数据流通的“桥” 。接收函数收到报文后按照协议栈要求,将报文封装成ST_SLINKEDLIST_NODE类型的链表节点,然后传递给ethernet_put_packet()函数 。该函数将立即把传递过来的节点挂载到由协议栈管理的以太网接收链表的尾部,然后投递一个“有新报文到达”的信号量 。前文提到的以太网接收线程thread_ethernet_ii_recv()会轮询等待这个信号量 。一旦信号到达 , 接收线程将立即读取链表并取出报文交给协议栈处理 。
至此,ethernet网卡相关的移植工作完成 。
4.2 ppp拨号网卡在Linux系统,2g/4g/5g模块作为一个通讯终端,驱动层会把它当作一个tty设备来看待 。Linux下ppp栈也是围绕着操作一个标准的tty设备来实现底层通讯逻辑的 。至于如何操作这个ppp拨号终端进行实际的数据收发tty层并不关心 。所以,协议栈完全借鉴了这个成功的设计思想,在底层驱动与拨号终端之间增加了一个tty层,将具体的设备操作与上层的业务逻辑进行了剥离 。ppp拨号网卡的的移植工作其实就是完成tty层到底层驱动的封装工作 。协议栈利用句柄来唯一的标识一个tty设备 。在os_datatype.h文件中定义了这个句柄类型:
#if SUPPORT_PPPtypedef INT HTTY;//* tty终端句柄#define INVALID_HTTY -1 //* 无效的tty终端句柄#endif
这个句柄类型非常重要,所有与tty操作相关的函数都要用到这个句柄类型 。tty层要完成的驱动封装工作涉及的函数原型定义依然是在os_adapter.h文件中:
#if SUPPORT_PPP//* 打开 tty 设备 , 返回 tty 设备句柄,参数 pszTTYName 指定要打开的 tty 设备的名称OS_ADAPTER_EXT HTTY os_open_tty(const CHAR *pszTTYName);//* 关闭 tty 设备,参数 hTTY 为要关闭的 tty 设备的句柄OS_ADAPTER_EXT void os_close_tty(HTTY hTTY);//* 向 hTTY 指定的 tty 设备发送数据,返回实际发送的数据长度//*hTTY:设备句柄//*pubData:指针 , 指向要发送的数据的指针//* nDataLen:要发送的数据长度//* 返回值为实际发送的字节数OS_ADAPTER_EXT INT os_tty_send(HTTY hTTY, UCHAR *pubData, INT nDataLen);//* 从参数 hTTY 指定的 tty 设备等待接收数据,阻塞型//*hTTY:设备句柄//*pubRcvBuf:指针,指向数据接收缓冲区的指针,用于保存收到的数据//* nRcvBufLen:接收缓冲区的长度//*nWaitSecs:等待的时长,单位:秒 。0 一直等待;直至收到数据或报错 , 大于 0 , 等待指定秒数;小于 0,不支持//* 返回值为实际收到的数据长度,单位:字节OS_ADAPTER_EXT INT os_tty_recv(HTTY hTTY, UCHAR *pubRcvBuf, INT nRcvBufLen, INT nWaitSecs); //* 复位 tty 设备 , 这个函数名称体现了2g/4g/5g模块作为tty设备的特殊性,其功能从本质上看就是一个 modem,modem 设备出现通讯//* 故障时 , 最好的修复故障的方式就是直接复位,复位可以修复绝大部分的因软件问题产生的故障OS_ADAPTER_EXT void os_modem_reset(HTTY hTTY);#endif
依据上述函数的原型定义及功能说明 , 我们在os_adapter.c文件编码实现它们,相关伪代码实现如下:
#if SUPPORT_PPPHTTY os_open_tty(const CHAR *pszTTYName){//* 如果你的系统存在多个ppp拨号终端,那么pszTTYName参数用于区分打开哪个串口//* 在这里添加串口打开代码将连接拨号终端的串口打开…………//* 如果目标系统只有一个拨号终端,那么这里返回的tty句柄x值为0 , 如果目标系统存在多个模块,这里需要你根据参数//* pszTTYName指定的名称来区分是哪个设备,并据此返回不同的tty句柄,句柄值x应从0开始自增 , 步长为1return x;}void os_close_tty(HTTY hTTY){//* 在这里添加串口关闭代码,关闭哪个串口的依据是tty设备句柄hTTY……}INT os_tty_send(HTTY hTTY, UCHAR *pubData, INT nDataLen){//* 在这里添加数据发送代码,其实就是调用对应的串口驱动函数发送数据到拨号终端 , 如果存在多个tty设备,请依据参数hTTY来//* 确定需要调用哪个串口驱动函数发送数据,返回值为实际发送的字节数……}INT os_tty_recv(HTTY hTTY, UCHAR *pubRcvBuf, INT nRcvBufLen, INT nWaitSecs){//* 同上 , 在这里添加数据读取代码,其实就是调用对应的串口驱动函数从拨号终端读取数据 , 如果存在多个tty设备,请依据参数hTTY来//* 确定需要调用哪个串口驱动函数读取数据,返回值为实际读取到的字节数……}void os_modem_reset(HTTY hTTY){//* 在这里添加拨号终端的复位代码,如果你的目标板不支持软件复位模块,可以省略这一步//* 复位模块的目的是解决绝大部分的因软件问题产生的故障……}#endif
推荐阅读
- 2 onps栈移植说明——编译器及os适配层移植
- 1 onps栈移植说明——onps栈的配置及裁剪
- 开源网络协议栈onps诞生记
- <一>从指令角度了解函数堆栈调用过程
- stm32h750移植lvgl
- 3 Python全栈工程师之从网页搭建入门到Flask全栈项目实战 - 入门Flask微框架
- 都卷Java,你看看你得学多少技术栈才能工作!
- flutter系列之:flutter中可以建索引的栈布局IndexedStack
- SpringBoot+Vue3 AgileBoot - 手把手一步一步带你Run起全栈项目
- C++ 使用栈求解中缀、后缀表达式的值