感谢原作者。
刚完成了uip在ucos下的移植,总结一下,其实uip部分的移植非常的简单,我整整花了2个星期,是因为cs8900的接收部分驱动程序一直没有处理好,由于uip收发都使用uip_buf,cs8900就一直处于要丢弃接收包的状态,而cs8900丢弃包似乎到现在我都没有做好!最后终于自己加了个环形缓冲区,让cs8900基本把rx的所有包收入内存,不作丢弃处理,之后就万事顺利了,希望有那位高人看到这个文章后赐我一个好点的cs8900驱动。
言归正传,uip的结构非常简单,网卡只需要接收的包填入uip_buf,设置uip_len的长度为包长。然后在uip的轮询循环中检查uip_len是否>0(调用network_device_read()函数),如果uip_len>0说明收到了数据,循环中就分类处理各种协议的请求,如果程序有数据需要发送调用uip_send发送数据,它同样是把数据送入uip_buf,设置uip_len,主循环会在本次循环中把数据送入网卡(调用network_device_send()函数)。因此uip与网卡的接口就network_device_read(), network_device_send()两个函数,一个缓冲uip_buf,一个数据uip_len.当然,真如我前面说的,为了提高效率你可以在中间加入自己的转存缓冲,否则很多包会被丢弃,你可能会看到网络里满是被丢弃和重发的包。
你的主程序循环需要被uip循环调用,这是通过把你的程序的主循环函数声明为宏UIP_APPCALL来实现的,uip_process里调用这个宏,也就执行了你的程序循环,因此你的程序主体不应该写的太长太繁琐,以免一次循环的时间过长。
由于uip不处理重发,你的程序必须知道之前发送了什么数据,程序处在什么状态,如果发送uip_rexmit(),程序就需要把上次送出的数据再发送一遍,实现重发。我后面的例子里发送了不同的数据,是为了测试重发的频率。因此程序需要维持一个状态机,我的程序里是example2_state 结构体。
uip还保持一个计数器,一定时间间隔后,通过uip_poll()调用返回真值,你的程序能获得主动发送数据的机会,同时能对空闲时间进行计数,程序可以选择在空闲太久后关闭连接,以避免死连接。
另外如果你打算在你的网卡驱动中打开中断,最好别像uip文档的例子那样先初始化设备,后初始化uip,而应该把设备初始化放到最后。有arp协议时,初始化时应该也初始化arp: uip_arp_init()
下面是我的example程序,在头文件中定义UIP_APPCALL:
#define UIP_APPCALL example2_app
#define UIP_APPSTATE_SIZE sizeof(struct example2_state)
程序的主体:
void example2_init(void) {
uip_listen(HTONS(2345));
}
void example2_app(void) {
struct example2_state *s;
s = (struct example2_state *)uip_conn->appstate;
if(uip_connected()) {
s->state = WELCOME_SENT;
uip_send("Welcome!\n", 9);
//DBGMSG("app connected \n");
return;
}
if(uip_acked()) {
switch(s->state){
case(WELCOME_SENT):
s->state= WELCOME_ACKED;
uip_send("Wbcdefghijklmnopqrstuvwxyz", 26);
break;
case(WELCOME_ACKED):
s->state=TX_SYNC_ING;
uip_send("CBCDEFGHIJKLMNOPQRSTUVWXYZ", 26);
break;
case(TX_SYNC_ING):
s->state=WELCOME_ACKED;
uip_send("Sbcdefghijklmnopqrstuvwxyz", 26);
break;
}
// DBGMSG("app acked \n");
}
if(uip_poll()){
DBGMSG("app poll \n");
}
if(uip_newdata()) {
if( s->state=WELCOME_ACKED){
s->state=TX_SYNC_ING;
uip_send("NSCDEFGHIJKLMNOPQRSTUVWXYZ", 26);
}else{
s->state=WELCOME_ACKED;
uip_send("NAcdefghijklmnopqrstuvwxyz", 26);
}
//DBGMSG("app newdata \n");
}
if(uip_rexmit()) {
DBGMSG("rxm\n");
switch(s->state) {
case WELCOME_SENT:
uip_send("Welcome!\n", 9);
break;
case WELCOME_ACKED:
s->state=TX_SYNC_ING;
uip_send("RCcdefghijklmnopqrstuvwxyz", 26);
break;
case TX_SYNC_ING:
s->state=WELCOME_ACKED;
uip_send("RSCDEFGHIJKLMNOPQRSTUVWXYZ", 26);
break;
}
}
}
/*-------------------------------------------------------------------------*/
void uip_task_init()
{
uip_ipaddr_t ipaddr;
//tapdev_init();
uip_init();
uip_arp_init();
landev_init();
uip_ipaddr(ipaddr, 192,168,1,2);
uip_sethostaddr(ipaddr);
uip_ipaddr(ipaddr, 192,168,1,64);
uip_setdraddr(ipaddr);
uip_ipaddr(ipaddr, 255,255,255,0);
uip_setnetmask(ipaddr);
example2_init();
}
/*---------------------------------------------------------------------------*/
void uip_main(void *arg)
{
int i;
struct timer periodic_timer, arp_timer;
timer_set(&periodic_timer, 1000);
timer_set(&arp_timer, 1000* 10);
uip_task_init();
while(1) {
//uip_len = landev_read();
uip_len = landev_read();
if(uip_len > 0) {
if(BUF->type == htons(UIP_ETHTYPE_IP)) {
uip_arp_ipin();
uip_input();
//DBGMSG("ip input\n");
/* If the above function invocation resulted in data that
should be sent out on the network, the global variable
uip_len is set to a value > 0. */
if(uip_len > 0) {
uip_arp_out();
landev_send();
}
} else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {
uip_arp_arpin();
/* If the above function invocation resulted in data that
should be sent out on the network, the global variable
uip_len is set to a value > 0. */
if(uip_len > 0) {
landev_send();
}
}
} else if(timer_expired(&periodic_timer)) {
timer_reset(&periodic_timer);
for(i = 0; i < UIP_CONNS; i++) {
uip_periodic(i);
/* If the above function invocation resulted in data that
should be sent out on the network, the global variable
uip_len is set to a value > 0. */
if(uip_len > 0) {
uip_arp_out();
landev_send();
}
}
#if UIP_UDP
for(i = 0; i < UIP_UDP_CONNS; i++) {
uip_udp_periodic(i);
/* If the above function invocation resulted in data that
should be sent out on the network, the global variable
uip_len is set to a value > 0. */
if(uip_len > 0) {
uip_arp_out();
landev_send();
}
}
#endif /* UIP_UDP */
/* Call the ARP timer function every 10 seconds. */
if(timer_expired(&arp_timer)) {
timer_reset(&arp_timer);
uip_arp_timer();
}
}
}
//return 0;
}