Scan Module: Allowing short name filtering

Hello All,

I am attempting to use the scanning module to scan with a filter. Right now I am trying to implement a short name filter.

I am using the nrf Connect extension for VS code for the environment and I am using the <bluetooth/scan.h> include to import the nordic Bluetooth LE Scanning library for use.

I am using windows and using the Seeed Studio XIAO nRF52840 board for development.

The Issue Explained:

To my understanding so far to enable a filtered scan, at a high level I need to:

  1. Add the filter to the scanning parameters through bt_scan_filter_add
    1. The structure for the filter should be found from the source code
  2. Enable the filters which would need you to specify the filter modes that you want to include bt_scan_filter_enable
  3. Set the callback functions through bt_scan_cb_register. the scan_filter_match callback will define how the filter matches are delt with
  4. Start the scanning with bt_scan_start

Given this highlevel understanding I have written the below code:

```

//--------------SCAN TESTING START---------------------//

        // int err = 0;
        const struct bt_scan_init_param bt_scan_init_opts = {
                        .scan_param = NULL, //default config
                        .connect_if_match = true,
                        .conn_param = NULL, //default config
        };
       
        bt_scan_init(&bt_scan_init_opts);

        bt_scan_filter_remove_all();
        bt_scan_filter_disable();

        //double check if the definitin of the short name filter is correct
        struct bt_scan_short_name ble_shrt_name;
        ble_shrt_name.name = "shrtname";
        ble_shrt_name.min_len = 8;

        err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_SHORT_NAME, &ble_shrt_name);
        if (err < 0) {
                LOG_ERR("Error setting the short name filter (err: %d)\n", err);
                // return err;
        }

        uint8_t filter_modes = BT_SCAN_SHORT_NAME_FILTER | BT_SCAN_UUID_FILTER;
        err = bt_scan_filter_enable(filter_modes, true); //Want all filters to be matched when looking for a new device
        if (err < 0) {
                LOG_ERR("Error establishing scan filters (err: %d)\n", err);
                // return err;
        }


        bt_scan_cb_register(scan_filter_match);
        bt_scan_cb_register(scan_filter_no_match);
        bt_scan_cb_register(scan_connecting);
        bt_scan_cb_register(scan_connecting_error);

        err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
        if (err < 0) {
                LOG_ERR("Error starting the bt scan (err: %d)\n", err);
        }

        //--------------SCAN TESTING END---------------------//

```

I am getting an ENOMEM (-12) Cannot allocate memory when I try to add the short name filter to the scan system.

to my understanding this is due to calling for more memory than what is available to the mcu. However, I have increase the memory available to the mcu through the config file by setting the following parameter:

  • CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
  • CONFIG_MAIN_STACK_SIZE=4096
  • CONFIG_HEAP_MEM_POOL_SIZE=8192
  • CONFIG_LOG_BUFFER_SIZE=4096

Going through some other posts on a similar problem here:  how to bt_scan_filter_add by short name ? 

in the end it is stated: "Edit: This still requires you to set the number of Short Name Filters in the `guiconfig` or `menuconfig` via `BT_SCAN_SHORT_NAME_CNT`."

I think the guiconfig and menuconfig are the same as the proj.config file used in the NRF Connect extension for vs code as well. However when I se this config flag I get an error that

  • ignoring malformed line 'BT_SCAN_SHORT_NAME_CNT=1'

And through googling the zephyr configs it seems like this flag is not available.

Can anyone guide me as to what the error could be?

Any guidance is much appreciated.

Thanks All.

Update: Have attached my main.c file for viewing. I have been trying to solve the issue by commenting out a bunch of code.

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/adc.h>
#include <stdlib.h>

#include "led_control.h"
#include "adc_control.h"
#include "bluetooth_control.h"

#include <math.h>

#define NUM_SENSORS (2)

#define NUM_ADC_SEL_PINS (1) //should be the bits needed to rep the num_sensors value

#define PIN_ADC_SEL_0 (28) //to be coordinated with the rest of the sytem
#define PIN_ADC_SEL_1 (29) 
#define PIN_ADC_SEL_2 (4) 
#define PIN_ADC_SEL_3 (5)
// adc read pin is set to be pin 3 in the overlay file 
#define PIN_BOARD_LED (2)
#define PIN_PAIRING_BUTTON (5)


#define ADC_BUFFER_SIZE (2) //based of resolution, samples taken, and number of channesl (12 bits = 2 bytes)
                                // 2 bytes * 1 sample taken * 1 channel = 2 

#define PRESSURE_THRESHOLD (10)


// FUNCTION DEFINITIONS

void pairing_button_cb(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins);

LOG_MODULE_REGISTER(base_station, LOG_LEVEL_INF);

