读写特征值之前,用户需要先选择对应的特征值ID,用户选择了特征值ID以后,通过变量记录下来,方便下次使用。
currWriteChar: { // 当前选择的写入特征值
flag: false, // 表示是否可用
serId: "", // 服务ID
charId: "" // 特征值ID
},
currReadChar: { // 当前选择的读/通知特征值
flag: false, // 表示是否可用
serId: "", // 服务ID
charId: "" // 特征值ID
},
为了方便查找到用户选择的是哪个服务下的哪个特征值ID,在特征值view的ID设置为当前对应的服务列表的index和特征值index的集合。
<view class="dialogContentCharsListItemView" id="{{sersIndex}},{{charsIndex}}" bindtap="charsListItemClick">
用户选择以后,直接通过解析出来的index去数组里面索引出来就好了。
charsListItemClick: function(e) {
debug.Debug(BLECTR_MODUAL_NAME, debug.DEBUG_DEBUG, "点击特征值", e.currentTarget.id);
// 解析出当前点击的特征值item在数组中的位置,逗号前面的是service对应的index,逗号后面的是chars中的index位置
var index = e.currentTarget.id.split(',');
var serIndex = parseInt(index[0], 10);
var charIndex = parseInt(index[1], 10);
debug.Debug(BLECTR_MODUAL_NAME, debug.DEBUG_DEBUG, "点击的index", serIndex, charIndex);
if (serIndex < this.data.devInfo.length && charIndex < this.data.devInfo[serIndex].serviceChars.length) {
....
根据index从devInfo中获取对应的服务ID和特征值ID并记录在currWriteChar或currReadChar数据中
....
}
},
选择好了特征值ID后,就可以开始对特征值进行读写了。
写入操作:
sendDataListButtonClick: function(e) {
....
设备是否连接、是否输入了发送数据的判断处理
....
var index = parseInt(e.currentTarget.id, 10);
if (index < this.data.sendDataList.length) {
if (this.data.sendDataList[index].inputText.length != 0){
.....
根据选择,按16进制或者字符方式解析出输入框的内容,存储到writeValue变量中
.....
ble.writeDevCharValue(
this.userData.currDevId,
this.userData.currWriteChar.serId,
this.userData.currWriteChar.charId,
writeValue,
(res, errCode)=> {
if (res) {
debug.Debug(BLECTR_MODUAL_NAME, debug.DEBUG_DEBUG, "数据发送成功", errCode);
wx.showToast({
title: '发送成功',
icon: 'none',
duration: 1500
});
} else {
debug.Debug(BLECTR_MODUAL_NAME, debug.DEBUG_DEBUG, "数据发送失败", errCode);
wx.showToast({
title: '发送失败',
icon: 'none',
duration: 1500
});
}
}
);
} else {
wx.showToast({
title: '请输入发送内容',
icon: 'none',
duration: 1500
})
}
}
},
这里分为16进制发送和字符发送,这两种发送方式只是在解析输入数据的地方有差别。
还需要注意,根据BLE协议,一次只能发送最大20个字节的数据,当数据量大于20个字节后,就需要进行分包处理,所以在ble模块中新增的writeDevCharValue对需要发送的数据进行了自动的分包处理,防止在某些手机上发送失败。
ble模块的writeDevCharValue接口:
/**
* 写特征值
* @param {string} devId
* @param {string} serId
* @param {string} charId
* @param {ArrayBuffer} writeValue
* @param {function} cb 参数1成功标志:true为成功, 参数2错误码
*/
function writeDevCharValue(devId, serId, charId, writeValue, cb) {
.....
各种异常判断:蓝牙是否初始化,设备是否连接,writeValue长度是否为零等等
.....
debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG,"发送数据", devId, serId, charId);
// 如果数据长度超过20,需要做分包发送处理才行
let sendArrayBuffer = new ArrayBuffer(20);
let uint8ArrayBuffer = new Uint8Array(sendArrayBuffer);
let srcArrayBuffer = new Uint8Array(writeValue);
let currSendNum = 0;
do {
let revSendNum = srcArrayBuffer.length-currSendNum; // 剩余的发送字节数
let currSendNumTmp = 0; // 本次需要发送的字节数
if (revSendNum >= 20) {
currSendNumTmp = 20;
} else {
currSendNumTmp = revSendNum;
}
for (let i=0; i<currSendNumTmp; i++) {
uint8ArrayBuffer[i] = srcArrayBuffer[currSendNum];
currSendNum++;
}
wx.writeBLECharacteristicValue({
// 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
deviceId: devId,
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
serviceId: serId,
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
characteristicId: charId,
// 这里的value是ArrayBuffer类型
value: sendArrayBuffer,
success: (res) => {
// 这里要做到所有数据发送成功才返回成功回调
if (currSendNum >= srcArrayBuffer.length) {
if (typeof cb == "function") {
cb(true, 0);
}
}
},
fail: (res) => {
if (typeof cb == "function") {
cb(false, res.errCode);
}
debug.Debug(BLE_MODULE_NAME, debug.DEBUG_DEBUG, "writeBLECharacteristicValue 失败", res.errCode, res.errMsg);
return;
}
});
} while(currSendNum < srcArrayBuffer.length);
}
BLE数据的读取,并不是直接获取的,而是通过wx.onBLECharacteristicValueChange注册的回调函数返回的,设备通过Notify发送给手机的信息也是通过该回调返回的。
所以我们在blectr.js页面加载的时候就开启该回调,并在界面释放的时候关闭该回调
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
.....
其他操作
.....
// 设置特征值回调
ble.onDevCharValueChange((res) => {
// res.value是一个ArrayBuffer
var buffer = new Uint8Array(res.value);
var currText = "";
.....
根据用户选择,以16进制显示,还是以字符显示的处理
.....
// 最长接收显示指定个字符,再长最先接收到在的字符就会被删除
var subText = "";
if (this.data.recieveText.length + currText.length > BLECTR_RECIEVE_TEXT_MAX_LEN) {
subText = this.data.recieveText.slice(this.data.recieveText.length + currText.length - BLECTR_RECIEVE_TEXT_MAX_LEN, this.data.recieveText.length);
this.data.recieveText = subText + currText;
} else {
this.data.recieveText += currText;
}
this.setData({['recieveText']: this.data.recieveText});
});
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
.....
其他操作
.....
// 关闭特征值监听
ble.offDevCharValueChange(()=> {
debug.Debug(BLECTR_MODUAL_NAME, debug.DEBUG_DEBUG, "关闭特征值监听");
});
},
当用户点击读取按钮的时候,调用一次读取方法就行了
// 读一次对应的特征值ID
recieveReadButtonClick: function(e) {
let status = ble.getDevConStaus(this.userData.currDevId);
if (status != ble.BLE_CON_SUCCESS) {
wx.showToast({
title: '设备未连接',
icon: 'none',
duration: 1500
});
return;
}
if (this.userData.currReadChar.flag) {
var devID = this.userData.currDevId;
var serID = this.userData.currReadChar.serId;
var charID = this.userData.currReadChar.charId;
debug.Debug(BLECTR_MODUAL_NAME, debug.DEBUG_DEBUG, "读取特征值", devID, serID, charID);
ble.readDevCharValue(
devID,
serID,
charID,
(res, errCode)=> {
if (res) {
debug.Debug(BLECTR_MODUAL_NAME, debug.DEBUG_DEBUG, "读取特征值成功", errCode);
} else {
debug.Debug(BLECTR_MODUAL_NAME, debug.DEBUG_DEBUG, "读取特征值失败", errCode);
}
}
);
} else {
wx.showToast({
title: '请先选择要读取的ID',
icon: 'none',
duration: 1500
});
}
},
最终的实际效果演示视频:
iBLETool读写特征值演示视频-小程序文档类资源-CSDN下载iBLETool读写特征值演示视频更多下载资源、学习资料请访问CSDN下载频道.https://download.csdn.net/download/Losthome/82439068
|