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