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.

  • DiBosco said:
    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!

    Thanks, I just had to make sure Slight smile

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

    You can press Ctrl+Shift+f to open the search window and search across all files. Make sure the SDK folder is included in your VS Code workspace and not only your project for this to work.

    DiBosco said:
    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?

    Like with the nus_client.c implementation, the heart rate client  also provides callbacks that can be registered by an application to receive data and events from the service. This part is not relevant in your case, what is relevant to look at is what parameters are passed to bt_gatt_read() and how the attribute handle for this characteristic is found through service discovery. The other parts of the code is mostly specific to interfacing with the standard Heart Rate service.

    bt_gatt_read_params struct that needs to be passed to bt_gatt_read():

  • I'm still not getting this I'm afraid:


    My code:

    /** @brief CUSTOM Client structure. */
    struct bt_custom_client
    {
    struct bt_conn *conn; // Connection object.
    atomic_t state; // Internal state.
    /** Handles on the connected peer device that are needed
    * to interact with the device.
    */
    struct bt_custom_client_handles handles;

    /** GATT subscribe parameters for CUSTOM TX Characteristic. */
    struct bt_gatt_subscribe_params tx_notif_params;

    /** GATT write parameters for CUSTOM RX Characteristic. */
    struct bt_gatt_subscribe_params rx_notif_params;
    struct bt_gatt_write_params tx_write_params;

    // GATT discovery
    struct bt_gatt_subscribe_params association_parameters;

    };
    The heart rate demo:

    /**@brief Heart Rate Service Client instance structure.
    * This structure contains status information for the client.
    */
    struct bt_hrs_client
    {
    /** Connection object. */
    struct bt_conn *conn;

    /** Heart Rate Measurement characteristic. */
    struct bt_hrs_client_hr_meas measurement_char;

    /** Sensor Body Location characteristic. */
    struct bt_hrs_client_body_sensor_location sensor_location_char;

    /** Heart Rate Control Point characteristic. */
    struct bt_hrs_client_control_point cp_char;

    /** Internal state. */
    atomic_t state;
    };

    In hrd_client.c

    params = &hrs_c->sensor_location_char.read_params;
     
    So the demo has this sensor_location_char which is of type

    struct bt_hrs_client_body_sensor_location

    Whereas my code has structs

    bt_gatt_subscribe_params
    bt_gatt_write_params

    These looko like system structs as opposed to the heart
    rate which look like custom ones

    The one I want to read is:

    struct bt_gatt_subscribe_params association_parameters;

    But I've realised that bt_gatt_subscribe_params
    is almost definitely wrong. Also it's surely not:

    bt_gatt_write_params

    So am I needing to create a custom struct like this:

    struct bt_custom_association_struct
    {
    /** 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;
    };

    But with a different callback. Maybe this:

    typedef uint8_t (*on_association_value_read)(struct bt_conn *conn, uint8_t err,
    struct bt_gatt_read_params *params,
    const void *data, uint16_t length);

    I don't understand what

    bt_gatt_subscribe_params
    bt_gatt_write_params

    Are for and why they are different to the
    heart rate one which seems to have all custom structs

    I'm not at all sure I've asked a good question here.




  • I also don't get why when I put things in an inline code block on this forum it looks so wrong.

  • You can use the "insert" option in the editor to insert a code snippet. This provides better code formatting.

    These looko like system structs as opposed to the heart
    rate which look like custom ones

    The bt_hrs_client_body_sensor_location struct defined by the hrs client contains elements relevant to the body sensor location characteristic for this implementation. This includes the bt_gatt_read_params struct and a callback function which is registered by the application to receive read responses.

    Are you able to share your current project here or in a private ticket so I can have a look? If so, please zip the project directory and upload the zip file.

  • OK, I have got it going. Out of desperation I made a custom struct up with only a handle and

    struct bt_gatt_read_params read_params;

    And that now works; I can read the value. There's still bits
    I don't understand, but if it works I shouldn't worry too much
    about it.

    I'm not too far off having the whole thing
    working now I think. (Famous last words!)

    Many thanks again for the patience and the help.

Related