OpenHarmony开发者论坛
标题:
[OpenHarmony Socket通信]DAYU200遥控3861小车
[打印本页]
作者:
离北况归
时间:
2023-10-17 15:33
标题:
[OpenHarmony Socket通信]DAYU200遥控3861小车
[md]笔者最近学习了OpenHarmony Socket通信相关内容,制作了一个DAYU200(OpenHarmony标准系统)遥控3861小车(OpenHarmony轻量系统)的样例
- 样例开源地址:
https://gitee.com/hihope_iot/his ... 6%E6%A0%B7%E4%BE%8B
---
# 1. DAYU200和3861小车简单介绍
- 润开鸿OpenHarmony标准系统开发板 DAYU200
https://gitee.com/hihope_iot/docs/tree/master/HiHope_DAYU200
- 购买链接:
https://item.taobao.com/item.htm ... 101&abbucket=15

- 3861小车 ,购买链接:
https://item.taobao.com/item.htm ... 350&abbucket=15

# 2. DAYU200遥控HiSpark-Pegasus智能小车样例介绍
- 本样例通过TCP socket通信实现DAYU200开发板(OpenHarmony标准系统) 遥控 HiSpark-Pegasus智能小车(OpenHarmony轻量系统)前进、后退、左转、右转、停止等操作,实现了一个简单的OpenHarmony南北向开发互通案例。
- 样例开发分成3568端小车控制hap应用和3861端c代码
## 2.1 3568端小车控制hap应用代码讲解
> - Socket连接
https://gitee.com/openharmony/do ... ocket-connection.md
> - @ohos.net.socket (Socket连接)
https://gitee.com/openharmony/do ... ket.md#onmessage7-1
1.3568端小车控制hap应用基于 (需要特别注意开发环境!!!OpenHarmony应用开发更新速度很快)
- OpenHarmony3.2release
- DevEco Studio 3.1.0.500
- sdk 3.2.12.2
2.DAYU200通过tcp socket与3861建立通信,hap应用主要实现代码:
https://gitee.com/hihope_iot/his ... B7%E4%BE%8B/DAYU200
(3568)/car_socket_control/entry/src/main/ets/pages/Index.ets

3.hap应用TCP协议进行通信大致步骤
- import需要的socket模块。
- 创建一个TCPSocket连接,返回一个TCPSocket对象
- (可选)订阅TCPSocket相关的订阅事件
- 绑定IP地址和端口,端口可以指定或由系统随机分配
- 连接到指定的IP地址和端口
- 发送数据/接收数据
- Socket连接使用完毕后,关闭
4.添加获取wifi信息和网络的权限,在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"
}
}
]
```
5.建立tcp通信需要首先获取本地ip地址和端口号
```
//为了获取本地IP地址,需要导入@ohos.wifiManager
import wifiManager from '@ohos.wifiManager';
// 解析标准系统开发板(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);
}
// 获取标准系统开发板(3568)端本地IP地址
let localAddress = resolveIP(wifiManager.getIpInfo().ipAddress);
// 标准系统开发板(3568)本地ip地址和端口
let bindAddress = {
address: localAddress,
port: 5678, // 绑定端口,如1234
family: 1
};
...
...
//用一个test组件显示本地IP地址
Text(this.message0)
.fontSize(25)
.margin({top:0})
.fontWeight(FontWeight.Normal)
.backgroundColor(Color.White)
//用一个test组件显示本地socket端口号
Text(this.message1)
.fontSize(25)
.margin({top:0})
.fontWeight(FontWeight.Normal)
.backgroundColor(Color.White)
```
6.tcp初始化,订阅TCPSocket相关的订阅事件,绑定本地ip地址和端口
```
// 订阅TCPSocket相关的订阅事件
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');
});
```
7.绑定轻量系统(3861)的ip地址和端口
```
// 3861 IP地址和端口
let connectAddress = {
address: this.car_ipaddress,
port: num, // 端口号
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');
});
```
8.3568发送数据至3861
```
tcp.send({
data: '0'
}, err => {
if (err) {
console.log('[3861_car_control] send fail');
return;
}
console.log('[3861_car_control] send success');
})
```
9.3568接收3861发送的数据
```
//解析标准系统开发板(3568)接收到的 轻量系统(3861)发送的数据
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相关的订阅事件
tcp.on('message',value => {
this.message_recv = this.resolveArrayBuffer(value.message)
console.log(`TCP_data` + this.message_recv);
});
···
···
//用一个text显示标准系统开发板(3568)接收到轻量系统(3861)发出的数据
Text('接收到的3861发送的数据:' + this.message_recv)
.fontSize(25)
.margin({top:0})
.fontWeight(FontWeight.Normal)
.backgroundColor(Color.White)
```
10.关闭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');
```
11.完成代码实现请查看:
https://gitee.com/hihope_iot/his ... B7%E4%BE%8B/DAYU200
(3568)/car_socket_control/entry/src/main/ets/pages/Index.ets
12.如果要修改hap应用的名称,在car_socket_control\entry\src\main\resources\zh_CN\element\string.json文件中修改EntryAbility_label属性

