onps栈移植说明(2)——编译器及os适配层移植
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适配层移植的更多相关文章
- onps栈移植说明(3)——添加网卡
4. 添加网卡 移植的最后一步就是编写网卡驱动然后将网卡添加到协议栈.网卡驱动其本质上完成的是数据链路层的工作,在整个通讯链路上处于通讯枢纽位置,通讯报文的发送和接收均由其实际完成.针对网卡部分的移植 ...
- onps栈移植说明(1)——onps栈的配置及裁剪
onps栈的移植涉及几个部分:1)系统配置及裁剪:2)基础数据类型定义:3)RTOS适配层实现:4)编写网卡驱动并注册网卡.本文作为onps栈移植的指导性文件将给出一般性的移植说明及建议,具体的移植样 ...
- 基于Linux的kfifo移植到STM32(支持os的互斥访问)
基于Linux的kfifo移植到STM32(支持os的互斥访问) 关于kfifo kfifo是内核里面的一个First In First Out数据结构,它采用环形循环队列的数据结构来实现:它提供一个 ...
- onps栈使用说明(1)——API接口手册
1. 底层API 由协议栈底层提供的api,用于涉及底层操作的一些功能实现,这些api接口函数的原型定义分布于不同的文件,它们被统一include进了onps.h中: open_npstack_loa ...
- uc/os iii移植到STM32F4---IAR开发环境
也许是先入为主的原因,时钟用不惯Keil环境,大多数的教程都是拿keil写的,尝试将官方的uc/os iii 移植到IAR环境. 1.首先尝试从官网上下载的官方移植的代码,编译通过,但是执行会报堆栈溢 ...
- 【课程分享】深入浅出嵌入式linux系统移植开发 (环境搭建、uboot的移植、嵌入式内核的配置与编译)
深入浅出嵌入式linux系统移植开发 (环境搭建.uboot的移植.嵌入式内核的配置与编译) 亲爱的网友,我这里有套课程想和大家分享,假设对这个课程有兴趣的,能够加我的QQ2059055336和我联系 ...
- onps栈使用说明(2)——ping、域名解析等网络工具测试
1. ping测试 协议栈提供ping工具,其头文件为"net_tools/ping.h",将其include进你的目标系统中即可使用这个工具. -- #include " ...
- uC/OS - III 移植 IAR平台
关于移植uC/OS-III 网上已经有很多教程了此处只是做个记录 首先下载源码然后解压得到下面的文件: 然后在模版工程里新建各种文件夹: 最后全部都添加进工程: OK了,编译一下,惊呆了,竟然 0错误 ...
- 自己写个 Drools 文件语法检查工具——栈的应用之编译器检测语法错误
一.背景 当前自己开发的 Android 项目是一个智能推荐系统,用到 drools 规则引擎,于我来说是一个新知识点,以前都没听说过的东东,不过用起来也不算太难,经过一段时间学习,基本掌握.关于 d ...
随机推荐
- spring使用junit单元测试
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test& ...
- systemd之导致内核 crash
本文主要讲解linux kernel panic系列其中一种情况: Attempted to kill init! exitcode=0x0000000b 背景:linux kernel 的panic ...
- (四连测)滑雪场的高度差题解---二分 + 搜索---DD(XYX)的博客
滑雪场的高度差 时间限制: 1 Sec 内存限制: 128 MB 题目描述 滑雪场可以看成M x N的网格状山地(1 <= M,N <= 500),每个网格是一个近似的平面,具有水平高度 ...
- 检查原生 JavaScript 函数是否被覆盖
你如何确定一个JavaScript原生函数是否被覆盖? 你不能--或者至少无法可靠地确定.有一些检测方法很接近,但你不能完全相信它们. JavaScript原生函数 在JavaScript中,原生函数 ...
- 【Java】学习路径34-文件IO练习题
练习题: 1.检测某目录(scr目录为例)下java源程序文件的数量. 参考思路: 首先获取到scr目录,然后使用list()获取所有名字,再使用String类下的endsWith方法检查即可. 参考 ...
- windows下Inno Setup打包
基于inno setup的windos打包,主要脚本语言inno script.下载地址:https://jrsoftware.org/isdl.php相关打包教程:https://blog.csdn ...
- KingbaseES R3 集群主库归档失败案例
案例说明: 本案例用于KingbaseES R3集群归档进程归档日志失败的处理,对于一线的生产环境具有 一定的参考意义. 数据库版本: TEST=# select version(); VERSION ...
- Taurus.MVC-Java 版本打包上传到Maven中央仓库(详细过程):2、PGP下载安装与密钥生成发布
文章目录: Taurus.MVC-Java 版本打包上传到Maven中央仓库(详细过程):1.JIRA账号注册 Taurus.MVC-Java 版本打包上传到Maven中央仓库(详细过程):2.PGP ...
- 阿色全息脑图,及制作软件AHMM
阿色全息脑图 AHMM 全息脑图是按照大系统观原理开发的新型思维工具,用于升维思考. 让您以系统的观点看待世界,专注系统的结构信息--全息,抓住事物的本质,透过表象和数据发现规律. 世间每项事物都是一 ...
- 容器化|自建 MySQL 集群迁移到 Kubernetes
背景 如果你有自建的 MySQL 集群,并且已经感受到了云原生的春风拂面,想将数据迁移到 Kubernetes 上,那么这篇文章可以给你一些思路. 文中将自建 MySQL 集群数据,在线迁移到 Kub ...