OpenHarmony Socket通信—DAYU200遙控3861小車
想了解更多關(guān)于開(kāi)源的內(nèi)容,請(qǐng)?jiān)L問(wèn):
一、DAYU200和3861小車簡(jiǎn)單介紹
- 潤(rùn)開(kāi)鴻OpenHarmony標(biāo)準(zhǔn)系統(tǒng)開(kāi)發(fā)板 DAYU200https://gitee.com/hihope_iot/docs/tree/master/HiHope_DAYU200
- 購(gòu)買鏈接:https://item.taobao.com/item.htm?spm=a230r.7195193.1997079397.7.6e3855b0FokvDV&id=655971020101&abbucket=15
[OpenHarmony Socket通信]DAYU200遙控3861小車-開(kāi)源基礎(chǔ)軟件社區(qū)
3861小車 ,購(gòu)買鏈接:https://item.taobao.com/item.htm?spm=a230r.7195193.1997079397.35.2cb75ea4PUqbMk&id=632728730350&abbucket=15。
[OpenHarmony Socket通信]DAYU200遙控3861小車-開(kāi)源基礎(chǔ)軟件社區(qū)
二、DAYU200遙控HiSpark-Pegasus智能小車樣例介紹
- 本樣例通過(guò)TCP socket通信實(shí)現(xiàn)DAYU200開(kāi)發(fā)板(OpenHarmony標(biāo)準(zhǔn)系統(tǒng)) 遙控 HiSpark-Pegasus智能小車(OpenHarmony輕量系統(tǒng))前進(jìn)、后退、左轉(zhuǎn)、右轉(zhuǎn)、停止等操作,實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的OpenHarmony南北向開(kāi)發(fā)互通案例。
- 樣例開(kāi)發(fā)分成3568端小車控制hap應(yīng)用和3861端c代碼
1、3568端小車控制hap應(yīng)用代碼講解
- Socket連接 https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/connectivity/socket-connection.md
- @ohos.net.socket (Socket連接) https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-socket.md#onmessage7-1
3568端小車控制hap應(yīng)用基于 (需要特別注意開(kāi)發(fā)環(huán)境!!!OpenHarmony應(yīng)用開(kāi)發(fā)更新速度很快)。
- OpenHarmony3.2release
- DevEco Studio 3.1.0.500
- sdk 3.2.12.2
DAYU200通過(guò)tcp socket與3861建立通信,hap應(yīng)用主要實(shí)現(xiàn)代碼:https://gitee.com/hihope_iot/hispark-pegasus-smart-car/blob/master/DAYU200遙控HiSpark-Pegasus智能小車樣例/DAYU200(3568)/car_socket_control/entry/src/main/ets/pages/Index.ets。
[OpenHarmony Socket通信]DAYU200遙控3861小車-開(kāi)源基礎(chǔ)軟件社區(qū)
hap應(yīng)用TCP協(xié)議進(jìn)行通信大致步驟:
- import需要的socket模塊。
- 創(chuàng)建一個(gè)TCPSocket連接,返回一個(gè)TCPSocket對(duì)象。
- (可選)訂閱TCPSocket相關(guān)的訂閱事件。
- 綁定IP地址和端口,端口可以指定或由系統(tǒng)隨機(jī)分配。
- 連接到指定的IP地址和端口。
- 發(fā)送數(shù)據(jù)/接收數(shù)據(jù)。
- Socket連接使用完畢后,關(guān)閉。
添加獲取wifi信息和網(wǎng)絡(luò)的權(quán)限,在entry\src\main\module.json5中。
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"usedScene": {
"abilities": [
"ohos.samples.socket.EntryAbility"
],
"when": "always"
}
},
{
"name": "ohos.permission.GET_WIFI_INFO",
"usedScene": {
"abilities": [
"ohos.samples.socket.EntryAbility"
],
"when": "always"
}
}
]
建立tcp通信需要首先獲取本地ip地址和端口號(hào)。
//為了獲取本地IP地址,需要導(dǎo)入@ohos.wifiManager
import wifiManager from '@ohos.wifiManager';
// 解析標(biāo)準(zhǔn)系統(tǒng)開(kāi)發(fā)板(3568)端本地IP地址
export function resolveIP(ip: number): string {
if (ip < 0 || ip > 0xFFFFFFFF) {
throw ('The number is not normal!');
}
return (ip >>> 24) + '.' + (ip >> 16 & 0xFF) + '.' + (ip >> 8 & 0xFF) + '.' + (ip & 0xFF);
}
// 獲取標(biāo)準(zhǔn)系統(tǒng)開(kāi)發(fā)板(3568)端本地IP地址
let localAddress = resolveIP(wifiManager.getIpInfo().ipAddress);
// 標(biāo)準(zhǔn)系統(tǒng)開(kāi)發(fā)板(3568)本地ip地址和端口
let bindAddress = {
address: localAddress,
port: 5678, // 綁定端口,如1234
family: 1
};
...
...
//用一個(gè)test組件顯示本地IP地址
Text(this.message0)
.fontSize(25)
.margin({top:0})
.fontWeight(FontWeight.Normal)
.backgroundColor(Color.White)
//用一個(gè)test組件顯示本地socket端口號(hào)
Text(this.message1)
.fontSize(25)
.margin({top:0})
.fontWeight(FontWeight.Normal)
.backgroundColor(Color.White)
tcp初始化,訂閱TCPSocket相關(guān)的訂閱事件,綁定本地ip地址和端口。
// 訂閱TCPSocket相關(guān)的訂閱事件
tcp.on('message',value => {
this.message_recv = this.resolveArrayBuffer(value.message)
console.log(`TCP_data` + this.message_recv);
});
tcp.on('connect', () => {
console.log("on connect")
});
tcp.on('close', () => {
console.log("on close")
});
// 綁定本地ip地址和端口
tcp.bind(bindAddress, err => {
if (err) {
promptAction.showToast({
message: '[3861_car_control] bind fail',
duration: 3000,
bottom: 10
});
console.log('[3861_car_control] bind fail');
return;
}
promptAction.showToast({
message: '[3861_car_control] bind success',
duration: 3000,
bottom: 10
});
console.log('[3861_car_control] bind success');
});
綁定輕量系統(tǒng)(3861)的ip地址和端口。
// 3861 IP地址和端口
let connectAddress = {
address: this.car_ipaddress,
port: num, // 端口號(hào)
family: 1
};
//連接到指定的3861IP地址和端口
tcp.connect({
address: connectAddress, timeout: 6000
}, err => {
if (err) {
promptAction.showToast({
message: '[3861_car_control] connect'+this.car_ipaddress+' fail',
duration: 3000,
bottom: 10
});
console.log('[3861_car_control] connect'+this.car_ipaddress+' fail');
return;
}
promptAction.showToast({
message: '[3861_car_control] connect'+this.car_ipaddress+' success',
duration: 3000,
bottom: 10
});
console.log('[3861_car_control] connect'+this.car_ipaddress+' success');
});
3568發(fā)送數(shù)據(jù)至3861。
tcp.send({
data: '0'
}, err => {
if (err) {
console.log('[3861_car_control] send fail');
return;
}
console.log('[3861_car_control] send success');
})
3568接收3861發(fā)送的數(shù)據(jù)。
//解析標(biāo)準(zhǔn)系統(tǒng)開(kāi)發(fā)板(3568)接收到的 輕量系統(tǒng)(3861)發(fā)送的數(shù)據(jù)
resolveArrayBuffer(message: ArrayBuffer): string {
if (message instanceof ArrayBuffer) {
let dataView = new DataView(message)
console.info(`length ${dataView.byteLength}`)
let str = ""
for (let i = 0;i < dataView.byteLength; ++i) {
let c = String.fromCharCode(dataView.getUint8(i))
if (c !== "\n") {
str += c
}
}
console.info(`message aray buffer:${str}`)
return str;
}
}
...
...
// 訂閱TCPSocket相關(guān)的訂閱事件
tcp.on('message',value => {
this.message_recv = this.resolveArrayBuffer(value.message)
console.log(`TCP_data` + this.message_recv);
});
···
···
//用一個(gè)text顯示標(biāo)準(zhǔn)系統(tǒng)開(kāi)發(fā)板(3568)接收到輕量系統(tǒng)(3861)發(fā)出的數(shù)據(jù)
Text('接收到的3861發(fā)送的數(shù)據(jù):' + this.message_recv)
.fontSize(25)
.margin({top:0})
.fontWeight(FontWeight.Normal)
.backgroundColor(Color.White)
關(guān)閉tcp連接。
tcp.close((err) => {
promptAction.showToast({
message: '[3861_car_control] close socket.',
duration: 3000,
bottom: 10
});
console.log('[3861_car_control] close socket.')
});
tcp.off('message');
tcp.off('connect');
tcp.off('close');
完成代碼實(shí)現(xiàn)請(qǐng)查看: https://gitee.com/hihope_iot/hispark-pegasus-smart-car/blob/master/DAYU200遙控HiSpark-Pegasus智能小車樣例/DAYU200(3568)/car_socket_control/entry/src/main/ets/pages/Index.ets。
如果要修改hap應(yīng)用的名稱,在car_socket_control\entry\src\main\resources\zh_CN\element\string.json文件中修改EntryAbility_label屬性。
[OpenHarmony Socket通信]DAYU200遙控3861小車-開(kāi)源基礎(chǔ)軟件社區(qū)
如果要修改應(yīng)用圖標(biāo)修改car_socket_control\entry\src\main\resources\base\media下icon.png(像素大小為114×114)。
[OpenHarmony Socket通信]DAYU200遙控3861小車-開(kāi)源基礎(chǔ)軟件社區(qū)
2、3861端小車代碼講解
代碼地址: https://gitee.com/hihope_iot/hispark-pegasus-smart-car/tree/master/DAYU200遙控HiSpark-Pegasus智能小車樣例/HiSpark-Pegasus-smart-car(3861)/car_tcp_control。
文件名 | 說(shuō)明 |
BUILD.gn | OpenHarmony構(gòu)建腳本 |
demo_entry_cmsis.c | OpenHarmony liteos-m程序入口 |
net_common.h | 系統(tǒng)網(wǎng)絡(luò)接口頭文件 |
net_demo.h | demo腳手架頭文件 |
net_params.h | 網(wǎng)絡(luò)參數(shù),包括WiFi熱點(diǎn)信息、端口信息 |
car_tcp_server_test.c | TCP socket控制小車實(shí)現(xiàn)代碼 |
wifi_connecter.c | OpenHarmony WiFi STA模式API的封裝實(shí)現(xiàn)文件 |
wifi_connecter.h | OpenHarmony WiFi STA模式API的封裝頭文件 |
本篇文章主要講解主要實(shí)現(xiàn)代碼car_tcp_server_test.c (筆者在代碼提交了比較詳細(xì)的注釋)
3861tcp發(fā)送數(shù)據(jù)。
//3861發(fā)送數(shù)據(jù)
retval = send(connfd, request, strlen(request), 0);
if (retval <= 0) {
//3568側(cè)斷開(kāi)與3861的tcp連接后進(jìn)行的處理
printf("_______________________________________\r\n");
printf("send response failed, %ld!\r\n", retval);
printf("do_reconnect...\r\n");
sleep(DELAY_1S);
close(connfd);//關(guān)閉與客戶端的連接
sleep(DELAY_1S); // for debug
break;//跳出while循環(huán)
car_stop();//小車進(jìn)入停止?fàn)顟B(tài)
}else{
printf("The data responsed to the client is %s\r\n", request);
}
3861接收數(shù)據(jù)。
//3861接收數(shù)據(jù)
retval = recv(connfd, request, sizeof(request), 0);
if (retval < 0) {
//3568側(cè)斷開(kāi)與3861的tcp連接后進(jìn)行的處理
printf("_______________________________________\r\n");
printf("recv request failed, %ld!\r\n", retval);
printf("do_reconnect...\r\n");
sleep(DELAY_1S);
close(connfd);//關(guān)閉與客戶端的連接
sleep(DELAY_1S); // for debug
break;//跳出while循環(huán)
car_stop();//小車進(jìn)入停止?fàn)顟B(tài)
}else{
printf("_______________________________________\r\n");
printf("The data received from the client is %s \r\n", request);
}
當(dāng)3568與3861斷開(kāi)連接后,可以進(jìn)行重新連接。相關(guān)代碼:
while (1) {
connfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
if (connfd < 0) {
printf("accept failed, %d, %d\r\n", connfd, errno);
continue;
}else{
printf("_______________________________________\r\n");
printf("accept success, connfd = %d!\r\n", connfd);
printf("client addr info: host = %s, port = %hu\r\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
}
/***********************************socket收、發(fā)的部分************************************************/
// 后續(xù) 收、發(fā) 都在 表示連接的 socket 上進(jìn)行;
while (1) {
char request[128] = "";
.................
.................
/*************************************************************************************************/
}
}