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