How to use Directed advertising (high duty cycle) in Zephyr development?

Greetings,

Previously we were developing with the nRF5 SDK. At that time, we were able to execute high duty cycle directed advertising with the following code. Using this, the advertising interval would be less than 3.75 ms.

err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_DIRECTED_HIGH_DUTY);

Now we are developing with zephyr OS and would like to know how to achieve the above implementation. If you know of any useful information, I would appreciate it if you could share it with us.

Parents
  • Hi 

    There is no simple example showing how to use directed advertising in Zephyr unfortunately, but as long as you use the extended advertising API (bt_le_ext_adv) it is relatively straight forward to set up. Essentially, as long as you set the peer field in the bt_le_adv_param struct to a valid BLE address the advertising will become directed automatically. 

    You can use the code snippets shared in this case for reference. 

    If you are having problems getting this to work just let me know, and I will do my best to help Slight smile

    Best regards
    Torbjørn 

  •   
    First of all, thank you for your fast response and sorry for my really late reply.

    I understood how to use extended advertising in Zephyr OS.

    Now, I have a few questions. I'm using nrf52840 and nrf52832, and NCS 2.1.1.

    1.  

    In the docstring of the function sdc_hci_cmd_le_set_adv_params() in nrfxlib\softdevice_controller\include\sdc_hci_cmd_le.h, there is a descripton about high duty cycle directed advertising.

      * For high duty cycle directed advertising, i.e. when Advertising_Type is 0x01
     * (ADV_DIRECT_IND, high duty cycle), the Advertising_Interval_Min and
     * Advertising_Interval_Max parameters are not used and shall be ignored.
     
     * If directed advertising is performed, i.e. when Advertising_Type is set to 0x01
     * (ADV_DIRECT_IND, high duty cycle) or 0x04 (ADV_DIRECT_IND, low duty
     * cycle mode), then the Peer_Address_Type and Peer_Address shall be valid.

    What I want to realize is the above advertising. As far as I know, this can be implemented with nRF SDK5 by the below code.

    err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_DIRECTED_HIGH_DUTY);

    Since the below code enable high duty mode because there is no flag of 

    BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY, I expect BLE to do high duty directed advertising and the advertising interval is less than 3.75ms, but it doesn't. I confirmed the interval by the sniffer.

    /*
     * Copyright (c) 2021 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/bluetooth/addr.h>
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/conn.h>
    #include <zephyr/bluetooth/gap.h>
    #include <zephyr/bluetooth/gatt.h>
    #include <zephyr/bluetooth/uuid.h>
    
    struct bt_le_adv_param *adv_param = BT_LE_ADV_PARAM(
    	BT_LE_ADV_OPT_USE_IDENTITY |
    		BT_LE_ADV_OPT_CONNECTABLE,
    	BT_GAP_ADV_FAST_INT_MIN_2,
    	BT_GAP_ADV_FAST_INT_MAX_2,
    	((bt_addr_le_t[]){{0,
    					   {{0x3f, 0x3f, 0xe3, 0xcd, 0xef, 0xef}}}}));
    
    void main(void)
    {
    	int err;
    	err = bt_enable(NULL);
    	if (err)
    	{
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	k_sleep(K_MSEC(1000));
    	bt_le_adv_start(
    		&adv_param,
    		NULL, 0,
    		NULL, 0);
    }
    

    If there is any sample or suggestion, could you share it with us?
    2.

    Do I need to use extended advertising? As far as I understand, extended advertising use both data channels and advertising channels, but in our case, I want to use only advertising channel. So I think high duty cycle directed advertising is not extend adverting but "normal" advertising.

    Is this correct?

    Best regards

  • Hi 

    YHT said:
    So I think high duty cycle directed advertising is not extend adverting but "normal" advertising.

    That is correct. 

    Confusingly the bt_le_ext_adv API is not limited to extended advertising only. Rather it supports an 'extended' set of features compared to the basic bt_le_adv API. 

    Essentially it was decided not to break compatibility by altering the bt_le_adv API to support more advertising features, but add the bt_le_ext_adv API instead. Unfortunately whoever designed the API didn't realize that the term 'extended' had a special meaning in the context of Bluetooth advertising. 

    In order to use actual extended advertising you need to set the BT_LE_ADV_OPT_EXT flag, otherwise you should get legacy advertising even when using the 'ext' API. 

    If you are still having issues getting this to work using the bt_le_ext_adv API let me know, and I will try it out myself. 

    Best regards
    Torbjørn

  • Thank you so much for your clear explanation.

    I agree with you that the advertising related functions in Zephyr RTOS are a bit confusing.

    I will try the implementation myself and share reults with you later.

Reply Children
  • Sounds good. If you have any problems getting it to work just let me know Slight smile

  • Sorry for my late reply again.

    I found there is a function "sdc_hci_cmd_le_set_adv_params" & "start_high_duty_directed_adv" in ncs\v2.1.1\nrfxlib\softdevice_controller\include\sdc_hci_cmd_le.h .

    So I wrote a simple code and tried to use these function, but I got the following error.

    00> [00:00:00.000,244] <dbg> main: main: Starting Broadcaster
    00> [00:00:00.000,366] <inf> sdc_hci_driver: SoftDevice Controller build revision: 
    00>                                          f2 e7 5f 6f 23 a2 f3 e8  10 2f c3 35 9e d7 1d fe |.._o#... ./.5....
    00>                                          8f 80 42 f9                                      |..B.             
    00> [00:01:02.758,544] <dbg> main: connected: connected
    00> [00:01:03.371,765] <wrn> bt_l2cap: Ignoring data for unknown channel ID 0x003a
    00> [00:01:07.061,920] <dbg> main: disconnected: Disconnected (reason 0x13)
    00> [00:01:07.061,981] <dbg> main: set_high_duty_adv_params: Set adv params.
    00> [00:01:07.062,103] <dbg> main: start_high_duty_directed_adv: 
    00> [00:01:08.342,895] <err> bt_hci_core: No pending peripheral connection

    Here is the code I wrote. 

    #include <stddef.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/sys/util.h>
    #include <zephyr/types.h>
    
    #include <zephyr/bluetooth/addr.h>
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/hci.h>
    
    #include "sdc_hci_cmd_le.h"
    
    #define MODULE main
    #include <zephyr/logging/log.h>
    LOG_MODULE_REGISTER(MODULE);
    
    static uint8_t mfg_data[] = {0xff, 0xff, 0x00};
    
    static const struct bt_data ad[] = {
    	BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 3),
    };
    
    static void connected(struct bt_conn *conn, uint8_t err)
    {
    	if (err)
    	{
    		LOG_DBG("connection failed: %u", err);
    		return;
    	}
    	LOG_DBG("connected");
    	bt_le_adv_stop();
    }
    
    static void set_high_duty_adv_params(const bt_addr_le_t *addr)
    {
    	int err;
    	sdc_hci_cmd_le_set_adv_params_t adv_params;
    
    	adv_params.adv_type = 0x01;
    	adv_params.own_address_type = BT_ADDR_LE_RANDOM;
    	adv_params.peer_address_type = addr->type;
    	for (uint8_t i = 0; i < BT_ADDR_SIZE; i++)
    	{
    		adv_params.peer_address[i] = addr->a.val[i];
    	}
    	adv_params.adv_channel_map = 0b00000111;
    
    	err = sdc_hci_cmd_le_set_adv_params(&adv_params);
    	if (err)
    	{
    		LOG_WRN("Failed to set adv params(err:0x%x)", err);
    		return;
    	}
    	LOG_DBG("Set adv params.");
    }
    
    static void start_high_duty_directed_adv(const bt_addr_le_t *peer)
    {
    	int err;
    
    	set_high_duty_adv_params(peer);
    	sdc_hci_cmd_le_set_adv_enable_t adv_enable;
    	adv_enable.adv_enable = 1;
    	err = sdc_hci_cmd_le_set_adv_enable(&adv_enable);
    
    	if (err)
    	{
    		LOG_ERR("Failed to set adv params(err:0x%x)", err);
    		return;
    	}
    	LOG_DBG("");
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
    	LOG_DBG("Disconnected (reason 0x%02x)", reason);
    	struct bt_conn_info info;
    	bt_addr_le_t peer_addr;
    	bt_conn_get_info(conn, &info);
    	bt_addr_le_copy(&peer_addr, info.le.remote);
    	start_high_duty_directed_adv(&peer_addr);
    }
    
    BT_CONN_CB_DEFINE(conn_callbacks) = {.connected = connected,
    									 .disconnected = disconnected};
    
    void main(void)
    {
    	int err;
    
    	LOG_DBG("Starting Broadcaster");
    
    	/* Initialize the Bluetooth Subsystem */
    	err = bt_enable(NULL);
    	if (err)
    	{
    		LOG_DBG("Bluetooth init failed (err %d)", err);
    		return;
    	}
    
    	bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad),
    					NULL, 0);
    }

    I can't get how to fix this. Could you help me?

  • I used nRF Connect mobile app as a central.

  • Hi 

    Typically you should not call the sdc functions directly, unless you need to access unique features in the SoftDevice controller that are not supported by the Zephyr host. 

    Did you try to do this using the normal Bluetooth API as I described earlier? 

    Best regards
    Torbjørn

Related