Retrieving BLE characteristics from GATT server

Hello. I’m a beginner to Mbed, and have been tasking with writing an application to read Bluetooth data from a sensor. I am very new to developing for BLE, but have been reading as much Mbed documentation as I can find.

Starting with the Mbed BLE_GattClient_CharacteristicUpdates example, I have been able to see valid data from my sensor. However, I am not certain the best way to read the data directly from the Gatt Server. The example code only prints the value on an event, and doesn’t show how to retrieve the data on an as-needed basis.

The way I have been doing it is by inserting a function in the when_characteristic_changed and when_characteristic_changed functions of the example. My function checks to see if the read_event handle matches what data I’m looking for, and updates a local struct that holds sensor data.

From what I’ve read, the handles are not meant to be used this way. How am I supposed to read sensor data as-needed? I’d also rather do it based on the UUID, but the GattReadCallbacksParams do not hold the attribute UUID.

Any help would be appreciated, thank you!

I recommend also using the API reference to guide you: GattClient - API references and tutorials | Mbed OS 6 Documentation

In reality this is determined by the sensor. If the sensor offers a notification service then use it as this automatically triggers value updates once you’ve enabled to be notified, unless of course you’ve a specific reason for polling to read values.

So according to API documentation, if you want to read you’d use this function:

ble_error_t read ( ble::connection_handle_t connHandle,
GattAttribute::Handle_t attributeHandle,
uint16_t offset
) const

This initiate the read procedure of an attribute handle. Then once the attribute value has been read in its entirety, the process issues an attribute read event and passes it to all events handlers registered by onDataRead.

Thus you would also need to set up this callback function.

So in the example you attached, the read function is handled by

void read_characteristic(const DiscoveredCharacteristic &characteristic) { ... }

And the callback function is handled by

void when_characteristic_read(const GattReadCallbackParams *read_event) { ... }

Hope that helps.

Hi Gerriko,

Thank you for your reply. It looks like I have been doing this correctly then, as I have the when_characteristic_read and when_characteristic_changed functions checking the attribute handle and then updating the local data accordingly. I wasn’t sure if that was the right way to do it, since I’m checking the attribute handle and not the UUID. The UUIDs are in the datasheet of my device, but the attribute handles are not, so I assumed I was doing something wrong.

I am having an unrelated problem, where my system crashes upon reconnection with the device. I’ve narrowed this problem down to the function in the example when_descirptor_written, which triggers the error “Error: Received write response from unsolicited request” which then triggers the stop() function.

I seem to have been able to circumvent this by commenting out the stop() function, but I’m not sure why this is triggering at all. The comments show that “this should never happen.” I’m going to play around with it some more and then maybe create a new topic here if I can’t figure it out, unless you or someone else has an idea.

I want to make this system be able to reconnect automatically without issue, and I’m not familiar enough with BLE to know the best way to implement that.

Yes attribute handles are used, not UUID’s once connected.

Unfortunately, there is no clean way to handling auto reconnects as there are always going to be edge cases due to how connection checking is done and due to sporadic failures etc. So needs to be managed through custom error handling etc. as you’ve discovered if you want it to work more robustly. One aspect to review is to make sure you handle the disconnect process properly - some process take a while so need to check that these have completed (there are functions available for this). Then connection “bonding” is another option to consider as this can help speed up the connection and reconnection process too.