|
|
/*!
|
|
|
* Create by Winford
|
|
|
*/
|
|
|
|
|
|
// var HEX = require('./HEX.min.js');
|
|
|
|
|
|
// 初始化蓝牙
|
|
|
const _openBluetoothAdapter = () => {
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
uni.closeBluetoothAdapter({
|
|
|
fail: reject,
|
|
|
success () {
|
|
|
// 初始化蓝牙
|
|
|
console.log('初始化蓝牙')
|
|
|
uni.openBluetoothAdapter({
|
|
|
success: resolve,
|
|
|
fail: reject
|
|
|
})
|
|
|
}
|
|
|
})
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// 蓝牙建立连接
|
|
|
const _createBLEConnection = (deviceId) => {
|
|
|
// 连接BLE
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
uni.createBLEConnection({
|
|
|
deviceId,
|
|
|
success: resolve,
|
|
|
fail: reject
|
|
|
})
|
|
|
});
|
|
|
}
|
|
|
|
|
|
const _getBLEDeviceServices = (deviceId) => {
|
|
|
// 获取服务
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
uni.getBLEDeviceServices({
|
|
|
deviceId,
|
|
|
success: (res) => {
|
|
|
for (let i = 0; i < res.services.length; i++) {
|
|
|
let service = res.services[i];
|
|
|
if (service.uuid.startsWith('0000FF00')) {
|
|
|
resolve(service);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
resolve();
|
|
|
//resolve(await _getBLEDeviceServices(deviceId))
|
|
|
},
|
|
|
fail: reject
|
|
|
// fail: function(e) {
|
|
|
// console.log(e);
|
|
|
// }
|
|
|
})
|
|
|
});
|
|
|
}
|
|
|
|
|
|
const _getBLEDeviceCharacteristics = (deviceId, serviceId) => {
|
|
|
// 获取读写特征值
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
uni.getBLEDeviceCharacteristics({
|
|
|
deviceId,
|
|
|
serviceId,
|
|
|
success: (res) => {
|
|
|
let characteristics = {};
|
|
|
for (let i = 0; i < res.characteristics.length; i++) {
|
|
|
let item = res.characteristics[i];
|
|
|
// console.log(item);
|
|
|
if (item.properties.notify) {
|
|
|
characteristics.notify = characteristics.notify || item;
|
|
|
}
|
|
|
|
|
|
if (item.properties.write) {
|
|
|
characteristics.write = characteristics.write || item;
|
|
|
}
|
|
|
|
|
|
if (item.uuid.startsWith('0000FF03')) {
|
|
|
characteristics.dataFC = characteristics.dataFC || item;
|
|
|
}
|
|
|
}
|
|
|
resolve(characteristics);
|
|
|
},
|
|
|
fail: reject
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// 写数据
|
|
|
const _wxWriteBLECharacteristicValue = ({
|
|
|
deviceId,
|
|
|
serviceId,
|
|
|
characteristicId,
|
|
|
value
|
|
|
}) => {
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
uni.writeBLECharacteristicValue({
|
|
|
deviceId,
|
|
|
serviceId,
|
|
|
characteristicId,
|
|
|
value,
|
|
|
writeType: 'writeNoResponse',
|
|
|
//writeType: 'write',
|
|
|
success: function() {
|
|
|
resolve(true);
|
|
|
},
|
|
|
fail: function(e) {
|
|
|
console.log(e);
|
|
|
if (e.code == 10007) {
|
|
|
// uniapp bug, retry.
|
|
|
resolve(false);
|
|
|
} else {
|
|
|
reject(e)
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
|
|
|
const sleep = (time) => new Promise((resolve, reject) => setTimeout(resolve, time));
|
|
|
|
|
|
// 写数据
|
|
|
const _writeBLECharacteristicValue = async (deviceId, serviceId, characteristicId, value, mtu = 20) => {
|
|
|
const total = value.byteLength;
|
|
|
console.log("================mtu=" + mtu, new Date())
|
|
|
let num = 0;
|
|
|
let count = 0;
|
|
|
while (count < total) {
|
|
|
const element = value.slice(count, count + mtu); // 取出MTU个数据
|
|
|
if (element.byteLength === 0) break; // 表示已经发送完毕
|
|
|
|
|
|
// #ifdef APP-PLUS
|
|
|
// await sleep(50);
|
|
|
let writeResult = await _wxWriteBLECharacteristicValue({
|
|
|
deviceId,
|
|
|
serviceId,
|
|
|
characteristicId,
|
|
|
value: element
|
|
|
});
|
|
|
if (writeResult) {
|
|
|
count = count + element.byteLength;
|
|
|
num++;
|
|
|
}
|
|
|
// #endif
|
|
|
|
|
|
// #ifdef MP-WEIXIN
|
|
|
// num % 100 == 0 && await sleep(100);
|
|
|
_wxWriteBLECharacteristicValue({
|
|
|
deviceId,
|
|
|
serviceId,
|
|
|
characteristicId,
|
|
|
value: element
|
|
|
});
|
|
|
count = count + element.byteLength;
|
|
|
num++;
|
|
|
// #endif
|
|
|
// console.log("================count=" + count)
|
|
|
// console.log("================num=" + num)
|
|
|
}
|
|
|
console.log("================num=" + num, new Date())
|
|
|
|
|
|
}
|
|
|
|
|
|
// 写数据
|
|
|
const _writeBLECharacteristicValueWithDataFC = async (device, value) => {
|
|
|
// const data = value.slice(); // copy一份,浅拷贝
|
|
|
const total = value.byteLength;
|
|
|
console.log('total--->', total);
|
|
|
let num = 0;
|
|
|
let count = 0;
|
|
|
const dataFC = device.dataFC;
|
|
|
while (count < total) {
|
|
|
if (dataFC.mtu > 0 && dataFC.credit > 0) {
|
|
|
const subData = value.slice(count, count + dataFC.mtu - 3); // 取出MTU-3个数据
|
|
|
if (subData.byteLength === 0) break; // 表示已经发送完毕
|
|
|
count = count + subData.byteLength;
|
|
|
|
|
|
dataFC.credit--;
|
|
|
// #ifdef APP-PLUS
|
|
|
while (!(await _wxWriteBLECharacteristicValue({
|
|
|
deviceId: device.deviceId,
|
|
|
serviceId: device.serviceId,
|
|
|
characteristicId: device.writeCharacteristicId,
|
|
|
value: subData,
|
|
|
}))) {
|
|
|
await sleep(100); // I don't know why, but uni-app is shit, okay
|
|
|
console.log('写入失败,正在重新写入。。。');
|
|
|
}
|
|
|
// #endif
|
|
|
// #ifndef APP-PLUS
|
|
|
_wxWriteBLECharacteristicValue({
|
|
|
deviceId: device.deviceId,
|
|
|
serviceId: device.serviceId,
|
|
|
characteristicId: device.writeCharacteristicId,
|
|
|
value: subData,
|
|
|
});
|
|
|
// #endif
|
|
|
num++;
|
|
|
} else {
|
|
|
// 令牌用尽,等待令牌
|
|
|
await sleep(0);
|
|
|
// console.log('令牌用尽,等待令牌');
|
|
|
}
|
|
|
}
|
|
|
console.log('num--->', num);
|
|
|
}
|
|
|
|
|
|
|
|
|
// 发现设备
|
|
|
const find = (onBluetoothDeviceFound) => {
|
|
|
_openBluetoothAdapter().then(function(res) {
|
|
|
// 添加监听
|
|
|
uni.onBluetoothDeviceFound(function(res) {
|
|
|
if (onBluetoothDeviceFound) {
|
|
|
onBluetoothDeviceFound(res);
|
|
|
}
|
|
|
});
|
|
|
uni.startBluetoothDevicesDiscovery({
|
|
|
interval: 1000
|
|
|
});
|
|
|
}).catch(function(res) {
|
|
|
uni.showToast({
|
|
|
title: '请打开蓝牙',
|
|
|
icon: 'none'
|
|
|
})
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// 停止发现设备
|
|
|
const stopFind = () => {
|
|
|
uni.stopBluetoothDevicesDiscovery();
|
|
|
}
|
|
|
|
|
|
// 连接
|
|
|
const connect = async ({
|
|
|
deviceId,
|
|
|
onBLEConnectionStateChange,
|
|
|
onBLECharacteristicValueChange,
|
|
|
onDataFCValueChange,
|
|
|
fail,
|
|
|
}) => {
|
|
|
let device = {
|
|
|
connected: false,
|
|
|
deviceId: deviceId,
|
|
|
serviceId: '',
|
|
|
notifyCharacteristicId: '',
|
|
|
writeCharacteristicId: '',
|
|
|
dataFCCharacteristicId: '',
|
|
|
onBLEConnectionStateChange,
|
|
|
onBLECharacteristicValueChange,
|
|
|
onDataFCValueChange,
|
|
|
dataFC: {
|
|
|
mtu: 0,
|
|
|
credit: 0,
|
|
|
},
|
|
|
};
|
|
|
|
|
|
// 请求蓝牙权限
|
|
|
await _openBluetoothAdapter().then(function(res) {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
// 添加监听
|
|
|
uni.onBLEConnectionStateChange(function(res) {
|
|
|
// 该方法回调中可以用于处理连接意外断开等异常情况
|
|
|
device.connected = res.connected;
|
|
|
if (device.onBLEConnectionStateChange) {
|
|
|
device.onBLEConnectionStateChange(res);
|
|
|
}
|
|
|
if (res.connected) {
|
|
|
resolve(res);
|
|
|
} else {
|
|
|
reject(res);
|
|
|
}
|
|
|
});
|
|
|
// 连接BLE
|
|
|
_createBLEConnection(deviceId);
|
|
|
});
|
|
|
|
|
|
// 添加监听
|
|
|
// uni.onBLEConnectionStateChange(function(res) {
|
|
|
// // 该方法回调中可以用于处理连接意外断开等异常情况
|
|
|
// device.connected = res.connected;
|
|
|
// if (device.onBLEConnectionStateChange) {
|
|
|
// device.onBLEConnectionStateChange(res);
|
|
|
// }
|
|
|
// });
|
|
|
// // 连接BLE
|
|
|
// return _createBLEConnection(deviceId);
|
|
|
})
|
|
|
.then(async function(res) {
|
|
|
// 获取服务
|
|
|
await sleep(1000);
|
|
|
let service = await _getBLEDeviceServices(deviceId);
|
|
|
if (!service) {
|
|
|
// 有时候获取不到,尝试重新获取
|
|
|
await sleep(2000);
|
|
|
service = await _getBLEDeviceServices(deviceId);
|
|
|
}
|
|
|
if (!service) {
|
|
|
Promise.reject('获取service失败');
|
|
|
} else {
|
|
|
return service;
|
|
|
}
|
|
|
})
|
|
|
.then(function(service) {
|
|
|
// 获取读写特征值
|
|
|
console.log('获取读写特征值')
|
|
|
device.serviceId = service.uuid;
|
|
|
return _getBLEDeviceCharacteristics(device.deviceId, device.serviceId);
|
|
|
})
|
|
|
.then(function(characteristics) {
|
|
|
// 读
|
|
|
device.notifyCharacteristicId = characteristics.notify ? characteristics.notify.uuid : '';
|
|
|
// 写
|
|
|
device.writeCharacteristicId = characteristics.write ? characteristics.write.uuid : '';
|
|
|
// 流控
|
|
|
device.dataFCCharacteristicId = characteristics.dataFC ? characteristics.dataFC.uuid : '';
|
|
|
})
|
|
|
.catch(function(err) {
|
|
|
console.log(err);
|
|
|
fail(err)
|
|
|
});
|
|
|
|
|
|
device.mtu = 20;
|
|
|
if (uni.getSystemInfoSync().platform === 'android') {
|
|
|
await new Promise(function(resolve, reject) {
|
|
|
uni.setBLEMTU({
|
|
|
deviceId: deviceId,
|
|
|
mtu: 512,
|
|
|
success(res) {
|
|
|
//device.mtu = res.mtu;
|
|
|
console.log('setBLEMTU success', res);
|
|
|
resolve(res);
|
|
|
},
|
|
|
fail(res) {
|
|
|
console.log('setBLEMTU fail', res);
|
|
|
reject(res);
|
|
|
},
|
|
|
});
|
|
|
});
|
|
|
// #ifdef APP-PLUS
|
|
|
await sleep(500); // I don't know why, but uni-app is shit, okay
|
|
|
// #endif
|
|
|
}
|
|
|
|
|
|
console.log('onBLECharacteristicValueChange')
|
|
|
// 监听
|
|
|
uni.onBLECharacteristicValueChange(function(res) {
|
|
|
// 读监听
|
|
|
if (res.characteristicId === device.notifyCharacteristicId) {
|
|
|
device.onBLECharacteristicValueChange && device.onBLECharacteristicValueChange(res);
|
|
|
}
|
|
|
// 流控监听
|
|
|
if (res.characteristicId === device.dataFCCharacteristicId) {
|
|
|
const data = new Uint8Array(res.value);
|
|
|
const flag = data[0];
|
|
|
if (flag === 1) {
|
|
|
device.dataFC.credit += data[1];
|
|
|
// console.log('===流控更新,credit', data[1]);
|
|
|
} else if (flag === 2) {
|
|
|
device.dataFC.mtu = (data[2] << 8) + data[1]; // 低位在前,高位在后
|
|
|
// console.log('===流控更新,mtu', device.dataFC.mtu);
|
|
|
}
|
|
|
device.onDataFCValueChange && device.onDataFCValueChange(res);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 读监听
|
|
|
if (device.notifyCharacteristicId) {
|
|
|
console.log('notifyBLECharacteristicValueChange: ' + device.notifyCharacteristicId)
|
|
|
await new Promise(function(resolve, reject) {
|
|
|
uni.notifyBLECharacteristicValueChange({
|
|
|
state: true, // 启用 notify 功能
|
|
|
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
|
|
|
deviceId: device.deviceId,
|
|
|
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
|
|
|
serviceId: device.serviceId,
|
|
|
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
|
|
|
characteristicId: device.notifyCharacteristicId,
|
|
|
success: resolve,
|
|
|
fail: reject
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
// 流控监听
|
|
|
if (device.dataFCCharacteristicId) {
|
|
|
// #ifdef APP-PLUS
|
|
|
await sleep(500); // I don't know why, but uni-app is shit, okay
|
|
|
// #endif
|
|
|
console.log('notifyBLECharacteristicValueChange: ' + device.dataFCCharacteristicId)
|
|
|
await new Promise(function(resolve, reject) {
|
|
|
uni.notifyBLECharacteristicValueChange({
|
|
|
state: true, // 启用 notify 功能
|
|
|
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
|
|
|
deviceId: device.deviceId,
|
|
|
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
|
|
|
serviceId: device.serviceId,
|
|
|
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
|
|
|
characteristicId: device.dataFCCharacteristicId,
|
|
|
success: resolve,
|
|
|
fail: reject
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// 写方法
|
|
|
// device.write = async (value, {
|
|
|
// mtu = 20
|
|
|
// }) => {
|
|
|
// // console.log(device.deviceId, 'write', HEX.ab2hex(value));
|
|
|
// if (device.writeCharacteristicId) {
|
|
|
// await _writeBLECharacteristicValue(device.deviceId, device.serviceId, device
|
|
|
// .writeCharacteristicId, value, mtu);
|
|
|
// }
|
|
|
// };
|
|
|
|
|
|
// 流控写方法(传输速度提升6倍)
|
|
|
device.write = async (value) => {
|
|
|
// console.log(device.deviceId, 'writeWithDataFC', HEX.ab2hex(value));
|
|
|
if (device.writeCharacteristicId && device.dataFCCharacteristicId) {
|
|
|
await _writeBLECharacteristicValueWithDataFC(device, value);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 断开连接
|
|
|
device.close = () => {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
uni.closeBLEConnection({
|
|
|
deviceId: device.deviceId,
|
|
|
success: resolve,
|
|
|
fail: reject
|
|
|
})
|
|
|
})
|
|
|
};
|
|
|
|
|
|
console.log(device);
|
|
|
return device;
|
|
|
}
|
|
|
|
|
|
|
|
|
export default {
|
|
|
find,
|
|
|
stopFind,
|
|
|
connect
|
|
|
} |