2. 字节对齐及基础数据类型定义

协议栈源码(码云/github)port/include/port/datatype.h中根据目标系统架构(16位 or 32位)及所使用的编译器定义基础数据类型及字节对齐方法。这个文件中最重要的移植工作就是依据目标编译器手册定义字节对齐方法。因为网络协议栈最关键的地方就是底层通讯报文结构必须字节对齐,而不是通常情形下的缺省四字节对齐。

#define	PACKED __attribute__((packed)) //* 缺省提供了gcc编译器的字节对齐方法
#define PACKED_FIELD(x) PACKED x
#define PACKED_BEGIN
#define PACKED_END

协议栈源码提供了常用的gcc编译器的字节对齐方法。PACKED宏及PACKED_BEGIN/PACKET_END组合体宏通常用于结构体字节对齐定义。二者选其一实现即可。PACKED_FIELD宏用于定义单个变量字节对齐。注意,字节对齐定义是整个协议栈能否正常运转的关键。所以,必须确保该定义能正常工作。

协议栈源码提供了32位系统下的基础数据类型定义样例,具体移植时可参考该样例进行调整:

//* 系统常用数据类型定义(不同的编译器版本,各数据类型的位宽亦不同,请根据后面注释选择相同位宽的类型定义)
typedef unsigned long long ULONGLONG; //* 64位无符号长整型
typedef long long LONGLONG; //* 64位有符号长整型
typedef signed long LONG; //* 32位的有符号长整型
typedef unsigned long ULONG; //* 32位的无符号长整型
typedef float FLOAT; //* 32位的浮点型
typedef double DOUBLE; //* 64位的双精度浮点型
typedef signed int INT; //* 32位的有符号整型
typedef unsigned int UINT; //* 32位的无符号整型
typedef signed short SHORT; //* 16位的有符号短整型
typedef unsigned short USHORT; //* 16位的无符号短整型
typedef char CHAR; //* 8位有符号字节型
typedef unsigned char UCHAR; //* 8位无符号字节型
typedef unsigned int in_addr_t; //* internet地址类型

其中in_addr_t比较特殊,用于socket编程,其为IPv4地址类型,其必须是无符号4字节整型数。

3. OS适配层

对于 os 适配层,主要的移植工作就几块:1)提供多任务(线程)建立函数;2)提供系统级的秒级、毫秒级延时函数及运行时长统计函数;3)提供同步(互斥)锁相关操作函数;4)提供信号量操作函数;5)提供一组临界区保护也就是中断禁止/使能函数。os 适配层的移植工作涉及 os_datatype.h、os_adapter.h、os_adapter.c 三个文件。

3.1 os_datatype.h

这个文件负责完成与目标操作系统相关的数据类型定义,主要就是互斥锁、信号量、tty这三种数据类型的定义。互斥锁用于线程同步,信号量用于线程间通讯,tty则用于ppp模块。我们需要在这个文件里定义能够唯一的标识它们的访问句柄供协议栈使用。

typedef INT HMUTEX;       //* 线程互斥(同步)锁句柄
#define INVALID_HMUTEX -1 //* 无效的线程互斥(同步)锁句柄 #if SUPPORT_PPP
typedef INT HTTY; //* tty终端句柄
#define INVALID_HTTY -1 //* 无效的tty终端句柄
#endif typedef INT HSEM; //* 信号量,适用与不同线程间通讯
#define INVALID_HSEM -1 //* 无效的信号量句柄

注意,上面给出的只是一般性定义,使用时请依据目标os的实际情形进行调整。另外,如果你的目标系统不需要ppp模块,HTTY及INVALID_HTTY无须定义。

源码工程提供的os_datatype.h文件为样例文件。基于协议栈的通用性考虑,样例文件提供的与os相关的数据类型定义存在冗余。除上述三种数据类型必须定义外,其它预留的类型如目标系统已提供,建议直接使用目标系统的定义,os_datatype.h文件中的冗余定义直接注释掉即可;如不存在,则直接使用样例文件中的通用定义即可。

3.2 os_adapter.h

协议栈业务逻辑的完成离不开os的支持,这个文件的主要作用就是提供与os相关的接口函数声明,然后在os_adapter.c中实现这些函数。所以,这个文件中要调整的地方并不多,只有两处。一个是协议栈内部工作线程控制块:

typedef struct _STCB_PSTACKTHREAD_ { //* 协议栈内部工作线程控制块,其用于线程建立
void(*pfunThread)(void *pvParam); //* 线程入口函数
void *pvParam; //* 传递给入口函数的用户参数
} STCB_PSTACKTHREAD, *PSTCB_PSTACKTHREAD;

