Can't get BLE extended connectable advertising timeout callback

Using SDK 2.1.2

Trying to set up connectable advertising for specific period of time and be notified when this period of time expired.
My setup sequence (simplified for demonstration purpose):

struct bt_le_ext_adv_cb ext_adv_cb = {
.sent = adv_timed_out,
};

static struct bt_conn_cb conn_callbacks = {
.connected = connected,
.disconnected = disconnected,
.security_changed = security_changed,
};
 

Init (one time at boot):
------
bt_conn_cb_register(&conn_callbacks);
bt_conn_auth_cb_register(&conn_auth_callbacks);
bt_conn_auth_info_cb_register(&auth_cb_info);
bt_enable(NULL);
settings_load();
bt_nus_init(&nus_cb);
struct bt_le_adv_param *adv_param = BT_LE_ADV_CONN;
bt_le_ext_adv_create(adv_param, &ext_adv_cb, out_adv);
bt_le_ext_adv_set_data(...);


Start advertising (every time I want to give opportunity to my central device to connect):
----------------------
#define BLE_CONN_ADV_TIMEOUT (4 * 100) // 4 sec in 10ms units
param = BT_LE_EXT_ADV_START_PARAM(BLE_CONN_ADV_TIMEOUT, 0); 
bt_le_ext_adv_stop(adv);  // JIC there is a previous advertisement in progress
bt_le_ext_adv_start(adv, param);


If connection happens, I receive both bt_conn_cb.connected and subsequent .disconnected callbacks 
If no connection happened within 4 seconds I would expect (perhaps mistakenly) to receive bt_le_ext_adv_cb.sent callback, but it doesn't happen.

Interestingly, if I change my advertising to non-connectable, and set param as
param = BT_LE_EXT_ADV_START_PARAM(0, 3);

then I do receive this .sent callback, and info->num_events is correctly set to 3.

Looking at zephyr/include/zephyr/bluetooth/bluetooth.h

struct bt_le_ext_adv_cb {
/**
* @brief The advertising set has finished sending adv data.
*
* This callback notifies the application that the advertising set has
* finished sending advertising data.
* The advertising set can either have been stopped by a timeout or
* because the specified number of advertising events has been reached.
*
* @param adv The advertising set object.
* @param info Information about the sent event.
*/
void (*sent)(struct bt_le_ext_adv *adv,  <-----------------------
struct bt_le_ext_adv_sent_info *info);

it appears that it should work on either timeout or number of events

What am I missing ?



Parents
  • Hi

    Okay, so we were able to add this on our end after a bit trial and error. Here is the relevant source code and configs (tested on NCS 2.1.1):

    main.c

    /*
     * Copyright (c) 2021 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    /** @file
     *  @brief Peripheral example
     */
    
    #include <zephyr/types.h>
    #include <stddef.h>
    #include <string.h>
    #include <errno.h>
    #include <sys/printk.h>
    #include <zephyr.h>
    
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/conn.h>
    #include <bluetooth/uuid.h>
    #include <bluetooth/gatt.h>
    
    #include <logging/log.h>
    LOG_MODULE_REGISTER(app, CONFIG_LOG_DEFAULT_LEVEL);
    
    
    #define BLE_INT                         (0x140) // N * 0.625. corresponds to dec. 320; 320*0.625 = 200ms
    #define BLE_ADV_TIMEOUT                 (1000)  // N * 10ms for advertiser timeout
    #define BLE_ADV_EVENTS                  (0)
    
    static struct k_work start_advertising_worker;
    
