OpenHarmony轻量设备应用BLE接口的使用(三):设备通信
本文讲述的是在OpenHarmony轻量设备(L0设备)上进行BLE相关应用程序的开发。应用所在设备作为Gatt Client与其他Gatt Server设备进行连接和通信。
本文重点讲述BLE设备间的通信,当二个设备BLE连接成功后,就可以开始获取server端的服务,通过获取到的特征值来进行设备间的通信。
BLE设备通信的接口
在进行设备通信之前,需要先创建GattClientDevice并成功建立二台设备间的连接。
// 以下接口都为GattClientDevice类的方法
// client端获取蓝牙低功耗设备的所有服务,即服务发现。
getServices(callback: AsyncCallback<number, Array<GattService>>): void
// client端读取蓝牙低功耗设备特定服务的特征值。
readCharacteristicValue(characteristic: BLECharacteristic, callback: AsyncCallback<number, BLECharacteristic>): void
// client端读取蓝牙低功耗设备特定的特征包含的描述符。
readDescriptorValue(descriptor: BLEDescriptor, callback: AsyncCallback<number, BLEDescriptor>): void
// client端向低功耗蓝牙设备写入特定的特征值。
writeCharacteristicValue(characteristic: BLECharacteristic, writeType: GattWriteType, callback: AsyncCallback<number>): void
// client端向低功耗蓝牙设备特定的描述符写入二进制数据
writeDescriptorValue(descriptor: BLEDescriptor, callback: AsyncCallback<number>): void
// 向服务端发送设置通知此特征值请求。
setCharacteristicChangeNotification(characteristic: BLECharacteristic, enable: boolean, callback: AsyncCallback<number>): void
// 向服务端发送设置通知此特征值请求,需要对端设备的回复。
setCharacteristicChangeIndication(characteristic: BLECharacteristic, enable: boolean, callback: AsyncCallback<number>): void
// 订阅蓝牙低功耗设备的特征值变化事件。需要先调用setCharacteristicChangeNotification接口或
// setCharacteristicChangeIndication接口才能接收server端的通知。
on(type: 'BLECharacteristicChange', callback: Callback<number, BLECharacteristic>): void
// 取消订阅蓝牙低功耗设备的特征值变化事件。
off(type: 'BLECharacteristicChange', callback?: Callback<number, BLECharacteristic>): void
详细的BLE设备通信的接口说明请参考 蓝牙BLE模块
BLE设备通信接口的使用
以下为BLE设备间通信的示例代码,其中省略了连接的操作,BLE的连接可以参考 OpenHarmony轻量设备应用BLE接口的使用(二):设备连接
当BLE设备连接成功后,调用onDeviceConnect函数开始进行后续的业务处理。这里主要完成BLE设备通信通道的配置,以及实现消息收发的接口。
点击按钮通过写特征值向对端设备发送消息,通过订阅notify特征值来接收对端设备发送的消息。
1、在订阅BLE设备连接状态变化事件callback函数中,当设备连接成功时,调用onDeviceConnect函数进行业务层的处理。
通过GattClientDevice的getServices接口获取gatt server端所有的服务、特征值。
2、在获取gatt server端所有服务的回调函数obtainCameraServices中,根据业务指定的UUID查找对应的服务和特征值,并进行设置为设备间的消息通信做好准备。在setAppCharacteristic函数中,记录write特征值用于本端设备消息的发送,订阅notify特征值变化事件用于对端设备消息的接收。
3、在订阅notify特征值变化事件的回调函数bleRecvNotify中,就可以对接收的特征值进行业务上的处理了。
4、当用户点击"发送消息"按钮,在事件响应函数onSendMsgClick中,通过调用GattClientDevice类的writeCharacteristicValue接口发送一段固定的消息给对端设备。
这里需要注意的是,write特征值的属性可能是write或者writeNoResponse,那么在调用writeCharacteristicValue接口时,对应的第二个参数writeType就要选择1(WRITE)或者2(WRITE_NO_RESPONSE),否则写特征值可能会失败。
5、当用户退出本页面时,取消订阅BLE设备notify特征值变化事件,然后断开BLE连接并关闭GATT client。
// connect.js
import ble from '@ohos.bluetooth.ble';
const APP_SERVICE_UUID = 'ff00'; // 128位UUID '0000FF00-0000-1000-8000-00805F9B34FB';
const APP_NOTIFY_UUID = 'ff07'; // 128位UUID '0000FFF7-0000-1000-8000-00805F9B34FB';
const APP_WRITE_UUID = 'ff08'; // 128位UUID '0000FFF8-0000-1000-8000-00805F9B34FB';
let bleData = {
gattClient: null,
bleConnected: false, // 当前BLE设备是否为连接状态
gattReady: false, // 当前GATT通道是否正常
// recvChar接收报文,保存notify特征值的参数;sendChar发送报文,保存write特征值的参数
recvChar: { valid: false, srvUuid: '', charaUuid: '', charaHandle: 0 },
// 写特征值的属性有write和writeNoResponse,如果为writeNoResponse则不支持写入后应答
sendChar: { valid: false, srvUuid: '', charaUuid: '', charaHandle: 0, isSupportResp: false },
};
// 打印接收到的特征值
function printCharacteristic(char)
{
console.debug('service UUID: ' + char.serviceUuid);
console.debug('characteristic UUID: ' + char.characteristicUuid);
console.debug('characteristic handle: ' + char.characteristicValueHandle);
console.debug('characteristic value:');
// char.characteristicValue中保存的就是对端设备发送的消息
let value = new Uint8Array(char.characteristicValue);
let line = '';
let hex = '';
for (let i = 0; i < value.length; i++) {
if ((i > 0) && (i % 16) === 0) {
console.debug(line);
line = '';
}
hex = value[i].toString(16);
if (hex.length === 1) {
hex = '0' + hex;
}
line += hex + ' ';
}
if (line != '') {
console.debug(line);
}
}
function manageRecvMsg(msgArray)
{
// 根据业务需求处理接收到的消息
}
// 处理对端BLE设备通过notify characteristic发送的消息
function bleRecvNotify(code, notifyChar)
{
if (code != 0) {
console.error(`bleRecvNotify code is ${code}`);
return;
}
printCharacteristic(notifyChar);
if (!bleData.recvChar.valid) {
console.debug('notify characteristic is invalid, ignore recv message!!');
return;
}
if ((notifyChar.characteristicUuid.toLowerCase() != APP_NOTIFY_UUID.toLowerCase()) ||
(notifyChar.serviceUuid.toLowerCase() != APP_SERVICE_UUID.toLowerCase()) ||
(notifyChar.characteristicValueHandle != bleData.recvChar.charaHandle)) {
console.warn('ignore recv notify, it not my notify characteristic');
console.warn(`characteristic changed: srv ${notifyChar.serviceUuid} chara ${notifyChar.characteristicUuid} handle ${notifyChar.characteristicValueHandle}`);
console.warn(`except notify: srv ${bleData.recvChar.srvUuid} chara ${bleData.recvChar.charaUuid} handle ${bleData.recvChar.charaHandle}`);
return;
}
let value = new Uint8Array(notifyChar.characteristicValue);
manageRecvMsg(value);
}
function setAppCharacteristic(charaArray)
{
for (let i = 0; i < charaArray.length; i++) {
// 根据UUID获取notify characteristic
if ((charaArray[i].characteristicUuid.toLowerCase() === APP_NOTIFY_UUID.toLowerCase()) &&
charaArray[i].properties.notify) {
bleData.recvChar.valid = true;
bleData.recvChar.srvUuid = charaArray[i].serviceUuid;
bleData.recvChar.charaUuid = charaArray[i].characteristicUuid;
bleData.recvChar.charaHandle = charaArray[i].characteristicValueHandle;
let char = {
serviceUuid: charaArray[i].serviceUuid,
characteristicUuid: charaArray[i].characteristicUuid,
characteristicValueHandle: charaArray[i].characteristicValueHandle,
};
// 设置服务端启用notify通知
bleData.gattClient.setCharacteristicChangeNotification(char, true, (err) => {
if (err) {
console.error(`set notify characteristic callback failed, err=${err}`);
return;
}
console.debug('set notify characteristic callback successfully');
// 订阅notify characteristic变化事件
bleData.gattClient.on('BLECharacteristicChange', bleRecvNotify);
});
} else if ((charaArray[i].characteristicUuid.toLowerCase() === APP_WRITE_UUID.toLowerCase()) &&
(charaArray[i].properties.write || charaArray[i].properties.writeNoResponse)) {
bleData.sendChar.valid = true;
bleData.sendChar.srvUuid = charaArray[i].serviceUuid;
bleData.sendChar.charaUuid = charaArray[i].characteristicUuid;
bleData.sendChar.charaHandle = charaArray[i].characteristicValueHandle;
// 正常情况下write和writeNoResponse是有一个为true,这里只判断一个write即可
bleData.sendChar.isSupportResp = charaArray[i].properties.write;
}
}
if (!bleData.recvChar.valid || !bleData.sendChar.valid) {
console.error('no write or notify characteristic!!');
return -1;
}
bleData.gattReady = true;
return 0;
}
function obtainCameraServices(code, gattServices)
{
if (code != 0) {
console.error(`gattclient getServices callback code is ${code}`);
return;
}
console.debug('gattclient services: ' + JSON.stringify(gattServices));
let chars;
// 根据服务UUID查找GATT服务
for (let i = 0; i < gattServices.length; i++) {
// UUID为字符串类型,比较UUID时注意统一转换大小写
if (gattServices[i].serviceUuid.toLowerCase() === APP_SERVICE_UUID.toLowerCase()) {
console.debug('find app service!!');
chars = gattServices[i].characteristics;
break;
}
}
if (chars == undefined) {
console.warn(`can not find app service by UUID ${APP_SERVICE_UUID}`);
return;
}
let ret = setAppCharacteristic(chars);
if (ret != 0) {
console.error(`set characteristic failed, ret=${ret}`);
}
}
function startGattClientService()
{
// 开始发现GATT服务、特征
bleData.gattClient.getServices(obtainCameraServices);
}
function writeCharacteristicCallback(code) {
if (code != 0) {
console.error(`writeCharacteristicCallback: write characteristic failed ${code} in callback`);
} else {
console.debug('writeCharacteristicCallback: write characteristic success');
}
}
function sendMsgWithResp(dataArray)
{
if (!bleData.gattReady) {
console.error('gatt client is not ready');
return -1;
}
let writeChar = {
serviceUuid: APP_SERVICE_UUID,
characteristicUuid: APP_WRITE_UUID,
characteristicValueHandle: bleData.sendChar.charaHandle,
characteristicValue: dataArray.buffer,
descriptors: []
};
// 根据写特征值的属性决定调用写特征值接口时,是否需要对端设备应答
if (bleData.sendChar.isSupportResp) {
bleData.gattClient.writeCharacteristicValue(writeChar, 1, writeCharacteristicCallback);
} else {
bleData.gattClient.writeCharacteristicValue(writeChar, 2, writeCharacteristicCallback);
}
return 0;
}
// BLE连接成功后,开始进行设备连接成功后的业务处理
function onDeviceConnect()
{
console.debug('onDeviceConnect calling');
startGattClientService();
}
// BLE连接断开,进行业务层的相应处理
function onDeviceDisconnect()
{
console.debug('onDeviceDisconnect calling');
bleData.gattReady = false;
}
export default {
data: {
remoteMac: '00:ac:13:fe:65:41', // 保存扫描阶段选择要连接的对端设备mac
},
// 点击按钮发送一段数据给对端设备
onSendMsgClick() {
// data为要发送给对端设备的数据
let data = new Uint8Array([0,1,2,3,4,5,6,7,8,9]);
let ret = sendMsgWithResp(data);
if (ret != 0) {
console.error(`send msg with response failed, ret=${ret}`);
}
},
onDestroy() {
if (bleData.gattClient == null) {
return;
}
bleData.gattClient.off('BLECharacteristicChange');
bleData.recvChar.valid = false;
bleData.sendChar.valid = false;
if (bleData.bleConnected) {
bleData.gattClient.disconnect();
}
bleData.gattClient.off('BLEConnectionStateChange');
bleData.gattClient.close();
bleData.gattClient = null;
},
}
更多推荐

所有评论(0)