LwIP移植和使用


LwIP移植和使用

本手冊基於lwip-1.4.x編寫,本人沒有移植過1.4.0之前的版本,更早的版本或許有差別。如果看官發現問題歡迎聯系<QQ: 937431539  email: 937431539@qq.com>

 

本文系個人原創,你可以轉載,修改,重新發布,但請保留作者信息。

 

LwIP官網是:http://savannah.nongnu.org/projects/lwip/

你可以從這里獲取源代碼。當然也可以從Git獲取源代碼:

git clone git://git.savannah.nongnu.org/lwip.git

 

LwIP以BSD協議發布源代碼,我們可以自由的使用,修改,發布或不發布源代碼。

 

附件中有我移植的文件,可以用來參考。祝你移植順利。

 

移植

1)新建幾個頭文件:

include/lwipopts.h         // lwip配置文件

include/arch/cc.h          // 平台相關。類型定義,大小端設置,內存對齊等

include/arch/perf.h        // 平台相關的性能測量實現(沒用)

include/arch/sys_arch.h    // RTOS抽象層。信號量,mbox等類型定義,函數聲明

 

lwipopts.h                // lwip配置文件,詳見附件

 

cc.h                      //類型定義,大小端設置,內存對齊等

#ifndef __CC_H__ 
#define __CC_H__ 

#include <stdint.h>

/* Types based on stdint.h */ typedef uint8_t            u8_t; 
typedef int8_t             s8_t; 
typedef uint16_t           u16_t; 
typedef int16_t            s16_t; 
typedef uint32_t           u32_t; 
typedef int32_t            s32_t; 
typedef uintptr_t          mem_ptr_t; 
 
/* Define (sn)printf formatters for these lwIP types */
#define U16_F "hu"
#define S16_F "hd"
#define X16_F "hx"
#define U32_F "lu"
#define S32_F "ld"
#define X32_F "lx"
#define SZT_F "uz"
 
/* 選擇小端模式 */
#define BYTE_ORDER LITTLE_ENDIAN
 
/* Use LWIP error codes */
#define LWIP_PROVIDE_ERRNO

/* 內存對齊 */
#if defined(__arm__) && defined(__ARMCC_VERSION) 
/* Keil uVision4 tools */
    #define PACK_STRUCT_BEGIN __packed
    #define PACK_STRUCT_STRUCT
    #define PACK_STRUCT_END
    #define PACK_STRUCT_FIELD(fld) fld
#define ALIGNED(n)  __align(n)

#endif

 

perf.h                     // 兩個宏定義為空即可

#ifndef __PERF_H__
#define __PERF_H__

#define PERF_START    /* null definition */
#define PERF_STOP(x)  /* null definition */

#endif /* END __PERF_H__ */

 

sys_arch.h 

RTOS抽象層的類型定義,函數聲明,詳細內容見 doc/sys_arch.h

 

2)建立RTOS抽象層文件:

port/sys_arch.c            // RTOS抽象層實現

為了屏蔽不同RTOS在信號量,互斥鎖,消息,任務創建等OS原語使用上的差別,lwip構造了一個RTOS的抽象層,規定了OS原語的數據類型名稱和對應方法名稱。我們要做的就是根據所用RTOS的api去實現這些原語。

比如移植lwip到raw-os上,信號量的移植:

 

類型定義,宏定義在sys_arch.h中 

struct _sys_sem 
{
    RAW_SEMAPHORE *sem;
};

typedef struct _sys_sem sys_sem_t; // sys_sem_t是lwip的信號量類型名 
#define SYS_SEM_NULL NULL 
#define sys_sem_valid(sema) (((sema) != NULL) && ((sema)->sem != NULL)) 
#define sys_sem_set_invalid(sema) ((sema)->sem = NULL) 
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
{ 
    RAW_SEMAPHORE *semaphore_ptr = 0;
    if (sem == NULL) 
    {
        RAW_ASSERT(0); 
    }

    semaphore_ptr = port_malloc(sizeof(RAW_SEMAPHORE));
    if(semaphore_ptr == 0)
    {
        RAW_ASSERT(0);
    }

    //這是raw-os的API 
    raw_semaphore_create(semaphore_ptr, (RAW_U8 *)"name_ptr", count);
    sem->sem = semaphore_ptr;

    return ERR_OK;
} 

void sys_sem_free(sys_sem_t *sem)
{
    if((sem == NULL) || (sem->sem == NULL)) 
    {
        RAW_ASSERT(0);
    }

    raw_semaphore_delete(sem->sem); //這是raw-os的API 

    raw_memset(sem->sem, sizeof(RAW_SEMAPHORE), 0); 
    port_free(sem->sem);
    sem->sem = NULL;
}

 

還有幾個函數就不一一列舉了,如有疑問看doc/sys_arch.txt

 

3)修改網卡框架文件:

netif/ethernetif.c

 

該文件是作者提供的網卡驅動和lwip的接口框架。

該文件中要改動的函數只有3個:

static void   low_level_init(struct netif *netif);

static err_t  low_level_output(struct netif *netif, struct pbuf *p);

static struct pbuf *low_level_input(struct netif *netif);

 

/* 你可以給網卡起個名字 */
/* Define those to better describe your network interface. */
#define IFNAME0 'e'
#define IFNAME1 '0'

