uIP使用记录
uIP(WIKI:https://en.wikipedia.org/wiki/UIP_(micro_IP))的初始开发者是Adam Dunkels(http://dunkels.com/adam/),这是一个开源的轻量级的TCP/IP协议栈,适用于8位或16位MCU,占用的RAM可从几百byte到几千byte不等,它仅可以处理单网络接口:IP、ICMP、UDP、TCP。uIP可从Adam Dunkels的Github获取,最新的版本是1.0,且已经不更新,现在uIP已经是开源系统Contiki的一部分,更新的部分也会在Contiki中完成。
我们先来看看uIP在系统中的位置
硬件驱动是需要提前完成,然后和uIP连接。在本例中,网卡驱动就是ENC28J60驱动。
uIP1.0文件结构如下:
apps/ - 例子应用
doc/ - 文档
lib/ - 一些应用会使用到的
uip/ - uIP TCP/IP协议栈核心代码
unix/ - 与硬件平台有关的代码
我们本次移植涉及到文件夹apps、uip、unix。
我们将uip文件中的源码放入uip_core中,将unix文件中的源码放入uip_dev中(除了main.c)
1.uip_dev/clock-arch.h
2.uip_dev/tapdev.c
我们需要在这个文件中完成3个驱动函数。
#include "tapdev.h"
#include "uip.h"
#include "enc28j60.h"
//用于固定IP地址开关打开后的IP设置
#define UIP_DRIPADDR0 192
#define UIP_DRIPADDR1 168
#define UIP_DRIPADDR2 1
#define UIP_DRIPADDR3 15
//MAC地址
const u8 mymac[6]={0x04,0x02,0x35,0x00,0x00,0x01};
//网卡初始化
u8 tapdev_init(void)
{
u8 i,res=0;
res=ENC28J60_Init((u8*)mymac);
for (i = 0; i < 6; i++)uip_ethaddr.addr[i]=mymac[i];
//LED控制寄存器
ENC28J60_PHY_Write(PHLCON,0x0476);
return res;
}
//读取一包数据
uint16_t tapdev_read(void)
{
return ENC28J60_Packet_Receive(MAX_FRAMELEN,uip_buf);
}
//发送一包数据
void tapdev_send(void)
{
ENC28J60_Packet_Send(uip_len,uip_buf);
}
3.uip_dev/uip_conf.h
根据需要配置uIP,并取消include的App头文件
//STM32是小端模式
#define UIP_CONF_BYTE_ORDER LITTLE_ENDIAN
//关闭log记录
#define UIP_CONF_LOGGING 0
4.uip_dev/clock-arch.c
时钟部分,我们需要为uIP提供10ms的时钟,我们定义了全局变量uip_timer,使用了一个定时器,在中断中,全局变量uip_timer加1
#include "clock-arch.h"
clock_time_t uip_timer;
clock_time_t clock_time(void)
{
return uip_timer;
}
好,我们开始编译,之后会出现比较多的错误和警告,具体如下:
1. uIP\core\uip.h(1180): error: #20: identifier “uip_tcp_appstate_t” is undefined
2. uIP\core\psock.c(303): warning: #167-D: argument of type “char ” is incompatible with parameter of type “u8_t ”
这个使用强制类型转换
//原本为buf_setup(&psock->buf, psock->bufptr, psock->bufsize);
buf_setup(&psock->buf, (u8_t*)psock->bufptr, psock->bufsize);
3. uIP\core\psock.c(188): warning: #513-D: a value of type “const char ” cannot be assigned to an entity of type “const u8_t ”
这个使用强制类型转换
//原本为s->sendptr = buf;
s->sendptr = (const u8_t *)buf;
4. uIP\core\psock.c(179): warning: #550-D: variable “PT_YIELD_FLAG” was set but never used
注释掉pt.h中的两处即可
5. uIP\core\uip.c(700): warning: #223-D: function “UIP_APPCALL” declared implicitly
.\Output\STM32Test.axf: Error: L6218E: Undefined symbol UIP_APPCALL (referred from uip.o).
这两个错误都和UIP_APPCALL有关,我们在uip.h中加入一个宏定义
#define UIP_APPCALL()
6. uIP\core\uip.c(1847): warning: #177-D: label “ip_send_nolen” was declared but never referenced
//将label ip_send_nolen放入宏中
#if UIP_UDP
ip_send_nolen:
#endif
7. uIP\core\uip.c(113): warning: #177-D: variable “all_ones_addr” was declared but never referenced
注释掉all_ones_addr变量
8. uIP\core\uip-neighbor.c(90): warning: #223-D: function “printf” declared implicitly
注释掉printf
9. uIP\core\uip-split.c(90): warning: #223-D: function “tcpip_output” declared implicitly
将tcpip_output注释掉
10. uIP\dev\tapdev.c(57): error: #20: identifier “uip_ethaddr” is undefined
uip_ethaddr这个变量的定义在uip.c中,在此处使用需要声明
extern struct uip_eth_addr uip_ethaddr;
11.若之前uip_conf.h中的log记录没有关闭,就会出现下述的linking错误
至此我们是0 Error(s),0 Warning(s)
由于这时我们没有调用uip相关的函数,所以这时程序的大小是和加入uip之前是一样的。
我们将uip/unix下的main.c中的main函数复制到新工程中,这时,STM32就可以响应ping命令了,这样一个简单的uIPdemo,大概占用了9K的FLASH,3K的RAM
【Reference】http://forum.eepw.com.cn/thread/262079/1/