这个结构体与目标os高度相关,其用于保存协议栈内部工作线程列表。协议栈内部设计了一个one-shot定时器。该定时器被用于一些需要等待一小段时间才能进行后续处理或定期执行的业务模块。这个定时器是以线程的方式实现的。协议栈的核心业务逻辑均与这个one-shot定时器线程有关。协议栈被目标系统加载时该线程将由os_thread_onpstack_start()函数自动启动。这个函数要启动的线程列表就被保存在STCB_PSTACKTHREAD结构体数组中。这个数组是一个静态存储时期的变量,变量名为lr_stcbaPStackThread,在os_adapter.c中定义。STCB_PSTACKTHREAD结构体需要定义哪些成员变量由目标os提供的线程启动函数的入口参数决定。我们会将线程启动用到的入口参数值定义在lr_stcbaPStackThread数组中,然后由os_thread_onpstack_start()将这些参数值传递给线程启动函数启动相应工作线程。

另外一个地方是临界区保护函数:

#define os_critical_init()  //* 临界区初始化
#define os_enter_critical() //* 进入临界区(关中断)
#define os_exit_critical() //* 退出临界区(开中断)

一般的os临界区保护函数基本都是进入临界区关中断,离开临界区开中断。代码非常简单,所以这里直接给出了三个函数宏原型,移植时请依据目标系统具体情形添加对应的开、关中断代码即可。

3.3 os_adapter.c

这个文件的核心工作就是编码实现 os_adapter.h 文件声明的所有与 os 相关的接口函数。os_adapter.h中有这些函数的详细功能说明,移植时按照说明实现具体功能即可,不再赘述。

//* 当前线程休眠指定的秒数,参数 unSecs 指定要休眠的秒数
OS_ADAPTER_EXT void os_sleep_secs(UINT unSecs); //* 当前线程休眠指定的毫秒数,单位:毫秒
OS_ADAPTER_EXT void os_sleep_ms(UINT unMSecs); //* 获取系统启动以来已运行的秒数(从 0 开始)
OS_ADAPTER_EXT UINT os_get_system_secs(void); //* 线程同步锁初始化,成功返回同步锁句柄,失败则返回INVALID_HMUTEX
OS_ADAPTER_EXT HMUTEX os_thread_mutex_init(void); //* 线程同步区加锁
OS_ADAPTER_EXT void os_thread_mutex_lock(HMUTEX hMutex); //* 线程同步区解锁
OS_ADAPTER_EXT void os_thread_mutex_unlock(HMUTEX hMutex); //* 删除线程同步锁,释放该资源
OS_ADAPTER_EXT void os_thread_mutex_uninit(HMUTEX hMutex); //* 信号量初始化,参数unInitVal指定初始信号量值, unCount指定信号量最大数值
OS_ADAPTER_EXT HSEM os_thread_sem_init(UINT unInitVal, UINT unCount); //* 投递信号量
OS_ADAPTER_EXT void os_thread_sem_post(HSEM hSem); //* 等待信号量到达,参数unWaitSecs指定要等待的超时时间(单位为秒):
//* 0,一直等下去直至信号量到达,收到信号则返回值为0,出错则返回值为-1;
//* 大于0,等待指定时间,如果指定时间内信号量到达,则返回值为0,超时则返回值为1,出错则返回值为-1
OS_ADAPTER_EXT INT os_thread_sem_pend(HSEM hSem, INT nWaitSecs); //* 信号量去初始化,释放该资源
OS_ADAPTER_EXT void os_thread_sem_uninit(HSEM hSem); //* 启动协议栈内部工作线程
OS_ADAPTER_EXT void os_thread_onpstack_start(void *pvParam); #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 设备,这个函数名称体现了 4g 模块作为 tty 设备的特殊性,其功能从本质上看就是一个 modem,modem 设备出现通讯
//* 故障时,最好的修复故障的方式就是直接复位,复位可以修复绝大部分的因软件问题产生的故障
OS_ADAPTER_EXT void os_modem_reset(HTTY hTTY);
#endif

