rxandroidble只写发送第一个20B

时间:2018-01-11 22:01:56

标签: android bluetooth-lowenergy rxandroidble nrf52

我尝试在给定(自定义)特征上写入> 20字节数据。在以下日志中,我尝试写入85个字节:

代码:

connectionObservable
                .flatMap(rxBleConnection -> rxBleConnection.writeCharacteristic(
                        wChar.uuid(),
                        wChar.bytes()))
                .observeOn(mainThread())
                .subscribe(
                        bytes -> wChar.success(),
                        this::onWriteFailure
                );

结果: 在服务器端(nrf52),我可以看到EXEC_WRITE,但只发送了前20B。

这是logcat:

  

D / RxBle#ClientOperationQueue:QUEUED ConnectOperation(17461182)   D / RxBle#ClientOperationQueue:STARTED ConnectOperation(17461182)   D / RxBle#ClientOperationQueue:QUEUED ConnectOperation(218660306)   D / RxBle#ClientOperationQueue:STARTED ConnectOperation(218660306)   D / RxBle #BluetoothGatt:onConnectionStateChange newState = 2 status = 0   D / RxBle #BluetoothGatt:onConnectionStateChange newState = 2 status = 0   D / RxBle#ClientOperationQueue:FINISHED ConnectOperation(218660306)   D / RxBle#ClientOperationQueue:FINISHED ConnectOperation(17461182)   D / RxBle#ConnectionOperationQueue:QUEUED ServiceDiscoveryOperation(125599796)   D / RxBle#ConnectionOperationQueue:STARTED ServiceDiscoveryOperation(125599796)   D / RxBle#BluetoothGatt:onServicesDiscovered status = 0   D / RxBle#ConnectionOperationQueue:QUEUED CharacteristicsReadOperation(2626026)   D / RxBle#ConnectionOperationQueue:FINISHED ServiceDiscoveryOperation(125599796)   D / RxBle#ConnectionOperationQueue:STARTED CharacteristicsReadOperation(2626026)   D / RxBle #BluetoothGatt:onCharacteristicRead特征= 0000fa03-0278-03be-4447-091eba91df8e status = 0   D / RxBle#ConnectionOperationQueue:FINISHED CharacteristicsReadOperation(2626026)   D / RxBle#ClientOperationQueue:QUEUED ConnectOperation(158692575)   D / RxBle#ClientOperationQueue:STARTED ConnectOperation(158692575)   D / RxBle #BluetoothGatt:onConnectionStateChange newState = 2 status = 0   D / RxBle#ClientOperationQueue:FINISHED ConnectOperation(158692575)   D / RxBle#ConnectionOperationQueue:QUEUED ServiceDiscoveryOperation(20778996)   D / RxBle#ConnectionOperationQueue:STARTED ServiceDiscoveryOperation(20778996)> D / RxBle #BluetoothGatt:onServicesDiscovered status = 0
  D / RxBle#ConnectionOperationQueue:QUEUED CharacteristicsWriteOperation(51009974)   D / RxBle#ConnectionOperationQueue:FINISHED ServiceDiscoveryOperation(20778996)   D / RxBle#ConnectionOperationQueue:STARTED CharacteristicsWriteOperation(51009974)
  的> D / RxBle #BluetoothGatt:onCharacteristicWrite characteristic = 0000fa04-0278-03be-4447-091eba91df8e status = 0

     

D / RxBle#ConnectionOperationQueue:FINISHED CharacteristicsWriteOperation(51009974)

我还尝试使用long rxAndroidBlewrite过程:

connectionObservable
                .flatMap(rxBleConnection -> {
                            rxBleConnection.setupNotification(wChar.uuid()); 
                            return rxBleConnection.createNewLongWriteBuilder()
                                    .setCharacteristicUuid(wChar.uuid()) 
                                    .setBytes(array)
                                    .build();
                        }
                )
                .subscribe(
                        bytes -> wChar.success(),
                        this::onWriteFailure
                );

并且它发送了几个连续的写命令,但它不是长写程序(使用n ATT_prepare和1 ATT_exec),它是独立的写入:

  

D / RxBle#ConnectionOperationQueue:QUEUED   CharacteristicLongWriteOperation(74131396)   D / RxBle#ConnectionOperationQueue:完成   ServiceDiscoveryOperation(250008320)D / RxBle#ConnectionOperationQueue:   STARTED CharacteristicsLongWriteOperation(74131396)

     

D / RxBle#BluetoothGatt:onCharacteristicWrite   特征= 0000fa04-0278-03be-4447-091eba91df8e status = 0

     

D / RxBle#BluetoothGatt:onCharacteristicWrite   特征= 0000fa04-0278-03be-4447-091eba91df8e status = 0

     

D / RxBle#BluetoothGatt:onCharacteristicWrite   特征= 0000fa04-0278-03be-4447-091eba91df8e status = 0

     

D / RxBle#BluetoothGatt:onCharacteristicWrite   特征= 0000fa04-0278-03be-4447-091eba91df8e status = 0

     

D / RxBle#BluetoothGatt:onCharacteristicWrite   特征= 0000fa04-0278-03be-4447-091eba91df8e status = 0

     

D / RxBle#ConnectionOperationQueue:已完成   CharacteristicLongWriteOperation(74131396)

