This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Proper way to handle a bonded reconnect

According to the spec, this is how a bonded reconnect should work:

On first pass, the central client does discovery and enables descriptors to characteristics of interest. At sometime during this sequence, pairing occurs. The central saves the pairing data, services, etc,, and enabled state information. The peripheral server does the same.

On a reconnect, service discovery, pairing, and enabling descriptors is no longer needed as it is done and saved. One can get right down to data transfer after encryption is established.

Okay, in my pulse ox peripheral, I am having trouble with the restoring of the enabled states of the descriptors. This involves perhaps the most confusing of the sd_* procedures, the notorious

sd_ble_gatts_sys_attr_set

sd_ble_gatts_sys_attr_get 

and saving that info to a file between connections. One of the parameters in the calls is BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS or BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS or (and I am not sure here) entering nothing (0) or maybe the ORing?. I am not sure what I should be saving (and therefore restoring). My understanding is that the 'system services' are things like the service changed characteristic enabled state. 'user' services are things like the continuous measurement characteristic, spot measurement characteristic, and RACP characteristic but I am not sure.

I call the methods using BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS yet on a reconnect I get the error BLE_ERROR_GATTS_SYS_ATTR_MISSING and though I handle the BLE_GATTS_EVT_SYS_ATTR_MISSING event, it never gets signaled.

What do I need to do to fix this?

  • Should I call these methods with just a 0 value and that gives me both?
  • Since when I get the error I am trying to send a continuous measurement by notification should I just assume that the error BLE_ERROR_GATTS_SYS_ATTR_MISSING is misleading, it  really should be BLE_ERROR_GATTS_USR_ATTR_MISSING?

What is the procedure I should follow when disconnecting the first time connect?

  • call the sd_ble_gatts_sys_attr_get  method a couple of times to get the information with BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS or BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS or 0 or (BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS)?
  • save the data to a file

On a reconnect, when should I restore the info by calling the sd_ble_gatts_sys_attr_set during the connection event? It better not be later because an RACP transaction can come real fast!

Do I also need to write to the client characteristic configuration descriptors myself on reconnect to restore their 'enabled' state?

Parents
  • Hi,

    Unfortunately we do not have a bonding example for the pc-ble-driver. However serialization uses the same softdevice calls as the sdk does. In the SDK the Peer manager will create an event (PM_EVT_BONDED_PEER_CONNECTED) on connection that is forwarded to the gatts_cache_manager. This event will call a function local_db_apply_in_evt ( this will call gscm_local_db_cache_apply) that eventually results in sd_ble_gatts_sys_attr_set being called. Look at gatts_cache_manager.c:218

Reply
  • Hi,

    Unfortunately we do not have a bonding example for the pc-ble-driver. However serialization uses the same softdevice calls as the sdk does. In the SDK the Peer manager will create an event (PM_EVT_BONDED_PEER_CONNECTED) on connection that is forwarded to the gatts_cache_manager. This event will call a function local_db_apply_in_evt ( this will call gscm_local_db_cache_apply) that eventually results in sd_ble_gatts_sys_attr_set being called. Look at gatts_cache_manager.c:218

Children
  • Pairing is not the problem.I have no problems with pairing or encryption on a reconnect. The problem is saving the 'enabled' state of the descriptors. On the first time connect, the peer pairs and then sets the CCCDs for indications or notifications (as needed). I save that information according to the documentation. On a reconnect I restore it according to the documentation. As I understand it, the peer should NOT have to re-set the CCCDs. But if the peer does not reset the CCCDs, no data will be sent and I get the above errors. So either my understanding of the pairing/bonding procedure is incorrect, or something is wrong with the documentation on how to restore the CCCD data.

    I guess I should add that when following the sequence diagram that you mention I never get the BLE_GATTS_EVT_SYS_ATTR_MISSING event. I submitted a ticket on that some time ago, but have received no resolution. So I am assuming that approach (as in the sequence diagram) does not work and I am trying to do what is done in the handling of that event in the connection event. I have long given up on the BLE_GATTS_EVT_SYS_ATTR_MISSING event.

    https://devzone.nordicsemi.com/f/nordic-q-a/54039/why-don-t-i-get-a-ble_gatts_evt_sys_attr_missing-event/223027#223027

  • Yes, you are correct. The peer should not have to re-set the CCCD's or perform service discovery on a reconnect when it is bonded.

    However I am a bit confused, as you say you do not get the BLE_ERROR_GATTS_SYS_ATTR_MISSING event? But is the peer actually trying to read something in this case?

    Also in case you call sd_ble_gatts_hvx, you can get an BLE_ERROR_GATTS_SYS_ATTR_MISSING error message. This is also a case where you need to set the system attribute.

    However, since this is serialization. Can you collect the content using system attribute get command, first before esthablishing a connection at all, then on disconnect. And then again after setting them after reestablishing the bond. Just want to check that it is actually updated during the connection and that the last get matches what you received on disconnect.

  • There is a lot to filter through here. I will need to change my central to get back to testing these situations. Because of the problem, I have added code in my central that writes CCCDs EVERY connection, bonded or not, which is not ideal. However, there are health devices in the field which also have this bug.

    The problem with doing the 'set' and 'get' calls pre-connection is that the calls themselves require a connection handle which you don't get until a connection event.

    I know the first pass at doing this I had my set and get calls in the BLE_ERROR_GATTS_SYS_ATTR_MISSING event handler. But calling the sd_ble_gatts_hvx did not signal the event and the central did not receive the indications/notification. So I gave up that approach a long time ago and went for the setting during the connection event. Interestingly, when I read back what I set, it looks good.

    I am at an IHE connectathon at the moment so am a little tied when it comes to further testing.

  • Yes, you are right, you have to wait until the connection is established befor setting the system attribures. But you already confirmed the get looks good when you read it back after a write. So that is a bit strange. Are you using the flags or are you getting and restoring both system and user attributes? Note that it should be fine to set the attribute on connection,  I do not see a reason to wait for the system attribute missing event or error. However you should probably wait until the bond has been reestablished so you know you are setting the system attributes for a known device and not just someone who randomly connected.

    Note that calling sd_ble_gatts_hvx will not trigger an event. Instead it will return an error message with the error code

    BLE_ERROR_GATTS_SYS_ATTR_MISSING compared to the event

    BLE_GATTS_EVT_SYS_ATTR_MISSING which will be generated in case the peer tries to read a system attribute handle.

  • I do not know what will trigger the attrs missing event. It is never triggered.

    I have tried all combinations for the get and set. At the moment I am ORing all the available flags in the hope that I am getting both system and 'application' CCCD settings. From parsing the data (which is not the easiest to read) it looks like everything is there (service changed AND my app''s CCCDs).

    This prevents me from sending a service changed event ... it never works. But having the central re-set the CCCDs every connection works. A bad solution and not following the spec.

Related