Peripheral_HRS example: Only notify when connected?

I've adapted the peripheral_hr example for my purposes and its working but one thing I see is that the example never checks if the connection is established before calling notify. 

I guess this will just fill up the buffer and shouldn't massively impact battery life but is there a simple way to check if the connection is active before calling notify? 


Parents
  • Hello,

    I guess this will just fill up the buffer

    This is not quite accurate - the function call to queue the notification for sending will fail with the invalid state error code if you attempt to call it while not in a connection.
    This could have a massive impact on battery life in the case that you are performing samplings regularly which are then just discarded.

    is there a simple way to check if the connection is active before calling notify? 

    You can use the connection handle to see if the device is in a connection before attempting to queue the notification.

    Are you working with the nRF Connect SDK or the nRF5 SDK?

    Best regards,
    Karl

  • Thanks for the quick response,

    I'm working with the nrfConnect SDK 2.2.0 

    Either way I still need to be able to check when it's connected since powering up the sensor when there's no active connection is going to waste a lot of energy.

  • Anton Maes said:
    Thanks for the quick response,

    No problem at all, I am happy to help!

    Anton Maes said:
    I'm working with the nrfConnect SDK 2.2.0 

    Thank you for clarifying.

    Anton Maes said:
    Either way I still need to be able to check when it's connected since powering up the sensor when there's no active connection is going to waste a lot of energy.

    Absolutely. You could for instance power up the sensor on the BLE CONNECTED event, and power it down again on the DISCONNECTED/CONNECTION TERMINATED events?
    Additionally, if you should need to check if there is a connection anytime during the program you can check the connection handle to see if a connection is active.

    Please do not hesitate to ask if anything should be unclear! :)

    Best regards,
    Karl

  • Since I want to loop the measurements I'd need to call it within main()

    (I tried within the connected callback but it caused issues with advertising the services so I figure it's best to just put the loop in main) 

    i see that I need to get the bt_conn_state enum and check if the BT state is connected but I'm not really clear on how to get that. 

    or I need some way to get 

    struct bt_conn *conn;
    but if i just declare that it breaks everything. 
  • Anton Maes said:
    Since I want to loop the measurements I'd need to call it within main()

    It might be more power efficient and periodically accurate to have them triggered by a TIMER or RTC event instead of having them triggered by the CPU through the main() loop.
    Could you show me the code for the section where this is processed?

    Anton Maes said:
    (I tried within the connected callback but it caused issues with advertising the services so I figure it's best to just put the loop in main) 

    What did you do as part of the connected callback?
    Did you set a flag, start a timer, or did you attempt to do any processing directly in the callback?
    I would recommend that you start the 'sampling timer' in the callback, and then have the samplings happen whenever the timer expires.

    Best regards,
    Karl

  • Here's what I was doing before. 

    setting up a timer interrupt makes sense. 

    what I tried to implement in connected was actually moving the loop inside the connected callback which obviously caused problems. Setting a flag makes a lot more sense. 


    void measure(int readings)
    {
    	static struct sensor_value weight;
    	int ret;
    	
    	int32_t avg;
    
    	avia_hx711_power(hx711_dev,HX711_POWER_ON);
    
    	ret = sensor_sample_fetch(hx711_dev);
    	
    	if (ret != 0) {
    		LOG_ERR("Cannot take measurement: %d", ret);
    	} else {
    		readings = 100; 
    		for (int i = 0; i < readings; i++) {
    			sensor_channel_get(hx711_dev, HX711_SENSOR_CHAN_WEIGHT, &weight);
    			avg += weight.val1;
    		}
    		
    		int32_t adjusted = avg/readings;
    		LOG_INF("Weight: %i", adjusted);
    		bt_ws_notify(adjusted);
    	}
    
    	avia_hx711_power(hx711_dev, HX711_POWER_OFF);
    }
    
    
    void main(void)
    {
    	int err;
    	
    	int calibration_weight = 100; // grams
    	hx711_dev = DEVICE_DT_GET_ANY(avia_hx711);
    	__ASSERT(hx711_dev == NULL, "Failed to get device binding");
    
    	LOG_INF("Device is %p, name is %s", hx711_dev, hx711_dev->name);
    	LOG_INF("Calculating offset...");
    	//avia_hx711_tare(hx711_dev, 5);
    
    	struct hx711_data *data = hx711_dev->data;
    
    	data->offset = -1*(2^23);
    	data->slope.val1 = 1; 
    	data->slope.val2 = 0; 
    
    
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	bt_ready();
    
    	bt_conn_auth_cb_register(&auth_cb_display);
    
    	/* Implement notification. At the moment there is no suitable way
    	 * of starting delayed work so we do it here
    	 */
    
    	
    	while (1) {
    		k_sleep(K_SECONDS(5));
    
    		bt_conn_foreach(connect_active,NULL);
    
    			//LOG_INF("BT Status : %i", default_conn);
    		measure(100);
    			/* Battery level simulation */
    		//	bas_notify();
    
    			//log_inf("disconnected");
    		
    
    
    	}
    }

Reply
  • Here's what I was doing before. 

    setting up a timer interrupt makes sense. 

    what I tried to implement in connected was actually moving the loop inside the connected callback which obviously caused problems. Setting a flag makes a lot more sense. 


    void measure(int readings)
    {
    	static struct sensor_value weight;
    	int ret;
    	
    	int32_t avg;
    
    	avia_hx711_power(hx711_dev,HX711_POWER_ON);
    
    	ret = sensor_sample_fetch(hx711_dev);
    	
    	if (ret != 0) {
    		LOG_ERR("Cannot take measurement: %d", ret);
    	} else {
    		readings = 100; 
    		for (int i = 0; i < readings; i++) {
    			sensor_channel_get(hx711_dev, HX711_SENSOR_CHAN_WEIGHT, &weight);
    			avg += weight.val1;
    		}
    		
    		int32_t adjusted = avg/readings;
    		LOG_INF("Weight: %i", adjusted);
    		bt_ws_notify(adjusted);
    	}
    
    	avia_hx711_power(hx711_dev, HX711_POWER_OFF);
    }
    
    
    void main(void)
    {
    	int err;
    	
    	int calibration_weight = 100; // grams
    	hx711_dev = DEVICE_DT_GET_ANY(avia_hx711);
    	__ASSERT(hx711_dev == NULL, "Failed to get device binding");
    
    	LOG_INF("Device is %p, name is %s", hx711_dev, hx711_dev->name);
    	LOG_INF("Calculating offset...");
    	//avia_hx711_tare(hx711_dev, 5);
    
    	struct hx711_data *data = hx711_dev->data;
    
    	data->offset = -1*(2^23);
    	data->slope.val1 = 1; 
    	data->slope.val2 = 0; 
    
    
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	bt_ready();
    
    	bt_conn_auth_cb_register(&auth_cb_display);
    
    	/* Implement notification. At the moment there is no suitable way
    	 * of starting delayed work so we do it here
    	 */
    
    	
    	while (1) {
    		k_sleep(K_SECONDS(5));
    
    		bt_conn_foreach(connect_active,NULL);
    
    			//LOG_INF("BT Status : %i", default_conn);
    		measure(100);
    			/* Battery level simulation */
    		//	bas_notify();
    
    			//log_inf("disconnected");
    		
    
    
    	}
    }

Children
  • I am glad to read that you found the comment helpful :) 
    In general it is better to move processing outside of the interrupt context, since they should be kept as short as possible.

    Are you sampling at a specific interval or frequency?
    If so, you might benefit from starting a timer instead, and then having that RTC / TIMER instance trigger the sampling operation when it expires.
    If you are sampling at high frequencies you should also consider setting this up using PPI to connect the RTC/TIMER EVENT and the sampling TASK.
    This could reduce your power consumption since the CPU does not have to wake up to trigger each sampling.

    Best regards,
    Karl

Related