Discovering Gatt Parameters is stalling/crashing system system

Hello All,

I am programming an nrf52480 using zephyr on a windows machine.

I am trying to write a bluetooth peripheral characteristic, ore specifically to the led characteristic in the nordic led and button service.

In my code far I have verified:

  1. the central scanning mechanism works to find the peripheral device I want to attached to,
  2. filtering is working correctly such that I connect to the correct device.

Upon this step I didn't know how to write to the characteristic to turn on an led on the peripheral and I have determined the following steps need to be followed to write to a characteristic:

  1. I need to discover the characteristics that are attached with the uuid using the bt_gatt_discover function
  2. Once the desired characteristic is found using the discover_cb funciton that is set in the bt_gatt_discover funciton as a parameter structure then the handles value can be extracted.
  3. The characteristic handle value is used with bt_gatt_write_without_response function to transmit the data.

Please correct me if the above understanding is incorrect.

Given these steps I am getting stuck on step one.

The following is th ebackground for the steps I am taking before getting stuck. I think the issue is how I have implemented the bt_gatt_discover function:

  1. Once the filter match is done, the system automatically attempts to connect with the device at which point the scan_connecting callback function is called. INn my case this function just produces the logs.
    1. To my understanding the scan_connecting function is a call back before the actuatl connection is done.
  2. Once the connection to the peripheral is made the connected callbacck set using the bt_conn_cb_resiter funciton is called.
  3. In the connected callback I am attempting to call the bt_gatt_discover function.

My program either crashes or stalls when I call the bt_gatt)discover function. I think the issue is how or when I am calling this function because if I do not include it the logs for the connected callback function are outputted properly as shown below:

```

[00:01:07.612,884] <inf> button_control: IN the connected callback
[00:01:07.612,915] <inf> button_control: Bluetooth Connection Sucessfull
[00:01:07.612,915] <err> button_control: RIGHT BEFORE THE DISCOVER FUNCTION

```

Given this connected code:

```

void connected(struct bt_conn *conn, uint8_t err){
    LOG_INF("IN the connected callback");
    if (err < 0){
        LOG_ERR("Conection error has occured (err %d)", err);
    }

    LOG_INF("Bluetooth Connection Sucessfull");

    if(conn == NULL){
        LOG_ERR("The Conneciton ptr is not set properly");
    }

    static struct bt_uuid_128 uuid = BT_UUID_INIT_128(0);
    memcpy(&uuid, BT_UUID_LBS, sizeof(uuid));

    struct bt_gatt_discover_params discover_params = {
        .uuid = NULL,
        .func = discover_cb, //discover attribute callback
        .start_handle = 0x0001,
        .end_handle = 0xffff,
        .type = BT_GATT_DISCOVER_CHARACTERISTIC,
    };

    wrist_conn = conn;

    LOG_ERR("RIGHT BEFORE THE DISCOVER FUNCTION");
    // int result = bt_gatt_discover(conn, &discover_params);
    // if (result < 0) {
    //  LOG_ERR("Error occured when discovering the bluetooth services (err: %d)", result);
    // }
};

```

When I uncomment the bt_gatt_discover line as below:

```

void connected(struct bt_conn *conn, uint8_t err){
    LOG_INF("IN the connected callback");
    if (err < 0){
        LOG_ERR("Conection error has occured (err %d)", err);
    }

    LOG_INF("Bluetooth Connection Sucessfull");

    if(conn == NULL){
        LOG_ERR("The Conneciton ptr is not set properly");
    }

    static struct bt_uuid_128 uuid = BT_UUID_INIT_128(0);
    memcpy(&uuid, BT_UUID_LBS, sizeof(uuid));

    struct bt_gatt_discover_params discover_params = {
        .uuid = NULL,
        .func = discover_cb, //discover attribute callback
        .start_handle = 0x0001,
        .end_handle = 0xffff,
        .type = BT_GATT_DISCOVER_CHARACTERISTIC,
    };

    wrist_conn = conn;

    LOG_ERR("RIGHT BEFORE THE DISCOVER FUNCTION");
    int result = bt_gatt_discover(conn, &discover_params);
    if (result < 0) {
        LOG_ERR("Error occured when discovering the bluetooth services (err: %d)", result);
    }

};

```

