Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Characteristic notification data automatically sent back to the device #60

Closed
vicobz opened this issue Dec 12, 2018 · 8 comments
Closed

Comments

@vicobz
Copy link

vicobz commented Dec 12, 2018

Hi,

I use this nice library to connect to a Nordic device and subscribe to notifications from one specific characteristic.

To communicate in both ways, I (the Android app) receive notifications from the characteristic and when I need to send a message, I write to that characteristic and the device replies with the same exact data.

Multiple issues were fixed from 2.0.1 & 2.0.3 releases.

However, I'm still facing something weird. I sometimes receive a notification from the Nordic device and then, I can see in logs that the exact same data is automatically written to the device, without no link with my own code, meaning I'm not sending any write request for that specific message.

Unfortunately, this issue breaks the communication protocol between our Nordic device and the Android app as we rely on a specific sequence order.

Here are some logs:

D: BleManager Log - Message: Writing characteristic 00000001-XXXX-XXXX-XXXX-000000000000 (WRITE COMMAND)
D: BleManager Log - Message: gatt.writeCharacteristic(00000001-XXXX-XXXX-XXXX-000000000000)
D: BleManager Log - Message: Data written to 00000001-XXXX-XXXX-XXXX-000000000000, value: (0x) YY-YY-YY-YY-YY-YY-YY-YY-YY-YY-YY-YY
I: Data sent to device CD:XX:XX:XX:XX:XX (0x) YY-YY-YY-YY-YY-YY-YY-YY-YY-YY-YY-YY
I: onWriteDone
D: BleManager Log - Message: Writing characteristic 00000001-XXXX-XXXX-XXXX-000000000000 (WRITE COMMAND)
D: BleManager Log - Message: gatt.writeCharacteristic(00000001-XXXX-XXXX-XXXX-000000000000)
D: BleManager Log - Message: Notification received from 00000001-XXXX-XXXX-XXXX-000000000000, value: (0x) AA-AA-AA-AA-AA-AA-AA-AA-AA-AA
I: Data received from device CD:XX:XX:XX:XX:XX (0x) AA-AA-AA-AA-AA-AA-AA-AA-AA-AA
I: Receive (0x) AA-AA-AA-AA-AA-AA-AA-AA-AA-AA
D: BleManager Log - Message: Data written to 00000001-XXXX-XXXX-XXXX-000000000000, value: (0x) AA-AA-AA-AA-AA-AA-AA-AA-AA-AA
I: Data sent to device CD:XX:XX:XX:XX:XX (0x) BB-BB-BB-BB-BB-BB-BB-BB-BB-BB-BB-BB-BB-BB-BB
I: onWriteDone

All values have been changed , but the issue is visible with the AA-AA-AA-AA-AA-AA-AA-AA-AA-AA message.

I receive a notification with this value on line 8, and that same frame is automatically sent back to the device, visible on line 11, but I didn't chose to send this message from my code.

Thanks

@philips77
Copy link
Member

philips77 commented Dec 12, 2018

Hello @vicobz,
I see 2 problems here. One could be solved easily. Does your communication protocol requires waiting for a notification before writing next message? From the logs I can see, that you write YYYs and then start writing AAAs, before the notification is received. Was that intentional? Are the outgoing and incoming data independent? Did you try using:

