1
0
forked from dyf/APP
Files
APP/store/BLETools.js
2025-07-11 16:11:40 +08:00

1299 lines
31 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 蓝牙设备结果集
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
}
//
if (uni.getSystemInfoSync().platform){
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);
}