4.4 lib_arch中库函数的实现
LwIP协议栈中用到了8个外部函数,这些函数通常与用户使用的系统或编译器有关,因此留给用户自己实现。如下:
u16_t htONs(u16_t n); //16位数据高低字节交换
u16_t ntohs(u16_t n);
u32_t htonl(u32_t n); //32位数据大小头对调
u32_t ntohl(u32_t n);
int strlen(const char *str); //返回字符串长度
int strncmp(const char *str1, const char *str2, int len); //字符串比较
void bcopy(const void *SRC, void *dest, int len); //内存数据块之间的互相拷贝
void bzero(void *data, int n); //内存中指定长度的数据块清零
前四个函数通常由用户自己实现。Skyeye(ARM7)中,由于使用了gCC编译器,gcc的lib库里已经有了后四个函数。而ez80的编译器函数库中缺少bcopy和bzero两个,需要自己编写。用户在其它CPU上实现时应根据自己的编译器来决定。
4.5 网络设备驱动程序
ez80开发板自带的网络芯片为ReaLTEk的8019as芯片,这是ISA 10BASE-T的以太网芯片,与Ne2k兼容。而我们在AT91模拟器Skyeye中所仿真的网络芯片也是Ne2k,所以目前实现的网络设备驱动是针对Ne2k的,其它类型的网络芯片驱动可以在LwIP的网站上找到。LwIP的网络驱动有一定的模型,/src/netif/ethernetif.c 文件即为驱动的模板,用户为自己的网络设备实现驱动时应参照此模板。
在LwIP中可以有多个网络接口,每个网络接口都对应了一个struct netif,这个netif包含了相应网络接口的属性、收发函数。LwIP调用netif的方法netif->input()及netif->output()进行以太网PACket的收、发等操作。在驱动中主要做的,就是实现网络接口的收、发、初始化以及中断处理函数。驱动程序工作在IP协议模型的网络接口层,它提供给上层(IP层)的接口函数如下:
//网卡初始化函数
void ethernetif_init(struct netif *netif)
//网卡接收函数,从网络接口接收以太网数据包并把其中的IP报文向IP层发送
//在中断方式下由网卡ISR调用
void ethernetif_input(struct netif *netif)
//网卡发送函数,给IP层传过来的IP报文加上以太网包头并通过网络接口发送
err_t ethernetif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
//网卡中断处理函数ISR
void ethernetif_isr(void);
以上的函数都可以分为协议栈本身的处理和对网络接口硬件的操作两部份,但硬件操作是对上层屏蔽的,具体参见RTL8019as、DM9008等Ne2k网络芯片的数据手册。驱动程序可以到Skyeye或LwIP的网站下载。
5 应用实例的建立和测试
做完上面的移植修改工作以后,就可以在uC/0SII中初始化LwIP,并创建TCP或UDP任务进行测试了。这部份完全是C语言的实现,因此这部份在ez80和ARM7上基本都是一样的。值得注意的是LwIP的初始化必须在uC/0SII完全启动之后也就是在任务中进行,因为它的初始化用到了信号量等OS相关的操作。关键部份的代码和说明如下:
main(){
OSInit();
OSTaskCreate(lwip_init_task, &LineNo11, &lwip_init_stk[TASK_STK_SIZE-1], 0);
OSTaskCreate(usr_task,&LineNo12,&usr_stk[TASK_STK_SIZE-1],1);
OSStart();
}
主程序中创建了lwip_init_task初始化LwIP任务(优先级0)和usr_task用户任务(优先级1)。lwip_init_task任务中除了初始化硬件时钟和LwIP之外,还创建了tcpip_thread(优先级5)和tcpecho_thread(优先级6)。实际上tcpip_thread才是LwIP的主线程,多线程的Berkley API也是基于这个线程实现的,即上面的tcpecho_thread线程也要依靠tcpip_thread线程来与外界通信,这样做的好处是编程简单,结构清晰。
www.55dianzi.com
实用Berkley API实现的tcpecho_thread是一个TCP echo服务器,*7号端口,程序框架如下:
void tcpecho_thread(void *arg){
conn = netconn_new(NETCONN_TCP); //创建新的连接标识
netconn_bind(conn, NULL, 7); //绑定到7号端口
netconn_listen(conn); //开始*端口
while(1){
newconn = netconn_aCCept(conn); //接收外部到来的连接
buf = netconn_recv(newconn) //获取数据
……. //处理数据
netconn_write(newconn, data, len, NETCONN_COPY); //发送数据
netconn_delete(newconn); //释放本次连接
}
}
编译运行后,用PINg ip地址命令可以得到ICMP reply响应。用telnet ip地址 7(登录7号端口)命令可以看到echo server的回显效果。说明ARP、ICMP、IP、TCP协议都已正确运行。
上一篇:用软件实现DAA实现方法