waitForNotification(characteristic)
   .trigger(writeCharacteristic(characteristic, YYYs))
   .with((device, data)->Log.i(TAG, "Data sent to device ... " + data))
   .done(device-> Log.i(TAG, "onWriteDone")
   .enqueue()
waitForNotification(characteristic)
   .trigger(writeCharacteristic(characteristic, AAAs))
   .with((device, data)->Log.i(TAG, "Data sent to device ... " + data))
   .done(device-> Log.i(TAG, "onWriteDone")
   .enqueue()

If notification should be received before the new write, this should fix the issue, unless there's a bug in the library.

However, if you indeed want to write independently from receiving notifications, than the problem lies on the Android side. As you are using the same characteristic to write and received data, both operations (write and notify) share the same BluetoothGattCharacteristic object. It may happen, that just after calling characteristic.setValue(AAAs) a notification is received (in another thread) and overwrites your data with those from the notification. Those new data will then be sent. The only way to solve this problem is to split sending and receiving into 2 characteristics, thus modify your communication protocol.

@vicobz
Copy link
Author

vicobz commented Dec 12, 2018

Hello @philips77, thanks again for your quick reply.

Our protocol does not require to wait for a notification receipt before writing the next message. The data value should be considered as independent even if in some cases, the device can reply through a notification with the same data. But from the app to the device, I never reply with the same exact data.

To precise the logs a bit:

  • I'm writing some YYYs
  • Then I receive an independent (meaning not related) reply through a notification with value of AAAs
  • My code doesn't take those AAAs into account, and doesn't reply to them. But we can see AAAs are written back to the characteristic from the BleManager logs on line 11
  • Then I continue sending proper data with BBBs

I don't think this could solve the issue as there is no direct link between write attempts and notification receipt at BLE level. It still seems strange that these AAAs are sent back anyway.

@vicobz
Copy link
Author

vicobz commented Dec 12, 2018

@philips77 I just updated my last reply

@philips77
Copy link
Member

There is a direct link in Android. To send data you do:

characteristic.setValue(AAA);
gatt.writeCharacteristic(characterstic);

Then you will receive onCharacteristicWrite(gatt, characteristic, status) callback (when the data were ack in case of write with response, or when they were prepared to be sent, in case of write without response).

When the notification is received you get onCharacteristicChanged(gatt, characteristic) with the notification's data. It may happen, that the notification is received after

characteristic.setValue(AAA);

but before the data were obtained from it and sent to controller. The notification will overwrite the data in characteristic object, and those data will in fact be sent.
There is nothing more I could improve in the library. Writing and receiving notifications is not thread safe and is done on some BLE threads. You need to split sending and receiving into 2 characteristics, or wait for a notification each time you send the data, like in my previous comment.

@vicobz
Copy link
Author

vicobz commented Dec 12, 2018

Yes, I implemented the same features directly with the Android BLE SDK and thus used to implement those methods & callbacks before using your library ;)

So, when you say:

It may happen, that the notification is received after

characteristic.setValue(AAA);

but before the data were obtained from it and sent to controller. The notification will overwrite the data in characteristic object, and those data will in fact be sent.

... looking at the logs example & keeping in mind that I never try to write AAAs myself, does it mean this is an Android-related issue that makes my app:

1 - call

characteristic.setValue(YYY);
gatt.writeCharacteristic(characteristic);

2 - Receive a notification with AAA
3 - call

characteristic.setValue(BBB);
gatt.writeCharacteristic(characteristic);

4 - The instruction 3 value (BBB) is overriden because of some thread issue so then my BBB write attempt translates into AAA write ?

In that case, why would my BBB message be sent as it should have been exactly replaced by this noisy AAA message ?

Splitting communication into two characteristics is not an option in our case, and waiting for notification before writing is either not suitable as the device waits for the app to write on its characteristic before replying.

@philips77
Copy link
Member

It's rather like that:

  1. You call setValue(AAA) and writeCharacteristic.

  2. You get onCharacteristicWrite callback with AAA.

  3. You call setValue(BBB) and writeCharacteristic.

  4. You get notification with AAA.

  5. Android states sending what's in characteristic, that is AAA.

  6. You get onCharacteristicWrite callback with AAA.

  7. and 6. may be replaced. From calling writeCharacteristic it may be few ms until the data we copied and sent. When a notification comes in right that moment it overrides the shared buffer (reference).

@vicobz
Copy link
Author

vicobz commented Dec 13, 2018

Okay so I think we agree on this, but as I told you in my replies I never call by myself setValue(AAA) :)

Anyway, I discussed with our embedded software team and we chose to decouple the characteristic into two as you advised: a first one for writing and a second for notification, and this works well.

Android should improve that BLE stack and provide developers with quality documentation and guidelines...

Thanks for your time and this great library!

@Maragues
Copy link
Contributor

Maragues commented Nov 29, 2019

Thanks to both for the insightful description and comments. We are facing the same issue and I was absolutely baffled until i read these issue in detail.

Let's see how we fix it, because we can't split the characteristic.

@philips77 is there a ticket in Android's big tracker system? It sounds like it should be easy to fix on their side, so I wonder if they are aware

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants