Android基于FastBLE向RN4871 BLE模块发数据超量失败求助
问题:Android向RN4871 BLE模块发送数据无法突破字节上限
我在Android应用中无法向BLE模块发送超过160字节的数据,当前使用修改后的FastBLE安卓应用向Microchip RN4871蓝牙模块发送数据,BLE运行在透传UART模式。连接模块后,安卓应用先调用notify函数,再调用write函数以20字节分片发送数据包。
但发送160字节后,安卓应用就不再发送更多数据;增大MTU后最多能发送600字节,但依旧无法突破上限。我们发现修改FastBLE安卓代码后,notify descriptor的值为NULL,由于不清楚原因,无法修复。
调用代码("hex"为待写入字符串)
setCharaProp(2); ((CharacteristicOperationFragment) fragments.get(2)).showData(hex); setCharaProp(1); ((CharacteristicOperationFragment) fragments.get(2)).showData(hex); setCharaProp(2);
Notify和Write的实现代码
public void showData(String hex) { final BleDevice bleDevice = ((OperationActivity) getActivity()).getBleDevice(); final BluetoothGattCharacteristic characteristic = ((OperationActivity) getActivity()).getCharacteristic(); final int charaProp = ((OperationActivity) getActivity()).getCharaProp(); String child = characteristic.getUuid().toString() + String.valueOf(charaProp); for (int i = 0; i < layout_container.getChildCount(); i++) { layout_container.getChildAt(i).setVisibility(View.GONE); } if (childList.contains(child)) { layout_container.findViewWithTag(bleDevice.getKey() + characteristic.getUuid().toString() + charaProp).setVisibility(View.VISIBLE); } else { childList.add(child); View view = LayoutInflater.from(getActivity()).inflate(R.layout.layout_characteric_operation, null); view.setTag(bleDevice.getKey() + characteristic.getUuid().toString() + charaProp); LinearLayout layout_add = (LinearLayout) view.findViewById(R.id.layout_add); final TextView txt_title = (TextView) view.findViewById(R.id.txt_title); txt_title.setText(String.valueOf(characteristic.getUuid().toString() + getActivity().getString(R.string.data_changed))); final TextView txt = (TextView) view.findViewById(R.id.txt); txt.setMovementMethod(ScrollingMovementMethod.getInstance()); switch (charaProp) { case PROPERTY_WRITE: { View view_add = LayoutInflater.from(getActivity()).inflate(R.layout.layout_characteric_operation_et, null); if (TextUtils.isEmpty(hex)) { return; } BleManager.getInstance().write( bleDevice, characteristic.getService().getUuid().toString(), characteristic.getUuid().toString(), HexUtil.hexStringToBytes(hex), new BleWriteCallback() { @Override public void onWriteSuccess(final int current, final int total, final byte[] justWrite) { runOnUiThread(new Runnable() { @Override public void run() { addText(txt, "write success, current: " + current + " total: " + total + " justWrite: " + HexUtil.formatHexString(justWrite, true)); } }); } @Override public void onWriteFailure(final BleException exception) { runOnUiThread(new Runnable() { @Override public void run() { addText(txt, exception.toString()); } }); } }); layout_add.addView(view_add); } break; case PROPERTY_NOTIFY: { View view_add = LayoutInflater.from(getActivity()).inflate(R.layout.layout_characteric_operation_button, null); if (my_notify_ctl == 1) { my_notify_ctl = 0; BleManager.getInstance().notify( bleDevice, characteristic.getService().getUuid().toString(), characteristic.getUuid().toString(), new BleNotifyCallback() { @Override public void onNotifySuccess() { runOnUiThread(new Runnable() { @Override public void run() { addText(txt, "notify success"); } }); } @Override public void onNotifyFailure(final BleException exception) { runOnUiThread(new Runnable() { @Override public void run() { addText(txt, exception.toString()); } }); } @Override public void onCharacteristicChanged(byte[] data) { runOnUiThread(new Runnable() { @Override public void run() { addText(txt, HexUtil.formatHexString(characteristic.getValue(), true)); } }); } }); } else { BleManager.getInstance().stopNotify( bleDevice, characteristic.getService().getUuid().toString(), characteristic.getUuid().toString()); my_notify_ctl = 1; } layout_add.addView(view_add); } break; layout_container.addView(view); } }
问题分析与解决方案
1. Notify Descriptor为NULL的原因
FastBLE调用notify时如果找不到对应的Client Characteristic Configuration Descriptor(UUID: 00002902-0000-1000-8000-00805f9b34fb),会导致descriptor为NULL,通常是因为:
- 设备端的Notify特征未正确配置该Descriptor
- 连接BLE设备后,未完整完成服务/特征/Descriptor发现就调用了notify
2. 发送字节上限问题的核心原因
- FastBLE分片逻辑缺陷:默认异步分片可能存在队列阻塞,未等待前一片发送完成就触发下一片发送
- RN4871透传模式限制:RN4871在透传UART模式下对连续写入速率有要求,无流量控制会导致设备拒绝接收或丢包
- Notify与Write资源竞争:连续切换
charaProp调用两个操作,会抢占BLE链路资源
3. 具体修复步骤
(1)确保Notify Descriptor正常获取
连接设备时必须等待服务发现完成后再操作:
BleManager.getInstance().connect(bleDevice, new BleConnectCallback() { @Override public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) { // 触发服务发现 gatt.discoverServices(); } @Override public void onServicesDiscovered(BleDevice bleDevice, BluetoothGatt gatt) { // 服务发现完成后,再执行notify和write逻辑 } });
(2)自定义分片发送逻辑
在onWriteSuccess回调中触发下一片发送,避免队列阻塞:
public class BleBatchWriter { private BleDevice bleDevice; private String serviceUuid; private String charaUuid; private byte[] totalData; private int chunkSize; private int currentIndex = 0; private BleWriteCallback callback; public BleBatchWriter(BleDevice bleDevice, String serviceUuid, String charaUuid, byte[] totalData, int mtu, BleWriteCallback callback) { this.bleDevice = bleDevice; this.serviceUuid = serviceUuid; this.charaUuid = charaUuid; this.totalData = totalData; this.chunkSize = mtu - 3; // 减去BLE层3字节开销 this.callback = callback; } public void start() { sendNextChunk(); } private void sendNextChunk() { if (currentIndex >= totalData.length) { callback.onWriteSuccess(totalData.length, totalData.length, new byte[0]); return; } int end = Math.min(currentIndex + chunkSize, totalData.length); byte[] chunk = Arrays.copyOfRange(totalData, currentIndex, end); BleManager.getInstance().write(bleDevice, serviceUuid, charaUuid, chunk, new BleWriteCallback() { @Override public void onWriteSuccess(int current, int total, byte[] justWrite) { currentIndex += justWrite.length; callback.onWriteSuccess(currentIndex, totalData.length, justWrite); sendNextChunk(); } @Override public void onWriteFailure(BleException exception) { callback.onWriteFailure(exception); } }); } } // 使用示例 new BleBatchWriter(bleDevice, serviceUuid, charaUuid, HexUtil.hexStringToBytes(hex), mtuSize, new BleWriteCallback() { @Override public void onWriteSuccess(int current, int total, byte[] justWrite) { // 处理成功回调 } @Override public void onWriteFailure(BleException exception) { // 处理失败回调 } }).start();
(3)RN4871端配置优化
开启流量控制避免丢包:
- 发送
$SF,1开启软件流量控制(Android端需配合发送XON/XOFF) - 或发送
$SF,2开启硬件流量控制(需硬件支持)
(4)避免Notify与Write资源竞争
先确保Notify启动成功后再执行Write:
BleManager.getInstance().notify(bleDevice, notifyServiceUuid, notifyCharaUuid, new BleNotifyCallback() { @Override public void onNotifySuccess() { // Notify启动成功后执行批量Write new BleBatchWriter(bleDevice, writeServiceUuid, writeCharaUuid, data, mtuSize, writeCallback).start(); } @Override public void onNotifyFailure(BleException exception) { // 处理Notify失败 } @Override public void onCharacteristicChanged(byte[] data) { // 处理设备回传数据 } });
内容的提问来源于stack exchange,提问作者Nisha
相关产品推荐
相关产品推荐

