STM32移植uIP
2012-12-27 13:28
801 查看
文件说明:
这是uIP1.0源码文件,apps是作者写好的应用程序demo,doc是一些文档,lib里面只有一个文件是内存申请与释放函数的接口,uip是tcp/ip的协议栈了,unix是与外部的接口,我们移植也主要去改这些文件。
说一下一眼看不出作用的文件。lc.h、lc-addrlabels.h、lc-switch.h、psock.c、psock.h和pt.h这些是一个模拟线程的轻量级库protothreads。uip_arp.c地址解析协议的接口。uip-fw.c是多重网络转发数据包的借口(没用到)。uiplib.c里只有一个函数uiplib_ipaddrconv:把ip地址转换成字符格式(没用到)。uip-neighbor.c可能是存储网络上一下ip与mac(网络邻居?没用到)。uip-split.c拆包发送的借口,tcp/ip协议规定包的长度不能超过1500个字节,否则需要拆包发送(没用到)。
clock-arch.c里面只有一个函数clock_time。main函数自己重写吧。tapdev.c是与硬件网络模块的接口。uip-conf.h是一些配置。
为什么我觉得uip比RL_TCPnet移植更麻烦?就是因为uip的文件关系有点乱,而且一些数据类型需要重定义,甚至还需要改动库文件里的,可能RL_TCPnet是因为Keil公司专门写了用于M3内核的库才没有这么些问题吧。下面是简单的头文件包含关系,在移植的时候需要注意。
移植:
因为只做udp、tcp(客户端与服务器)和http,所以添加这些文件就够了。工程结构如下图。uip_user.c是自己写的应用函数。我用的网络模块是enc28j60。网络上有很多该模块的驱动,只要改一下spi管脚配置就行。
tapdev.c就是uip与硬件的接口函数了。具体见下。
void tapdev_init(unsigned char *my_mac) { int i; /*初始化 enc28j60*/ enc28j60Init(my_mac); for (i = 0; i < 6; i++) { uip_ethaddr.addr[i] = my_mac[i]; } } /*---------------------------------------------------------------------------*/ /**************************************************************************** * 名 称:uint16_t tapdev_read(void) * 功 能: * 入口参数:读取一包数据 * 出口参数: 如果一个数据包收到返回数据包长度,以字节为单位,否则为零。 * 说 明: * 调用方法: ****************************************************************************/ unsigned int tapdev_read(void) { return enc28j60PacketReceive(1500,uip_buf); } /**************************************************************************** * 名 称:void tapdev_send(void) * 功 能: * 入口参数:发送一包数据 * 出口参数: * 说 明: * 调用方法: ****************************************************************************/ void tapdev_send(void) { enc28j60PacketSend(uip_len,uip_buf); }
uip-conf.h是配置文件,关闭日志输出:#define UIP_CONF_LOGGING 0。打开udp连接:#define UIP_CONF_UDP 1。只留下#include webserver.h(里面有个http回调函数,不过最好在之前自己写回调函数,因为还要做tcp的其他连接)。ps.实际的配置文件是uipopth.h,不过那里面的一般不用改。
/* 定义应用程序回调函数 */ #ifndef UIP_APPCALL #define UIP_APPCALL tcp_appcall #endif #define UIP_UDP_APPCALL udp_appcall //uip-tcp的总回调函数 void tcp_appcall(void) { if(uip_conn->lport == HTONS(80)) { httpd_appcall();//指向了http.c的httpd_appcall()回调函数。 } if(uip_conn->lport == HTONS(LocalPort)) { tcp_server_appcall(); } if(uip_conn->rport == HTONS(RemotePort)) { tcp_client_appcall(); } }
clock-arch.h中只有一个函数clock_time()。uip这个协议栈需要时间轮询函数,在clock-arch.h中定义#define CLOCK_CONF_SECOND 100,也就是100毫秒。由于我是用的ucos-ii,所以就写在系统时间钩子函数(在os_cpu_c.c里),如果没有用的话,也只需要另开一个定时器就可以了。
volatile INT32U uIP_time = 0; #if (OS_CPU_HOOKS_EN > 0) && (OS_TIME_TICK_HOOK_EN > 0) void OSTimeTickHook (void) { #if OS_APP_HOOKS_EN > 0 App_TimeTickHook(); #endif static INT8U s_count = 0; if (++s_count >= 10) { s_count = 0; uIP_time++; /* 全局运行时间每10ms增1 */ if (uIP_time == 0x80000000) { uIP_time = 0; } } #if OS_TMR_EN > 0 OSTmrCtr++; if (OSTmrCtr >= (OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC)) { OSTmrCtr = 0; OSTmrSignal(); } #endif } #endif
uip_user.c是自己写的一些应用函数
extern u16 LocalPort; //本地端口 extern u16 RemotePort; //远端端口 extern u8 RemoteIP[4]; //远端ip extern u8 enc_send_buf[256]; //发送数据最大字节256 extern u8 enc_send_size; //需要发送的字节数 void Net_Init(void); //网络初始化 void Udp_Init(void); //udp初始化 void Tcp_Init(void); //tcp初始化 void tcp_appcall(void); //tcp总回调函数 void udp_appcall(void); //udp总回调函数 void Uip_Proc(void); //uip的处理函数(需要循环调用) void tcp_server_appcall(void); //tcp作为服务器时的回调函数 void tcp_client_appcall(void); //tcp作为客户端时的回调函数 void tcp_newdata(void); //tcp接收函数 void tcp_senddata(void); //tcp发送函数 void udp_newdata(void); //udp接收函数 void udp_senddata(void); //udp发送函数
到此,uip的移植基本上差不多了。只需要再修改一些小错误:比如,数据类型的重定义,删除一些打印函数,tcp_udp_appstate_t(用户自定义类型)的重定义在http.c里面有了,如果不需要用到作者的一些应用函数可以直接定义成int,同样uip_udp_appstate_t(用户自定义类型)也可以直接定义为int,当然也可以定义成数组,把数据的指针和长度放里面。
pt.h中115行中把PT_YIELD_FLAG定义为volatile可变的,可以减少好的警告信息。
psock.c中164行,添加一行uip_flags &= ~UIP_ACKDATA。还有一个udp连接bug在uip.c里,具体可见奋斗板。
static char data_acked(register struct psock *s) { if(s->state == STATE_DATA_SENT && uip_acked()) { uip_flags &= ~UIP_ACKDATA; if(s->sendlen > uip_mss()) { s->sendlen -= uip_mss(); s->sendptr += uip_mss(); } else { s->sendptr += s->sendlen; s->sendlen = 0; } s->state = STATE_ACKED; return 1; } return 0; }
应用:
uip初始化要设置网络基本信息和轮询时间。void Net_Init(void) { uip_ipaddr_t ipaddr; unsigned char mymac[6] = {0x04, 0x02, 0x35, 0x00, 0x00, 0x01}; //MAC地址 tapdev_init(mymac); //ENC28J60初始化 uip_init(); //UIP协议栈初始化 uip_ipaddr(ipaddr, 172, 72, 100, 212); //设置IP地址 uip_sethostaddr(ipaddr); uip_ipaddr(ipaddr, 172, 72, 101, 1); //设置默认路由器IP地址 uip_setdraddr(ipaddr); uip_ipaddr(ipaddr, 255, 255, 252, 0); //设置网络掩码 uip_setnetmask(ipaddr); timer_set(&periodic_timer, CLOCK_SECOND / 2); timer_set(&arp_timer, CLOCK_SECOND * 10); //设置轮询时间 }
udp的初始化连接注意一下绑定本地ip。tcp服务器端只需要监听某个端口(80是http服务端口)。tcp客户端需要建立连接。
//建立UDP连接初始化***************************** void Udp_Init(void) { uip_ipaddr_t ipaddr;//定义IP类型变量 uip_ipaddr(ipaddr, RemoteIP[0], RemoteIP[1], RemoteIP[2], RemoteIP[3]); //远端IP if(my_udp_conn != NULL) { uip_udp_remove(my_udp_conn);//如果连接已经建立,则删除之 } my_udp_conn = uip_udp_new(&ipaddr, HTONS(RemotePort));//建立到远程端口 if(my_udp_conn != NULL) { uip_udp_bind(my_udp_conn, HTONS(LocalPort));//绑定本地端口 } } //作为tcp客户端初始化 void Tcp_Init(void) { uip_ipaddr_t ipaddr;//定义IP类型变量 uip_ipaddr(ipaddr, RemoteIP[0], RemoteIP[1], RemoteIP[2], RemoteIP[3]); //远程IP my_tcp_conn = uip_connect(&ipaddr, HTONS(RemotePort));//建立到远程端口 }
还有一个问题是:作为tcp客户端的时候,pc机使用网络调试助手,如果在连接后再点断开的话就重连不上。 PC机断开连接后,那个端口先是timeout然后应该就删除了,断开后会进入2次uip_closed(),所以判断一下重新连接(会分配新的端口)。如果在程序运行开始但是PC机并没有打开连接的话,会一直进入uip_aborted(),在里面设置重新连接,这样会直到PC机打开。
if(uip_closed()) { tcp_server_flag++; if(tcp_server_flag == 2) { uip_ipaddr_t ipaddr;//定义IP类型变量 uip_ipaddr(ipaddr, RemoteIP[0], RemoteIP[1], RemoteIP[2], RemoteIP[3]); //远程IP my_tcp_conn = uip_connect(&ipaddr, HTONS(RemotePort));//建立到远程端口 tcp_server_flag = 0; } } if( uip_aborted()) { uip_ipaddr_t ipaddr;//定义IP类型变量 uip_ipaddr(ipaddr, RemoteIP[0], RemoteIP[1], RemoteIP[2], RemoteIP[3]); //远程IP my_tcp_conn = uip_connect(&ipaddr, HTONS(RemotePort)); //建立到远程端口 }
有关http的应用请见下一篇。ps.uip1.0的smtp好像不完整,请参照0.9版。
下载:
uip1.0英文使用指南下载,请点击。stm32移植uip1.0工程源码下载,请点击。如果使用HG 只要clone https://zouw96@bitbucket.org/zouw96/uip_http
相关文章推荐
- Uip在STM32平台移植之建立UDP链接
- 网络通信之UIP在STM32上的移植
- Uip在STM32平台移植
- Uip + Stm32移植问题总结
- Uip + Stm32移植问题总结【转】
- uip-学习笔记(移植篇)
- STM32上移植ds1307笔记
- ucosii在stm32上的移植详解4 http://blog.csdn.net/lbl1234
- 关于freertos移植到stm32出错,程序直接跳到HardFault_Handler的问题。
- RT-Thread-v2.0.0移植到STM32及驱动LCD和测温
- ucosii在stm32上的移植详解3 .
- IAR环境下ucosii在STM32上的移植
- STM32移植RT-Thread后的串口在调试助手上出现:(mq != RT_NULL) assert failed at rt_mq_recv:2085和串口只发送数据不能接收数据问题
- ucOS_II移植:Stm32启动代码分析
- stm32小四轴之MPU6050的DMP库移植
- uip协议栈移植的原理图、pcb、原理图库、pcb库
- 求解:uIP协议栈在51系类单片机上的移植
- UCGUI+触摸在STM32上的移植
- STM32 USB-HID通信移植步骤
- STM32移植uCOS-II