0

I'm doing a long write to a BLE for making an OTA update, but I need to wait for the write response of the BLE device for sending more data but I don't know how to catch the device write response, I'm using a Samsung galaxy tab s2 with android 7, and Kotlin for my code

override fun otaDataWrite(data:ByteArray) {
    manager.connection?.flatMap { rxBleConnection: RxBleConnection? -> rxBleConnection?.createNewLongWriteBuilder()
            ?.setCharacteristicUuid(OTACharacteristics.OTA_DATA.uuid)
            ?.setBytes(data)
            ?.setMaxBatchSize(totalPackages)
            ?.build()
    }?.subscribe({ t: ByteArray? ->
        Log.i("arrive", "data ${converter.bytesToHex(t)}")
        manageOtaWrite()
    }, { t: Throwable? -> t?.printStackTrace() })

every time that I write the characteristic the subscriptions respond me immediately with the written data, I need capture the response of the characteristic, for sending more data

  • Not really an answer to your question, but you should really not use long write if you need to write much data fast. Instead use write without response as that has so much more throughput. – Emil Aug 03 '17 at 01:01
  • Leonardo — 1. `.setMaxBatchSize()` is for setting the maximum amount of bytes that can be sent in one package and `totalPackages` seem to be the number of packages to send 2. What exactly is the `totalPackages`? 3. By the `device write response` you think of a notification from a specific characteristic or just the acknowledgement from the peripheral that it has received a single package? @Emil — is it possible to contact you in any way? – Dariusz Seweryn Aug 03 '17 at 08:33
  • Sure.. Was it something particular you wanted to talk about? I think the easiest is to just start a stack overflow chat. – Emil Aug 03 '17 at 09:43
  • @DariuszSeweryn yes I notice my mistake in `setMaxBatchSize()` method now I pass data.size to that method, 2 totalPackages was the total amount of packages that I need to send (I'm sending a file through BLE for an OTA update), and 3 yes I need the acknowledgement from the peripheral that it has received the package, in base of that I would send the other package – Leonardo Fuenmayor Aug 03 '17 at 12:36
  • @Emil I know, but is a DFU characteristic for an OTA update, I do that IOS and the characteristic response for every write – Leonardo Fuenmayor Aug 03 '17 at 12:38
  • This acknowledgement is in your situation just a `BluetoothGattCallback.onCharacteristicWrite()` — right? Please confirm and I will write an answer. – Dariusz Seweryn Aug 03 '17 at 12:41
  • @Emil https://chat.stackoverflow.com/rooms/150956/room-for-s-noopy-and-emil – Dariusz Seweryn Aug 03 '17 at 12:42
  • @DariuszSeweryn this method return when I write the characteristic or catch when the peripheral sent me the write response? – Leonardo Fuenmayor Aug 03 '17 at 12:47
  • Depending on the `BluetoothGattCharacteristic` setting (`WRITE_TYPE_DEFAULT`, `WRITE_TYPE_NO_RESPONSE`) `.onCharacteristicWrite()` is called when the remote peripheral has received the packet (when it's BLE stack has sent acknowledgement of transmission but not necessarily handled already) or when the local BLE stack has queued it for sending respectively. So you probably are thinking about notifications sent by the characteristic after handling. – Dariusz Seweryn Aug 03 '17 at 12:56
  • @LeonardoFuenmayor — did my solution worked for you? – Dariusz Seweryn Aug 07 '17 at 09:35
  • @DariuszSeweryn Hi sorry for the delay, I was working in other parts of the project, y test your code today, but I get this error `BleCannotSetCharacteristicNotificationException{bluetoothGattCharacteristic=984227f3-34fc-4045-a5d0-2c581f81a153, reason=CANNOT_FIND_CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR` – Leonardo Fuenmayor Oct 10 '17 at 13:28

2 Answers2

0

You are writing about response from the characteristic — I assume that the characteristic you refer is the one with UUID=OTA_DATA. The Long Write consist of small writes internally (so called batches).

What you probably want to achieve is something like:

fun otaDataWrite(data: ByteArray) {
    manager.connection!!.setupNotification(OTA_DATA) // first we need to get the notification on to get the response
            .flatMap { responseNotificationObservable -> // when the notification is ready we create the long write
                connection.createNewLongWriteBuilder()
                        .setCharacteristicUuid(OTA_DATA)
                        .setBytes(data)
//                        .setMaxBatchSize() // -> if omitted will default to the MTU (20 bytes if MTU was not changed). Should be used only if a single write should be less than MTU in size
                        .setWriteOperationAckStrategy { writeCompletedObservable -> // we need to postpone writing of the next batch of data till we get the response notification
                            Observable.zip( // so we zip the response notification
                                    responseNotificationObservable,
                                    writeCompletedObservable, // with the acknowledgement of the written batch
                                    { _, writeCompletedBoolean -> writeCompletedBoolean } // when both are available the next batch will be written
                            )
                        }
                        .build()
            }
            .take(1) // with this line the notification that was set above will be discarded after the long write will finish
            .subscribe(
                    { byteArray ->
                        Log.i("arrive", "data ${converter.bytesToHex(byteArray)}")
                        manageOtaWrite()
                    },
                    { it.printStackTrace() }
            )
}
Dariusz Seweryn
  • 3,212
  • 2
  • 14
  • 21
  • Hi sorry for the delay, I was working in other parts of the project, y test your code today, but I get this error `BleCannotSetCharacteristicNotificationException{bluetoothGattCharacteristic=984227f3-34fc-4045-a5d0-2c581f81a153, reason=CANNOT_FIND_CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR` – Leonardo Fuenmayor Oct 10 '17 at 13:27
  • So apparently your `OTA_DATA` characteristic either does not support notifications or it does not have the `Client Characteristic Config Descriptor` which would violate the Bluetooth Specification (if it does support notifications). Either way you need to specify what behaviour your peripheral needs to update as it is pretty much guessing right now. – Dariusz Seweryn Oct 10 '17 at 22:07
  • is correct the OTA_DATA characteristic does not support notifications, and that characteristic belongs to a Silicon labs OTA Service, and I don't have control over that service, is a default service in my peripheral – Leonardo Fuenmayor Oct 11 '17 at 14:47
  • the behaviour of the OTA process is, I have a service called OTA service with only 1 characteristic OTA_CONTROl, I write 0x00 to that characteristic and the device reboots in DFU mode and present me the OTA Service with 2 characteristics OTA_CONTROL(write), and OTA_DATA(Write with response), I write 0x00 to OTA_CONTROL and later I write to the OTA_DATA a portion of the binary file with a longWriter, the thing is that I need to wait for the response of the writer(like an acknowledgement) to send the next part of the file – Leonardo Fuenmayor Oct 11 '17 at 14:54
  • Not sure if you are using OTA in the version described in point 5.4 `OTA_UPLOAD`: https://www.silabs.com/documents/login/application-notes/an1045-bt-ota-dfu.pdf but if that is the case then I am not sure why your initial code did not work as there is no `ACK` from the peripheral side. – Dariusz Seweryn Oct 11 '17 at 15:07
-1

Well, after a lot of testing, I finally develop a standalone class for the OTA update with the android BLE API, and I used it together with all my RxBle methods, I don't know if I have a hardware problem or something else, but I solve the problem, thanks a lot.