I get the following log output (the connected function doesn't provide it's log)

```
[00:00:06.744,781] <inf> button_control: Connected in the Scan Connecting callback

```

What is going on? What is incorrect about my thinking and code? Any guidance on this would be much appreciated.

the below are the important pieces of code then settingup the bluetooth connection in the bluetooth_control.c file:

```

/** @brief Scan event handler function to handle with filter passed devices
 *
 *  The following are the situations that can be set to check in the @ref bt_scan_filter match struct:
    1. name //will the filter work like a contain function or a hard name?
    2. short_name x
    3. addr x
    4. uuid //using the lbs service uuid
    5. appearance x
    6. manufacturer_data x
 *  
 *  @param device_info ptr to structure that holds device data to make a connection
 *  @param bt_scan_filter_match ptr to a struct that holds the information of filter matches for a device. Would change based on the filter opetions used
 *  @param connectable  inform the central that the device is connectable.
 *  
*/
void scan_filter_match(struct bt_scan_device_info *device_info, struct bt_scan_filter_match *filter_match, bool connectable)
{
    // Handle filter match event
    //assume anything with a uuid and a name that are filtered will work.
    int err;
   
    if (filter_match->short_name.match){
        LOG_INF("NAME: ");
        for (int i = 0; i < filter_match->short_name.len; i++){
            LOG_INF("%c", filter_match->short_name.name[i]);
        }
        LOG_INF("\n");
    }

    if(filter_match->uuid.match){
        LOG_INF("UUID: ");
        for (int i = 0; i < filter_match->uuid.count; i++){
            LOG_INF("%d", filter_match->uuid.uuid[i]->type); // Logging as hexadecimal
            if (filter_match->uuid.uuid[i]->type == BT_UUID_TYPE_128) {
                LOG_INF("128 bit uuid found");
                struct bt_uuid_128 *u128 = (struct bt_uuid_128 *)filter_match->uuid.uuid;
                LOG_INF("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
                        // u128->val[0], u128->val[1], u128->val[2], u128->val[3],
                        // u128->val[4], u128->val[5],
                        // u128->val[6], u128->val[7],
                        // u128->val[8], u128->val[9],
                        // u128->val[10], u128->val[11], u128->val[12], u128->val[13], u128->val[14], u128->val[15]
                       
                        u128->val[15], u128->val[14], u128->val[13], u128->val[12],
                        u128->val[11], u128->val[10],
                        u128->val[9], u128->val[8],
                        u128->val[7], u128->val[6],
                        u128->val[5], u128->val[4], u128->val[3], u128->val[2], u128->val[1], u128->val[0]
                        );
                LOG_INF("END OF UUID 128 bit");
            }
        }
    }

    if(filter_match->name.match){
        LOG_INF("NAME: ");
        for (int i = 0; i < filter_match->name.len; i++){
            LOG_INF("%c", filter_match->name.name[i]);
        }

        LOG_INF("\n");
    }

   

    //two options: perform a manual connect operation or allow the auto connect to work?
    if (connectable) {
        struct bt_conn *conn;
        err = bt_conn_le_create(device_info->recv_info->addr,
                                BT_CONN_LE_CREATE_CONN,
                                device_info->conn_param,
                                &conn);

        if (!err){
            if (!err) {
                default_conn = bt_conn_ref(conn);
                bt_conn_unref(conn);
            }
        }
    }



   
};

/** @brief Scan event handler function to handle with non filter passed devices
 *         The device information is simpley outputed for debugging purposes.
 *  
 *  @param device_info ptr to structure that holds device data to make a connection
 *  @param connectable  inform the central that the device is connectable.
 *  
*/

void scan_filter_no_match(struct bt_scan_device_info *device_info, bool connectable)
{
    // Handle filter no match event
    // LOG_ERR("DEVICE WITH ALL FILTERS NOT FOUND\n");
};

/** @brief Event handler runnign when a connection is made. Output the status of the connection.
 *          - what device is connected to
 *          - status of the connection
 *          
 *  
 *  @param device_info ptr to structure that holds device data to make a connection
 *  @param conn ptr to connection info
 *  
*/

void scan_connecting(struct bt_scan_device_info *device_info, struct bt_conn *conn)
{
    LOG_INF("Connected in the Scan Connecting callback\n");

    if(conn == NULL){
        LOG_ERR("The Conneciton ptr is not set properly");
    }

    // static struct bt_uuid_128 uuid = BT_UUID_INIT_128(0);
    // memcpy(&uuid, BT_UUID_LBS, sizeof(uuid));

    // struct bt_gatt_discover_params discover_params = {
    //  .uuid = &uuid.uuid,
    //  .func = discover_cb, //discover attribute callback
    //  .start_handle = 0x0001,
    //  .end_handle = 0xffff,
    //  .type = BT_GATT_DISCOVER_CHARACTERISTIC,
    // };

    // wrist_conn = conn;

    // int result = bt_gatt_discover(conn, &discover_params);
    // if (result < 0) {
    //  LOG_ERR("Error occured when discovering the bluetooth services (err: %d)", result);
    // }
};

/** @brief Event handler runnign when a connection has failed.
 *          Output:
 *          - what device was attempted to connect to
 *          - Error/reason for the connection failing
 *          
 *  @param device_info ptr to structure that holds device data to make a connection
 *  
*/

void scan_connecting_error(struct bt_scan_device_info *device_info)
{
    LOG_ERR("Failed to Connect\n");
};

/** @brief Macro for establishing the scan callbacks for when scanning is started
 *          
 *  @param _name scan_cb name of the bt_can_cb structure that is made
 *  @param match_fun scan_filter_match function handler for when filters match
 *  @param no_match_fun function handler for when filters do not match a device
 *  @param err_fun handler for handling error if connection failed (connect_if_match flag in the scan param must be set for connect to occur with this callback)
 *  @param connecting_fun handler for when a connection occurs (connect_if_match flag must be present)

*/

BT_SCAN_CB_INIT(scan_cb, scan_filter_match, scan_filter_no_match, scan_connecting_error, scan_connecting);

/** @brief starting the discovery of the services after a central connection is made
 *
 *  @param  bt_conn * conn: struct holding the connectin parameters
 *  @param  err if error in connection has occured
 *            
*/

void connected(struct bt_conn *conn, uint8_t err){
    LOG_INF("IN the connected callback");
    if (err < 0){
        LOG_ERR("Conection error has occured (err %d)", err);
    }

    LOG_INF("Bluetooth Connection Sucessfull");

    if(conn == NULL){
        LOG_ERR("The Conneciton ptr is not set properly");
    }

    static struct bt_uuid_128 uuid = BT_UUID_INIT_128(0);
    memcpy(&uuid, BT_UUID_LBS, sizeof(uuid));

    struct bt_gatt_discover_params discover_params = {
        .uuid = NULL,
        .func = discover_cb, //discover attribute callback
        .start_handle = 0x0001,
        .end_handle = 0xffff,
        .type = BT_GATT_DISCOVER_CHARACTERISTIC,
    };

    wrist_conn = conn;

    LOG_ERR("RIGHT BEFORE THE DISCOVER FUNCTION");
    int result = bt_gatt_discover(conn, &discover_params);
    if (result < 0) {
        LOG_ERR("Error occured when discovering the bluetooth services (err: %d)", result);
    }
};

/** @brief starting the discovery of the services after a central connection is made
 *
 *  @param  bt_conn * conn: struct holding the connectin parameters
 *  @param  reason error code for why disconnected occured  
*/

void disconnected(struct bt_conn *conn, uint8_t reason){
    LOG_ERR("Disconnection occured. (err: %d)", reason);
    wrist_conn = NULL;
    ledHandleReady = false;
};

/** @brief callback funciton to address cycling through characteristics of the incoming connection
 *
 *  Want to find the led characteristic of the led service then get the required information
 *
 *  @param bt_conn *conn: ptr to the connection parameters needed for a bluetooth conneciton
 *  @param bt_gatt_attr *attr: the gatt attribute that is found currently
 *  @param bt_gatt_discover_params *params: Discovery parameters that are given
 *  
 */

uint8_t discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params){
    LOG_INF("IN THE DISCOVERY CALLBACK");
    if(attr == NULL){
        LOG_INF("Discovery complete");
        return BT_GATT_ITER_STOP;
    }

    //set the struct for a characteristic
    struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data;

    if(bt_uuid_cmp(chrc->uuid,BT_UUID_LBS_LED) == 0) {
        led_handle = chrc->value_handle;
        LOG_INF("LED characteristic handle: %u", led_handle);
        ledHandleReady = true;
        return BT_GATT_ITER_STOP;  
    }

    return BT_GATT_ITER_CONTINUE;
    // return BT_GATT_ITER_STOP;
};

```