13.如果要修改应用图标修改car_socket_control\entry\src\main\resources\base\media下icon.png(像素大小为114×114)

## 2.2 3861端小车代码讲解
代码地址:
https://gitee.com/hihope_iot/his ... k-Pegasus-smart-car
(3861)/car_tcp_control
| 文件名 | 说明 |
| ------------------ | ----------------------------------------------------------- |
| BUILD.gn | OpenHarmony构建脚本 |
| demo_entry_cmsis.c | OpenHarmony liteos-m程序入口 |
| net_common.h | 系统网络接口头文件 |
| net_demo.h | demo脚手架头文件 |
| net_params.h | 网络参数,包括WiFi热点信息、端口信息 |
| car_tcp_server_test.c | TCP socket控制小车实现代码 |
| wifi_connecter.c | OpenHarmony WiFi STA模式API的封装实现文件 |
| wifi_connecter.h | OpenHarmony WiFi STA模式API的封装头文件 |
本篇文章主要讲解主要实现代码[car_tcp_server_test.c](
https://gitee.com/hihope_iot/his ... k-Pegasus-smart-car
(3861)/car_tcp_control/car_tcp_server_test.c) (笔者在代码提交了比较详细的注释)
1.3861tcp发送数据
```
//3861发送数据
retval = send(connfd, request, strlen(request), 0);
if (retval <= 0) {
//3568侧断开与3861的tcp连接后进行的处理
printf("_______________________________________\r\n");
printf("send response failed, %ld!\r\n", retval);
printf("do_reconnect...\r\n");
sleep(DELAY_1S);
close(connfd);//关闭与客户端的连接
sleep(DELAY_1S); // for debug
break;//跳出while循环
car_stop();//小车进入停止状态
}else{
printf("The data responsed to the client is %s\r\n", request);
}
```
2.3861接收数据
```
//3861接收数据
retval = recv(connfd, request, sizeof(request), 0);
if (retval < 0) {
//3568侧断开与3861的tcp连接后进行的处理
printf("_______________________________________\r\n");
printf("recv request failed, %ld!\r\n", retval);
printf("do_reconnect...\r\n");
sleep(DELAY_1S);
close(connfd);//关闭与客户端的连接
sleep(DELAY_1S); // for debug
break;//跳出while循环
car_stop();//小车进入停止状态
}else{
printf("_______________________________________\r\n");
printf("The data received from the client is %s \r\n", request);
}
```
3、当3568与3861断开连接后,可以进行重新连接。相关代码:
```
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收、发的部分************************************************/
// 后续 收、发 都在 表示连接的 socket 上进行;
while (1) {
char request[128] = "";
.................
.................
/*************************************************************************************************/
}
}
```
[/md]
欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/)
Powered by Discuz! X3.5