当然我可以设法在服务器上重建或修改MTU,但我想使用BLE排队写入,这通常由我的中心(rxandroidble)和我的外围设备(nrf52)支持

3 个答案:

答案 0 :(得分:1)

蓝牙4.0规范(包括BLE的引入)规定,一次最多可以在给定特征上传输20个字节。如果需要发送更多数据,则必须在某种类型的循环中一次发送20个字节。

事实上,这不是RxAndroidBle的问题,只是技术的局限。

见这里:https://stackoverflow.com/a/38914831/4321774

答案 1 :(得分:1)

如果您在Android API上引用queued writes,则它似乎被引用为reliable write。此API为not currently implemented in the RxAndroidBle,您需要使用RxBleCustomOperation API实施a shortcut to native BluetoothGattCallback。即便如此,它仍然是原生Android API is not fully functional in this matter

The RxAndroidBle long write没有使用准备好的写入,而是使用多个标准写入。这实际上可以在Javadoc中更好地描述......

长写mixed opinionsreally is。 @ Emil' excellent answer in this question clarifies it very well

我使用带有SDK 8.1.0的Softdevice S110的nRF51822进行了一些测试。

似乎在引擎盖下,Long Write只是一个Prepared Write- Android为用户管理它。

在外围方面,实现起来似乎比较棘手,因为Softdevice通知应用程序已完成Prepared Write并且数据已准备好进行解析(它没有附加到写BLE事件本身)。解析数据属于app逻辑,因为Long Write和Prepared / Reliable Write之间似乎没有区别,可能会考虑一次写入多个特性,并且可能存在一些与业务逻辑相关的一致性问题(是否应该接受一组特定的写入)。

结论: Android vanilla API(和RxAndroidBle)支持所谓的Long Write开箱即用,通过制作多个Prepared / Queued写入。由外围设备固件来正确处理

答案 2 :(得分:1)

对于客户端(Android),只需使用标准的Write程序,你就可以了。在内部,它会将其分成多个准备写请求,然后是执行写请求。也就是说,使用你的第一种方法。

为了帮助解决这个问题,有两个层次:GATT和ATT。 ATT层定义了一个名为" Queued Writes"其中包括准备写请求/响应和执行写请求/响应。这个想法是所有准备写入(其中每个都限制为MTU-5的大小,具有偏移参数和ATT句柄)被放入外围端的队列中。在执行写操作发生之前,写操作不会在外设中提交。 (执行写入有一个标志,也可用于取消整个队列。)

在GATT层,我们有一些名为"写长特征值"。这是一个程序,当应该写出的特征值超过单个写入请求中可以放入的值时,将使用该过程。此过程定义为使用"排队写入" ATT中的功能,因此它将值分成多个段,将它们全部发送到Prepared Write数据包中,最后发送Execute Write数据包。 "写长特征值"应该不惜一切代价避免由于其大量开销(每个数据包往返一次,响应数据包很长,因为它们包含值的副本,并且需要一个最终的执行写请求)。相反,将MTU增加到最大值要好得多,因为如果你幸运的话,它可以在一个连接事件中发送所有内容。

Reliable Writes也是GATT图层功能,使用"排队写入" ATT中的功能。这个想法是用户应该能够在一次操作中对多个特征进行多次原子写入。可靠一词来自客户端应该验证值是否正确发送。每个准备写入响应包括来自准备写入请求的接收值,客户端应比较这些并看到它们是相等的,如果不相等,则中止。现在在Android中,使用当前的API +实现来执行此检查是不可能的,因此虽然操作仍然有效,但实际上并非如此可靠"因为它应该是(但你在所有BLE数据包上都有CRC,所以我不认为会有问题)。请注意,如果您遵循GATT规则,您可能只对特征(非描述符)执行可靠写入,并且仅对声明此属性的特征执行。

在外围方面,我们无法真正知道传入的准备写入请求是否是“写入长特征值”的一部分"操作或"可靠写"操作。但无论如何,大多数BLE堆栈组合检索到的部分,然后在收到执行写入时传送单个写入。在我看来,他们反而暴露了一个相当低级别的API;通常只是或多或少地转发ATT数据包。

对于Nordic Semiconductor的软件设备,最简单的方法是使用" GATTS排队写入:堆栈处理,没有属性需要授权" http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.s132.api.v5.0.0/group___b_l_e___g_a_t_t_s___q_u_e_u_e_d___w_r_i_t_e___b_u_f___n_o_a_u_t_h___m_s_c.html。这样,它会在应用程序提供的缓冲区中排队所有Prepared Writes,并在Execute Write到达时通知应用程序。然后应用程序应解析堆栈放入缓冲区的所有(或多或少)原始ATT准备写入请求数据包。此结构在此处定义http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.s132.api.v5.0.0%2Fgroup___b_l_e___g_a_t_t_s___q_u_e_u_e_d___w_r_i_t_e_s___u_s_e_r___m_e_m.html&cp=2_3_1_1_0_2_4_5。请注意,缓冲区是一个列表(连接这些结构的数组)而不是单个值。该列表以包含BLE_GATT_HANDLE_INVALID作为句柄的项目终止。我认为你的错误是你只解析了这个列表中的第一项。