Extend number of devices for PAwR (Coded PHY)

Hi all !

I'm writing this message because I'm having problems trying to increase the number of devices in PAwR (I use Coded PHY).

I based my development on the SDK 2.8.0 example (Periodic_adv_conn / Periodic_sync_conn). I also tried Periodic_adv_rsp / Periodic_sync_rsp examples without success.

I've modified it so that I don't have to connect every time via on the TX side:

bt_conn_le_create_synced function()

On the RX side, I have a fixed subevent and slot numbers to answer to TX.

Based on SDK example, I can exchange data with 25 devices (5 subevents / 5 slots)

I used the following configuration:

#define NUM_RSP_SLOTS 5
#define NUM_SUBEVENTS 5
#define SUBEVENT_INTERVAL 0x30

static const struct bt_le_per_adv_param per_adv_params = {
	.interval_min = 0xFF,
	.interval_max = 0xFF,
	.options = 0,
	.num_subevents = NUM_SUBEVENTS,
	.subevent_interval = SUBEVENT_INTERVAL,
	.response_slot_delay = 0x5,
	.response_slot_spacing = 0x50,
	.num_response_slots = NUM_RSP_SLOTS,
};

When I try to increase the number of devices (8 subevents / 20 slots per subevent), I don't get the same behavior.

Below are the timings I use depending on the number of subevents and slots.

#define NUM_RSP_SLOTS 20
#define NUM_SUBEVENTS 8

static const struct bt_le_per_adv_param per_adv_params = {
	.interval_min = 0x960,
	.interval_max = 0x960,
	.options = 0,
	.num_subevents = NUM_SUBEVENTS,
	.subevent_interval = 0xF0,
	.response_slot_delay = 0x10,
	.response_slot_spacing = 0x50,
	.num_response_slots = NUM_RSP_SLOTS,
};

I saw that the PAwR feature is still experimental in the las version of the SDK, could this be related or is there something I'm doing wrong?

Thank you in advance for your answers or feedbacks.

Yann

