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