Change adv interval in PAwR BLE in runtime

Hello,

I am using PAwR (Periodic Advertsing with Response) in coded PHY (S8) with SDK 2.7.0, following the Nordic demo :

8562.PAwR_Demo.zip 

Periodic Advertising with Responses (PAwR): A practical guide - Software - nRF Connect SDK guides - Nordic DevZone

I want to change, in run time, the advertising interval ".interval_min" and ".interval_max" initialised with the structure "static const struct bt_le_per_adv_param per_adv_params"

More precisely I want to change it frequently between fast and slow advertising. 

Is it possible to do so in the case of PAwR ? Is there any example for illustration ? Should I go through the whole process of sync (initialisation connexion disconnexion) to be able to change it whenever I want ?  Or should I just use the following snippet which stops advertising resets the new parameters and starts advertising :

	struct bt_le_ext_adv *pawr_adv;

	struct bt_le_adv_param *params = BT_LE_EXT_ADV_NCONN;
	params->options |= BT_LE_ADV_OPT_USE_IDENTITY | BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_CODED;
	params->sid = 0;
	

	/* Create a non-connectable non-scannable advertising set */
	err = bt_le_ext_adv_create(params, &adv_cb, &pawr_adv); //BT_LE_EXT_ADV_NCONN //BT_LE_EXT_ADV_CODED_NCONN
	if (err) {
		LOG_ERR("Failed to create advertising set (err %d)\n", err);
		return 0;
	}
	
    // Stop periodic advertising
    err = bt_le_per_adv_stop(pawr_adv);
    if (err) {
        LOG_INF("Failed to stop periodic advertising (err %d)\n", err);
        return;
    }
    
	// Set new adv parameters
    struct bt_le_per_adv_param per_adv_param = {
        .interval_min = min_int,
        .interval_max = max_int,
		.options = 0,
		.num_subevents = NUM_SUBEVENTS,
		.subevent_interval = 120,
		.response_slot_delay = 5, 
		.response_slot_spacing = 40,
		.num_response_slots = NUM_RSP_SLOTS,
    };

	/* Set periodic advertising parameters */
	err = bt_le_per_adv_set_param(pawr_adv, &per_adv_params);
	if (err) {
		LOG_ERR("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) {
		LOG_ERR("Failed to enable periodic advertising (err %d)\n", err);
		return 0;
	}

	LOG_DBG("Start Periodic Advertising\n");
	err = bt_le_ext_adv_start(pawr_adv, BT_LE_EXT_ADV_START_DEFAULT);
	if (err) {
		LOG_ERR("Failed to start extended advertising (err %d)\n", err);
		return 0;
	}

Kind regards,
Yanis
Parents
  • Now I do not know anything about your use case. But, depending on what you want to accomplish, you can also consider another approach.

    Instead of changing the Advertising Interval of the PAwR train on the broadcaster, subscribers can choose a different subset of Subevents to subscribe to. So if you want to save power on a subscriber node, it can listen to only subevent 0 by default, and to all Subevents during selected periods.

  • Thank you for your reply Jakob,

    Do you mean to switch between one "standby" subevent with no expected response and all subevents to send response ?

    But if no response it will timeout the sync ?

    Besides, It is the broadcaster that writes the subevents and slots to sych to,

    Changing the subevent to listen to means to go through another sync subscription cycle, isn't it ?

    The subevent to listen to is set when the sync_cb call back is triggered (bt_le_per_adv_sync_subevent).

  • In my application, for instance, I want the subscriber to send data during 5 minutes at a high data rate (period of 0.5 s) and sleep for the next 15 minutes (send one packet per minute in the sleep period). I can trigger these routines and change the adv period of PAwR, but the sync is lost and a new sync cycle is required. 

  • I see. If you use for example the following:

    - Subevent Interval: 0.5 seconds
    - Number of Subevents: 30
    - Periodic Interval: 15 seconds (30 x 0.5)

    During a high data rate session, a subscriber listens to all Subevents and sends a packet in its Response Slot every 0.5 second 

    During a low data rate session, a subscriber can choose to listen only to subevent 0, which takes place with an interval of 15 seconds. A subscriber can choose to respond in every 4th of those in order to send something every minute. A good approach is to let the broadcaster decide when it wants a subscriber to show that it is alive.

    Note that packets can get lost so therefore it is probably a good idea to wake up a bit more often than just every minute. Listening at a short period takes very little energy.

    Would this work for your use case?

  • Interesting approche !

    I did not know that a subscriber can respond to many subevents in one periodic advertising interval. Have you tryed this before ?

    I will have to see if it is not too complex to toggle the subevent listening from one to multiple subevents.

    So based on your approche, the subevent to listen to can be changed as the following snippet by changing the "struct bt_le_per_adv_sync_subevent_params params" and calling "bt_le_per_adv_sync_subevent()"

    	struct bt_le_per_adv_sync_subevent_params params;
    	
    	uint8_t subevents[]; // here define the subevents to listen to
    	subevents[0] = pawr_timing.subevent;
    
    	params.properties = 0;
    	params.num_subevents = 1;
    	params.subevents = subevents;
    
    	bt_le_per_adv_sync_subevent(default_sync, &params);

     

    I did not mention that, in the application, we want to have at least 15 subscribers. I guess that, your approche is possible even with many subscribers, since each subscriber will take one slot and the subevent lestening remains the same.

    I agree that ideally, even in standby mode, the subscriber should be able to send something often to make sure it is runing even if there a packet loss.

  • Yes, I have tried this approach.

    The snippet you have shared is indeed a good start. Here is a function that subscribes to the `num` first Subevents:

    static int listen_to_subevents(struct bt_le_per_adv_sync *sync, uint8_t num)
    {
    	static uint8_t subevents[256];
    	static bool subevents_initialized = false;
    
    	if (!subevents_initialized) {
    		for (size_t i = 0; i < ARRAY_SIZE(subevents); i++) {
    			subevents[i] = i;
    		}
    		subevents_initialized = true;
    	}
    
    	struct bt_le_per_adv_sync_subevent_params params = {
    		.properties = 0,
    		.num_subevents = num,
    		.subevents = subevents,
    	};
    
    	return bt_le_per_adv_sync_subevent(sync, &params);
    }

    A subscriber gets the number of Subevents in the sync callback as part of the `bt_le_per_adv_sync_synced_info` struct. 

    You need to reserve one Response Slot for each subscriber. 15 Response Slots should fit without problem in a Subevent of 500 ms. You need to adjust the Response Slot Delay so that the broadcaster have time to transmit and the subscribers time to process the request and prepare a response. The Response Slot Spacing should be adjusted so that each Subscriber can send the amount of data needed to be sent.

    Good luck!

  • Yes, timing parameters should be adjusted acconrdingly.

    Thank you very much for your relevant suggestions and explanations, I am going to try this out and let you all know.

    Best regards.

Reply Children
No Data
Related