int main(void)
{
        k_sleep(K_SECONDS(2));
        //Setup
        int err = 0; 

        //flags 
        bool sensorDataRequested = false;
        adcReady = false; 
        bool turnOnRightSide = false; 
        bool turnOnLeftSide = false; 

        //variables
        int checkSensorNum = 0; 
        int pressureDiff = 0; 
        LED_Operation led_operation = BLANK; 
        LED_Operation* led_operation_ptr = &led_operation;   

        //get the gpio binding
        const struct device *gpio0_dev = DEVICE_DT_GET(DT_NODELABEL(gpio0));
	if (gpio0_dev == NULL) {
		LOG_ERR("Device binding is not found\n");
		return -1; 
	}

        // // dynamically allocated memory        
        // uint16_t* boardLedMap = init_board_led(PIN_BOARD_LED);
        // if (boardLedMap == NULL){
        //         LOG_ERR("Initilization of board led failed\n");
        // }

        // //define the array to hold the selec pins 
        // int adc_sel_pins[] = {PIN_ADC_SEL_0, PIN_ADC_SEL_1, PIN_ADC_SEL_2, PIN_ADC_SEL_3};

        // // ---------------------------ADC INIT---------------------------//

        // // //initalize the adc device tree variable 
        // static const struct adc_dt_spec adc_channel = ADC_DT_SPEC_GET(DT_PATH(zephyr_user));
        // if (!adc_is_ready_dt(&adc_channel)) {
        //         LOG_ERR("ADC controller devivce %s not ready", adc_channel.dev->name);
        //         return 0;
        // }

        // int adcSensorReading[ADC_BUFFER_SIZE] = {0};

        // //default sequence options struct to be used. 
        // struct adc_sequence_options opts = {
        //         .interval_us = 0,
        //         .callback = my_adc_sequence_callback,
        //         .user_data = NULL, 
        //         .extra_samplings = 0,
        // };

        // //returns a dynamically allocated sensor pressure map
        // int* sensorPressureMap = init_multiplexer_reader(&adc_channel, adcSensorReading, &opts,NUM_SENSORS);
        // if (sensorPressureMap == NULL) {
        //         LOG_ERR("Initalization of sensorPressureMap failed\n");
        // }

        // err = init_multiplexer_sel(gpio0_dev, adc_sel_pins, NUM_ADC_SEL_PINS);
        // if (err < 0){
        //         LOG_ERR("Failed to intializlize the multiplexer init pins (err %d)\n", err);
        // }

        // //----------------------------PWM INIT--------------------------------//
        // //initalize the pwm pin and the array for the board led 
        // uint16_t* led_board_map = init_board_led(PIN_BOARD_LED);

        // //remeber to change to gpio1_dev for the buttons
        // err = init_pairing_button(gpio0_dev,PIN_PAIRING_BUTTON,pairing_button_cb);

        //-----------------------BLUETOOTH SCAN TESTING----------------------//
        

        //--------------SCAN TESTING START---------------------//

        // int err = 0; 
	const struct bt_scan_init_param bt_scan_init_opts = {
			.scan_param = NULL, //default config 
			.connect_if_match = true,
			.conn_param = NULL, //default config
	};
	
	bt_scan_init(&bt_scan_init_opts); 

        bt_scan_filter_remove_all();
	bt_scan_filter_disable(); 

        // //double check if the definitin of the short name filter is correct
	// static struct bt_scan_short_name ble_shrt_name;
	// ble_shrt_name.name = "shrtname";
	// ble_shrt_name.min_len = 8;

	// err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_SHORT_NAME, &ble_shrt_name);
	// if (err < 0) {
        //         LOG_ERR("Error setting the short name filter (err: %d)\n", err);
        //         // return err; 
	// }

	// uint8_t filter_modes = BT_SCAN_SHORT_NAME_FILTER | BT_SCAN_UUID_FILTER;
	// err = bt_scan_filter_enable(filter_modes, true); //Want all filters to be matched when looking for a new device
	// if (err < 0) {
        //         LOG_ERR("Error establishing scan filters (err: %d)\n", err);
        //         // return err; 
	// }


	// bt_scan_cb_register(scan_filter_match); 
	// bt_scan_cb_register(scan_filter_no_match); 
	// bt_scan_cb_register(scan_connecting); 
	// bt_scan_cb_register(scan_connecting_error); 

        err = bt_enable(NULL);
        if (err < 0){
                LOG_ERR("Error in enabling the bluetooh (err: %d)\n", err);
        }
        LOG_INF("Bluetooth Initialized\n");


        err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
        if (err < 0) {
                LOG_ERR("Error starting the bt scan (err: %d)\n", err);
        }

        //--------------SCAN TESTING END---------------------//

        *led_operation_ptr = BOARD_ALIVE;

        for(;;){

                // if (sensorDataRequested == false) {
                //         //send the reques to the adc to read
                //         err = request_sensor_data(gpio0_dev, &adc_channel, adc_sel_pins, NUM_ADC_SEL_PINS, checkSensorNum, NUM_SENSORS, &opts);
                //         if (err < 0){
                //                 LOG_ERR("Failed to request the sensor data (err %d)\n", err);
                //         }

                //         sensorDataRequested = true; 
                // }

                // if(adcReady){
                //         //update the array of the sensor value 
                //         sensorPressureMap[checkSensorNum] = adcSensorReading[0];
                //         //calculate the pressure difference 
                //         pressureDiff = calculate_pressure_diffrential(checkSensorNum, adcSensorReading[0], NUM_SENSORS);

                //         //based on the pressureDiff decide which side to turn on
                //         turnOnLeftSide = false; 
                //         turnOnRightSide = false; 
                //         if (abs(pressureDiff) > PRESSURE_THRESHOLD) {
                //                 //yes something need to turn on
                //                 if(pressureDiff > 0) {
                //                         turnOnRightSide = true;
                //                 } else {
                //                         turnOnLeftSide = true; 
                                        
                //                 }
                //         }

                //         //update the led as needed 
                //         update_board_led_pressure(led_board_map, turnOnLeftSide, turnOnRightSide);

                //         checkSensorNum = (checkSensorNum + 1) % NUM_SENSORS;
                //         adcReady = false; 
                //         sensorDataRequested = false; 
                // }

                //electronics status indicator
                status_led_operation(*led_operation_ptr);

        }
        return 0;
}


