Caching service discovery results for faster reconnects

Hi,

I'm working on a BLE Central application running on the nRF52840 using nRF Connect SDK. It connects to mice/keyboards and uses the HIDS Client functions (bt_hogp_*). A Bluetooth mouse will usually go to sleep and disconnect when not used for some time and then reconnect (start advertising) when moved. I've noticed that while reestablishing the connection itself is fairly quick, doing the service discovery on each reconnect takes a noticeable amount of time. From what I understand, it is standard practice for a Central device to cache the service discovery results and reuse them when reconnecting to a previously bonded peer for precisely this reason. But I am at a loss as to how to achieve it with the nRF Connect SDK. I can see the Service Changed indication being used in the ANCS sample, but it doesn't seem like it's actually caching the discovered services.

Is this something I should expect the stack/library to be doing for me? Or could I do that myself in application code somehow?

(To be clear, I'm not talking about the GATT Caching introduced in Bluetooth 5.1, just the older mechanism that I believe exists since 4.0.)

Parents
  • Hi,

    This should be enabled by default (by CONFIG_BT_GATT_CACHING). Have you disabled that, or done some other changes? Or does the central indicate service changed (which will then cause a re-discovery)? There are also some adjustments you can do to write immediately to flash, like settings CONFIG_BT_SETTINGS_CCC_STORE_ON_WRITE=y and CONFIG_BT_SETTINGS_CCC_LAZY_LOADING=n.

  • I'm a bit confused. Perhaps I wasn't clear enough on what I'm trying to do.

    From what I can tell CONFIG_BT_GATT_CACHING seems to control the "5.1" GATT Caching feature, the thing I'm NOT trying to do.

    Again, here's what I'm doing. I'm writing the Central/Client side, the Peripheral/Server is an off-the-shelf mouse or keyboard.

    After connecting to the peripheral, in the security changed callback, I'm calling bt_gatt_dm_start().

    In the discovery completed callback, I'm calling bt_hogp_handles_assign().

    Then in the hogp ready_cb, I'm iterating over the reports and calling bt_hogp_rep_subscribe() on each.

    Basically what the central_hids sample is doing.

    As I understand it, this results in extra radio traffic on every reconnect, even though the service structure of the device doesn't change, meaning that it takes longer than it could if I just reused all the information that I could store after the initial bonding. How do I do that?

  • Hi,

    You are right, this is not at all as simple as I expected, in fact it is not currently supported and therefor not used by the nRF Dekstop (HID mouse/keyboard) reference design either. I checked with the team that maintains the nRF Desktop, and this is currently far from trivial in Zephyr, and some work has to be done in order to support it.

  • Ah, I see. Thank you for checking.

    I did come up with a sort of a solution, but it's a bit of a dirty hack so I don't necessarily recommend anyone uses it.

    It turns out that if I don't call bt_hogp_release() on disconnect, but instead keep the bt_hogp structure around and after a reconnect don't do any discovery and don't call bt_hogp_handles_assign(), but just update the bt_hogp structure with the current connection handle (bt_conn) and subscribe to the reports, it all just works. The only trick is that you have to set notify_cb to NULL in each report before calling bt_hogp_rep_subscribe().

    There are probably some unwanted consequences of this method that I'm currently missing and it also doesn't speed up the first connection after reboot, because I'm not persisting anything to flash, but for now I think I can live with it.

Reply
  • Ah, I see. Thank you for checking.

    I did come up with a sort of a solution, but it's a bit of a dirty hack so I don't necessarily recommend anyone uses it.

    It turns out that if I don't call bt_hogp_release() on disconnect, but instead keep the bt_hogp structure around and after a reconnect don't do any discovery and don't call bt_hogp_handles_assign(), but just update the bt_hogp structure with the current connection handle (bt_conn) and subscribe to the reports, it all just works. The only trick is that you have to set notify_cb to NULL in each report before calling bt_hogp_rep_subscribe().

    There are probably some unwanted consequences of this method that I'm currently missing and it also doesn't speed up the first connection after reboot, because I'm not persisting anything to flash, but for now I think I can live with it.

Children
No Data
Related