3、LwIP移植心得
平臺是LPC2136+ENC28J60,32K的RAM,軟件是uCOS-II 2.51+LwIP 1.1.1。
感覺主要解決兩個問題:
操作系統仿真層的移植。這個基于uCOS-II的代碼太多了。COPY下就行!
1)設備驅動的移植
驅動的移植主要就是完成ethernetif.c的工作。作者已經給好了驅動的接口。
struct netif {
struct netif *next;
struct ip_addr ip_addr;
struct ip_addr netmask;
struct ip_addr gw;
err_t (* input)(struct pbuf *p, struct netif *inp);
err_t (* output)(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr);
err_t (* linkoutput)(struct netif *netif, struct pbuf *p);
void *state;
#if LWIP_DHCP
struct dhcp *dhcp;
#endif
unsigned char hwaddr_len;
unsigned char hwaddr[NETIF_MAX_HWADDR_LEN];
u16_t mtu;
char name[2];
u8_t num;
u8_t flags;
};
主要就是:
err_t (* input)(struct pbuf *p, struct netif *inp);
這個是被驅動調用的,傳遞一個數據包給TCP/IP棧。
err_t (* output)(struct netif *netif, struct pbuf *p,struct ip_addr *ipaddr);
這個是被IP模塊調用的,向以太網上發送一個數據包,函數要先通過IP地址獲得解決硬件地址,然后發包。
err_t (* linkoutput)(struct netif *netif, struct pbuf *p);
這個是直接發送數據包的接口。
相應的作者在ethernetif.c里面給了幾個函數框架,這個文件相當于一個硬件抽象層。
static void low_level_init(struct netif *netif)
網卡初始化函數
static err_t low_level_output(struct netif *netif, struct pbuf *p)
鏈路層發送函數,實現err_t (* linkoutput)接口。
static struct pbuf *low_level_input(struct netif *netif)
得到一整幀數據
static err_t ethernetif_output(struct netif *netif, struct pbuf *p,struct ip_addr *ipaddr)
實現發送線程,實現err_t (* output)接口。
static void ethernetif_input(struct netif *netif)
實現接收線程,識別數據包是ARP包還是IP包
err_t ethernetif_init(struct netif *netif)
初始化底層接口,給作者給好了驅動的接口賦值啊啥的。
其實,寫驅動的時候只要自己再建個ethernet.c,實際的網絡硬件控制的文件
然后提供幾個函數
比如:
void EMACInit( void )
硬件的初始化
void EMACPacketSend ( u8_t *buffer, u16_t length )
用來將buffer里面的包復制到網絡設備的發送緩沖里面,發送。
u16_t EMACPacketReceive ( u8_t *buffer, u16_t max_length )
用來將網絡設備的接收緩沖里面的包數據復制到buffer里面。
u16_t EMACPacketLength ( u16_t max_length )
獲得包長度
還有其他控制類函數。
最后,用ethernet.c里的函數完成ethernetif.c里的框架。這樣脈絡可能會清楚一點。
2)應用層的那邊問題
?。?).lwip提供三種API:1)RAW API 2)lwip API 3)BSD API。
對于多任務系統而言,因為lwip采用的是將TCP/IP協議放在一個單獨的線程里面,所以那個線程是tcpip_thread。采用RAW API回調技術,就得把應用層程序寫在tcpip_thread這個線程里面,作為同一個任務運行。
而采用lwip API,就可以將TCP/IP協議和應用層程序放在不同的任務里面,通過調api_lib.c提供的函數,編寫相應的應用層代碼。好象一般都會采用這種方式。
BSD API就是那sockets.c里面的,沒用過。
(2)任務間是如何調度的
從底層到應用層,一般將底層數據接收做為一個線程,可以建個任務也可以直接在中斷里解決。
然后tcpip_thread是一個線程,最后是應用層一個線程。
底層的郵箱投遞活動是通過調用tcpip.c里的tcpip_input。這個函數向tcpip_thread投遞消息。高層的投遞應該是通過tcpip_apimsg。
遇到的問題:
一開始移植的時候,驅動寫好的,能PING通,但TCP的任務沒反應,這個我那問題是lwip協議棧的問題,換個版本的協議棧就搞定了,網上吧,下的協議棧,有的是有問題的。
電子發燒友App













評論