The below is my bluetooth implementation in my main.c file:

```

//--------------SCAN TESTING START---------------------//

        // int err = 0;
        err = bt_enable(bt_ready_cb);
        if (err) {
                LOG_ERR("Bluetooth init failed (err %d)", err);
                return 0;
        }

        struct bt_conn_cb cb = {
                .connected = connected,
                .disconnected = disconnected,
        };

        bt_conn_cb_register(&cb);

        while(!btReady);

        const struct bt_scan_init_param bt_scan_init_opts = {
                        .scan_param = NULL, //default config
                        .connect_if_match = true,
                        .conn_param = NULL, //default config
        };
       
        bt_scan_init(&bt_scan_init_opts);
        BT_SCAN_CB_INIT(scan_cb, scan_filter_match, scan_filter_no_match, scan_connecting_error, scan_connecting);
        bt_scan_cb_register(&scan_cb);

        //--------------------UUID FILTER

        err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, BT_UUID_LBS);
        if (err) {
                LOG_ERR("UUID scanning filters cannot be set (err %d)", err);
                return err;
        }

        //------------------SHORT NAME FILTER

        // struct bt_scan_short_name short_name_filter_data = {
        //         .name = TARGET_DEVICE_NAME,
        //         .min_len = sizeof(TARGET_DEVICE_NAME),
        // };

        // err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_SHORT_NAME,&short_name_filter_data);
        // if (err) {
        //      LOG_ERR("Short Name scanning filters cannot be set (err %d)", err);
        //      return err;
        // }

        //------------------NAME FILTER
        err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_NAME, TARGET_DEVICE_NAME);
        if (err) {
                LOG_ERR("Name scanning filters cannot be set (err %d)", err);
                return err;
        }


        err = bt_scan_filter_enable(BT_SCAN_UUID_FILTER | BT_SCAN_NAME_FILTER, true);
        // err = bt_scan_filter_enable(BT_SCAN_NAME_FILTER, true);

        if (err) {
                LOG_ERR("Filters cannot be turned on (err %d)", err);
                return err;
        }

        LOG_INF("Scan module initialized");


        err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
        if (err) {
                LOG_ERR("Scanning failed to start (err %d)", err);
                return 0;
        }

        LOG_INF("Scanning successfully started");

        //--------------SCAN TESTING END---------------------//

```

I have also attached the full main.c and the bluetooth_control.c files as well for your reference.

Parents
  • Hi genmastermega,

    I will analyze this and come back to you in a couple of days.

    From the function names, it seems like you based your application on one of the samples. Could you please let me know what sample that is?

    Hieu

Reply
  • Hi genmastermega,

    I will analyze this and come back to you in a couple of days.

    From the function names, it seems like you based your application on one of the samples. Could you please let me know what sample that is?

    Hieu

Children
  • Hello Hieu,

    To be honest, I don't remember. I looked at many resources when compiling the code to make sure that I was getting the structure correct. The (main) error was that I was referencing memory of the discover_params that would de allocate as soon as the bt_gatt_discover function would run.