/**
 * Helper struct to hold private data used to operate your ethernet
 * interface.
 * Keeping the ethernet address of the MAC in this struct is not
 * necessary as it is already kept in the struct netif.
 * But this is only an example, anyway...
 */
struct ethernetif 
{
    struct eth_addr *ethaddr;
    // Add whatever per-interface state that is needed here.
    // 在這里添加網卡的私有數據,比如和網卡相關的信號量,互斥鎖,
    // 網卡狀態等等,這不是必須的
};

 

3個網卡相關的函數只要改動紅色部分,需根據具體的網卡驅動函數改動

static void low_level_init(struct netif *netif)
{
    struct ethernetif *ethernetif = netif->state;

    /* set MAC hardware address length */
    netif->hwaddr_len = ETHARP_HWADDR_LEN;

    /* 設置MAC地址, 必須與網卡初始化的地址相同 */
    netif->hwaddr[0] = ;
    netif->hwaddr[1] = ;
    netif->hwaddr[2] = ;
    netif->hwaddr[3] = ;
    netif->hwaddr[4] = ;
    netif->hwaddr[5] = ;

    /* maximum transfer unit */
    netif->mtu = 1500;

    /* device capabilities */
    /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
    netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;

    /* 在這里添加其他初始化代碼(如真正的網卡初始化, phy初始化等) */ 
}

 

static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
    struct ethernetif *ethernetif = netif->state;
    struct pbuf *q;
 
    initiate transfer(); #if ETH_PAD_SIZE
    pbuf_header(p, -ETH_PAD_SIZE);   /* drop the padding word */
#endif
 
    for(q = p; q != NULL; q = q->next){
        /* Send the data from the pbuf to the interface, one pbuf at a
            time. The size of the data in each pbuf is kept in the ->len
            variable. */
        send data from(q->payload, q->len);
    }

    signal that packet should be sent(); #if ETH_PAD_SIZE
    pbuf_header(p, ETH_PAD_SIZE);   /* reclaim the padding word */
#endif

    LINK_STATS_INC(link.xmit);
 
    return ERR_OK;
}

static struct pbuf * low_level_input(struct netif *netif)
{
    struct ethernetif *ethernetif = netif->state;
    struct pbuf *p, *q;
    u16_t len;

    /* Obtain the size of the packet and put it into the "len" variable. */
    len = ;  // 獲取將要接收的數據長度

#if ETH_PAD_SIZE
    len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif

    /* We allocate a pbuf chain of pbufs from the pool. */
    p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);

    if (p != NULL){ 
#if ETH_PAD_SIZE
        pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif

        /* We iterate over the pbuf chain until we have read the entire
         * packet into the pbuf. */
        for(q = p; q != NULL; q = q->next) {
            /* Read enough bytes to fill this pbuf in the chain. The
             * available data in the pbuf is given by the q->len
             * variable.
             * This does not necessarily have to be a memcpy, you can also 
             * preallocate pbufs for a DMA-enabled MAC and after receiving truncate 
             * it to the actually received size. In this case, ensure the tot_len 
             * member of the pbuf is the sum of the chained pbuf len members.
             */
            read data into(q->payload, q->len);
        }

        acknowledge that packet has been read(); #if ETH_PAD_SIZE
        pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif

        LINK_STATS_INC(link.recv); 
    } 
else
{ drop packet(); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); }
return p; }


LwIP的使用

LwIP的初始化:

 

LwIP的初始化必須在RTOS啟動之后才可以進行, 因為它的初始化代碼使用了一些OS提供的功能!!!

 

初始化代碼示例:

extern err_t ethernetif_init(struct netif *netif);
struct netif lpc1788_netif;
ip_addr_t e0ip, e0mask, e0gw;

/* tcpip_init使用的回調函數,用於判斷tcpip_init初始化完成 */
static void tcpip_init_done(void *pdat)
{
    *(int *)pdat = 0;
}

void  ethernetif_input(struct netif *netif);
// 一直調用ethernetif_input函數,從網卡讀取數據
static void lwip_read_task(void *netif)
{
    while(1)
    {
        ethernetif_input(netif);
    }
}
 
void init_lwip()
{
    struct netif *pnetif = NULL;
    int flag = 1;

    tcpip_init(tcpip_init_done, &flag);  // lwip協議棧的初始化
    while(flag);

    IP4_ADDR(&e0ip, 192,168,6,188);      // 設置網卡ip
    IP4_ADDR(&e0mask, 255,255,255,0);    // 設置子網掩碼
    IP4_ADDR(&e0gw, 192,168,6,1);        // 設置網關

    //給lwip添加網卡
    pnetif = netif_add(&lpc1788_netif, &e0ip, &e0mask, &e0gw,
                       NULL, ethernetif_init, tcpip_input);
    netif_set_default(pnetif);     // 設置該網卡為默認網卡
    netif_set_up(&lpc1788_netif);  // 啟動網卡,可以喚醒DHCP等服務

    // 創建一個任務。這個任務負責不停的調用ethernetif_input函數從網卡讀取數據
    raw_task_create(&lwip_read_obj, (RAW_U8  *)"lwip_read", &lpc1788_netif,
                    CONFIG_RAW_PRIO_MAX - 25, 0,  lwip_read_stk, 
                    LWIP_READ_STK_SIZE ,  lwip_read_task, 1);  
}

 

附件:

http://pan.baidu.com/s/1gdfz1zd


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM