Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Attempting to print out device name data with "device_found()" in "central_hrs"

Hi,

I am trying to modify the Zephyr central_hrs module so that it will print out the name of any peripheral it discovers and eventually store them in some 2D array. The problem is that I can't get it to work properly. I found this post:  How to read advertising BLE devices' name? which does let you print out device names. The issue is that they are using the generic "central" example and bt_data_parse() eats the pointer to the advertisement data you give it so it can't be reused. In "central_hr" you already have an essential call to bt_data_parse() in order to establish a connection. The obvious solution to this is to create "struct net_buf_simple ad_temp" and copy the advertisement data structure into it but all attempts to do so have failed. Everything I have tried has either given me a memory fault or or just given me garbled characters. I also tried modifying the existing bt_data_parse() callback function in "central_hr" but to little success. I don't know if this is more a zephyr or a straight up C fundamentals question but any help copying the advertisement data into a temporary net_buf_simple struct would be greatly appreciated. I will post the relevant code I have below: 

This is the central_code. In this state it the code seems to memory fault and I am not sure why:

static bool eir_found(struct bt_data *data, void *user_data)
{
    bt_addr_le_t *addr = user_data;
    int i;

    printk("[AD]: %u data_len %u Actual Data: %u\n", data->type, data->data_len, data->data);

    switch (data->type) {
    case BT_DATA_UUID16_SOME:
    case BT_DATA_UUID16_ALL:
        if (data->data_len % sizeof(uint16_t) != 0U) {
            printk("AD malformed\n");
            return true;
        }

        for (i = 0; i < data->data_len; i += sizeof(uint16_t)) {
            struct bt_le_conn_param *param;
            struct bt_uuid *uuid;
            uint16_t u16;
            int err;

            memcpy(&u16, &data->data[i], sizeof(u16));
   
            uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16));
            if (bt_uuid_cmp(uuid, BT_UUID_HRS)) {
                continue;
            }

            err = bt_le_scan_stop();
            if (err) {
                printk("Stop LE scan failed (err %d)\n", err);
                continue;
            }

            param = BT_LE_CONN_PARAM_DEFAULT;
            err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
                        param, &default_conn);
            if (err) {
                printk("Create conn failed (err %d)\n", err);
                start_scan();
            }

            return false;
        }
    }

    return true;
}

static bool data_cb2(struct bt_data *data, void *user_data){

    char *name = user_data;

    switch(data->type){
        case BT_DATA_NAME_SHORTENED:
        case BT_DATA_NAME_COMPLETE:
            memcpy(name, data->data, MIN(data->data_len, NAME_LEN - 1));
            return false;
        default:
            return false;
    }
}

static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
             struct net_buf_simple *ad)
{
    char dev[BT_ADDR_LE_STR_LEN];
    char name[30];
    struct net_buf_simple ad_temp;
   
    memcpy(&ad_temp, ad->data, net_buf_simple_max_len(ad->len));

    bt_addr_le_to_str(&addr, dev, sizeof(dev));

    bt_data_parse(&ad_temp, data_cb2, name);
    printk("Device found: %s \n", *name);

    printk("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n",
           dev, type, ad->len, rssi);

    /* We're only interested in connectable events */
    if (type == BT_GAP_ADV_TYPE_ADV_IND ||
        type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
        bt_data_parse(ad, eir_found, (void *)addr);
    }
}

And then here is the relevant stuff on the peripheral code:

static const struct bt_data ad[] = {
    BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    BT_DATA_BYTES(BT_DATA_UUID16_ALL,
              BT_UUID_16_ENCODE(BT_UUID_HRS_VAL),
              BT_UUID_16_ENCODE(BT_UUID_BAS_VAL),
              BT_UUID_16_ENCODE(BT_UUID_DIS_VAL))
};
static void bt_ready(void)
{
    int err;

    printk("Bluetooth initialized\n");

    err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
    if (err) {
        printk("Advertising failed to start (err %d)\n", err);
        return;
    }

    printk("Advertising successfully started\n");
}
Parents Reply Children
  • Thanks! Looking through that got me to net_buf_simple_clone(buf, &buf_copy); which is helpful. Unfortunately, I am still not able to print anything intelligible even with the properly copied buffer. Still prints out garbage despite trying to copy the code you pointed me to as closely as possible. I have since discovered that if I comment out "bt_data_parse(ad, eir_found, (void *)addr);" the name prints properly. Of course that's kinda a non-starter bc I need eir_found to connect and I am not sure why it is doing that. Is there some reason why having that second bt_data_parse() in there would be a problem?

  • UPDATE: I managed to figure this out. I havn't gotten this exact implementation to working buy by shoving the device name in the advertisement data and then folding data_cb2 into eir_found I was able to get it printing out the peripheral name. I can share code if anyone would like.

Related