关于BluetoothRemoteGATTCharacteristic.writeValueWithResponse()最大安全缓冲区的咨询
Web Bluetooth 与 MicroPython BLE 设备通信的缓冲区异常问题
我通过Chrome的Web Bluetooth向运行MicroPython的BLE设备发送数据,使用的代码如下:
var value = new TextEncoder('utf-8').encode(str); for (i=0; i<value.byteLength; i+=self.DATA_BUFFER_SIZE) { await self.dataCharacteristic.writeValueWithResponse(value.slice(i, i + self.DATA_BUFFER_SIZE)); }
该MicroPython BLE设备的接收缓冲区设置为512字节,多数设备上将self.DATA_BUFFER_SIZE设为512时代码可正常运行,但在运行Ubuntu 22.04、Chrome 108.0.5359.124、搭载Qualcomm Atheros QCA9377的笔记本上,必须将缓冲区大小降至20才能正常工作;若设为大于20的值,writeValueWithResponse()会一直挂起,开发者控制台无任何错误信息。
已验证支持512字节缓冲区的设备:
- 多款MacBook
- 多款Win10笔记本
- 运行Ubuntu 20.04和22.04的台式机及笔记本
- Android手机
- Fire平板
仅支持20字节缓冲区的设备:
- 运行Ubuntu 22.04、Chrome 108.0.5359.124、搭载Qualcomm Atheros QCA9377的笔记本
问题解答
这是否是Chrome/Linux qca9377驱动/硬件的bug?
大概率是Linux下QCA9377的BLE驱动或硬件适配问题。QCA9377是Wi-Fi+BLE combo芯片,Linux环境下的旧版本BLE驱动常存在MTU(最大传输单元)协商异常的情况。Chrome的Web Bluetooth依赖系统底层BLE栈,当系统栈无法正确处理大尺寸带响应写入时,就会出现writeValueWithResponse()挂起的现象。20字节是BLE默认的ATT MTU最小值,说明该设备的BLE栈可能无法成功协商更大的MTU,或是驱动对带响应写入存在尺寸限制。是否有方法检测writeValueWithResponse()的最大安全缓冲区大小?
可以通过两种方式实现:
- MTU协商值参考:设备连接后,可通过
device.gatt.maxMTU获取协商后的MTU值,ATT层有效负载为MTU-3(减去ATT头的3字节),可将此值作为初始缓冲区大小参考。但需注意,部分设备虽协商了大MTU,实际却无法处理带响应的大尺寸写入,需结合测试验证。 - 渐进式测试:从较大的缓冲区尺寸(比如设备支持的512)开始,逐步减小尺寸进行写入测试,直到找到能成功完成
writeValueWithResponse()的最大值。可给每个写入操作设置超时,超时则判定当前尺寸不可用,尝试更小的值。示例逻辑如下:
async function findMaxSafeBufferSize(characteristic, initialSize = 512) { let testData = new Uint8Array(initialSize); for (let size = initialSize; size >= 20; size -= 10) { try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 2000); await characteristic.writeValueWithResponse(testData.slice(0, size), { signal: controller.signal }); clearTimeout(timeoutId); return size; } catch (e) { // 超时或错误则尝试更小尺寸 } } return 20; // 退回到默认最小值 }
内容的提问来源于stack exchange,提问作者Cort
相关产品推荐
相关产品推荐

