在開發(fā)過程中想要與開發(fā)板進行通信一般使用串口通信,當開發(fā)板使用串口與pc通信還需要專門的串口轉換工具才行,而小凌派開發(fā)板自帶wifi功能。因此與pc通信時可以使用wifi功能進行tcp通信這樣就不需要專門的轉換工具非常方便。
在使用小凌派開發(fā)板wifi進行tcp通信的步驟
1、要確定pc機所連接路由的wifi名稱和密碼,通過修改代碼使小凌派連接到與pc同一網絡。
修改文件device/rockchip/rk2206/sdk_liteos/board/src/config_network.c 中的SSID 即wifi名稱,和PASSWORD 即wifi密碼。
(左右移動查看全部內容)
2、確認小凌派wifi功能是否開啟
查看device/rockchip/rk2206/sdk_liteos/board/main.c 文件是否調用ExternalTaskConfigNetwork();
3、確認小凌派開發(fā)板與開發(fā)板在同一網段
在修改以上配置后先編譯燒錄程序然后查看log確認小凌派開發(fā)板獲取到的ip地址。

在確認pc的ip地址,在控制臺輸入ipconfig

可以看到兩個ip地址都是點2網段,說明已經在同一局域網。
4、 修改wifi_tcp 例程中服務地址及端口號
(左右移動查看全部內容)
這個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地址:服務端監(jiān)聽端口為6666,這表示小凌派tcp客戶端和服務端任務都已經啟動。
7、 在pc網絡調試助手點擊啟動客戶端和服務端

可以觀察到網絡調試助手服務端有設備連接成功并且接收到了調試數(shù)據。網絡調試助手的客戶端也顯示連接成功。
8、 使用網絡調試助手發(fā)送數(shù)據

可以查看log發(fā)現(xiàn)小凌派開發(fā)板已經可以正常收發(fā)數(shù)據了,這樣就可以通過使用wifi與pc進行通信。
接下來分析一下代碼的工作流程
首先包含必要的頭文件:
(左右移動查看全部內容)
這些定義主要是 ip地址和端口號以及緩存大小
(左右移動查看全部內容)
這部分是獲取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()會處于阻塞狀態(tài),即沒有客戶端連接時一直阻塞。單客戶端連接后又進入接收數(shù)據狀態(tài),此狀態(tài)也是阻塞狀態(tài)。
沒有數(shù)據時一直阻塞,不過需要注意的是在此狀態(tài)下當客戶端斷開連接時recv會返回-1,接收到pc客戶端的消息后通過send()發(fā)響應消息給PC客戶端。
void tcp_server_msg_handle(int fd)
{
char buf[BUFF_LEN]; //接收緩沖區(qū)
socklen_t client_addr_len;
int cnt = 0, count;
int client_fd;
struct sockaddr_in client_addr = {0};
printf("waitting for client connect... ");
/* 監(jiān)聽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 <%s:%d> ", 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是阻塞函數(shù),沒有數(shù)據就一直阻塞
// count = lwip_read(client_fd, buf, BUFF_LEN); //read是阻塞函數(shù),沒有數(shù)據就一直阻塞
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); //發(fā)送信息給client
// lwip_write(client_fd, buf, strlen(buf)); //發(fā)送信息給client
}
lwip_close(client_fd);
lwip_close(fd);
}
(左右移動查看全部內容)
這部分是tcp服務端任務代碼,服務端處理流程
socket-->bind-->listen-->accept-->recv-->send-->lwip_close
先通過socket()接口打開一個服務端socket文件,然后設置需要綁定的服務端ip地址及端口號。在進行監(jiān)聽,需要注意的是此處監(jiān)聽不會處于阻塞態(tài)。
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)后,仍可繼續(xù)重用該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;
}
/* 監(jiān)聽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<%s:%d> ",server_fd, inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
tcp_server_msg_handle(server_fd); //處理接收到的數(shù)據
LOS_Msleep(1000);
}
}
(左右移動查看全部內容)
這部分是tcp客戶端的接收消息處理函數(shù),先進行嘗試連接pc機的服務端,如果失敗則延遲5秒后重新連接直到連接成功。
連接成功后先發(fā)消息給PC的服務端,然后進入接收狀態(tài),此狀態(tài)是阻塞態(tài)。當接收到pc的消息后進入循環(huán)發(fā)送狀態(tài)。
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) < 0)
{
printf("connect server faiLED...%d ", ++count);
lwip_close(fd);
LOS_Msleep(5000);
fd = socket(AF_INET, SOCK_STREAM, 0); //AF_INET:IPV4;SOCK_STREAM:TCP
}
while (1)
{
char buf[BUFF_LEN];
sprintf(buf, "TCP TEST cilent send:%d", ++cnt);
count = send(fd, buf, strlen(buf), 0); //發(fā)送數(shù)據給server
// count = lwip_write(fd, buf, strlen(buf)); //發(fā)送數(shù)據給server
printf("------------------------------------------------------------ ");
printf("[tcp client] send:%s ", buf);
printf("[tcp client] client sendto msg to server %d,waitting server respond msg!!! ", count);
memset(buf, 0, BUFF_LEN);
count = recv(fd, buf, BUFF_LEN, 0); //接收來自server的信息
// count = lwip_read(fd, buf, BUFF_LEN); //接收來自server的信息
if(count == -1)
{
printf("[tcp client] recieve data fail! ");
LOS_Msleep(3000);
break;
}
printf("[tcp client] rev:%s ", buf);
}
lwip_close(fd);
}
(左右移動查看全部內容)
這部分代碼是tcp客戶端代碼,客戶端處理流程:socket-->connect-->send-->recv-->lwip_close
先通過socket()接口創(chuàng)建客戶端的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)后,仍可繼續(xù)重用該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<%s:%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創(chuàng)建客戶端和服務端任務,可以看到在創(chuàng)建客戶端和服務端任務前先阻塞判斷wifi的連接狀態(tài)。只有wifi連接成功后才創(chuàng)建客戶端和服務端任務
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");
}
(左右移動查看全部內容)
這部分是創(chuàng)建wifi tcp 通信任務主要是為了使用APP_FEATURE_INIT(wifi_tcp_example);這樣當OpenHarmony初始化完成后會自動執(zhí)行此任務。
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);
(左右移動查看全部內容)
-
WIFI
+關注
關注
81文章
5386瀏覽量
207869 -
開發(fā)板
+關注
關注
25文章
5620瀏覽量
103511 -
TCP通信
+關注
關注
0文章
146瀏覽量
4513
原文標題:基于小凌派RK2206鴻蒙開發(fā)板wifi-tcp通信實驗
文章出處:【微信號:HarmonyOS_Community,微信公眾號:電子發(fā)燒友開源社區(qū)】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
每周精選 | 小凌派RK2206開發(fā)板wifi-tcp通信實驗,Markdown編輯器有獎體驗活動
【小凌派RK2206開發(fā)板試用體驗】小凌派手勢應用之原力控制星球大戰(zhàn)BB-8機器人
基于小凌派RK2206開發(fā)板wifi-udp通信實驗
如何在小凌派RK2206開發(fā)板上使用wifi進行tcp通信
基于凌蒙派開發(fā)板的FastDeploy適配
NXP iMX6ULL開發(fā)板的WIFI接口功能測試
基于小凌派RK2206開發(fā)板所制作的簡易示波器

樹莓派Pico開發(fā)板擴展ESP01S無線WiFi模塊通信實踐

小凌派-RK2206開發(fā)板:UART控制案例

基于OpenHarmony輕量級操作系統(tǒng)實現(xiàn)RK2206 WiFi-AP模式通信開發(fā)案例

評論