Parents
  • Hi Yann,

    Your configurations seem feasible. Could you please provide more details on what kind of failure you are facing?

    Are there any logs? What are the symptoms?

    Hieu

  • Hi Hieu,

    Thanks for you answer.

    Yes sure, what I can see is that with the initial parameters (5 subevents / 5 slots per subevent) I can synchronize and exchange data between transmitter and receiver.

    Transmitter:

    [00:00:00.011,535] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
    [00:00:00.011,566] <inf> bt_hci_core: HW Variant: nRF52x (0x0002)
    [00:00:00.011,596] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 254.63788 Build 573996906
    [00:00:00.012,786] <inf> bt_hci_core: Identity: C8:22:35:1D:70:9F (random)
    [00:00:00.012,817] <inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x104e, manufacturer 0x0059
    [00:00:00.012,847] <inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x104e
    Start Periodic Advertising
    PAwR RSP : Subevent : 0 Slot : 2
    PAwR RSP : Subevent : 0 Slot : 2
    PAwR RSP : Subevent : 0 Slot : 2
    PAwR RSP : Subevent : 0 Slot : 2
    PAwR RSP : Subevent : 0 Slot : 2
    PAwR RSP : Subevent : 0 Slot : 2

    Receiver:

    Synced to 69:D7:06:00:1C:75 (random) with 5 subevents
    DEBUG - CMD RESP 0x0 0x1 0x0 0x0 0x0
    DEBUG - CMD RESP 0x0 0x1 0x0 0x0 0x0
    DEBUG - CMD RESP 0x0 0x1 0x0 0x0 0x0
    DEBUG - CMD RESP 0x0 0x1 0x0 0x0 0x0
    DEBUG - CMD RESP 0x0 0x1 0x0 0x0 0x0
    DEBUG - CMD RESP 0x0 0x1 0x0 0x0 0x0
    DEBUG - CMD RESP 0x0 0x1 0x0 0x0 0x0
    DEBUG - CMD RESP 0x0 0x1 0x0 0x0 0x0
    DEBUG - CMD RESP 0x0 0x1 0x0 0x0 0x0
    DEBUG - CMD RESP 0x0 0x1 0x0 0x0 0x0

    Now if I update parameters (Subevents 8 / Slots per subevent 20)

    With these settings, the device receiving the PAwR signals can't synchronize.

    Transmitter:

    [00:00:00.011,352] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
    [00:00:00.011,383] <inf> bt_hci_core: HW Variant: nRF52x (0x0002)
    [00:00:00.011,413] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 254.63788 Build 573996906
    [00:00:00.012,573] <inf> bt_hci_core: Identity: C8:22:35:1D:70:9F (random)
    [00:00:00.012,634] <inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x104e, manufacturer 0x0059
    [00:00:00.012,664] <inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x104e
    Start Periodic Advertising
    

    Receiver:

    Synced to 71:31:A2:CE:53:E5 (random) with 8 subevents
    Failed to set subevents to sync to (err -5)
    DEBUG - CMD RESP 0x0 0x1 0x0 0x0 0x0
    Failed to send response (err -5)
    Receive Terminated Callback

     

  • Hi Hieu,

    No problem, I can check again from my side if I change parameters step by step and I will tell you.

    Just a question, from your side in Nordic did you already tried to use PAwR with more than 25 devices (5 subevents / 5 slots) ?

    Thank you,

    Yann

  • Hi Hieu,

    Thank you for your reply. I will have a look on the tutorial.

    Best regards,

    Yann

  • Hi Hieu,

    I prepared a modified version of the periodic_adv/sync_conn example with my PAwR timings.

    Can you please have a look on it ?

    You can try from your side if you want, I used a nrf52840dk for the ADV side and only one nrf52840dk for the SYNC side and it's not possible to exchange data. 

    You will find diff to easily see my changes.

    ADV Side

    diff --git a/src/main.c b/src/main.c
    index 49c1c52..b04a8b4 100644
    --- a/src/main.c
    +++ b/src/main.c
    @@ -9,22 +9,40 @@
     #include <zephyr/bluetooth/gap.h>
     #include <zephyr/bluetooth/hci.h>
     
    -#define NUM_RSP_SLOTS	  5
    -#define NUM_SUBEVENTS	  5
    -#define PACKET_SIZE	  5
    +#define NUM_RSP_SLOTS	  20
    +#define NUM_SUBEVENTS	  8
    +// #define NUM_RSP_SLOTS	  5
    +// #define NUM_SUBEVENTS	  5
    +#define PACKET_SIZE	      5
     #define SUBEVENT_INTERVAL 0x30
     
    +#define BT_LE_EXT_ADV_NCONN_CODED BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | \
    +                        BT_LE_ADV_OPT_CODED, \
    +					    BT_GAP_ADV_FAST_INT_MIN_2, \
    +					    BT_GAP_ADV_FAST_INT_MAX_2, NULL)
    +
     static const struct bt_le_per_adv_param per_adv_params = {
    -	.interval_min = 0xFF,
    -	.interval_max = 0xFF,
    +	.interval_min = 0x960,
    +	.interval_max = 0x960,
     	.options = 0,
     	.num_subevents = NUM_SUBEVENTS,
    -	.subevent_interval = SUBEVENT_INTERVAL,
    -	.response_slot_delay = 0x5,
    +	.subevent_interval = 0xF0,
    +	.response_slot_delay = 0x10,
     	.response_slot_spacing = 0x50,
     	.num_response_slots = NUM_RSP_SLOTS,
     };
     
    +// static const struct bt_le_per_adv_param per_adv_params = {
    +// 	.interval_min = 0xFF,
    +// 	.interval_max = 0xFF,
    +// 	.options = 0,
    +// 	.num_subevents = NUM_SUBEVENTS,
    +// 	.subevent_interval = SUBEVENT_INTERVAL,
    +// 	.response_slot_delay = 0x5,
    +// 	.response_slot_spacing = 0x50,
    +// 	.num_response_slots = NUM_RSP_SLOTS,
    +// };
    +
     static struct bt_le_per_adv_subevent_data_params subevent_data_params[NUM_SUBEVENTS];
     static struct net_buf_simple bufs[NUM_SUBEVENTS];
     static uint8_t backing_store[NUM_SUBEVENTS][PACKET_SIZE];
    @@ -73,46 +91,12 @@ static struct bt_conn *default_conn;
     static void response_cb(struct bt_le_ext_adv *adv, struct bt_le_per_adv_response_info *info,
     			struct net_buf_simple *buf)
     {
    -	int err;
    -	bt_addr_le_t peer;
    -	char addr_str[BT_ADDR_LE_STR_LEN];
    -	struct bt_conn_le_create_synced_param synced_param;
    -	struct bt_le_conn_param conn_param;
    -
     	if (!buf) {
     		return;
     	}
     
    -	if (default_conn) {
    -		/* Do not initiate new connections while already connected */
    -		return;
    -	}
    -
    -	bt_addr_le_copy(&peer, &bt_addr_le_none);
    -	bt_data_parse(buf, get_address, &peer);
    -	if (bt_addr_le_eq(&peer, &bt_addr_le_none)) {
    -		/* No address found */
    -		return;
    -	}
    -
    -	bt_addr_le_to_str(&peer, addr_str, sizeof(addr_str));
    -	printk("Connecting to %s in subevent %d\n", addr_str, info->subevent);
    -
    -	synced_param.peer = &peer;
    -	synced_param.subevent = info->subevent;
    -
    -	/* Choose same interval as PAwR advertiser to avoid scheduling conflicts */
    -	conn_param.interval_min = SUBEVENT_INTERVAL;
    -	conn_param.interval_max = SUBEVENT_INTERVAL;
    -
    -	/* Default values */
    -	conn_param.latency = 0;
    -	conn_param.timeout = 400;
    -
    -	err = bt_conn_le_create_synced(adv, &synced_param, &conn_param, &default_conn);
    -	if (err) {
    -		printk("Failed to initiate connection (err %d)", err);
    -	}
    +    printk("RX DATA : SUB %u SLOT %u DATA %X%X%X%X%X\n", info->subevent, info->response_slot,
    +        buf->data[0], buf->data[1], buf->data[2], buf->data[3], buf->data[4]);
     }
     
     static const struct bt_le_ext_adv_cb adv_cb = {
    @@ -183,7 +167,7 @@ int main(void)
     	}
     
     	/* Create a non-connectable advertising set */
    -	err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, &adv_cb, &pawr_adv);
    +	err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_CODED, &adv_cb, &pawr_adv);
     	if (err) {
     		printk("Failed to create advertising set (err %d)\n", err);
     		return 0;
    

    SYNC side

    diff --git a/src/main.c b/src/main.c
    index db858ef..172acf8 100644
    --- a/src/main.c
    +++ b/src/main.c
    @@ -57,6 +57,7 @@ static void term_cb(struct bt_le_per_adv_sync *sync,
     static struct bt_le_per_adv_response_params rsp_params;
     
     NET_BUF_SIMPLE_DEFINE_STATIC(rsp_buf, sizeof(bt_addr_le_t) + 2 * sizeof(uint8_t));
    +uint8_t myDummyBuf[] = {0x11, 0x22, 0x33, 0x44, 0x55};
     
     static void recv_cb(struct bt_le_per_adv_sync *sync,
     		    const struct bt_le_per_adv_sync_recv_info *info, struct net_buf_simple *buf)
    @@ -79,25 +80,17 @@ static void recv_cb(struct bt_le_per_adv_sync *sync,
     		rsp_params.response_subevent = info->subevent;
     		rsp_params.response_slot = 0;
     
    -		err = bt_le_oob_get_local(BT_ID_DEFAULT, &oob);
    -		if (err) {
    -			printk("Failed to get OOB data (err %d)\n", err);
    -
    -			return;
    -		}
    -
    -		bt_addr_le_to_str(&oob.addr, addr_str, sizeof(addr_str));
    -		printk("Responding with own addr: %s\n", addr_str);
    -
    -		net_buf_simple_add_u8(&rsp_buf, sizeof(bt_addr_le_t));
    -		net_buf_simple_add_u8(&rsp_buf, BT_DATA_LE_BT_DEVICE_ADDRESS);
    -		net_buf_simple_add_mem(&rsp_buf, &oob.addr.a, sizeof(oob.addr.a));
    -		net_buf_simple_add_u8(&rsp_buf, oob.addr.type);
    +        net_buf_simple_add_mem(&rsp_buf, myDummyBuf, sizeof(myDummyBuf));
     
     		err = bt_le_per_adv_set_response_data(sync, &rsp_params, &rsp_buf);
     		if (err) {
     			printk("Failed to send response (err %d)\n", err);
     		}
    +        else
    +        {
    +            printk("Response data sent : 0x%2X:0x%2X:0x%2X:0x%2X:0x%2X\n",
    +                myDummyBuf[0], myDummyBuf[1], myDummyBuf[2], myDummyBuf[3], myDummyBuf[4]);
    +        }
     	} else if (buf) {
     		printk("Received empty indication: subevent %d\n", info->subevent);
     	} else {
    @@ -198,7 +191,7 @@ int main(void)
     	bt_le_scan_cb_register(&scan_callbacks);
     	bt_le_per_adv_sync_cb_register(&sync_callbacks);
     
    -	err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
    +	err = bt_le_scan_start(BT_LE_SCAN_CODED_ACTIVE, NULL);
     	if (err) {
     		printk("failed (err %d)\n", err);
     
    

    Thanks,

    Yann

  • Hi Yann,

    I am unfortunately not available right now and only return next week. Do you mind waiting until then?

    Best regards,

    Hieu

Reply Children
  • Hi Hieu,

    No problem, I can wait.

    Thank you.

    Yann

  • Hi Yann,

    I cannot reproduce the issue. Your changes work just fine for me. I didn't apply the patch with git but hand-picked each change and test incrementally. However, the result shouldn't be different.

    Here are my main files, just to be sure.

    periodic_adv_conn - main.c

    /*
     * Copyright (c) 2023 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/conn.h>
    #include <zephyr/bluetooth/gap.h>
    #include <zephyr/bluetooth/hci.h>
    
    #define NUM_RSP_SLOTS	  5
    #define NUM_SUBEVENTS	  5
    #define PACKET_SIZE	  5
    #define SUBEVENT_INTERVAL 0x30
    
    #define SAMPLE_INTERVAL_MIN 0xFF
    #define SAMPLE_INTERVAL_MAX 0xFF
    #define RESPONSE_SLOT_DELAY 0x5
    
    
    // #define NUM_RSP_SLOTS	  20
    // #define NUM_SUBEVENTS	  8
    // #define PACKET_SIZE	  5
    // #define SUBEVENT_INTERVAL 0xF0
    
    // #define SAMPLE_INTERVAL_MIN 0x960
    // #define SAMPLE_INTERVAL_MAX 0x960
    
    // #define RESPONSE_SLOT_DELAY 0x10
    
    
    #define BT_LE_EXT_ADV_NCONN_CODED BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | \
                            BT_LE_ADV_OPT_CODED, \
    					    BT_GAP_ADV_FAST_INT_MIN_2, \
    					    BT_GAP_ADV_FAST_INT_MAX_2, NULL)
    
    static const struct bt_le_per_adv_param per_adv_params = {
    	// .interval_min = 0xFF,
    	// .interval_max = 0xFF,
    	.interval_min = SAMPLE_INTERVAL_MIN,
    	.interval_max = SAMPLE_INTERVAL_MAX,
    	.options = 0,
    	.num_subevents = NUM_SUBEVENTS,
    	.subevent_interval = SUBEVENT_INTERVAL,
    	// .response_slot_delay = 0x5,
    	.response_slot_delay = RESPONSE_SLOT_DELAY,
    	.response_slot_spacing = 0x50,
    	.num_response_slots = NUM_RSP_SLOTS,
    };
    
    static struct bt_le_per_adv_subevent_data_params subevent_data_params[NUM_SUBEVENTS];
    static struct net_buf_simple bufs[NUM_SUBEVENTS];
    static uint8_t backing_store[NUM_SUBEVENTS][PACKET_SIZE];
    
    BUILD_ASSERT(ARRAY_SIZE(bufs) == ARRAY_SIZE(subevent_data_params));
    BUILD_ASSERT(ARRAY_SIZE(backing_store) == ARRAY_SIZE(subevent_data_params));
    
    static void request_cb(struct bt_le_ext_adv *adv, const struct bt_le_per_adv_data_request *request)
    {
    	int err;
    	uint8_t to_send;
    
    	/* Continuously send the same dummy data and listen to all response slots */
    
    	to_send = MIN(request->count, ARRAY_SIZE(subevent_data_params));
    	for (size_t i = 0; i < to_send; i++) {
    		subevent_data_params[i].subevent =
    			(request->start + i) % per_adv_params.num_subevents;
    		subevent_data_params[i].response_slot_start = 0;
    		subevent_data_params[i].response_slot_count = NUM_RSP_SLOTS;
    		subevent_data_params[i].data = &bufs[i];
    	}
    
    	err = bt_le_per_adv_set_subevent_data(adv, to_send, subevent_data_params);
    	if (err) {
    		printk("Failed to set subevent data (err %d)\n", err);
    	}
    }
    
    static bool get_address(struct bt_data *data, void *user_data)
    {
    	bt_addr_le_t *addr = user_data;
    
    	if (data->type == BT_DATA_LE_BT_DEVICE_ADDRESS) {
    		memcpy(addr->a.val, data->data, sizeof(addr->a.val));
    		addr->type = data->data[sizeof(addr->a)];
    
    		return false;
    	}
    
    	return true;
    }
    
    static struct bt_conn *default_conn;
    
    static void response_cb(struct bt_le_ext_adv *adv, struct bt_le_per_adv_response_info *info,
    			struct net_buf_simple *buf)
    {
    	// int err;
    	// bt_addr_le_t peer;
    	// char addr_str[BT_ADDR_LE_STR_LEN];
    	// struct bt_conn_le_create_synced_param synced_param;
    	// struct bt_le_conn_param conn_param;
    
    	// if (!buf) {
    	// 	return;
    	// }
    
    	// if (default_conn) {
    	// 	/* Do not initiate new connections while already connected */
    	// 	return;
    	// }
    
    	// bt_addr_le_copy(&peer, &bt_addr_le_none);
    	// bt_data_parse(buf, get_address, &peer);
    	// if (bt_addr_le_eq(&peer, &bt_addr_le_none)) {
    	// 	/* No address found */
    	// 	return;
    	// }
    
    	// bt_addr_le_to_str(&peer, addr_str, sizeof(addr_str));
    	// printk("Connecting to %s in subevent %d\n", addr_str, info->subevent);
    
    	// synced_param.peer = &peer;
    	// synced_param.subevent = info->subevent;
    
    	// /* Choose same interval as PAwR advertiser to avoid scheduling conflicts */
    	// conn_param.interval_min = SUBEVENT_INTERVAL;
    	// conn_param.interval_max = SUBEVENT_INTERVAL;
    
    	// /* Default values */
    	// conn_param.latency = 0;
    	// conn_param.timeout = 400;
    
    	// err = bt_conn_le_create_synced(adv, &synced_param, &conn_param, &default_conn);
    	// if (err) {
    	// 	printk("Failed to initiate connection (err %d)", err);
    	// }
    
    	printk("RX DATA : SUB %u SLOT %u DATA %02X%02X%02X%02X%02X\n", info->subevent, info->response_slot,
            buf->data[0], buf->data[1], buf->data[2], buf->data[3], buf->data[4]);
    }
    
    static const struct bt_le_ext_adv_cb adv_cb = {
    	.pawr_data_request = request_cb,
    	.pawr_response = response_cb,
    };
    
    static void connected_cb(struct bt_conn *conn, uint8_t err)
    {
    	printk("Connected (err 0x%02X)\n", err);
    
    	__ASSERT(conn == default_conn, "Unexpected connected callback");
    
    	if (err) {
    		bt_conn_unref(default_conn);
    		default_conn = NULL;
    	}
    }
    
    static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
    {
    	printk("Disconnected, reason 0x%02X %s\n", reason, bt_hci_err_to_str(reason));
    
    	__ASSERT(conn == default_conn, "Unexpected disconnected callback");
    
    	bt_conn_unref(default_conn);
    	default_conn = NULL;
    }
    
    BT_CONN_CB_DEFINE(conn_cb) = {
    	.connected = connected_cb,
    	.disconnected = disconnected_cb,
    };
    
    static void init_bufs(void)
    {
    	/* Set up some dummy data to send */
    	for (size_t i = 0; i < ARRAY_SIZE(backing_store); i++) {
    		backing_store[i][0] = ARRAY_SIZE(backing_store[i]) - 1;
    		backing_store[i][1] = BT_DATA_MANUFACTURER_DATA;
    		backing_store[i][2] = 0x59; /* Nordic */
    		backing_store[i][3] = 0x00;
    
    		net_buf_simple_init_with_data(&bufs[i], &backing_store[i],
    					      ARRAY_SIZE(backing_store[i]));
    	}
    }
    
    static const struct bt_data ad[] = {
    	BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
    };
    
    
    int main(void)
    {
    	int err;
    	struct bt_le_ext_adv *pawr_adv;
    
    	init_bufs();
    
    	printk("Starting Periodic Advertising Demo\n");
    
    	/* Initialize the Bluetooth Subsystem */
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return 0;
    	}
    
    	/* Create a non-connectable advertising set */
    	// err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, &adv_cb, &pawr_adv);
    	err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_CODED, &adv_cb, &pawr_adv);
    	if (err) {
    		printk("Failed to create advertising set (err %d)\n", err);
    		return 0;
    	}
    
    	/* Set advertising data to have complete local name set */
    	err = bt_le_ext_adv_set_data(pawr_adv, ad, ARRAY_SIZE(ad), NULL, 0);
    	if (err) {
    		printk("Failed to set advertising data (err %d)\n", err);
    		return 0;
    	}
    
    	/* Set periodic advertising parameters */
    	err = bt_le_per_adv_set_param(pawr_adv, &per_adv_params);
    	if (err) {
    		printk("Failed to set periodic advertising parameters (err %d)\n", err);
    		return 0;
    	}
    
    	/* Enable Periodic Advertising */
    	err = bt_le_per_adv_start(pawr_adv);
    	if (err) {
    		printk("Failed to enable periodic advertising (err %d)\n", err);
    		return 0;
    	}
    
    	printk("Start Periodic Advertising\n");
    	err = bt_le_ext_adv_start(pawr_adv, BT_LE_EXT_ADV_START_DEFAULT);
    	if (err) {
    		printk("Failed to start extended advertising (err %d)\n", err);
    		return 0;
    	}
    
    	while (true) {
    		k_sleep(K_SECONDS(1));
    	}
    
    	return 0;
    }
    

    periodic_sync_conn - main.c

    /*
     * Copyright (c) 2023 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/conn.h>
    #include <zephyr/bluetooth/gap.h>
    #include <zephyr/bluetooth/hci.h>
    #include <zephyr/sys/util.h>
    
    #define NAME_LEN 30
    
    static K_SEM_DEFINE(sem_per_adv, 0, 1);
    static K_SEM_DEFINE(sem_per_sync, 0, 1);
    static K_SEM_DEFINE(sem_connected, 0, 1);
    static K_SEM_DEFINE(sem_disconnected, 0, 1);
    
    static struct bt_conn *default_conn;
    static bool per_adv_found;
    static bt_addr_le_t per_addr;
    static uint8_t per_sid;
    
    static void sync_cb(struct bt_le_per_adv_sync *sync, struct bt_le_per_adv_sync_synced_info *info)
    {
    	struct bt_le_per_adv_sync_subevent_params params;
    	uint8_t subevents[1];
    	char le_addr[BT_ADDR_LE_STR_LEN];
    	int err;
    
    	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
    	printk("Synced to %s with %d subevents\n", le_addr, info->num_subevents);
    
    	params.properties = 0;
    	params.num_subevents = 1;
    	params.subevents = subevents;
    	subevents[0] = 0;
    	err = bt_le_per_adv_sync_subevent(sync, &params);
    	if (err) {
    		printk("Failed to set subevents to sync to (err %d)\n", err);
    	}
    
    	k_sem_give(&sem_per_sync);
    }
    
    static void term_cb(struct bt_le_per_adv_sync *sync,
    		    const struct bt_le_per_adv_sync_term_info *info)
    {
    	char le_addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
    
    	printk("Sync terminated (reason %d)\n", info->reason);
    }
    
    static struct bt_le_per_adv_response_params rsp_params;
    
    NET_BUF_SIMPLE_DEFINE_STATIC(rsp_buf, sizeof(bt_addr_le_t) + 2 * sizeof(uint8_t));
    uint8_t myDummyBuf[] = {0x11, 0x22, 0x33, 0x44, 0x55};
    
    static void recv_cb(struct bt_le_per_adv_sync *sync,
    		    const struct bt_le_per_adv_sync_recv_info *info, struct net_buf_simple *buf)
    {
    	int err;
    	struct bt_le_oob oob;
    	char addr_str[BT_ADDR_LE_STR_LEN];
    
    	if (default_conn) {
    		/* Only respond with address if not already connected */
    		return;
    	}
    
    	if (buf && buf->len) {
    		/* Respond with own address for the advertiser to connect to */
    		net_buf_simple_reset(&rsp_buf);
    
    		rsp_params.request_event = info->periodic_event_counter;
    		rsp_params.request_subevent = info->subevent;
    		rsp_params.response_subevent = info->subevent;
    		rsp_params.response_slot = 0;
    
    		// err = bt_le_oob_get_local(BT_ID_DEFAULT, &oob);
    		// if (err) {
    		// 	printk("Failed to get OOB data (err %d)\n", err);
    
    		// 	return;
    		// }
    
    		// bt_addr_le_to_str(&oob.addr, addr_str, sizeof(addr_str));
    		// printk("Responding with own addr: %s\n", addr_str);
    
    		// net_buf_simple_add_u8(&rsp_buf, sizeof(bt_addr_le_t));
    		// net_buf_simple_add_u8(&rsp_buf, BT_DATA_LE_BT_DEVICE_ADDRESS);
    		// net_buf_simple_add_mem(&rsp_buf, &oob.addr.a, sizeof(oob.addr.a));
    		// net_buf_simple_add_u8(&rsp_buf, oob.addr.type);
    		net_buf_simple_add_mem(&rsp_buf, myDummyBuf, sizeof(myDummyBuf));
    
    		err = bt_le_per_adv_set_response_data(sync, &rsp_params, &rsp_buf);
    		if (err) {
    			printk("Failed to send response (err %d)\n", err);
    		}
    		else
            {
                printk("Response data sent : 0x%2X:0x%2X:0x%2X:0x%2X:0x%2X\n",
                    myDummyBuf[0], myDummyBuf[1], myDummyBuf[2], myDummyBuf[3], myDummyBuf[4]);
            }
    	} else if (buf) {
    		printk("Received empty indication: subevent %d\n", info->subevent);
    	} else {
    		printk("Failed to receive indication: subevent %d\n", info->subevent);
    	}
    }
    
    static struct bt_le_per_adv_sync_cb sync_callbacks = {
    	.synced = sync_cb,
    	.term = term_cb,
    	.recv = recv_cb,
    };
    
    static void connected_cb(struct bt_conn *conn, uint8_t err)
    {
    	printk("Connected (err 0x%02X)\n", err);
    
    	if (err) {
    		return;
    	}
    
    	default_conn = bt_conn_ref(conn);
    	k_sem_give(&sem_connected);
    }
    
    static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
    {
    	bt_conn_unref(default_conn);
    	default_conn = NULL;
    
    	printk("Disconnected, reason 0x%02X %s\n", reason, bt_hci_err_to_str(reason));
    
    	k_sem_give(&sem_disconnected);
    }
    
    BT_CONN_CB_DEFINE(conn_cb) = {
    	.connected = connected_cb,
    	.disconnected = disconnected_cb,
    };
    
    static bool data_cb(struct bt_data *data, void *user_data)
    {
    	char *name = user_data;
    	uint8_t len;
    
    	switch (data->type) {
    	case BT_DATA_NAME_SHORTENED:
    	case BT_DATA_NAME_COMPLETE:
    		len = MIN(data->data_len, NAME_LEN - 1);
    		memcpy(name, data->data, len);
    		name[len] = '\0';
    		return false;
    	default:
    		return true;
    	}
    }
    
    static void scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf)
    {
    	char name[NAME_LEN];
    
    	(void)memset(name, 0, sizeof(name));
    	bt_data_parse(buf, data_cb, name);
    
    	if (strcmp(name, "PAwR conn sample")) {
    		return;
    	}
    
    	if (!per_adv_found && info->interval) {
    		per_adv_found = true;
    
    		per_sid = info->sid;
    		bt_addr_le_copy(&per_addr, info->addr);
    
    		k_sem_give(&sem_per_adv);
    	}
    }
    
    static struct bt_le_scan_cb scan_callbacks = {
    	.recv = scan_recv,
    };
    
    int main(void)
    {
    	struct bt_le_per_adv_sync_param sync_create_param;
    	struct bt_le_per_adv_sync *sync;
    	int err;
    
    	printk("Starting Periodic Advertising with Responses Synchronization Demo\n");
    
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    
    		return 0;
    	}
    
    	bt_le_scan_cb_register(&scan_callbacks);
    	bt_le_per_adv_sync_cb_register(&sync_callbacks);
    
    	// err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
    	err = bt_le_scan_start(BT_LE_SCAN_CODED_ACTIVE, NULL);
    	if (err) {
    		printk("failed (err %d)\n", err);
    
    		return 0;
    	}
    
    	err = k_sem_take(&sem_per_adv, K_FOREVER);
    	if (err) {
    		printk("failed (err %d)\n", err);
    
    		return 0;
    	}
    	printk("Found periodic advertising.\n");
    
    	printk("Creating Periodic Advertising Sync");
    	bt_addr_le_copy(&sync_create_param.addr, &per_addr);
    	sync_create_param.options = 0;
    	sync_create_param.sid = per_sid;
    	sync_create_param.skip = 0;
    	sync_create_param.timeout = 0xaa;
    	err = bt_le_per_adv_sync_create(&sync_create_param, &sync);
    	if (err) {
    		printk("Failed to create sync (err %d)\n", err);
    
    		return 0;
    	}
    
    	printk("Waiting for periodic sync\n");
    	err = k_sem_take(&sem_per_sync, K_FOREVER);
    	if (err) {
    		printk("Failed (err %d)\n", err);
    
    		return 0;
    	}
    
    	printk("Periodic sync established.\n");
    
    	err = bt_le_scan_stop();
    	if (err) {
    		printk("Failed to stop scanning (err %d)\n", err);
    	}
    
    	printk("Stopped scanning\n");
    
    	do {
    		err = k_sem_take(&sem_connected, K_FOREVER);
    		if (err) {
    			printk("failed (err %d)\n", err);
    
    			return 0;
    		}
    
    		printk("Disconnecting\n");
    
    		err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    		if (err) {
    			return 0;
    		}
    
    		err = k_sem_take(&sem_disconnected, K_FOREVER);
    		if (err) {
    			printk("failed (err %d)\n", err);
    
    			return 0;
    		}
    	} while (true);
    }
    

    Best regards,

    Hieu

  • Hi Hieu,

    Thank you for your answer.

    In the file periodic_adv_conn - main.c I see that you have used the following parameters:

    #define NUM_RSP_SLOTS	  5
    #define NUM_SUBEVENTS  5


    Is it possible for you to try with the parameters that I sent you ?

    #define NUM_RSP_SLOTS 20
    #define NUM_SUBEVENTS 8

    Because with 5 slots and 5 subevents (Default example values) it also works on my side.

    Thank you,

    Yann

  • Hi Yann,

    Yes, I have two set of parameters, yours, and the sample default. I tried both.

    Best regards,

    Hieu

  • Ok, thanks.

    Few questions:

    - You tried projects on NRF52840DK board or an other development board ?

    - Can you please share both projects (adv_conn and sync_conn), like this we can test the same things ? (Maybe my prj.conf files are different or something else)

    Thank you,

    Yann

Related