    static struct bt_le_ext_adv *adv;
    
    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, 0x0d, 0x18, 0x0f, 0x18, 0x0a, 0x18),
    };
    
    #if defined(CONFIG_BT_PERIPHERAL)
    
    static void connected(struct bt_conn *conn, uint8_t conn_err)
    {
        int err;
        struct bt_conn_info info;
        char addr[BT_ADDR_LE_STR_LEN];
    
        bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
        if (conn_err) {
            printk("Connection failed (err %d)\n", conn_err);
            return;
        }
    
        err = bt_conn_get_info(conn, &info);
    
        if (err) {
            printk("Failed to get connection info\n");
        } else {
            const struct bt_conn_le_phy_info *phy_info;
            phy_info = info.le.phy;
    
            printk("Connected: %s, tx_phy %u, rx_phy %u\n",
                   addr, phy_info->tx_phy, phy_info->rx_phy);
        }
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
        printk("Disconnected (reason 0x%02x)\n", reason);
    
        k_work_submit(&start_advertising_worker);
    }
    
    static struct bt_conn_cb conn_callbacks = {
        .connected = connected,
        .disconnected = disconnected,
        
    };
    
    #endif /* defined(CONFIG_BT_PERIPHERAL) */
    
    
    static void adv_sent(struct bt_le_ext_adv *instance,
                 struct bt_le_ext_adv_sent_info *info)
    {   
        //printk("Advertising stopped. num_sent: %d ", info->num_sent);
        LOG_INF("Advertising stopped");
    }
    
    static int create_advertising(void)
    {
        int err;
        struct bt_le_adv_param param =
            BT_LE_ADV_PARAM_INIT(
                         BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_USE_NAME,
                         BLE_INT,
                         BLE_INT,
                         NULL);
    
        static const struct bt_le_ext_adv_cb adv_cb = {
            .sent = adv_sent,
        };
    
        err = bt_le_ext_adv_create(&param, &adv_cb, &adv);
        if (err) {
            printk("Failed to create advertiser set (%d)\n", err);
            return err;
        }
    
        printk("Created adv: %p\n", adv);
    
        err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
        if (err) {
            printk("Failed to set advertising data (%d)\n", err);
            return err;
        }
    
        return 0;
    }
    
    static void start_advertising(struct k_work *item)
    {
        int err;
    
        err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_PARAM(BLE_ADV_TIMEOUT, BLE_ADV_EVENTS));
        if (err) {
            printk("Failed to start advertising set (%d)\n", err);
            return;
        }
    
        //printk("Advertiser %p set started\n", adv);
        LOG_INF("Advertising started");
    }
    
    static void bt_ready(void)
    {
        int err = 0;
    
        printk("Bluetooth initialized\n");
    
        k_work_init(&start_advertising_worker, start_advertising);
    
        err = create_advertising();
        if (err) {
            printk("Advertising failed to create (err %d)\n", err);
            return;
        }
    
        k_work_submit(&start_advertising_worker);
    }
    
    void radio_handler(const void *context)
    {
    
        printk("radio_handler");
    
    }
    
    void main(void)
    {
        int err;
    
        printk("Main start");
    
        err = bt_enable(NULL);
        if (err) {
            printk("Bluetooth init failed (err %d)\n", err);
            return;
        }
    
        bt_ready();
    
        bt_conn_cb_register(&conn_callbacks);
    }

    prj.conf

    CONFIG_BT=y
    CONFIG_BT_DEBUG_LOG=y
    CONFIG_BT_PERIPHERAL=y
    
    CONFIG_BT_CTLR_PHY_CODED=y
    CONFIG_BT_EXT_ADV=y
    CONFIG_BT_USER_PHY_UPDATE=y
    
    # Log
    CONFIG_LOG=y
    CONFIG_LOG_DEFAULT_LEVEL=3

    Here we get the callback after ~10 seconds when using BT_LE_EXT_ADV_START_PARAM(1000, 0)

     

    Best regards,

    Simon

Reply
  • Hi

    Okay, so we were able to add this on our end after a bit trial and error. Here is the relevant source code and configs (tested on NCS 2.1.1):

    main.c

    /*
     * Copyright (c) 2021 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    /** @file
     *  @brief Peripheral example
     */
    
    #include <zephyr/types.h>
    #include <stddef.h>
    #include <string.h>
    #include <errno.h>
    #include <sys/printk.h>
    #include <zephyr.h>
    
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/conn.h>
    #include <bluetooth/uuid.h>
    #include <bluetooth/gatt.h>
    
    #include <logging/log.h>
    LOG_MODULE_REGISTER(app, CONFIG_LOG_DEFAULT_LEVEL);
    
    
    #define BLE_INT                         (0x140) // N * 0.625. corresponds to dec. 320; 320*0.625 = 200ms
    #define BLE_ADV_TIMEOUT                 (1000)  // N * 10ms for advertiser timeout
    #define BLE_ADV_EVENTS                  (0)
    
    static struct k_work start_advertising_worker;
    
    static struct bt_le_ext_adv *adv;
    
    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, 0x0d, 0x18, 0x0f, 0x18, 0x0a, 0x18),
    };
    
    #if defined(CONFIG_BT_PERIPHERAL)
    
    static void connected(struct bt_conn *conn, uint8_t conn_err)
    {
        int err;
        struct bt_conn_info info;
        char addr[BT_ADDR_LE_STR_LEN];
    
        bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
        if (conn_err) {
            printk("Connection failed (err %d)\n", conn_err);
            return;
        }
    
        err = bt_conn_get_info(conn, &info);
    
        if (err) {
            printk("Failed to get connection info\n");
        } else {
            const struct bt_conn_le_phy_info *phy_info;
            phy_info = info.le.phy;
    
            printk("Connected: %s, tx_phy %u, rx_phy %u\n",
                   addr, phy_info->tx_phy, phy_info->rx_phy);
        }
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
        printk("Disconnected (reason 0x%02x)\n", reason);
    
        k_work_submit(&start_advertising_worker);
    }
    
    static struct bt_conn_cb conn_callbacks = {
        .connected = connected,
        .disconnected = disconnected,
        
    };
    
    #endif /* defined(CONFIG_BT_PERIPHERAL) */
    
    
    static void adv_sent(struct bt_le_ext_adv *instance,
                 struct bt_le_ext_adv_sent_info *info)
    {   
        //printk("Advertising stopped. num_sent: %d ", info->num_sent);
        LOG_INF("Advertising stopped");
    }
    
    static int create_advertising(void)
    {
        int err;
        struct bt_le_adv_param param =
            BT_LE_ADV_PARAM_INIT(
                         BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_USE_NAME,
                         BLE_INT,
                         BLE_INT,
                         NULL);
    
        static const struct bt_le_ext_adv_cb adv_cb = {
            .sent = adv_sent,
        };
    
        err = bt_le_ext_adv_create(&param, &adv_cb, &adv);
        if (err) {
            printk("Failed to create advertiser set (%d)\n", err);
            return err;
        }
    
        printk("Created adv: %p\n", adv);
    
        err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
        if (err) {
            printk("Failed to set advertising data (%d)\n", err);
            return err;
        }
    
        return 0;
    }
    
    static void start_advertising(struct k_work *item)
    {
        int err;
    
        err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_PARAM(BLE_ADV_TIMEOUT, BLE_ADV_EVENTS));
        if (err) {
            printk("Failed to start advertising set (%d)\n", err);
            return;
        }
    
        //printk("Advertiser %p set started\n", adv);
        LOG_INF("Advertising started");
    }
    
    static void bt_ready(void)
    {
        int err = 0;
    
        printk("Bluetooth initialized\n");
    
        k_work_init(&start_advertising_worker, start_advertising);
    
        err = create_advertising();
        if (err) {
            printk("Advertising failed to create (err %d)\n", err);
            return;
        }
    
        k_work_submit(&start_advertising_worker);
    }
    
    void radio_handler(const void *context)
    {
    
        printk("radio_handler");
    
    }
    
    void main(void)
    {
        int err;
    
        printk("Main start");
    
        err = bt_enable(NULL);
        if (err) {
            printk("Bluetooth init failed (err %d)\n", err);
            return;
        }
    
        bt_ready();
    
        bt_conn_cb_register(&conn_callbacks);
    }

    prj.conf

    CONFIG_BT=y
    CONFIG_BT_DEBUG_LOG=y
    CONFIG_BT_PERIPHERAL=y
    
    CONFIG_BT_CTLR_PHY_CODED=y
    CONFIG_BT_EXT_ADV=y
    CONFIG_BT_USER_PHY_UPDATE=y
    
    # Log
    CONFIG_LOG=y
    CONFIG_LOG_DEFAULT_LEVEL=3

    Here we get the callback after ~10 seconds when using BT_LE_EXT_ADV_START_PARAM(1000, 0)

     

    Best regards,

    Simon

Children
No Data
Related