/** @brief  callback function for the pairing button
 * 
 *  Allow the bluetooth scanning to occur to accept a new wrist module
 *  TODO: Make the button keep a time state for deliteing all of the connections 
 *  
 *  @param port: device binding device structure 
 *  @param gpio_callback: structure that is used to register callback function in the config stage
 *  @param pins: bitwise repersentation of what pin callback has occured. 
 *  
 *  implement concurrency control to ensure that the updates occur correctly
*/

void pairing_button_cb(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins){
	// Call the bluetoth advertising function to occur here. 
	uint32_t pin_vals = 0; 
        int err = 0; 

        err = gpio_port_get(port,&pin_vals);
        if (err < 0){
                LOG_ERR("Error: Unable to get gpio port levels (err: %d)", err);
        }
         //if the button is not pressed down then just return right away 
        if (!(pin_vals & (1 << PIN_PAIRING_BUTTON))) {
                return;
        }

        err = init_bt_scan();
        if (err < 0){
                LOG_ERR("Unable to initalize the bluetooth scan parameters (err: %d)\n", err);
        }
        
        //start the scan function 
        err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
        if (err < 0) {
                LOG_ERR("Error starting the bt scan (err: %d)\n", err);
        }

};

Parents
  • Hello,

    I am getting an ENOMEM (-12) Cannot allocate memory when I try to add the short name filter to the scan system.

    what function, exactly, is returning -12 (-ENOMEM)?

    I think the guiconfig and menuconfig are the same as the proj.config

    That is correct. I usually just use prj.conf directly. (NB: prj.conf, not prj.config, but it was probably just a typo). The gui tools can be nice if you don't know exactly what you are looking for, but I usually just end up editing prj.conf manually when I know the name of the config.

    ignoring malformed line 'BT_SCAN_SHORT_NAME_CNT=1'

    Whenever you see a config like this, and you want to add it to your prj.conf, you need to add "CONFIG_" before. So please try adding:

    CONFIG_BT_SCAN_SHORT_NAME_CNT=1

    Looking throught the source code of:

    bt_scan_filter_add() -> scan_short_name_filter_add() -> 

    static int scan_short_name_filter_add(const struct bt_scan_short_name *short_name)
    {
    	uint8_t counter =
    		bt_scan.scan_filters.short_name.cnt;
    	struct bt_scan_short_name_filter *short_name_filter =
    		    &bt_scan.scan_filters.short_name;
    	uint8_t name_len;
    
    	/* If no memory for filter. */
    	if (counter >= CONFIG_BT_SCAN_SHORT_NAME_CNT) {
    		return -ENOMEM;
    	}

    This seems to be the issue. If you have not set CONFIG_BT_SCAN_SHORT_NAME_CNT=1 in prj.conf, then this will return -ENOMEM.

    Also, looking at the definition of config BT_SCAN_SHORT_NAME_CNT from the file

    ncs\nrf\subsys\bluetooth\Kconfig.scan:

    config BT_SCAN_SHORT_NAME_CNT
    	int "Number of short name filters"
    	default 0
    	help
    	  Number of short name filters

    This defaults to 0, if not specified otherwise.

    A general hint. If you want to find the definition of a CONFIG_..., for example CONFIG_BT_SCAN_SHORT_NAME_CNT, search for the name of it, but replace the "_" directly after "CONFIG" with a whitespace, and it will usually show only one (or a couple) of definitions.

    I have not tried the short name filter specifically, but in general, if you want a filter that is a little bit outside of whatever the default filters that are available, then you can always ignore setting up the predefined filters, and look at the raw advertising packets when they are picked up instead. Then you can write your own filters. Some times, this is more convenient.

    Best regards,

    Edvin

    Best regards,

    Edvin

  • Hey Edvin,

    Yes the issue in this case was in fact the CONFIG_BT_SCAN_SHORT_NAME_CNT filed not being set to something other than 0.

    To me it wasn't obvious from the Nordic documentation, and instead I had to go through the source go to determine where the error was being generated within the bt_scan_filter_enable function.

    Thank you for your help.

Reply Children
No Data
Related