lwip 移植到新平台指南
参考
https://lwip.fandom.com/wiki/Porting_for_an_OS
总则
cc.h(定义平台相关的宏) 和 sys_arch.h( sys_arch.c 里面实现 sys_arch.h 里面导出的接口) 两个头文件承担起 lwip源码 和 平台相关实现 之间 的 衔接。
cc.h
一、依赖关系
include/lwip/arch.h 里面 include 了 arch/cc.h 头文件
也只有 arch.h 里面inlucde arch/cc.h
其他地方,需要 processor and compiler 相关的参数时,请 include lwip/arch.h 它是 ”Support for different processor and compiler architectures“
二、需要提供的内容
1、Data types 数据类型
u8_t, u16_t, u32_t
s8_t, s16_t, s32_t
mem_ptr_t: A generic pointer type. It has to be an integer type (not void*, due to some pointer arithmetics). 必须为 整形, 不能是 void * 类型,因为需要对 mem_ptr_t 做算术运算。
2、printf formatters - 格式化字符
U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F
3、Byte ordering 字节序
3.1 字节序定义
#define BYTE_ORDER LITTLE_ENDIAN
or
#define BYTE_ORDER BIG_ENDIAN
3.2 如果是 小端字节序,可以自定义 字节序反转 接口
#define LWIP_PLATFORM_BYTESWAP 1
#define LWIP_PLATFORM_HTONS(x) ( (((u16_t)(x))>>8) | (((x)&0xFF)<<8) )
#define LWIP_PLATFORM_HTONL(x) ( (((u32_t)(x))>>24) | (((x)&0xFF0000)>>8) \
| (((x)&0xFF00)<<8) | (((x)&0xFF)<<24) )
4、Computing cheksums 计算校验和的方法
有三种计算方法通过宏定义选择
/*
1. load byte by byte, construct 16 bits word and add: not efficient for
most platforms
2. load first byte if odd address, loop processing 16 bits words, add
last byte.
3. load first byte and word if not 4 byte aligned, loop processing 32
bits words, add last word/byte.
*/
#define LWIP_CHKSUM_ALGORITHM 2
也可以使用自己的校验和计算方法
u16_t my_chksum(void *dataptr, u16_t len);
#define LWIP_CHKSUM my_chksum
5、Structure packing 结构体对齐
需要 4 个宏定义:
PACK_STRUCT_BEGIN, PACK_STRUCT_FIELD, PACK_STRUCT_STRUCT and PACK_STRUCT_END should be included in cc.h.
Only PACK_STRUCT_STRUCT is required,lwip/src/include/lwip/arch.h provides empty defaults for the others.
只有 PACK_STRUCT_STRUCT 是必须自己定义的。其他的三个,在 lwip/arch.h 里面,会补充定义为空。
Optionally you can also define PACK_STRUCT_USE_INCLUDES and provide bpstruct.h and epstruct.h.
可选的,你也可以 定义 PACK_STRUCT_USE_INCLUDES 宏,并提供 bpstruct.h and epstruct.h 文件。
6、Platform specific diagnostic output 调试诊断输出方法
- LWIP_PLATFORM_DIAG(x) - non-fatal, print a message. Uses printf
formating. - LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
Uses printf formating. Unlike assert() from the standard c library,
the parameter x is the message, not a condition
sys_arch.h
一、依赖关系
如果没有定义宏 NO_SYS ,则会在
include/lwip/sys.h 中include arch/sys_arch.h
也只在这儿 include 一次,不要在其他地方直接 include arch/sys_arch.h 。 使用 sys.h 即可,它是 os abstract layer 接口。
二、需要提供的内容
0、sys_arch.h 里面的类型和宏
类型 :
sys_sem_t, sys_mbox_t, sys_thread_t sys_prot_t
宏定义:
SYS_MBOX_NULL, SYS_SEM_NULL
1、Preemption protection 抢占保护
lwip 中使用 下面三个宏进行 抢占保护
The macros used in lwip are:
1. SYS_ARCH_PROTECT(x): Begin a block of protection. Should generally return the previous state.
2. SYS_ARCH_UNPROTECT(x): End a block of protection, restoring the protection state back to "x".
3. SYS_ARCH_DECL_PROTECT(x): Declare the variable "x" to hold the protection. Used so you can specify what data type the protection will require.
在 lwipopts.h 中定义 宏SYS_LIGHTWEIGHT_PROT 为 1 .
在 sys_arch.h / sys_arch.c 中提供 1 个数据类型和2个函数
sys_prot_t 数据类型
sys_prot_t sys_arch_protect()函数
sys_arch_unprotect( sys_prot_t x) 函数
2、 Semaphores 信号量
数据类型 sys_sem_t,空信号 SYS_SEM_NULL
信号量操作函数
1. sys_sem_t sys_sem_new(u8_t count): Creates and returns a new semaphore. The count argument specifies the initial state of the semaphore. Returns the semaphore, or SYS_SEM_NULL on error.
2. void sys_sem_free(sys_sem_t sem): Frees a semaphore created by sys_sem_new. Since these two functions provide the entry and exit point for all semaphores used by lwIP, you have great flexibility in how these are allocated and deallocated (for example, from the heap, a memory pool, a semaphore pool, etc).
3. void sys_sem_signal(sys_sem_t sem): Signals (or releases) a semaphore.
4. u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout): Blocks the
thread while waiting for the semaphore to be signaled. The timeout parameter specifies how many milliseconds the function should block before returning; if the function times out, it should return SYS_ARCH_TIMEOUT. If timeout=0, then the function should block indefinitely. If the function acquires the semaphore, it should return how many milliseconds expired while waiting for the semaphore. The function may return 0 if the semaphore was immediately available.
3、Mailboxes 邮箱
数据类型 sys_mbox_t,空邮箱 SYS_MBOX_NULL
邮箱操作函数
1. sys_mbox_t sys_mbox_new(int size): Return a new mailbox, or SYS_MBOX_NULL on error.
2. void sys_mbox_free(sys_mbox_t mbox): Deallocates a mailbox. If there
are messages still present in the mailbox when the mailbox is
deallocated, it is an indication of a programming error in lwIP and
the developer should be notified.
3. void sys_mbox_post(sys_mbox_t mbox, void *msg): Posts the "msg" to
the mailbox.
4. u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg,
u32_t timeout). Blocks the thread until a message arrives in the
mailbox, but does not block the thread longer than timeout
milliseconds (similar to the sys_arch_sem_wait() function). The msg
argument is a pointer to the message in the mailbox and may be NULL
to indicate that the message should be dropped. This should return
either SYS_ARCH_TIMEOUT or the number of milliseconds elapsed
waiting for a message.
5. u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg): This is
similar to sys_arch_mbox_fetch, however if a message is not present
in the mailbox, it immediately returns with the code SYS_MBOX_EMPTY.
On success 0 is returned with msg pointing to the message retrieved
from the mailbox. If your implementation cannot support this
functionality, a simple workaround (but inefficient) is #define
sys_arch_mbox_tryfetch(mbox,msg) sys_arch_mbox_fetch(mbox,msg,1).
6. err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg). Tries to post a
message to mbox by polling (no timeout).
4、Threads 线程
类型
sys_thread_t
函数
sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
5、 struct sys_timeouts
结构体
struct sys_timeouts {xx};
函数
struct sys_timeouts *sys_arch_timeouts(void)
空的默认实现
struct sys_timeouts lwip_system_timeouts = NULL; // Default timeouts list for lwIP
struct sys_timeouts *sys_arch_timeouts(void) {
return &lwip_system_timeouts;
}
和thread 一起使用时的注意事项
If you do use threads, then you will need to give each thread its own sys_timeouts structure, and return that depending on what thread calls this function.
需要给每个 thread 一个 linked list of sys_timeouts .
函数sys_arch_timeouts(void) 需要根据调用的 thread 返回对应的 sys_timeouts list。下面是示例
struct thread_struct_wrapper {
struct thread_struct_wrapper *next;
MY_OS_THREAD_TYPE thread; // not a ptr in this example, but the actual space
struct sys_timeo *timeouts;
};
struct sys_timeouts lwip_system_timeouts = NULL; // Default timeouts list for lwIP
struct thread_struct_wrapper *lwip_system_threads = NULL; // a list of all threads created by lwIP
sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio) {
sys_thread_t newthread;
SYS_ARCH_DECL_PROTECT(old_val);
newthread = malloc(sizeof(struct thread_struct_wrapper)); // allocate the space for the thread wrapper
if (newthread==NULL) return NULL;
SYS_ARCH_PROTECT(old_val); // Need to protect this -- preemption here could be a problem!
newthread.next = lwip_system_threads;
lwip_system_threads = newthread;
SYS_ARCH_UNPROTECT(old_val);
newthread.timeouts = NULL; // initialize the linked list to NULL
my_system_os_create_thread_function(&newthread.thread, thread, arg, prio); // create it, however my OS does it
return newthread;
}
struct sys_timeouts *sys_arch_timeouts(void) {
sys_thread_t thread = lwip_system_threads;
MY_OS_THREAD_TYPE *self = my_system_os_get_current_thread();
// Search the threads list for the thread that is currently running
for ( ; thread!=NULL; thread=thread->next) {
if (thread->thread == self) return thread->timeouts;
}
// No match, so just return the system-wide default version
return &lwip_system_timeouts;
}
6、sys_arch.c 实现注意事项
6.1 sys_sem_new() 中不要调用 mem_malloc 函数。
因为 mem_init 函数里面 调用了 了 sys_sem_new 函数,如果 sys_sem_new 中再调用 mem_malloc ,则 mem_malloc 在 mem_init 之前被调用。