【笔记】lwip 移植到新平台指南

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 之前被调用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
lwip是瑞士计算机科学院的一个开源的TCP/IP协议栈实现.   lwIP是TCP/IP协议栈的一个实现。lwIP协议栈主要关注的是怎么样减少内存的使用和代码的大小,这样就可以让lwIP适用于资源有限的小型平台例如嵌入式系统。为了简化处理过程和内存要求,lwIP对API进行了裁减,可以不需要复制一些数据。   LwIP是Light Weight (轻型)IP协议,有无操作系统的支持都可以运行。LwIP实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用,一般它只需要几百字节的RAM和40K左右的ROM就可以运行,这使LwIP协议栈适合在低端的嵌入式系统中使用。   其主要特性如下:   ①支持多网络接口下的IP转发;   ②支持ICMP协议;   ③包括实验性扩展的UDP(用户数据报协议);   ④包括阻塞控制、RTT 估算、快速恢复和快速转发的TCP(传输控制协议);   ⑤提供专门的内部回调接口(Raw API),用于提高应用程序性能;   ⑥可选择的Berkeley接口API (在多线程情况下使用) 。   (1) 信号量   LwIP中需要使用信号量进行通信,所以在sys_arch中应实现相应的信号量结构体 struct sys_semt和处理函数sys_sem_new() 、sys_sem_free() 、sys_sem_signal ( ) 和sys_arch_sem_wait ( ) 。由于μC/OS已经实现了信号量OSEVENT的各种操作,并且功能和LwIP上面几个函数的目的功能是完全一样的,所以只要把μC/OS的函数重包装成上面的函数,就可直接使用。   (2) 消息队列   LwIP 使用消息队列来缓冲、传递数据报文,因此要实现消息队列结构sys_mbox_t ,以及相应的操作函数:sys_mbox_new() 、sys_mbox_free () 、sys_mbox _post () 和sys_arch_mbox_fetch() 。μC/OS实现了消息队列结构及其操作,但是μC/OS没有对消息队列中的消息进行管理,因此不能直接使用,必须在μC/OS的基础上重实现。具体实现时,对队列本身的管理利用μC/OS自己的OSQ操作完成,然后使用μC/OS中的内存管理模块实现对消息的创建、使用、删除和回收,两部分综合起来形成了LwIP的消息队列功能。   (3) 定时器函数   LwIP中每个和TCP/IP相关的任务的一系列定时事件组成一个单向链表,每个链表的起始指针存在lwip_timeouts 的对应表项中,如图2所示。移植时需要实现struct sys_timeouts * sys_arch_timeouts (void) 函数,该函数返回目前正处于运行态的线程所对应的timeout 队列指针。   (4) 创建线程函数   在μC/OS 中,没有线程(thread) 的概念,只有任务(Task) 。它提供了创建任务的系统API调用OSTaskCreate,因此只要把OSTaskCreate封装一下,就可以实现 sys_thread_new。需要注意的是LwIP中的thread并没有μC/OS 中优先级的概念,实现时要由用户事先为LwIP中创建的线程分配好优先级。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值