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 }