// 蓝牙设备结果集 let devices = [] // 当前连接的蓝牙设备 let device = '' // 蓝牙设备id let deviceId = '' // 写了数据等待通知结果返回 let waitingForResult = false // 连接状态 let isConnecting = false let connected = false // 服务 uuid 和 特征值 uuid //正式 //测试 let service_uuid = "0000AE30-0000-1000-8000-00805F9B34FB" let write_characteristic = "0000AE03-0000-1000-8000-00805F9B34FB" let notify_characteristic = "0000AE03-0000-1000-8000-00805F9B34FB" let notify_characteristic_2 = "0000AE02-0000-1000-8000-00805F9B34FB"//获取设备电量和设备mac地址 // 命名规则 let rule1 = "" // Android let rule2 = "" // ios // 手动断开 var manualDisconnect = true // ################################################# // # // # Callback Definitions // # // ################################################# // 回调事件 let connectCallback = '' // 连接成功回调 let scanCallback = '' // 搜索到蓝牙设备回调 let disconnectCallback = '' // 设备断开连接回调 let writeCallback = '' // 写成功回调 // 自定义 业务相关 回调事件 let realtimeCallback = '' // 实时发送指令的回调 let batteryCallback = '' // 电量回调 let macCallback = '' // MAC地址回调 let lastBatteryLevel = 'N/A'; // 自定义 业务相关 标识 let realtimeType = '' // 实时发送指令的标识 // 重连相关 let reconnectTimes = 0 // 重连次数 let reconnectTimer // 重连计时器 // 因为有心跳自动计时器发送,不是全是用户手动的操作,用户的手动操作设定为一个操作后才能操作下一个,但有自动心跳发送的话,可能会出现发送心跳时, // 用户也正好操作了,那这时可能会出现,同时写两条指令情况,即没收到上一条的回复就发送了下一条指令,现用数组暂存 let cmdList = [] // 看这里!!! 现在没有心跳,只有用户的操作,确保用户的操作都是有回复的,并且在队列内,等待前一条执行完才执行下一条 // 当前蓝牙适配器是否打开的状态 let isOpen = false // 自动连接 let auto_connect = false // 准备去自动连接的 deviceId let auto_mac = [] let auto_mac_backup = [] // 备份 // 扫描到设备后,再等待个几秒计时器 let after_timer = '' // 自动连接回调 let autoConnectCallback = '' // 自动连接检测计时器 let autoConnectTimer = '' /** * 手机蓝牙是否开启了 */ let isBleOn = false let listener = function(res) { console.log(res); // 该方法回调中可以用于处理连接意外断开等异常情况 if (!res.connected) { device = '' cmdList = [] // 这里清空指令 isConnecting = false connected = false lastBatteryLevel = 'N/A'; if (disconnectCallback && typeof disconnectCallback == 'function') { disconnectCallback() } uni.getBluetoothAdapterState({ success: (res) => { if (!res.available) { isOpen = false auto_connect = true } reconnectDevice() }, fail: (err) => {} }) } } // 初始化拓展函数 String.prototype.padLeft = function(len, char) { let str = this; return new Array(len - str.length + 1).join(char || '') + str } String.prototype.transFloat = function() { let str = this; return str.indexOf('.') != -1 ? parseFloat(str).toFixed(1) : str } // //uni uni.onBluetoothAdapterStateChange(function(res) { if (!res.available) { isOpen = false isBleOn = false } else { isBleOn = true } }) // 获取 校验 function getCheckSum(cmd) { // console.log(cmd, '我是cmd'); let checkSum = getCrc16(cmd); // console.log(checkSum, '我是checkSum'); // console.log(splitByLen(checkSum, 2).reverse().map(e => parseInt(e, 16)), 'woshi '); return splitByLen(checkSum, 2).reverse().map(e => parseInt(e, 16)) } function getCrc16(cmd) { let crc = 0xffff; let len = cmd.length; for (let i = 0; i < len; i++) { crc = crc ^ (cmd[i] & 0xff) for (let j = 0; j < 8; j++) { if ((crc & 0x0001) == 1) { crc >>= 1 crc ^= 0xA001 } else { crc >>= 1 } } } // console.log(crc.toString(16).padLeft(4, '0'), '0121454878'); return crc.toString(16).padLeft(4, '0') } // ################################################# // # // # Module Setup & Configuration // # // ################################################# // 初始化蓝牙模块 export function initBlue() { uni.onBluetoothDeviceFound((res) => { res.devices.forEach(device => { // 过滤掉没有名字的设备 if (!device.name) { return; } const foundDevices = devices const idx = inArray(foundDevices, 'deviceId', device.deviceId) if (idx === -1) { devices.push(device) } else { devices[idx] = device } // Always notify the UI of any found device if (scanCallback && typeof scanCallback == "function") { scanCallback() // 查找结果集回调 } // console.log('auto_connect:', auto_connect); // console.log('isConnecting:', isConnecting); // console.log('deviceId:', deviceId); if (auto_connect && !isConnecting && device.deviceId == deviceId) { isConnecting = true createBLEConnection(deviceId, true); } else if (auto_connect) { // console.log('111111100000000000000000//////////////'); if (!after_timer) { after_timer = setTimeout(() => { let valid = [] auto_mac = JSON.parse(JSON.stringify(auto_mac_backup)) auto_mac.forEach(item => { valid.push(devices.some(e => e.deviceId == item)) }) valid.forEach((item, index) => { if (!item) { auto_mac.splice(index, 1) } }) console.log('valid mac ', auto_mac) if (auto_mac.length > 0) { uni.showLoading({ title: '自动连接中...', mask: true }) let mac = auto_mac[0] createBLEConnection(mac) auto_mac.splice(0, 1) } else {} clearTimeout(after_timer) after_timer = '' }, 1000 * 6) } } }) }) } // 设置连接成功回调 export function setCallback(e) { connectCallback = e } // 设置搜索到蓝牙设备回调 export function setScanCallback(e) { scanCallback = e } // 设置设备断开连接回调 export function setDisconnectCallback(e) { disconnectCallback = e } // 设置写成功回调 export function setWriteCallback(e) { writeCallback = e; } export function setBatteryCallback(e) { batteryCallback = e; if (lastBatteryLevel !== 'N/A' && typeof batteryCallback === 'function') { batteryCallback(lastBatteryLevel); } } export function setMacCallback(e) { macCallback = e; } export function getDeviceId(){ return deviceId } export function getConnectedDevice() { return device; } // 业务相关回调 function setRealtimeCallback(type, e) { realtimeType = type // console.log('业务相关回调', e); realtimeCallback = e // console.log('set realtimeType ', realtimeType) } // ################################################# // # // # Core BLE Command Functions // # // ################################################# // 转换16进制 /** * @param {number} num 几位 */ function conversion(str, num) { const result = []; for (let i = 0; i < str.length; i += num) { let temp = str.slice(i, i + num); // temp.toString(16); result.push(parseInt(temp, 16)); } return result; } // 切换灯的模式 export function sendLightType(type, e){ setRealtimeCallback(type, e) let str1 = `FA${e}000100FF`; let arr = []; arr = conversion(str1, 2); executeCmd(arr); } // 调节灯亮度 export function setLight(type, e, num) { setRealtimeCallback(type, e) // let str = `FA05${parseInt(num, 16)}00FF`; let str = `FA050001${num.toString(16).padLeft(2,'0')}FF`; let arr = conversion(str, 2); console.log('light数组', arr); executeCmd(arr); } /** * @description 设置单位、部门、名字... * @param { Array } arr */ export function sendImg(arr,e) { let dataArr = conversion(arr, 2); console.log(dataArr); executeCmd(dataArr); } // 如未空(未收到回复,收到回复会清掉第一个指令)进队列, 空直接执行 function executeCmd(cmd) { // if (cmdList.length == 0) { // writeBLECharacteristicValue(write_characteristic, cmd) // } // cmdList.push(cmd) writeBLECharacteristicValue(write_characteristic, cmd) } // 清掉第一个指令,然后检查队列是否为空,不为空继续发送 function continueExecute() { cmdList.splice(0, 1) if (cmdList.length != 0) { writeBLECharacteristicValue(write_characteristic, cmdList[0]) } } // ################################################# // # // # Core BLE Connection Logic // # // ################################################# // step 1 // 打开蓝牙功能 export function openBluetoothAdapter(search, callback) { const operation = () => { openBleAdapter((err) => { if (!err) { // On success (no error), start scanning for devices. startBluetoothDevicesDiscovery(); } // Always call the page's callback to notify it of the result. if (callback) { callback(err); } }); }; if (search) { // First close any existing adapter session, then perform the operation. uni.closeBluetoothAdapter({ complete: operation, }); } else { operation(); } } function openBleAdapter(callback) { uni.openBluetoothAdapter({ success: (res) => { isOpen = true; isBleOn = true; if (callback) callback(); // Success, no error object. }, fail: (err) => { // Log the full error to help diagnose release version issues console.error('openBluetoothAdapter failed with error:', JSON.stringify(err)); if (err.errCode === 10001) { uni.showModal({ content: '请打开手机蓝牙', showCancel: false, }); } else { // For other errors, show a detailed modal for debugging in the release version. uni.showModal({ title: '蓝牙启动失败', content: `错误: ${JSON.stringify(err)}`, showCancel: false }); } isOpen = false; isBleOn = false; // Propagate the error to the calling page if (callback) callback(err); }, }); } // step 2 //开始搜索蓝牙设备 function startBluetoothDevicesDiscovery() { console.log('开始搜索'); let option = { allowDuplicatesKey: false, success: (res) => { console.log('搜索成功,有设备', res); onBluetoothDeviceFound(); }, fail: (err) => { console.log('当前搜索蓝牙设备失败', err); if(err.errCode == 10008) { uni.showToast({ title: '扫描太过频繁,请稍后再试', icon: 'none' }); } // resetDevices(); // devices = [] // openBluetoothAdapter(true); } } if (auto_connect) { option.services = [ service_uuid ] } uni.startBluetoothDevicesDiscovery(option) } let hexString = '' // step 3 // 设备查找结果处理 function onBluetoothDeviceFound() { uni.onBluetoothDeviceFound((res) => { res.devices.forEach(device => { // 过滤掉没有名字的设备 if (!device.name) { return; } const foundDevices = devices const idx = inArray(foundDevices, 'deviceId', device.deviceId) if (idx === -1) { devices.push(device) } else { devices[idx] = device } // Always notify the UI of any found device if (scanCallback && typeof scanCallback == "function") { scanCallback() // 查找结果集回调 } // console.log('auto_connect:', auto_connect); // console.log('isConnecting:', isConnecting); // console.log('deviceId:', deviceId); if (auto_connect && !isConnecting && device.deviceId == deviceId) { isConnecting = true createBLEConnection(deviceId, true); } else if (auto_connect) { // console.log('111111100000000000000000//////////////'); if (!after_timer) { after_timer = setTimeout(() => { let valid = [] auto_mac = JSON.parse(JSON.stringify(auto_mac_backup)) auto_mac.forEach(item => { valid.push(devices.some(e => e.deviceId == item)) }) valid.forEach((item, index) => { if (!item) { auto_mac.splice(index, 1) } }) console.log('valid mac ', auto_mac) if (auto_mac.length > 0) { uni.showLoading({ title: '自动连接中...', mask: true }) let mac = auto_mac[0] createBLEConnection(mac) auto_mac.splice(0, 1) } else {} clearTimeout(after_timer) after_timer = '' }, 1000 * 6) } } }) }) } // connect step 1 // 连接蓝牙设备 export function createBLEConnection(id, advertisData, sameDevice, closeConnectLoading) { //直接连接设备 console.log(id, advertisData, sameDevice, '连接蓝牙设备'); closeBLEConnection(false, () => { // #ifdef MP-WEIXIN uni.offBLEConnectionStateChange(listener) // 先移除 // #endif //监听蓝牙连接状态 uni.onBLEConnectionStateChange(listener) uni.createBLEConnection({ deviceId: id, timeout: 5000, success: (res) => { console.log(res, '蓝牙连接状态'); auto_connect = false // 重置 auto_mac = [] // 重置 closeAutoConnect() // 关闭全局自动连接 if (autoConnectCallback && typeof autoConnectCallback == 'function') { autoConnectCallback() } stopBluetoothDevicesDiscovery() // 停止扫描蓝牙设备 device = devices.find(item => item.deviceId == id) isConnecting = false connected = true manualDisconnect = false deviceId = id console.log('连接的设备ID', deviceId); getBLEDeviceServices(deviceId) // 获取服务,初始化特征值 uni.setStorageSync('deviceId', deviceId); // uni.setStorageSync('deviceName', name); }, fail: (err) => { console.log('设备连接失败', err); isConnecting = false; if (auto_connect) { if (auto_mac.length > 0) { let mac = auto_mac[0] createBLEConnection(mac) auto_mac.splice(0, 1) } else { if (autoConnectCallback && typeof autoConnectCallback == 'function') { autoConnectCallback() } } } else { console.log('设备连接失败'); uni.hideLoading() uni.showToast({ title: '设备连接失败!' + err.errMsg, icon: 'none', duration: 2000, }) } if (typeof closeConnectLoading === 'function') { closeConnectLoading(); } }, complete: () => { uni.hideLoading(); } }) }, sameDevice) // 关闭当前蓝牙连接 console.log('结束连接方法'); } // connect step 2 // 获取服务 function getBLEDeviceServices(deviceId) { console.log('我获取服务成功接收到的Id是', deviceId); //#ifdef APP-PLUS setTimeout(() => { uni.getBLEDeviceServices({ deviceId, success: (res) => { // console.log(res, '获取蓝牙设备所有服务2'); // console.log('测试1',res.services[i].uuid, service_uuid.toUpperCase()) for (let i = 0; i < res.services.length; i++) { // console.log('测试2',res.services[i].uuid, service_uuid.toUpperCase()) // 消息服务 if (res.services[i].uuid == service_uuid || res.services[i].uuid == service_uuid.toUpperCase()) { getBLEDeviceCharacteristics(deviceId, res.services[i].uuid) } } }, fail: (err) => { console.log(err, '获取服务失败') } }) }, 6000) //#endif //#ifdef MP-WEIXIN uni.getBLEDeviceServices({ deviceId, success: (res) => { console.log(res, '获取蓝牙设备所有服务'); for (let i = 0; i < res.services.length; i++) { console.log(res.services[i].uuid, service_uuid) // 消息服务 if (res.services[i].uuid == service_uuid || res.services[i].uuid == service_uuid.toUpperCase()) { getBLEDeviceCharacteristics(deviceId, res.services[i].uuid) } } }, fail: (err) => { console.log(err, '获取服务失败') } }) //#endif } // connect step 3 // 初始化特征值 function getBLEDeviceCharacteristics(deviceId, serviceId) { uni.getBLEDeviceCharacteristics({ deviceId, serviceId, success: (res) => { console.log(res,'通知特征值') for (let i = 0; i < res.characteristics.length; i++) { let item = res.characteristics[i] const itemUUID = item.uuid.toUpperCase(); const primaryNotifyUUID = notify_characteristic.toUpperCase(); const secondaryNotifyUUID = notify_characteristic_2.toUpperCase(); // Check if the characteristic is one of the notification sources if (itemUUID === primaryNotifyUUID || itemUUID === secondaryNotifyUUID) { if (item.properties.notify || item.properties.indicate) { uni.notifyBLECharacteristicValueChange({ deviceId, serviceId, characteristicId: item.uuid, state: true, success: () => { console.log(`已成功监听特征值: ${item.uuid}`); }, fail: (err) => { console.error(`监听特征值 ${item.uuid} 失败:`, err); } }); } } if (itemUUID === write_characteristic.toUpperCase()) { if (item.properties.write) {} } } }, fail: (res) => { console.error('getBLEDeviceCharacteristics', res) } }) // notify的回调函数,操作之前先监听,保证第一时间获取数据 // 针对不同特征值的回调处理 uni.onBLECharacteristicValueChange((res) => { let result = ab2hex(res.value) // 打印来自 notify_characteristic_2 的数据 if (res.characteristicId.toUpperCase() === notify_characteristic_2.toUpperCase()) { console.log(`接收到来自 [notify_characteristic_2] 的原始Hex数据: ${result}`); if (result.startsWith('fc') && result.endsWith('ff')) { const macHex = result.substring(2, result.length - 2); const macAddress = macHex.match(/.{1,2}/g).reverse().join(':').toUpperCase(); console.log(`[notify_characteristic_2] 解析后的MAC地址: ${macAddress}`); if (macCallback && typeof macCallback === 'function') { macCallback(macAddress); } return; } else if (result.startsWith('fb') && result.endsWith('ff')) { const dataHex = result.substring(2, result.length - 2); const batteryHex = dataHex.substring(0, 2); const batteryLevel = parseInt(batteryHex, 16); lastBatteryLevel = batteryLevel; console.log(`[notify_characteristic_2] 解析后的电量: ${batteryLevel}%`); if (batteryCallback && typeof batteryCallback === 'function') { batteryCallback(batteryLevel); } return; } } // This is the original logic for the primary notification characteristic. // It is now generalized to handle responses from either characteristic if not handled above. console.log('通知特征值',result) let length = result.length let len = parseInt(splitByLen(result.substr(2, 4), 2).reverse().join(''), 16) // console.log(len) let checkArrHex = splitByLen(result.substr(0, length - 4), 2) // console.log(checkArrHex) let checkArr = checkArrHex.map(e => parseInt(e, 16)) // console.log(checkArr) let sendCheckSum = result.substr(-4) let checkSum = getCheckSum(checkArr).map(e => e.toString(16).padLeft(2, '0')).join('') // console.log(checkSum) // console.log(sendCheckSum) // console.log(sendCheckSum === checkSum) if (sendCheckSum === checkSum) { let type = parseInt(result.substr(8, 2), 16) // console.log(type) // console.log(realtimeType) if (realtimeType == type && realtimeCallback && typeof realtimeCallback == 'function') { realtimeType = undefined let tempCallback = realtimeCallback realtimeCallback = undefined tempCallback(result) // console.log('realtimeType ', realtimeType) } continueExecute() } else { uni.hideLoading() // 校验值不对的情况 continueExecute() } }) connectCallback(deviceId) } // 获取当前是否连接上 export function getConnected() { return connected } // 设置自动连接的 mac 地址 function setAutoMac(arr) { auto_mac_backup = arr auto_connect = true openBluetoothAdapter() startAutoConnect() } /** * 开启全局自动连接 */ function startAutoConnect() { auto_connect = true autoConnectTimer = setInterval(() => { if (auto_connect) { if (!connected) { console.log('自动连接扫描 ', isOpen) if (isOpen) { } else { if (isBleOn) { openBluetoothAdapter() } } } } }, 1000 * 3) } /** * 关闭全局自动连接 */ function closeAutoConnect() { auto_connect = false clearInterval(autoConnectTimer) } /** * 取消全局自动连接 */ function cancelAutoConnect() { auto_connect = false auto_mac = [] autoConnectCallback = '' clearInterval(autoConnectTimer) closeBluetoothAdapter() } // 获取暂存的扫描到的设备数组 function getDevices() { if (device) { devices.push(device) } return devices } // 重置扫描到的设备数组 export function resetDevices() { devices = []; } // write msg 发送指令 // msg 为 hexstring 形式 function writeBLECharacteristicValue(characteristicId, msg) { if (connected == false) { reconnectDevice(); return; } let buffer = hexArr2ab(msg); waitingForResult = true; //等待通知返回结果。 let len = buffer.byteLength let arr = [] if (len > 20) { for (let i = 0, j = 0; i < len; i += 20) { let start = j * 20; let end = start + 20 > len ? len - start : 20 let data = Uint8Array.from(new Uint8Array(buffer, start, end)) // console.log(data) // let tempBuffer = data.buffer.slice(start, end) // console.log(tempBuffer) arr.push(data.buffer) j++ } stopFlag = false writeData(characteristicId, arr) } else { stopFlag = false writeData(characteristicId, [buffer]) } } let stopFlag = false let timeoutTimer = '' let timeoutCallback = '' function writeData(characteristicId, buffer) { console.log('准备发送'); clearTimeout(timeoutTimer) // console.log(buffer) if (stopFlag) { return } uni.writeBLECharacteristicValue({ deviceId, serviceId: service_uuid, characteristicId, value: buffer[0], success: (res) => { if (realtimeCallback) { let str = `写入 ${ab2hex(buffer[0])}` console.log(str) } // 写入一次进度条就前进 if (writeCallback && typeof writeCallback == 'function') { let str = `写入 ${ab2hex(buffer[0])}` console.log('分包发送了一次'); writeCallback(str); } if (!stopFlag && buffer.length > 1) { writeData(characteristicId, buffer.slice(1)) } else { let time = new Date().getTime() // console.log('time ', time) timeoutTimer = setTimeout(() => { if (timeoutCallback && typeof timeoutCallback == 'function') { timeoutCallback() } }, 2000) } }, fail: (res) => { cmdList = [] // 这里清空指令, 放弃队列中所有指令,为后续新指令的到来做准备 waitingForResult = false; console.error('write failed ', res); uni.showToast({ title: '请重新连接' }); uni.navigateTo({ url: '/pages/search/index' }) }, }) } // 550800019301112f // 550800019105118c //重连设备 function reconnectDevice() { // #ifdef MP-WEIXIN uni.offBLEConnectionStateChange(listener) // 先移除 // #endif reconnectTimes = 0; clearInterval(reconnectTimer) if (manualDisconnect) // 主动断开的不做处理 return uni.hideLoading() uni.showLoading({ mask: true, title: '重连中...' }) reconnect() reconnectTimer = setInterval( () => { console.log('重连?>>>>>>>'); reconnect() }, 3000); // 7000 } function reconnect() { if (connected) //已连接 { reconnectTimes = 0; clearInterval(reconnectTimer) return } if (reconnectTimes >= 2) //超时 // 9 { reconnectTimes = 0; clearInterval(reconnectTimer) uni.hideLoading() showModal() return } else { reconnectTimes += 1 if (isOpen) { if (!auto_connect) { connectNow() } } else { if (isBleOn) { openBluetoothAdapter(true) } } } } function connectNow() { if (!isConnecting) { isConnecting = true // #ifdef MP-WEIXIN uni.offBLEConnectionStateChange(listener) // 先移除 // #endif //监听蓝牙连接状态 uni.onBLEConnectionStateChange(listener) uni.createBLEConnection({ deviceId: deviceId, timeout: 3000, success: (res) => { uni.hideLoading() device = devices.find(item => item.deviceId == deviceId) isConnecting = false connected = true reconnectTimes = 0; clearInterval(reconnectTimer) //结束循环 getBLEDeviceServices(deviceId) }, fail: (res) => { isConnecting = false } }) } } // 获取当前状态 // 用于下拉刷新 function getBluetoothAdapterState() { uni.getBluetoothAdapterState({ success: (res) => { if (!res.available) { openBluetoothAdapter() } else { uni.stopBluetoothDevicesDiscovery({ complete: () => { startBluetoothDevicesDiscovery(); } }) } }, fail: (err) => {} }) } // 断开蓝牙设备连接 function closeBLEConnection(close, callback, sameDevice) { try { // console.log('123', close) if (close) { manualDisconnect = true; } console.log('123', deviceId) if (deviceId) { uni.closeBLEConnection({ deviceId: deviceId, success: (res) => { handleCloseBle(close, callback, sameDevice) }, fail: (err) => { if (err.errCode == 10006) { handleCloseBle(close, callback, sameDevice) } } }) } else { // console.log('123', typeof callback == 'function') if (callback && typeof callback == 'function') { callback() } } } catch (error) { uni.hideLoading() console.log(error) } } function handleCloseBle(close, callback, sameDevice) { if (!sameDevice) { deviceId = '' } connected = false lastBatteryLevel = 'N/A'; // 手动断开连接处理 if (close) { closeBluetoothAdapter(true) } if (callback && typeof callback == 'function') { callback() } } // 关闭蓝牙扫描 function stopBluetoothDevicesDiscovery() { isConnecting = false; uni.stopBluetoothDevicesDiscovery({ success: (res) => { } }) } export const stopBlue = stopBluetoothDevicesDiscovery; // 关闭蓝牙适配器 function closeBluetoothAdapter(doCallback) { uni.stopBluetoothDevicesDiscovery({ success: (result) => { uni.closeBluetoothAdapter({ success: (res) => { // 手动断开连接处理 } }) } }) } // 蓝牙断开 弹窗提示 (重连不可连上) function showModal() { deviceId = '' devices = [] // auto_connect = true // 开启全局自动连接 openBluetoothAdapter(true) // startAutoConnect() uni.showModal({ content: '设备重连失败,已断开连接!', showCancel: false, success() { uni.reLaunch({ url: '/pages/search/index' }); } }) } // ################################################# // # // # Utility Functions // # // ################################################# /////////////////// 工具函数 ///////////////////// function splitByLen(str, len) { let length = str.length let newArr = [] for (let i = 0; i < length; i += len) { newArr.push(str.substr(i, len)) } return newArr } function arrayBufferToString(arr) { if (typeof arr === 'string') { return arr; } var dataview = new DataView(arr); var ints = new Uint8Array(arr.byteLength); for (var i = 0; i < ints.length; i++) { ints[i] = dataview.getUint8(i); } arr = ints; var str = '', _arr = arr; for (var i = 0; i < _arr.length; i++) { var one = _arr[i].toString(2), v = one.match(/^1+?(?=0)/); if (v && one.length == 8) { var bytesLength = v[0].length; var store = _arr[i].toString(2).slice(7 - bytesLength); for (var st = 1; st < bytesLength; st++) { store += _arr[st + i].toString(2).slice(2); } str += String.fromCharCode(parseInt(store, 2)); i += bytesLength - 1; } else { str += String.fromCharCode(_arr[i]); } } return str; } function inArray(arr, key, val) { for (let i = 0; i < arr.length; i++) { if (arr[i][key] === val) { return i; } } return -1; } // 字符串转为ArrayBuffer对象,参数为字符串,注意这里的字符串为非hex字符串 function stringToArrayBuffer(str) { var bytes = new Array(); var len, c; len = str.length; for (var i = 0; i < len; i++) { c = str.charCodeAt(i); if (c >= 0x010000 && c <= 0x10FFFF) { bytes.push(((c >> 18) & 0x07) | 0xF0); bytes.push(((c >> 12) & 0x3F) | 0x80); bytes.push(((c >> 6) & 0x3F) | 0x80); bytes.push((c & 0x3F) | 0x80); } else if (c >= 0x000800 && c <= 0x00FFFF) { bytes.push(((c >> 12) & 0x0F) | 0xE0); bytes.push(((c >> 6) & 0x3F) | 0x80); bytes.push((c & 0x3F) | 0x80); } else if (c >= 0x000080 && c <= 0x0007FF) { bytes.push(((c >> 6) & 0x1F) | 0xC0); bytes.push((c & 0x3F) | 0x80); } else { bytes.push(c & 0xFF); } } var array = new Int8Array(bytes.length); for (var i in bytes) { array[i] = bytes[i]; } return array.buffer; } function hexArr2ab(hexArr) { let buffer = new ArrayBuffer(hexArr.length) let dataView = new DataView(buffer) for (var i = 0; i < hexArr.length; i++) { dataView.setUint8(i, hexArr[i]) } return buffer; } function hexStr2ab(hexStr) { let buffer = new ArrayBuffer(hexStr.length / 2) let dataView = new DataView(buffer) for (var i = 0, j = 0; i < hexStr.length; i += 2, j++) { let _str = "0x" + hexStr.substr(i, 2) dataView.setUint8(j, parseInt(_str, 16)) } return buffer; } // ArrayBuffer转16进度字符串示例 function ab2hex(buffer) { var hexArr = Array.prototype.map.call( new Uint8Array(buffer), function(bit) { return ('00' + bit.toString(16)).slice(-2) } ) return hexArr.join(''); } function hexStr2HexArr(hexStr) { var a = []; for (var i = 0; i < hexStr.length; i += 2) { let _str = "0x" + hexStr.substr(i, 2) a.push(parseInt(_str, 16)); } return a; } function hexArr2HexStr(hexArr) { let arr = [] hexArr.forEach(item => { arr.push(item.toString(16).padLeft(2, '0')) }) return arr.join('') } // 10进制转16进制补0 function dec2hex(dec, len) { //10进制转16进制补0 var hex = ""; while (dec) { var last = dec & 15; hex = String.fromCharCode(((last > 9) ? 55 : 48) + last) + hex; dec >>= 4; } if (len) { while (hex.length < len) hex = '0' + hex; } return hex; } // 10进制转16进制补0 function string_hex2int(hex) { //16进制转10进制 var len = hex.length, a = new Array(len), code; for (var i = 0; i < len; i++) { code = hex.charCodeAt(i); if (48 <= code && code < 58) { code -= 48; } else { code = (code & 0xdf) - 65 + 10; } a[i] = code; } return a.reduce(function(acc, c) { acc = 16 * acc + c; return acc; }, 0); } //校验和 function checkSumResult(hexStr, len) //返回校验和的hexstring { let abData = hexStr2HexArr(hexStr) var ucI = 0, ucJ = 0; var uiCrcValue = 0xffff; for (ucI = 0; ucI < len; ucI++) { uiCrcValue = (uiCrcValue ^ (abData[ucI] & 0xff)); for (ucJ = 0; ucJ < 8; ucJ++) { if ((uiCrcValue & 0x0001) == 1) { uiCrcValue = ((uiCrcValue >> 1) ^ 0x8408); } else { uiCrcValue = (uiCrcValue >> 1); } } } //校验和为uiCrcValue 的高低位互换 var hexStr = dec2hex(uiCrcValue, 4); var resultStr = hexStr.substr(2, 2) + hexStr.substr(0, 2) return resultStr; } function Uint8ToStr(arr) { for (var i = 0, str = ''; i < arr.length; i++) str += String.fromCharCode(arr[i]); return str; } function strToUint8(str) { for (var i = 0, arr = []; i < str.length; i++) { arr.push(str.charCodeAt(i)); } return new Uint8Array(arr); } export function getDiscoveredDevices() { return [...devices]; } // 手动断开蓝牙 export function manualDisconnectDevice() { closeBLEConnection(true); }