W801/W800-wifi-socket开发(一)-UDP
这是目录
- 一、项目概述
- 二、socket-udp官方SDK梳理
-
- 1、连接路由器
- 2、连接UDP
- 三、项目设计
- 四、测试
本文使用环境:
主控:W800-KIT (开发板)
兼容:W800 W801 AIR101
开发环境:CDK
SDK:W801/W800的SDK(tls库)
我的联盛德问答社区主页
WIFI系列文章:
W801/W800-wifi-socket开发(二)-UDP蓝牙控制wifi连接
写在前面:
我不准备修改官方的文件,我会直接调用对应的api,因为官方用了大量的回调和消息队列,一环扣着一环,要改动话费的时间太多了,也没有太大的必要。
一、项目概述
^^^^程序功能: 使用板载WIFI连接电脑端的服务器(UDP协议,使用网络调试助手模拟),传输数据。本文的代码可以参考:W801/W800-wifi-socket开发(二)-UDP蓝牙控制wifi连接
^^^^从本文起,将开始板载wifi的使用。写之前吐槽一句,开发W80X真就是拿着官方的SDK,一个函数一个函数的啃啊,属实有点难受啊。。。。
二、socket-udp官方SDK梳理
^^^^本小节主要用来梳理官方UDP连接的程序设计思路,这都是一个函数一个函数找出来的啊,真的辛苦。希望看官动动你发财的小手,帮忙点个关注,点个赞,点个收藏。
注意 :这里写的有点绕啊,如果新手可能不容易理解,自己多看几次把。程序设计会放在第三章节。
1、连接路由器
^^^^打开wm_connect_net_demo.c
文件,demo中wifi的连接函数在该文件下。
如上图所示,demo_connect_net
函数入口参数为wifi名和密码。
举个栗子:
demo_connect_net("yyds","1234567890");//注意,必须要有延时,否者连接会出问题。。。。。tls_os_time_delay(2000);
^^^执行完成后开发板就自动连接到wifi了,此时串口会打印:
表示已经成功加入路由器,可见路由器给开发板分配IP:192.168.1.74
。
2、连接UDP
^^^^打开wm_udp_demo.c
文件,udp_demp的连接函数在该文件下。
socket_udp_demo()'
函数参数分别表示模式(单播和多播),端口和IP。本文连接电脑服务器,因此配置如下:
socket_udp_demo(1,10086,"192.168.1.87");
上述IP是我的电脑IP,端口是我自定义的端口,可根据实际情况修改。接下来将会详细的理一下函数的执行思路。
^^^^socket_udp_demo()'
函数前半部分全是初始化相关,主要看下面这个结构体:demo_udp
结构体如下所示,可以看出该结构体包含连接相关的变量,*sock_rx
和*sock_tx
,是后续需要用到的接收和发送指针,意味着后续的发送可以直接使用该结构体传送。
/** * @typedef struct demo_udp */typedef struct demo_udp{ tls_os_queue_t *udp_q; struct ip_mreq mreq; char *sock_rx; char *sock_tx; int cast_mode; bool socket_ok; int socket_num; int port; u32 ip_addr; u32 rcv_data_len; int snd_skt_no; int snd_data_len;} ST_Demo_Udp;
^^^^函数中对输入和输出都进行了内存的分配,如果发送数据和接收数据长度很长需要特别注意。
^^^^接下来直接看以下两个任务,注意demo_udp
这个结构体传递给了这个两个任务。
^^^^第一个是配置和发送相关,第二个是接收数据。
2.1、首先进入demo_udp_task()'
函数:(函数中的udp
是上一个函数传进来的,和前文的demo_udp
等价)
^^^^判断网络是否正常连接。
if(ethif->status)/*connected to ap and get IP*/ { tls_os_queue_send(udp->udp_q, (void *)DEMO_MSG_SOCKET_CREATE, 0); } else { struct tls_param_ip ip_param; tls_param_get(TLS_PARAM_ID_IP, &ip_param, TRUE); ip_param.dhcp_enable = TRUE; tls_param_set(TLS_PARAM_ID_IP, &ip_param, TRUE); tls_wifi_set_oneshot_flag(1); /*Enable oneshot configuration*/ printf("\nwait one shot......\n"); }
^^^^查看当前连接的状态。
tls_netif_add_status_event(udp_net_status_changed_event);
^^^^直接进入udp_net_status_changed_event()'
函数,官方使用了一个demo_udp
消息队列发送当前需要执行的函数状态,和udp
等价。
static void udp_net_status_changed_event(u8 status ){ switch(status) { case NETIF_WIFI_JOIN_FAILED: tls_os_queue_send(demo_udp->udp_q, (void *)DEMO_MSG_WJOIN_FAILD, 0); break; case NETIF_WIFI_JOIN_SUCCESS: tls_os_queue_send(demo_udp->udp_q, (void *)DEMO_MSG_WJOIN_SUCCESS, 0); break; case NETIF_IP_NET_UP: tls_os_queue_send(demo_udp->udp_q, (void *)DEMO_MSG_SOCKET_CREATE, 0); break; default: break; }}
^^^^退出udp_net_status_changed_event()'
函数继续查看demo_udp_task()'
函数。一个死循环,接收udp
的消息,这里的switch中的msg来自于前文提到的upd
或demo_udp
(两者等价)。
for (;;) { tls_os_queue_receive(udp->udp_q, (void **)&msg, 0, 0); printf("\n udp msg =%d\n",msg); switch((u32)msg) { case DEMO_MSG_WJOIN_SUCCESS: break; case DEMO_MSG_SOCKET_CREATE: create_udp_socket_demo(); break; case DEMO_MSG_WJOIN_FAILD: if(udp->socket_num > 0) { udp->socket_num = 0; udp->socket_ok = FALSE; } break; case DEMO_MSG_SOCKET_RECEIVE_DATA: break; case DEMO_MSG_UART_RECEIVE_DATA: if (-1 == udp->snd_data_len) { len = DEMO_UDP_BUF_SIZE; } else if(udp->snd_data_len != 0) { len = (udp->snd_data_len > DEMO_UDP_BUF_SIZE) ? DEMO_UDP_BUF_SIZE : udp->snd_data_len; } else { break; } memset(udp->sock_tx, 'u', len); if (DEMO_UDP_BROADCAST == udp->cast_mode) { pin.sin_addr.s_addr = htonl(0xffffffffUL); //IPADDR_BROADCAST } else if (DEMO_UDP_MUTICAST == udp->cast_mode) { MEMCPY((char *) & (pin.sin_addr.s_addr), (char *)MCASTIP, 4); } else { pin.sin_addr.s_addr = udp->ip_addr; } pin.sin_port = htons(udp->port); ret = sendto(udp->socket_num, udp->sock_tx, len, 0, (struct sockaddr *)&pin, sizeof(struct sockaddr)); //printf("ret = %d\n",ret); if (ret < 0) { printf("send err\n"); break; } else { if (udp->snd_data_len != -1) { udp->snd_data_len -= ret; } } if (udp->socket_ok && udp->snd_data_len != 0) { tls_os_time_delay(8); tls_os_queue_send(udp->udp_q, (void *)DEMO_MSG_UART_RECEIVE_DATA, 0); } break; case DEMO_MSG_SOCKET_ERR: tls_os_time_delay(200); printf("\nsocket err\n"); create_udp_socket_demo( ); break; default: break; } }
^^^^梳理一下switch的执行顺序:首先执行create_udp_socket_demo()'
,创建连接,这个函数不用再看了,会自动创建成功。然后,就可以进入发送程序。demo中单独写了一个发送函数:
int udp_send_data_demo(int len){ printf("\nlen=%d\n", len); if (NULL == demo_udp) { return WM_FAILED; } if (!demo_udp->socket_ok) { printf("skt not created\n"); return WM_FAILED; } demo_udp->snd_data_len = len; tls_os_queue_send(demo_udp->udp_q, (void *)DEMO_MSG_UART_RECEIVE_DATA, 0); return WM_SUCCESS;}
该函数只规定了传输的长度,并未对内容进行赋值,tls_os_queue_send()'
函数发送消息DEMO_MSG_UART_RECEIVE_DATA
参数给 demo_udp_task()'
代码的for循环,tls_os_queue_receive()
函数接收消息队列的值,并switch执行。在case DEMO_MSG_UART_RECEIVE_DATA:
中才是真正的发生代码,发送的内容如下:
memset(udp->sock_tx, 'u', len);
上诉代码是将发送内容全部填充为’u’,因此直接修改这里的udp->sock_tx内容,就能通过socket发送数据。但实际发送的时候不再这里赋值。。。。。
**2.2、**接下来查看demo_udp_recv_task()'
函数,这个函数没有什么讲的,接收的数据会自动放到 udp->sock_rx
中。
ret = recvfrom(udp->socket_num, udp->sock_rx, DEMO_UDP_BUF_SIZE, 0, (struct sockaddr *)&pin, &addrlen);
三、项目设计
^^^^本小节将会部署自己的工程,读取并发送数据。
3.1、 修改发送和接收代码
^^^^ 必须修改: ,在 wm_udp_demo.c 找到demo_udp_task()'
函数,将 case DEMO_MSG_UART_RECEIVE_DATA:
中的memset屏蔽掉:
必须将这一条的代码屏蔽//memset(udp->sock_tx, 'u', len);//以下代码可加可不加,主要是打印发送的数据//添加在 case DEMO_MSG_UART_RECEIVE_DATA: 的 break之前。//add by zxx startprintf("send_led: %d data:\n",len);for(int ii = 0;ii < len; ii--){printf("%x ",udp->sock_tx[ii]);}printf("\n");//add by zxx endbreak;
^^^^ 不一定要修改: ,在 wm_udp_demo.c 找到demo_udp_recv_task()'
函数,添加打印代码。
if (ret > 0){printf("rcv from %s : port : %d len = %d rev_data: \n", inet_ntoa(pin.sin_addr), htons(pin.sin_port), ret);//add by zxx startfor(int ii = 0; ii < ret; ii++){printf("%d ",udp->sock_rx[ii]);}printf("\n");//add by zxx end}
3.2、 封装数据
^^^^在wm_udp_demp.c
文件的最后添加代码:
//add by zxx startvoid udp_send_data_self(u8 *data,int data_len){//将data的内容全部拷贝到demo_udp->sock_tx中memcpy(demo_udp->sock_tx, data, data_len);udp_send_data_demo(data_len);}//add by zxx end
3.3、 外部声明
^^^^在wm_demp_console.h
文件的最后添加代码:
//add by zxx startextern void udp_send_data_self(u8 *data,int data_len);//add by zxx end#endif /*__WM_DEMO_CMD_H__*/
3.4、 主函数
^^^^在你的任务中写上如下代码:
void your_task(){u8 test_data[10] = {0,1,2,3,4,5,6,7,8,9};demo_connect_net("yyds","1234567890");//必须要tls_os_time_delay(2000);socket_udp_demo(1,10086,"192.168.1.87");while(1){//发送数据udp_send_data_self(test_data,10);tls_os_time_delay(5000);}}
四、测试
1、 模拟服务器
^^^^打开网络调试助手,按照如下进行配置,IP根据自己实际情况进行配置。
2、程序下载至开发板
^^^^延时时间结束后,开发板和服务器互发数据。
^^^^开发板
^^^^服务器。