LwIP移植心得

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协议栈的问题,换个版本的协议栈就搞定了,网上吧,下的协议栈,有的是有问题的。

现在开始应用层的开发了......
参考了一个例子


你可能感兴趣的:(嵌入式开发)