在开发过程中想要与开发板进行通信一般使用串口通信,当开发板使用串口与pc通信还需要专门的串口转换工具才行,而小凌派开发板自带wifi功能。因此与pc通信时可以使用wifi功能进行tcp通信这样就不需要专门的转换工具非常方便。
在使用小凌派开发板wifi进行tcp通信的步骤
1、要确定pc机所连接路由的wifi名称和密码,通过修改代码使小凌派连接到与pc同一网络。
修改文件device/rockchip/rk2206/sdk_liteos/board/src/config_network.c 中的ssid 即wifi名称,和password 即wifi密码。
#define ssid 凌智电子#define password ******** (左右移动查看全部内容)
2、确认小凌派wifi功能是否开启
查看device/rockchip/rk2206/sdk_liteos/board/main.c 文件是否调用externaltaskconfignetwork();
3、确认小凌派开发板与开发板在同一网段
在修改以上配置后先编译烧录程序然后查看log确认小凌派开发板获取到的ip地址。
在确认pc的ip地址,在控制台输入ipconfig
可以看到两个ip地址都是点2网段,说明已经在同一局域网。
4、 修改wifi_tcp 例程中服务地址及端口号
#define oc_server_ip 192.168.2.49#define server_port 6666 (左右移动查看全部内容)
这个ip地址即pc的ip地址,修改后重新编译烧录程序。
5、 pc上打开两个网络调试工具,一个客户端和一个服务端,并设置ip地址和端口号:
服务端 ip地址:0.0.0.0
端口号:6666
客户端ip地址:192.168.2.50 (之前查看到小凌派的ip地址)
端口号:6666
6 、查看log等待小凌派的tcp客户端和服务端任务启动
可以看到客户端连接地址192.168.2.49:6666 即pc的ip地址:服务端监听端口为6666,这表示小凌派tcp客户端和服务端任务都已经启动。
7、 在pc网络调试助手点击启动客户端和服务端
可以观察到网络调试助手服务端有设备连接成功并且接收到了调试数据。网络调试助手的客户端也显示连接成功。
8、 使用网络调试助手发送数据
可以查看log发现小凌派开发板已经可以正常收发数据了,这样就可以通过使用wifi与pc进行通信。
接下来分析一下代码的工作流程
首先包含必要的头文件:
#include ohos_init.h#include cmsis_os2.h#include los_task.h#include lz_hardware.h#include config_network.h#include lwip/tcp.h#include lwip/ip_addr.h#include lwip/priv/tcp_priv.h#include lwip/stats.h#include lwip/inet_chksum.h (左右移动查看全部内容)
这些定义主要是 ip地址和端口号以及缓存大小
#define log_tag tcp#define oc_server_ip 192.168.2.49#define server_port 6666#define buff_len 256 (左右移动查看全部内容)
这部分是获取wifi连接信息,通过查询wifi连接信息确认wifi是否连接成功。只有wifi连接成功了才能进行tcp通信
int get_wifi_info(wifilinkedinfo *info){ int ret = -1; int gw, netmask; memset(info, 0, sizeof(wifilinkedinfo)); unsigned int retry = 15; while (retry) { if (getlinkedinfo(info) == wifi_success) { if (info->connstate == wifi_connected) { if (info->ipaddress != 0) { lz_hardware_logd(log_tag, rknetwork ip (%s), inet_ntoa(info->ipaddress)); if (wifi_success == getlocalwifigw(&gw)) { lz_hardware_logd(log_tag, network gw (%s), inet_ntoa(gw)); } if (wifi_success == getlocalwifinetmask(&netmask)) { lz_hardware_logd(log_tag, network netmask (%s), inet_ntoa(netmask)); } if (wifi_success == setlocalwifigw()) { lz_hardware_logd(log_tag, set network gw); } if (wifi_success == getlocalwifigw(&gw)) { lz_hardware_logd(log_tag, network gw (%s), inet_ntoa(gw)); } if (wifi_success == getlocalwifinetmask(&netmask)) { lz_hardware_logd(log_tag, network netmask (%s), inet_ntoa(netmask)); } ret = 0; goto connect_done; } } } los_msleep(1000); retry--; }connect_done: return ret;} (左右移动查看全部内容)
这部分是tcp服务端接收消息处理,先进入accept()会处于阻塞状态,即没有客户端连接时一直阻塞。单客户端连接后又进入接收数据状态,此状态也是阻塞状态。
没有数据时一直阻塞,不过需要注意的是在此状态下当客户端断开连接时recv会返回-1,接收到pc客户端的消息后通过send()发响应消息给pc客户端。
void tcp_server_msg_handle(int fd){ char buf[buff_len]; //接收缓冲区 socklen_t client_addr_len; int cnt = 0, count; int client_fd; struct sockaddr_in client_addr = {0}; printf(waitting for client connect...); /* 监听socket 此处会阻塞 */ client_fd = accept(fd, (struct sockaddr*)&client_addr, &client_addr_len); // client_fd = lwip_accept(fd, (struct sockaddr*)&client_addr, &client_addr_len); printf([tcp server] accept , inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); while (1) { memset(buf, 0, buff_len); printf(-------------------------------------------------------); printf([tcp server] waitting client msg); count = recv(client_fd, buf, buff_len, 0); //read是阻塞函数,没有数据就一直阻塞 // count = lwip_read(client_fd, buf, buff_len); //read是阻塞函数,没有数据就一直阻塞 if (count == -1) { printf([tcp server] recieve data fail!); los_msleep(3000); break; } printf([tcp server] rev client msg:%s, buf); memset(buf, 0, buff_len); sprintf(buf, i have recieved %d bytes data! recieved cnt:%d, count, ++cnt); printf([tcp server] send msg:%s, buf); send(client_fd, buf, strlen(buf), 0); //发送信息给client // lwip_write(client_fd, buf, strlen(buf)); //发送信息给client } lwip_close(client_fd); lwip_close(fd);} (左右移动查看全部内容)
这部分是tcp服务端任务代码,服务端处理流程
socket-->bind-->listen-->accept-->recv-->send-->lwip_close
先通过socket()接口打开一个服务端socket文件,然后设置需要绑定的服务端ip地址及端口号。在进行监听,需要注意的是此处监听不会处于阻塞态。
int wifi_server(void* arg){ int server_fd, ret; while(1) { server_fd = socket(af_inet, sock_stream, 0); //af_inet:ipv4;sock_stream:tcp // server_fd = lwip_socket(af_inet, sock_stream, 0); //af_inet:ipv4;sock_stream:tcp if (server_fd < 0) { printf(create socket fail!); return -1; } /*设置调用close(socket)后,仍可继续重用该socket。调用close(socket)一般不会立即关闭socket,而经历time_wait的过程。*/ int flag = 1; ret = setsockopt(server_fd, sol_socket, so_reuseaddr, &flag, sizeof(int)); if (ret != 0) { printf([comminittcpserver]setsockopt fail, ret[%d]!, ret); } struct sockaddr_in serv_addr = {0}; serv_addr.sin_family = af_inet; serv_addr.sin_addr.s_addr = htonl(inaddr_any); //ip地址,需要进行网络序转换,inaddr_any:本地地址 // serv_addr.sin_addr.s_addr = inet_addr(oc_server_ip); //ip地址,需要进行网络序转换,inaddr_any:本地地址 serv_addr.sin_port = htons(server_port); //端口号,需要网络序转换 /* 绑定服务器地址结构 */ ret = bind(server_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); // ret = lwip_bind(server_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); if (ret < 0) { printf(socket bind fail!); lwip_close(server_fd); return -1; } /* 监听socket 此处不阻塞 */ ret = listen(server_fd, 64); // ret = lwip_listen(server_fd, 64); if(ret != 0) { printf(socket listen fail!); lwip_close(server_fd); return -1; } printf([tcp server] listen:%d,server_fd, inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port)); tcp_server_msg_handle(server_fd); //处理接收到的数据 los_msleep(1000); }} (左右移动查看全部内容)
这部分是tcp客户端的接收消息处理函数,先进行尝试连接pc机的服务端,如果失败则延迟5秒后重新连接直到连接成功。
连接成功后先发消息给pc的服务端,然后进入接收状态,此状态是阻塞态。当接收到pc的消息后进入循环发送状态。
void tcp_client_msg_handle(int fd, struct sockaddr* dst){ socklen_t len = sizeof(*dst); int cnt = 0, count = 0; while (connect(fd, dst, len) connect-->send-->recv-->lwip_close
先通过socket()接口创建客户端的socket文件。然后设置客户端连接pc服务端的ip地址及端口号。在进行connect连接。
int wifi_client(void* arg){ int client_fd, ret; struct sockaddr_in serv_addr; while(1) { client_fd = socket(af_inet, sock_stream, 0);//af_inet:ipv4;sock_stream:tcp if (client_fd < 0) { printf(create socket fail!); return -1; } /*设置调用close(socket)后,仍可继续重用该socket。调用close(socket)一般不会立即关闭socket,而经历time_wait的过程。*/ int flag = 1; ret = setsockopt(client_fd, sol_socket, so_reuseaddr, &flag, sizeof(int)); if (ret != 0) { printf([comminittcpserver]setsockopt fail, ret[%d]!, ret); } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = af_inet; serv_addr.sin_addr.s_addr = inet_addr(oc_server_ip); serv_addr.sin_port = htons(server_port); printf([tcp client] connect:%d,client_fd, inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port)); tcp_client_msg_handle(client_fd, (struct sockaddr*)&serv_addr); los_msleep(1000); } return 0;} (左右移动查看全部内容)
这部分是tcp创建客户端和服务端任务,可以看到在创建客户端和服务端任务前先阻塞判断wifi的连接状态。只有wifi连接成功后才创建客户端和服务端任务
void wifi_process(void *args){ unsigned int threadid_client, threadid_server; unsigned int ret = los_ok; wifilinkedinfo info; while(get_wifi_info(&info) != 0) ; createthread(&threadid_client, wifi_client, null, client@ process); createthread(&threadid_server, wifi_server, null, server@ process);} (左右移动查看全部内容)
这部分是创建wifi tcp 通信任务主要是为了使用app_feature_init(wifi_tcp_example);这样当openharmony初始化完成后会自动执行此任务。
void wifi_tcp_example(void){ unsigned int ret = los_ok; unsigned int thread_id; tsk_init_param_s task = {0}; printf(%s start ...., __function__); task.pfntaskentry = (tsk_entry_func)wifi_process; task.uwstacksize = 10240; task.pcname = wifi_process; task.ustaskprio = 24; ret = los_taskcreate(&thread_id, &task); if (ret != los_ok) { printf(falied to create wifi_process ret:0x%x, ret); return; }}app_feature_init(wifi_tcp_example); (左右移动查看全部内容)
原文标题:基于小凌派rk2206鸿蒙开发板wifi-tcp通信实验
文章出处:【微信公众号:harmonyos官方合作社区】欢迎添加关注!文章转载请注明出处。
特斯拉正在更新Model 3外观设计,且增加了防盗功能
厉害了!一网友竟自己动手将一台16GB的iPhone 6 Plus升级到128GB
荣耀magic3屏幕分辨率及供应商
我国量子保密通信具备了全面检测能力,但产业发展还面临一些问题
区块链和互联网的关系是什么?互联网是信息高速公路 区块链是价值高速公路
使用小凌派开发板wifi进行tcp通信的步骤
任正非表示中国没有垄断核心网先进的核心网有44%让诺基亚和爱立信拿了
提高实验效率,了解万能试验机常见故障和维修方法
充电汽车也闹心:高速路突然没电、板车拉蔚来ES8
阐述物联网架构的几种协议
php的源码是什么开源语言
你会选择哪个无线技术,一起“过大年”?
那么问题来了 移动芯片进入烧钱淘汰战?
国芯思辰 |铁电存储器PB85RS128用于ETC读卡器,电压为2.7V-3.6V
努比亚Z17mini怎么样?努比亚Z17mini配置和价格介绍
确定性体验带来商业溢价,全光自动驾驶网络使能确定性体验
CD4040中文资料汇总(CD4040引脚图及功能_工作原理及应用电路)
FPGA是什么(超级详细)
美国的移动通信
维科技术与韩国株式会社LG化学达成了最新的战略合作