uni-app中给BLE设备进行OTA升级,若存在每次传输20字节大小的限制,那OTA升级是否有更好的方案?

发布于 1周前 作者 vueper 来自 Uni-App

uni-app中给BLE设备进行OTA升级,若存在每次传输20字节大小的限制,那OTA升级是否有更好的方案?
给BLE设备进行OTA升级,如果说uni app有每次传输20字节大小的限制,那OTA升级有没有其他更好的方案呢?不然,每次20字节的话,速度太慢了。

2 回复

前段时间刚做了蓝牙ota功能,我刚刚也去翻了下文档,指的是会对蓝牙4.0的手机会限制传输大小,第一批蓝牙5.0的手机是在16年出的(小米6,iPhone8),现在2025年了。我的建议是,放心做。但是蓝牙设备的硬件会限制一次能接收多少,建议从大往小试试


在uni-app中处理BLE设备的OTA(Over-The-Air)升级,当每次传输受到20字节大小限制时,确实需要设计一种高效的传输策略来确保升级过程既可靠又高效。以下是一个基于分块传输和校验机制的代码示例,展示了如何在这种限制下实现OTA升级。

1. 分块传输与校验

首先,将OTA固件文件分割成多个20字节的数据块,并添加校验机制(如CRC或MD5)以确保每个数据块在传输过程中的完整性。

// 假设固件文件已经加载到内存中,以ArrayBuffer形式存储
const firmwareBuffer = ...; // 加载固件文件得到的ArrayBuffer
const chunkSize = 20; // 每次传输的字节大小
const totalChunks = Math.ceil(firmwareBuffer.byteLength / chunkSize);

// 计算每个数据块的CRC校验值(示例使用CRC16,实际可根据需要选择校验算法)
function calculateCRC(data) {
  // CRC16计算逻辑省略,可使用第三方库或自定义实现
  return crc16(data);
}

// 发送数据块的函数
async function sendChunk(deviceId, chunkIndex, chunkData, crc) {
  const characteristic = ...; // 获取BLE设备的特征值用于写入
  const packet = {
    index: chunkIndex,
    data: chunkData,
    crc: crc.toString(16).toUpperCase()
  };
  const packetBuffer = new ArrayBuffer.from(JSON.stringify(packet));
  await bluetoothModule.writeCharacteristicValue(deviceId, characteristic, packetBuffer);
}

// 主升级流程
async function otaUpgrade(deviceId) {
  for (let i = 0; i < totalChunks; i++) {
    const start = i * chunkSize;
    const end = start + chunkSize;
    const chunkData = firmwareBuffer.slice(start, end);
    const crc = calculateCRC(chunkData);
    await sendChunk(deviceId, i, chunkData, crc);
  }
  // 发送完成信号(可选)
  await sendCompletionSignal(deviceId);
}

2. 接收端处理

在BLE设备的接收端,需要实现相应的逻辑来接收这些分块数据,并进行CRC校验。如果校验失败,则请求重发该数据块。

// 伪代码,实际实现需根据BLE设备的编程环境(如Arduino, ESP32等)调整
void onDataReceived(byte* data, int length) {
  static int expectedIndex = 0;
  static ArrayBuffer firmwareBuffer;

  // 解析接收到的数据包
  JsonDocument doc;
  DeserializationError error = deserializeJson(doc, data);
  if (error) {
    // 处理解析错误
    return;
  }

  int receivedIndex = doc["index"];
  String receivedCrc = doc["crc"];
  byte* receivedData = ...; // 从doc["data"]中提取数据

  if (receivedIndex != expectedIndex) {
    // 处理数据块顺序错误
    return;
  }

  uint16_t calculatedCrc = calculateCRC(receivedData);
  if (String(calculatedCrc, HEX).toUpperCase() != receivedCrc) {
    // CRC校验失败,请求重发
    requestChunkRetry(receivedIndex);
    return;
  }

  // 写入固件缓冲区
  memcpy(firmwareBuffer.data() + (expectedIndex * CHUNK_SIZE), receivedData, CHUNK_SIZE);
  expectedIndex++;

  if (expectedIndex == TOTAL_CHUNKS) {
    // 完成固件写入,启动固件更新流程
    startFirmwareUpdate();
  }
}

通过上述方法,可以有效处理每次传输20字节大小的限制,确保OTA升级过程的可靠性和高效性。

回到顶部