How to read a characteristic - just read, not get a notification. As a client

After a lot of help, I've managed to get a central_uart with custom UUIDs going.

After stripping out as much unwanted code and callback functions as possible, moving UART and BLE code  into their own files, getting rid of all mallocs and unnecessary queues, without all that noise, I think I now finally just about understand how all the stuff knits together and basically understand  how you, as a client, get data off a server. At least, if you subscribe to a characteristic.

In this particular instance, I need to read  one more two byte characteristic, but not subscribe to get notification of change. That characteristic will be set to a value before I try to connect to the remote unit and it will not change after that. So, how can I, as a client, simply read the value in a characteristic on a server?

I've tried searching for this and the closest I can find is this:

How to correctly read from a Characteristic

But it makes no sense to me. It says call:

sd_ble_gattc_read

But that doesn't, as  far as I can see actually read the data that's in the characteristic. It returns a  32-bit value indicating success of failure (which really should be an enum IMHO), but not data. So what do you call to get the data out of the characteristic on the server?


Also, for that function call in the API details on line it says:

offset    Offset into the attribute value to be read.

What does that even mean?

Am assuming conn_handle and handle are found when you do the gatt_discover.

As with all these things with this ecosystem it would be really useful to have very basic, clearly written examples. Maybe there is one somewhere, but I can't find it.

Thanks.

  • Hello,

    You can perform a GATT read using the bt_gatt_read() function. You can find several examples of this API being used by searching the through SDK tree in VS code:

    For example, here in the hrs_client.c file: https://github.com/nrfconnect/sdk-nrf/blob/67c885fb8d2d73067c77e0d105d8a88a8fbfca6c/subsys/bluetooth/services/hrs_client.c#L270 

    Best regards,

    Vidar

  • Hi, thanks for that.

    Like all this code I just find it impossible to follow.

    Before we get to that though, how do I get this SDK tree? I can't find anything like that in my VSC.

    So, let's go look at that function:

    int bt_hrs_client_sensor_location_read(struct bt_hrs_client *hrs_c,
                          bt_hrs_client_read_sensor_location_cb read_cb)

    I think this isn't actually reading, it's just setting up yet another callback function to be called once the read has been done?

    We're passing a pointer to a struct of bt_hrs_client which in my case I think is the  bt_custom_client that you came up with for me.

    I really struggle here. This is defined in hrs_cleint.h as :

    typedef void (*bt_hrs_client_read_sensor_location_cb)(struct bt_hrs_client *hrs_c,
                                  enum bt_hrs_client_sensor_location location,
                                  int err);

    Why is this callback function  necessary? Later on there is this:

    params->func = on_hrs_sensor_location_read;

    Which I am guessing is saying that once the characteristic has been read on  the remote node, then call the function:

    on_hrs_sensor_location_read

    Where you can get the data in the characteristic?

    I can't find where:

    struct bt_hrs_client_body_sensor_location  is filled. I'm guessing that in this:

    struct bt_hrs_client_body_sensor_location {
        /** Value handle. */
        uint16_t handle;

        /** Read parameters. */
        struct bt_gatt_read_params read_params;

        /** Read complete callback. */
        bt_hrs_client_read_sensor_location_cb read_cb;
    };

    handle is what was discovered in the gatt discovery for that particular UUID?

    Ideally I'd get rid of that callback.

    So then we check for NULL pointer I think with:

    (!hrs_c || !read_cb) which should read

    if (NULL == hrs_c) || (NULL == read_cb) ?

    Then there's this:

    if (!bt_hrs_client_has_sensor_location(hrs_c))

    Which I don't understand at all

    Then:

    if (atomic_test_and_set_bit(&hrs_c->state, HRS_SENSOR_LOCATION_READ_IN_PROGRES))

    I've seen this in a few places. I'm guessing this is doing the equivalent of this?

    Also, HRS_SENSOR_LOCATION_READ_IN_PROGRES is defined in hrs_client.h along with some other things:

    #define HRS_MEASUREMENT_NOTIFY_ENABLED BIT(0)
    #define HRS_MEASUREMENT_READ_IN_PROGRES BIT(1)
    #define HRS_SENSOR_LOCATION_READ_IN_PROGRES BIT(2)
    #define HRS_CONTROL_POINT_WRITE_PENDING BIT(3)

    But where does this come form, how are these assigned and how
    do they correspond to my custom_client setup please?



    ---------------------------------------------------------------

    bool ret_val;
    uint32_t value;
    ret_val = true;
    value = hrs_c->state

    hrs_c->state |= (1 << HRS_SENSOR_LOCATION_READ_IN_PROGRES);
    if (0 == (value & (1 << HRS_SENSOR_LOCATION_READ_IN_PROGRES)))
         ret_val = false;
    return ret_val;

    ---------------------------------------------------------------

    I'm guessing it's looking to see if a read's already in progress and if not, kicking one off.

    Then we come to assigning this first callback:

    hrs_c->sensor_location_char.read_cb = read_cb;

    Which I don't get.

    And I start to lose the trail with this even more:

    So there's a struct of type bt_gatt_read_params:

    I can see that in gatt.h but don't understand what some of the values do.

    There's yet another callback and I could just about understand func being needed to be called when the read was done, is that right?

    But there's this offset again which I have no idea about.
    Again the handle which I guess comes from gatt discovery but what is  handle_count for?


    And then I have a lack of knowledge of what calls bt_hrs_client_sensor_location_read, what should be passed to it and what the callback function(s) look like for when it's actually read.

    I can't find anything that calls bt_hrs_client_sensor_location_read and maybe that comes from not knowing how to get at this SDK tree.

    Am thinking that actually I don't really have a semi decent grip on how all this knits together yet.

    Thanks

  • ...

    Should I ignore your previous comment, or are you referring to an edit you made?

  • Should I ignore your previous comment, or are you referring to an edit you made

    Smiley I still need the previous, long post answering please, the second one, I altered because I realised what had happened and didn't need it answering!

Related