物联网的IPV6应用是一个趋势,contiki是集成了6lowpan的一个集成开发工具。uip是集成在内部的,支持IPV6以及IPV4,这里先通过IPV4与平台连接建立一个数据通道。后续会跟进IPV6以及6lowpan的应用。而且uip不需要OS支持,以事件驱动的方式编程,占用的RAM以及ROM都符合嵌入式的需求。
之前我们需要了解一些背景知识:
1,http的相关知识
2,yeelink http请求格式分析 (分析很透彻)
3,tcp/ip的连接
4,stm32平台+enc28j60网络模块
5,uip1.0 (contiki里面的uip已经是与6lowpan、ipv6耦合起来了,所以这里选择了uip1.0的版本)uip0.9 refman中文翻译 也是一个不错的博文,让大家更快熟悉uip的编程思想。
这一部分我们会先介绍uip在stm32平台上的移植工作。Enc28j60是带SPI 接口的独立以太网控制器,可以用mcu控制spi来实现tcp/ip数据流的收发,所以要先完成Enc28j60的驱动程序,再整合Uip。
这一部分可以参考:uip在stm32上的移植,说明的也很详细,我就不累赘了。
uip自带了一个dns的解析,配置如下:
void yeelink_init(void) { uip_ipaddr_t ipaddr; resolv_init(); uip_ipaddr(ipaddr, 221, 228, 255, 1); // DNS resolv_conf(ipaddr); resolv_query(YEELINK_HOST); }这里的DNS我们可以通过查看自己的网络参数获取。当然你也可以配置uip为DHCP模式,这样就会自动帮我们配置DNS查询上级IP。
当查找到目的网址的IP或者说查找失败,都会调用void resolv_found(char *name, u16_t *ipaddr);这个函数需要我们在main里自己实现:
void resolv_found(char *name, u16_t *ipaddr) { if (ipaddr == NULL) { printf("Host ‘%s‘ not found.\r\n", name); } else { printf("Found name ‘%s‘ = %d.%d.%d.%d\r\n", name, htons(ipaddr[0]) >> 8, htons(ipaddr[0]) & 0xff, htons(ipaddr[1]) >> 8, htons(ipaddr[1]) & 0xff); yeelink_connect(YEELINK_HOST, YEELINK_PORT); } }
如果查找到了yeelink的地址,我们就进行tcp连接。
剩下就是yeelink的client实现,代码如下:
void yeelink_client_appcall(void) { if (uip_connected()) { yeelink_request_get(); printf("yeelink_client: connected, waiting for data...\r\n"); return; } if (uip_aborted()) { printf("yeelink_client: connection aborted\r\n"); } if (uip_timedout()) { printf("yeelink_client: connection timed out\r\n"); } if (uip_acked()) { yeelink_request_acked(); } if ( uip_rexmit() || uip_newdata()) { yeelink_newdata(); // 这里的数据是分包发送过来的 return; } if (uip_poll()) { if (yeelink_poll()) { return; } } if (uip_closed()) { yeelink_closed(); printf("yeelink_client: connection closed\r\n"); } }
这个流程按照uip的网络编程流程来,这里需要注意几点:
http请求是根据mss来决定一包里面的有效数据长度的。这里就出现了yeelink的http应答分包发送,那么我们在处理http数据的时候就需要考虑到组包。实现的时候我取了个巧。
static void yeelink_newdata(void) { yeelink_client.timer = 0; u16_t len = uip_datalen(); memcpy(yeelink_client.data, uip_appdata, len); //{"timestamp":"2014-03-25T13:40:47","value":0} u8_t *value_info = (u8_t *)strstr(yeelink_client.data, "\"value\""); if (value_info != NULL) { // 分片传送的 len = strlen("\"value\":"); u8_t status = *(value_info + len); if (status == ‘0‘) { printf("yeelink_client: switch is close\r\n"); } else { printf("yeelink_client: switch is open\r\n"); } memset(yeelink_client.data, 0x00 , WEBCLIENT_CONF_MAX_URLLEN); /*uip_close();*/ yeelink_struct_init(); } }
查询的时候似乎并没有时间限制,我在poll里面设置了1s查询一次,结果也依然可以返回。之前提到的5s限制并不存在,不知道是否是升级了服务。
总结:
uip相对于lwip而言会更适合物联网的开发,但是编程相对lwip而言会需要一些技巧性,因为与我们常规的阻塞式编程有区别。
代码的地址如下:https://utopiaprince@bitbucket.org/utopiaprince/uip1.0-stm32-webserver 可以用hg clone。
原文:http://blog.csdn.net/utopiaprince/article/details/22373115