1
0
forked from dyf/APP
Files
APP/store/BLETools.js

1299 lines
31 KiB
JavaScript
Raw Normal View History

2025-07-05 14:49:26 +08:00
// 蓝牙设备结果集
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"
2025-07-11 16:11:40 +08:00
let write_characteristic = "0000AE03-0000-1000-8000-00805F9B34FB"
2025-07-05 14:49:26 +08:00
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
}
2025-07-11 16:11:40 +08:00
//
if (uni.getSystemInfoSync().platform){
uni.onBluetoothAdapterStateChange(function(res) {
if (!res.available) {
isOpen = false
isBleOn = false
} else {
isBleOn = true
}
})
}
2025-07-05 14:49:26 +08:00
// 获取 校验
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);
}