SEC_Warehouse/utils/ble/core/packet.js

85 lines
2.4 KiB
JavaScript
Raw Permalink 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.

import {splitUint8Array, toUint8Array} from '../utils/bytes'
import {utf8ToBytes} from '../utils/hex'
/**
* 按协议将 payload 拆成 A7 分包:
* 第 1 字节固定包头 0xA7第 2 字节高4位为总包数、低4位为包序号。
*/
export function buildA7Packets(payload, packetConfig = {}) {
const {
head = 0xA7,
chunkSize = 18,
maxChunk = 15
} = packetConfig
const bytes = typeof payload === 'string' ? utf8ToBytes(payload) : toUint8Array(payload)
const chunks = splitUint8Array(bytes, chunkSize)
if (chunks.length > maxChunk) {
throw new Error(`分包数量超过上限: ${chunks.length} > ${maxChunk}`)
}
return chunks.map((chunk, index) => {
const packetIndex = index + 1
const lenByte = ((chunks.length & 0x0F) << 4) | (packetIndex & 0x0F)
const packet = new Uint8Array(2 + chunk.length)
packet[0] = head
packet[1] = lenByte
packet.set(chunk, 2)
return packet
})
}
/**
* 将 payload 按 A7 规则分包后顺序写入目标特征。
* 统一 auth/wifi 分包发送逻辑,避免多处重复实现。
*/
export async function writeA7Payload(ble, characteristicId, payload, packetConfig = {}, options = {}) {
if (!ble || typeof ble.writeCharacteristic !== 'function') {
throw new Error('writeA7Payload 缺少有效的 ble 实例')
}
if (!characteristicId) {
throw new Error('writeA7Payload 缺少 characteristicId')
}
const { packetInterval = 0 } = options
const packets = buildA7Packets(payload, packetConfig)
for (const packet of packets) {
await ble.writeCharacteristic(characteristicId, packet)
if (packetInterval > 0) {
// 部分固件在连续写入时需要极短间隔,默认 0 兼容原行为。
await new Promise((resolve) => setTimeout(resolve, packetInterval))
}
}
return packets.length
}
/**
* 合并多个 A7 分包数据体(去掉前两字节头信息后拼接)。
*/
export function concatA7PacketData(packets = []) {
const sorted = [...packets].sort((a, b) => {
const indexA = a[1] & 0x0F
const indexB = b[1] & 0x0F
return indexA - indexB
})
const totalLength = sorted.reduce((sum, packet) => sum + Math.max(packet.length - 2, 0), 0)
const merged = new Uint8Array(totalLength)
let offset = 0
sorted.forEach((packet) => {
const body = packet.slice(2)
merged.set(body, offset)
offset += body.length
})
return merged
}