onps栈移植说明(2)——编译器及os适配层移植的更多相关文章

  1. onps栈移植说明(3)——添加网卡

    4. 添加网卡 移植的最后一步就是编写网卡驱动然后将网卡添加到协议栈.网卡驱动其本质上完成的是数据链路层的工作,在整个通讯链路上处于通讯枢纽位置,通讯报文的发送和接收均由其实际完成.针对网卡部分的移植 ...

  2. onps栈移植说明(1)——onps栈的配置及裁剪

    onps栈的移植涉及几个部分:1)系统配置及裁剪:2)基础数据类型定义:3)RTOS适配层实现:4)编写网卡驱动并注册网卡.本文作为onps栈移植的指导性文件将给出一般性的移植说明及建议,具体的移植样 ...

  3. 基于Linux的kfifo移植到STM32(支持os的互斥访问)

    基于Linux的kfifo移植到STM32(支持os的互斥访问) 关于kfifo kfifo是内核里面的一个First In First Out数据结构,它采用环形循环队列的数据结构来实现:它提供一个 ...

  4. onps栈使用说明(1)——API接口手册

    1. 底层API 由协议栈底层提供的api,用于涉及底层操作的一些功能实现,这些api接口函数的原型定义分布于不同的文件,它们被统一include进了onps.h中: open_npstack_loa ...

  5. uc/os iii移植到STM32F4---IAR开发环境

    也许是先入为主的原因,时钟用不惯Keil环境,大多数的教程都是拿keil写的,尝试将官方的uc/os iii 移植到IAR环境. 1.首先尝试从官网上下载的官方移植的代码,编译通过,但是执行会报堆栈溢 ...

  6. 【课程分享】深入浅出嵌入式linux系统移植开发 (环境搭建、uboot的移植、嵌入式内核的配置与编译)

    深入浅出嵌入式linux系统移植开发 (环境搭建.uboot的移植.嵌入式内核的配置与编译) 亲爱的网友,我这里有套课程想和大家分享,假设对这个课程有兴趣的,能够加我的QQ2059055336和我联系 ...

  7. onps栈使用说明(2)——ping、域名解析等网络工具测试

    1. ping测试 协议栈提供ping工具,其头文件为"net_tools/ping.h",将其include进你的目标系统中即可使用这个工具. -- #include " ...

  8. uC/OS - III 移植 IAR平台

    关于移植uC/OS-III 网上已经有很多教程了此处只是做个记录 首先下载源码然后解压得到下面的文件: 然后在模版工程里新建各种文件夹: 最后全部都添加进工程: OK了,编译一下,惊呆了,竟然 0错误 ...

  9. 自己写个 Drools 文件语法检查工具——栈的应用之编译器检测语法错误

    一.背景 当前自己开发的 Android 项目是一个智能推荐系统,用到 drools 规则引擎,于我来说是一个新知识点,以前都没听说过的东东,不过用起来也不算太难,经过一段时间学习,基本掌握.关于 d ...

随机推荐

  1. axios请求响应拦截器的应用

    什么是axios拦截器? 一般在使用axios时,会用到拦截器的功能,一般分为两种:请求拦截器.响应拦截器. 请求拦截器在请求发送前进行必要操作处理 例如添加统一cookie.请求体加验证.设置请求头 ...

  2. 座位安排(欧拉回路,高斯消元,bitset)

    题面 由于旋转大师 F r e n c h \rm French French 的离去, A r e x t r e \rm Arextre Arextre 光荣地承担了给全班换座位的重任. 由于这是 ...

  3. PHP极简短连接

    可用于短连接开发 随便找个PHP空间存放即可 点击查看代码 <html> <head> <meta charset="utf-8"/> < ...

  4. React Native入门 Enable live Reload

    在开发项目时,有时一点点小修改就需要重新编译,打包,安装,效率比较低 RN 提供了一种实时重载 (Enable live Reload)的方式,来实现快速的调试开发,修改保存后会立刻载真机或模拟器中显 ...

  5. Java开发学习(三十一)----Maven属性与版本管理

    一.属性 1.1 问题分析 如下图所示 你会发现,如果现在想更新Spring的版本,你会发现依然需要更新多个jar包的版本,这样的话还是有可能出现漏改导致程序出问题,而且改起来也是比较麻烦. 问题清楚 ...

  6. Webpack与Vite热更新差异对比

    随着项目的日渐迭代,项目整体的代码量也会越来越多,从而导致项目体积越来越大:在Webpack时代,很多人会对历史项目(巨型项目)感到头疼,因为往往巨型项目在本地开发调试的时候会因为本地代码的修改触发H ...

  7. 好书推荐之Mysql三剑客 :《高性能Mysql》、《Mysql技术内幕》、《数据库索引设计与优化》

    Mysql三剑客系列书籍: 大佬推荐 首先推荐<高性能 MySQL>,这本书是 MySQL 领域的经典之作,拥有广泛的影响力.不但适合数据库管理员(DBA)阅读,也适合开发人员参考学习.不 ...

  8. [GWCTF 2019]我有一个数据库 WP

    打开环境访问看到 提示我有一个数据库,但里面什么都没有,于是拿dirsearch跑了一下,没有出结果 但是有数据库嘛,那么试试常见的几个加上phpmyadmin 试试 于是看到了版本是4.8.1 拿到 ...

  9. Django CSRF验证失败. 请求被中断.

    当页面中form使用POST方式向后台提交时,报如下错误: 禁止访问 (403) CSRF验证失败. 请求被中断. Help Reason given for failure: ​ CSRF toke ...

  10. tcmalloc 动态库替换(CentOS 操作系统)

    Ceph 14.2.8版本中tcmalloc存在内存泄漏的问题,需要将tcmalloc pagesize调整为64,重新编译,替换tcmalloc动态库,该操作在三个Ceph存储节点上均需要执行. 步 ...