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