You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

445 lines
11 KiB
JavaScript

/*!
* 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
}