分类: LINUX
2010-08-18 10:42:08
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,应用层的那边的问题。
有几个概念。
1.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。
遇到的问题:
1,一开始移植的时候,驱动写好的,能PING通,但TCP的任务没反应,这个我那问题是lwip协议栈的问题,换个版本的协议栈就搞定了,网上吧,下的协议栈,有的是有问题的。
现在开始应用层的开发了......
参考了一个例子
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/t_larry/archive/2008/11/09/3262273.aspx