HarmonyOS 鸿蒙Next中BLE使用ble.GattWriteType.WRITE_NO_RESPONSE分包发送40多个字节数据设备收到成功率低问题

HarmonyOS 鸿蒙Next中BLE使用ble.GattWriteType.WRITE_NO_RESPONSE分包发送40多个字节数据设备收到成功率低问题

发送数据:AA5503001a0300321414000e00009600000190000000000000000000000000AE

代码如下:

// 新增命令队列及发送状态标识
private commandQueue: Uint8Array[] = [];  // 发送队列
private isSending: boolean = false;       // 是否正在发送中

async sendToBytes(stSent: string) {
  console.error(Tag, '=========发送数据:' + stSent);
  let bytes = BluHexUtils.hexStringToUint8Array(stSent);
  if (this.connectModel != null && this.gattClientDevice != null) {
    if (bytes.length > 20) {
      // console.error('aa','=============走这里')
      let dataArr = this.splitUint8Array(bytes, 20);
      // 将数据块加入队列(而不是直接发送)
      this.commandQueue.push(...dataArr);
      //  this.commandQueue.push(bytes)
      // 触发队列处理
      this.processQueue(ble.GattWriteType.WRITE_NO_RESPONSE);

    } else {
      // console.error('aa','=============走这里1111')
      this.commandQueue.push(bytes);
      // 触发队列处理
      this.processQueue(ble.GattWriteType.WRITE);
    }
  }
}

// 将 Uint8Array 按指定 chunkSize 分割成多个子数组
splitUint8Array(data: Uint8Array, chunkSize: number): Uint8Array[] {
  const chunks: Uint8Array[] = [];
  for (let i = 0; i < data.length; i += chunkSize) {
    // 使用 slice 截取当前块(不修改原数组)
    const chunk = data.slice(i, i + chunkSize);
    chunks.push(chunk);
  }
  return chunks;
}

private processQueue(writeType: ble.GattWriteType) {
  if (this.isSending || this.commandQueue.length === 0) {
    return; // 正在发送或队列为空时退出
  }
  this.isSending = true;
  const nextData = this.commandQueue.shift()!; // 取出队列头部数据
  this.sendData(nextData, writeType)
    .finally(() => {
      this.isSending = false;
      // 递归处理下一个数据
      this.processQueue(writeType);
    });
}

private async sendData(data: Uint8Array, writeType: ble.GattWriteType) {
  return new Promise<void>((resolve, reject) => {
    let write = this.connectModel?.writeCharacteristic;
    if (!write) {
      reject('Write characteristic not found');
      return;
    }
    let characteristic: ble.BLECharacteristic = {
      serviceUuid: write.serviceUuid,
      characteristicUuid: write.characteristicUuid,
      characteristicValue: this.typedArrayToBuffer(data),
      descriptors: write.descriptors
    };
    let stBytes = BluHexUtils.toHexWithSpaces(data);
    // console.error('aa','===============发送:writeType:'+writeType+'================='+stBytes)
    this.gattClientDevice?.writeCharacteristicValue(characteristic, writeType, (err) => {
      if (err) {
        console.error(Tag, 'errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
        if(writeType == ble.GattWriteType.WRITE_NO_RESPONSE){
          reject(err);
          // console.error('aa','===============发送:wwwwwwwwwwwwww:err')
        } else {
          // setTimeout(() => { 
            reject(err);
          // }, 300)
        }
      } else {
        console.error(Tag, 'writeCharacteristicValue success');
        if(writeType == ble.GattWriteType.WRITE_NO_RESPONSE){
          // console.error('aa','===============发送:wwwwwwwwwwwwww:success')
          resolve();
        } else {
          // setTimeout(() => { 
            resolve();
          // }, 300)
        }
      }
    });

  });
}

请问要如何处理 才能保证设备收到的成功率 。。 只有长命令成功率低,一般段命令成功率高。。只是偶尔出现成功率低问题


更多关于HarmonyOS 鸿蒙Next中BLE使用ble.GattWriteType.WRITE_NO_RESPONSE分包发送40多个字节数据设备收到成功率低问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS Next中,使用 WRITE_NO_RESPONSE 发送超过40字节数据时,建议将数据拆分为20字节/包进行发送。鸿蒙BLE协议栈对无响应写入有MTU限制,大包可能被底层丢弃。可通过调整发送间隔(建议15-20ms)提升成功率,同时确保设备端MTU配置匹配。若需可靠传输,可改用 WRITE_TYPE_DEFAULT 并在应用层实现确认机制。

更多关于HarmonyOS 鸿蒙Next中BLE使用ble.GattWriteType.WRITE_NO_RESPONSE分包发送40多个字节数据设备收到成功率低问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


针对BLE分包发送成功率低的问题,建议从以下几个方面优化:

  1. 增加发送间隔

processQueue方法中,建议在每次发送后添加50-100ms的延迟,避免蓝牙设备处理不过来:

private processQueue(writeType: ble.GattWriteType) {
  if (this.isSending || this.commandQueue.length === 0) {
    return;
  }
  this.isSending = true;
  const nextData = this.commandQueue.shift()!;
  this.sendData(nextData, writeType)
    .finally(() => {
      this.isSending = false;
      // 增加100ms延迟
      setTimeout(() => {
        this.processQueue(writeType);
      }, 100);
    });
}
  1. 实现重发机制

修改sendData方法,增加重试逻辑:

private async sendData(data: Uint8Array, writeType: ble.GattWriteType, retryCount = 3) {
  return new Promise<void>((resolve, reject) => {
    const attemptSend = (attempt = 0) => {
      let write = this.connectModel?.writeCharacteristic;
      // ...原有发送逻辑...
      
      this.gattClientDevice?.writeCharacteristicValue(characteristic, writeType, (err) => {
        if (err && attempt < retryCount) {
          setTimeout(() => attemptSend(attempt + 1), 50);
        } else if (err) {
          reject(err);
        } else {
          resolve();
        }
      });
    };
    attemptSend();
  });
}
  1. 检查MTU大小

确保设备支持足够的MTU大小(建议至少23字节):

// 在连接后检查MTU
this.gattClientDevice?.getBLEMtu((err, mtu) => {
  console.log('Current MTU:', mtu);
  if (mtu < 23) {
    this.gattClientDevice?.setBLEMtu(23);
  }
});
  1. 考虑使用WRITE_WITH_RESPONSE

对于关键数据包,可以混合使用两种写入方式:

// 修改processQueue逻辑
private processQueue() {
  // ...
  const useResponse = this.commandQueue.length === 1; // 最后一包使用response
  this.sendData(nextData, useResponse ? ble.GattWriteType.WRITE : ble.GattWriteType.WRITE_NO_RESPONSE)
  // ...
}

这些修改应该能显著提高长数据包的传输成功率。

回到顶部