petzval / btferret

Python and C Bluetooth Library
MIT License
111 stars 21 forks source link

Characteristics aren't updated correctly #5

Closed Ectalite closed 6 months ago

Ectalite commented 1 year ago

To start I would like to thank you for developping this library, because a tested a lot of different libraries and they were either badly documented or not functionnal on my raspberry and yours was the first I found that worked fine the first time I used it.

For my testing procedures I'm using the nRF Connect Application on my iPhone XS and the bluetooth server is running on a Raspberry Pi B3 (if it can help for the debugging).

I tried multiple things and found out that updating the devices.txt file between two runs wasn't working as it kept finding the characteristics I've set the first time on the nRF Connect application.

Here are screenshots of the application logs: image t

And the here is my devices.txt file: devices.txt

Here you can see that on nRF Connect there isn't the new "Send" Characteristic I added: T

Ectalite commented 1 year ago

I would also know if it would be possible to change the service UUID ?

petzval commented 1 year ago

Thanks for your comments about the library. The problem here is with Android on your phone. When Android first connects to an LE device, it reads the characteristic services and stores the information in a cache. The next time it connects, it assumes that the characteristics will still be the same, and instead of reading the services again, it gets the info from its cache. An internet search for clearing the cache reveals a lot of complaints about this, and requests for ways to force the Android to read the services on every connection. There are some unreliable methods, but only if you are writing the Android code. This problem seems to have been fixed with Android 12. Otherwise, the solution is to turn Bluetooth off and on again, which clears the cache. The characteristic UUIDs come from baseuuid[16] at about line 650 in btlib.c I now see you have an iPhone, not an Android - maybe the problem is the same. You can check whether the phone is reading the services each time by turning verbose mode on set_print_flag(PRINT_VERBOSE) and look for opcode 10 and 8 requests.

Ectalite commented 1 year ago

So what I found about clearing the cache is that the phone is waiting on a notification from the BLE server. https://developer.apple.com/forums/thread/76339?answerId=660510022#660510022 If you have some spare time you could check what they did in the nRF SDK to enable that. 

From what I'm reading, the BLE server has to create a Service Changed characteristic. https://stackoverflow.com/questions/67473791/how-to-clear-ble-cache-in-ios-connected-bluetooth-device​ 8 oct. 2022, 18:14 de @.***:

Thanks for your comments about the library. The problem here is with Android on your phone. When Android first connects to an LE device, it reads the characteristic services and stores the information in a cache. The next time it connects, it assumes that the characteristics will still be the same, and instead of reading the services again, it gets the info from its cache. An internet search for clearing the cache reveals a lot of complaints about this, and requests for ways to force the Android to read the services on every connection. There are some unreliable methods, but only if you are writing the Android code. This problem seems to have been fixed with Android 12. Otherwise, the solution is to turn Bluetooth off and on again, which clears the cache. The characteristic UUIDs come from baseuuid[16] at about line 650 in btlib.c

— Reply to this email directly, > view it on GitHub https://github.com/petzval/btferret/issues/5#issuecomment-1272350908> , or > unsubscribe https://github.com/notifications/unsubscribe-auth/AHPELNWTR5SUL7JIDJOCU7DWCGMYHANCNFSM6AAAAAARAGFUPE> . You are receiving this because you authored the thread.> Message ID: > <petzval/btferret/issues/5/1272350908> @> github> .> com>

petzval commented 1 year ago

There is no Service Changed characteristic in btferret, so this mechanism is not available. I thought about including it, but it all seemed a bit of a mess with some systems implementing the correct procedure and some not. For example, the Pi's bluez service does not issue a Service Changed indication on connection, which is needed here. It's not clear if any system issues one on connection, in addition to when characteristics change after connection. Turning the phone's Bluetooth off and on seems to be the only option,.

petzval commented 1 year ago

Here's an extraordinary thing - it is possible to add a services changed characteristic. I also realise I should have said you can set the UUID of a characteristic in the devices.txt file - as shown below. First, add a characteristic called, say, SERVICES with a UUID of 2A05 to the devices.txt file:

DEVICE = My Pi    TYPE=mesh   NODE=2  ADDRESS=11:22:33:44:55
    LECHAR=Test  PERMIT=06   SIZE=8  UUID=11111111-2222-3333-4444-555555555555 HANDLE=0005
    LECHAR=SERVICES   permit=10  UUID=2A05   handle=0007  size=4     ;  ctic index 1

When nRf connects, tap "Unknown Service", and "Service Changed" with a UUID of 2A05 will appear on the list of characteristics. Tap the three down arrows, which will enable notifications. To send a services changed notification to nRf, put the following code somewhere in your le_callback routine:

unsigned char dat[4];
int index;

dat[0] = 1;    // start handle
dat[1] = 0;
dat[2] = 0xFF;  // end handle
dat[3] = 0xFF;
index = 1;   // or whatever the index of the SERVICES devices.txt entry is
write_ctic(localnode(),index,dat,0);

nRf will report: "Affected Attribute Handle range 0x0001 - 0xFFFF received". So nRf has definitely recognised this as a services changed notification for all handles. However, I would have expected nRf to immediately re-read all the services, but my Android version does not. Maybe this is another example of a system not responding correctly, and maybe your iOS will, but the notification works - everything else is up to the phone.

Ectalite commented 1 year ago

Wow thanks for the research, I will try this out !

Ectalite commented 1 year ago

Ok thanks for the clarifications, I didn't know it was an OS problem.

8 oct. 2022, 18:14 de @.***:

Thanks for your comments about the library. The problem here is with Android on your phone. When Android first connects to an LE device, it reads the characteristic services and stores the information in a cache. The next time it connects, it assumes that the characteristics will still be the same, and instead of reading the services again, it gets the info from its cache. An internet search for clearing the cache reveals a lot of complaints about this, and requests for ways to force the Android to read the services on every connection. There are some unreliable methods, but only if you are writing the Android code. This problem seems to have been fixed with Android 12. Otherwise, the solution is to turn Bluetooth off and on again, which clears the cache. The characteristic UUIDs come from baseuuid[16] at about line 650 in btlib.c

— Reply to this email directly, > view it on GitHub https://github.com/petzval/btferret/issues/5#issuecomment-1272350908> , or > unsubscribe https://github.com/notifications/unsubscribe-auth/AHPELNWTR5SUL7JIDJOCU7DWCGMYHANCNFSM6AAAAAARAGFUPE> . You are receiving this because you authored the thread.> Message ID: > <petzval/btferret/issues/5/1272350908> @> github> .> com>