Hi there!
I'm trying to scan an extended advertising beacon in BLE peripheral to BLE central type logic.
I can scan the peripheral successfully with the nRF Connect app, however the BLE central scanner device is not able to find this specific beacon (it works with the regular beacon example and other manufacturer beacon devices).
My guess is that the problem lies somewhere within either the configuration of the scanner to capture extended beacons, I'm sending all of my data in the scan response buffer as it was suggested to me in this forum a while ago to take advantage of max advertising length, what do I need to do to get this working?
Here is the code for the peripheral (I tried to delete non BLE code as much as possible to facilitate reading):
#include <stdbool.h> #include <stdint.h> #include "nrf.h" #include "nrf_gpio.h" #include "nrf_drv_gpiote.h" #include "nrf_drv_timer.h" #include "nrf_drv_rtc.h" #include "nrf_drv_clock.h" #include "bsp.h" #include "app_error.h" #include "nrf_pwr_mgmt.h" #include "ble_conn_params.h" #include "ble_advertising.h" #include "nrf_sdh.h" #include "nrf_sdh_ble.h" #include "ble_advdata.h" #include "app_timer.h" #include "app_scheduler.h" #include "nrf_ble_gatt.h" #include "nrf_soc.h" #include "nrf_pwr_mgmt.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #define DEAD_BEEF 0xDEADBEEF //!< Value used as error code on stack dump, can be used to identify stack location on stack unwind. #define NON_CONNECTABLE_ADV_LED_PIN BSP_BOARD_LED_0 //!< Toggles when non-connectable advertisement is sent. #define CONNECTED_LED_PIN BSP_BOARD_LED_1 //!< Is on when device has connected. #define CONNECTABLE_ADV_LED_PIN BSP_BOARD_LED_2 //!< Is on when device is advertising connectable advertisements. /**@brief Priority of the application BLE event handler. * @note You shouldn't need to modify this value. */ #define APP_BLE_OBSERVER_PRIO 3 #define APP_BLE_CONN_CFG_TAG 1 /**< A tag identifying the SoftDevice BLE configuration. */ #define NON_CONNECTABLE_ADV_INTERVAL MSEC_TO_UNITS(100, UNIT_0_625_MS) /**< The advertising interval for non-connectable advertisement (100 ms). This value can vary between 100ms to 10.24s). */ #define APP_BEACON_INFO_LENGTH 0xF3 /**< Total length of information advertised by the Beacon. */ #define APP_ADV_DATA_LENGTH 0xF1 /**< Length of manufacturer specific data in the advertisement. */ #define APP_DEVICE_TYPE 0x02 /**< 0x02 refers to Beacon. */ #define APP_MEASURED_RSSI 0xC3 /**< The Beacon's measured RSSI at 1 meter distance in dBm. */ #define APP_COMPANY_IDENTIFIER 0x0059 /**< Company identifier for Nordic Semiconductor ASA. as per www.bluetooth.org. */ #define APP_BEACON_UUID 0x01, 0x02, 0x03, 0x04, 0x05 /**< Proprietary UUID for Beacon. */ #define BITMASK(b) (1 << ((b) % 8)) #define BITSLOT(b) ((b) / 8) #define BITSET(a, b) ((a)[BITSLOT(b)] |= BITMASK(b)) #define BITCLEAR(a, b) ((a)[BITSLOT(b)] &= ~BITMASK(b)) #define BITTEST(a, b) ((a)[BITSLOT(b)] & BITMASK(b)) #define BITNSLOTS(nb) ((nb + 8 - 1) / 8) #define PIN_IN NRF_GPIO_PIN_MAP(1, 7) #define OUTPUT_PIN NRF_GPIO_PIN_MAP(0, 15) #define TIMER_TICKS_TO_MS 0.01 #define BLINK_PERIOD (500 / TIMER_TICKS_TO_MS) // 500 ms #define IR_COOLDOWN 5 // cooldown from another IR read in seconds const nrf_drv_timer_t TIMER_LED = NRF_DRV_TIMER_INSTANCE(1); const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(2); /**< Declaring an instance of nrf_drv_rtc for RTC0. */ static volatile uint32_t _timer_counter = 0; static volatile uint32_t _led_counter = 0; static volatile uint32_t _burst_counter = 0; static volatile uint8_t nec_state = 0; static volatile uint8_t nec_ok = 0; static uint32_t nec_code = 0; static uint8_t *nec_code_ptr = (uint8_t *)&nec_code; static ble_gap_adv_params_t m_adv_params; static ble_advdata_t advdata; static ble_advdata_manuf_data_t manuf_specific_data; /**< Parameters to be passed to the stack when starting advertising. */ static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; /**< Advertising handle used to identify an advertising set. */ static uint8_t m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED]; /**< Buffer for storing an encoded advertising set. */ /**@brief Struct that contains pointers to the encoded advertising data. */ static ble_gap_adv_data_t m_adv_data = { .adv_data = { .p_data = NULL, .len = 0 }, .scan_rsp_data = { .p_data = m_enc_advdata, .len = BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED } }; static uint8_t m_beacon_info[APP_BEACON_INFO_LENGTH] = /**< Information advertised by the Beacon. */ { APP_DEVICE_TYPE, // Manufacturer specific information. Specifies the device type in this // implementation. APP_ADV_DATA_LENGTH, // Manufacturer specific information. Specifies the length of the // manufacturer specific data in this implementation. APP_BEACON_UUID // 128 bit UUID value. }; uint8_t reverseBits(uint8_t num); NRF_BLE_GATT_DEF(m_gatt); //!< GATT module instance. /**@brief Callback function for asserts in the SoftDevice. * * @details This function will be called in case of an assert in the SoftDevice. * * @warning This handler is an example only and does not fit a final product. You need to analyze * how your product is supposed to react in case of Assert. * @warning On assert from the SoftDevice, the system can only recover on reset. * * @param[in] line_num Line number of the failing ASSERT call. * @param[in] file_name File name of the failing ASSERT call. */ void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name) { app_error_handler(DEAD_BEEF, line_num, p_file_name); } static void advertising_init(void) { uint32_t err_code; manuf_specific_data.company_identifier = APP_COMPANY_IDENTIFIER; manuf_specific_data.data.p_data = (uint8_t *) m_beacon_info; manuf_specific_data.data.size = APP_BEACON_INFO_LENGTH; // Build and set advertising data. memset(&advdata, 0, sizeof(advdata)); advdata.name_type = BLE_ADVDATA_NO_NAME; advdata.p_manuf_specific_data = &manuf_specific_data; // Initialize advertising parameters (used when starting advertising). memset(&m_adv_params, 0, sizeof(m_adv_params)); m_adv_params.properties.type = BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED; m_adv_params.p_peer_addr = NULL; // Undirected advertisement. m_adv_params.filter_policy = BLE_GAP_ADV_FP_ANY; m_adv_params.interval = NON_CONNECTABLE_ADV_INTERVAL; m_adv_params.duration = 0; // Never time out. m_adv_params.set_id = 7; m_adv_params.primary_phy = BLE_GAP_PHY_AUTO; m_adv_params.secondary_phy = BLE_GAP_PHY_AUTO; err_code = ble_advdata_encode(&advdata, m_adv_data.scan_rsp_data.p_data, &m_adv_data.scan_rsp_data.len); APP_ERROR_CHECK(err_code); err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params); APP_ERROR_CHECK(err_code); } /**@brief Function for starting advertising. */ static void advertising_start(void) { ret_code_t err_code; err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG); APP_ERROR_CHECK(err_code); err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing the BLE stack. * * @details Initializes the SoftDevice and the BLE event interrupt. */ static void ble_stack_init(void) { ret_code_t err_code; err_code = nrf_sdh_enable_request(); APP_ERROR_CHECK(err_code); // Configure the BLE stack using the default settings. // Fetch the start address of the application RAM. uint32_t ram_start = 0; err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start); APP_ERROR_CHECK(err_code); // Enable BLE stack. err_code = nrf_sdh_ble_enable(&ram_start); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing power management. */ static void power_management_init(void) { ret_code_t err_code; err_code = nrf_pwr_mgmt_init(); APP_ERROR_CHECK(err_code); } /**@brief Function for handling the idle state (main loop). * * @details If there is no pending log operation, then sleep until next the next event occurs. */ static void idle_state_handle(void) { app_sched_execute(); nrf_pwr_mgmt_run(); } static void timers_init(void) { ret_code_t err_code = app_timer_init(); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing the nrf log module. */ static void log_init(void) { ret_code_t err_code = NRF_LOG_INIT(NULL); APP_ERROR_CHECK(err_code); NRF_LOG_DEFAULT_BACKENDS_INIT(); } /** @brief: Function for handling the RTC0 interrupts. * Triggered on TICK and COMPARE0 match. */ static void rtc_handler(nrf_drv_rtc_int_type_t int_type) { //DO NOTHING AT ALL } static void rtc_config(void) { uint32_t err_code; //Initialize RTC instance nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG; err_code = nrf_drv_rtc_init(&rtc, &config, rtc_handler); APP_ERROR_CHECK(err_code); //Power on RTC instance nrf_drv_rtc_enable(&rtc); } /** * @brief Function for main application entry. */ int main(void) { /* Initialize logging system and GPIOs. */ log_init(); timers_init(); // Configure all leds on board. bsp_board_init(BSP_INIT_LEDS); // Initialize. power_management_init(); ble_stack_init(); advertising_init(); // Start execution. NRF_LOG_INFO("Beacon example started."); NRF_LOG_FLUSH(); advertising_start(); rtc_config(); uint32_t err_code = NRF_SUCCESS; // Define start position for namespace id. uint8_t namespace_id = 2; uint16_t timestamp = 0; uint16_t last_timestamp = 0; // set p0.15 as output nrf_gpio_cfg_output(OUTPUT_PIN); // config int pin gpio_interrupt_init(); // Configure TIMER_LED for generating simple light effect - leds on board will invert his state one after the other. nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG; timer_cfg.mode = NRF_TIMER_MODE_TIMER; timer_cfg.frequency = NRF_TIMER_FREQ_16MHz; timer_cfg.interrupt_priority = 3; // 0 is the highest priority timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32; err_code = nrf_drv_timer_init(&TIMER_LED, &timer_cfg, timer_event_handler); APP_ERROR_CHECK(err_code); // 0.01ms precision counter nrf_drv_timer_extended_compare(&TIMER_LED, NRF_TIMER_CC_CHANNEL0, nrf_drv_timer_us_to_ticks(&TIMER_LED, 10), NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true); nrf_drv_timer_enable(&TIMER_LED); uint32_t start_time = 0; uint32_t error_expire_period = 0; uint8_t state = 1; // start with the led on bsp_board_led_on(0); while (1) { idle_state_handle(); } } /** @} */
This is the code on the central side:
/***************************************************************************************/ /* * beacon_scanner * Created by Manuel Montenegro, Sep 7, 2018. * * This is a Bluetooth 5 scanner. This code reads every advertisement from beacons * and sends its data through serial port. * * This code has been developed for Nordic Semiconductor nRF52840 PDK. */ /***************************************************************************************/ #include <stdint.h> #include <stdio.h> #include <string.h> #include "nordic_common.h" #include "nrf_sdm.h" #include "ble.h" #include "ble_hci.h" #include "ble_db_discovery.h" #include "ble_srv_common.h" #include "nrf_sdh.h" #include "nrf_sdh_ble.h" #include "nrf_sdh_soc.h" #include "nrf_pwr_mgmt.h" #include "app_util.h" #include "app_error.h" #include "ble_rscs_c.h" #include "app_util.h" #include "app_timer.h" #include "bsp_btn_ble.h" #include "peer_manager.h" #include "peer_manager_handler.h" #include "fds.h" #include "nrf_fstorage.h" #include "ble_conn_state.h" #include "nrf_ble_gatt.h" #include "nrf_pwr_mgmt.h" #include "nrf_ble_scan.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #define APP_BLE_CONN_CFG_TAG 1 /**< Tag that identifies the BLE configuration of the SoftDevice. */ #define APP_BLE_OBSERVER_PRIO 3 /**< BLE observer priority of the application. There is no need to modify this value. */ #define APP_SOC_OBSERVER_PRIO 1 /**< SoC observer priority of the application. There is no need to modify this value. */ #define SCAN_INTERVAL 0x0320 /**< Determines scan interval in units of 0.625 millisecond. */ #define SCAN_WINDOW 0x0320 /**< Determines scan window in units of 0.625 millisecond. */ #define SCAN_DURATION 0x0000 /**< Duration of the scanning in units of 10 milliseconds. If set to 0x0000, scanning continues until it is explicitly disabled. */ NRF_BLE_SCAN_DEF(m_scan); /**< Scanning Module instance. */ static bool m_memory_access_in_progress; /**< Flag to keep track of ongoing operations on persistent memory. */ static ble_gap_scan_params_t m_scan_param = /**< Scan parameters requested for scanning and connection. */ { .active = 0x00, .interval = SCAN_INTERVAL, .window = SCAN_WINDOW, .filter_policy = BLE_GAP_ADV_FP_ANY, .timeout = SCAN_DURATION, .scan_phys = BLE_GAP_PHY_AUTO, // Choose only one of the following scan_phys //.scan_phys = BLE_GAP_PHY_1MBPS, // .scan_phys = BLE_GAP_PHY_2MBPS, .extended = 1, }; static void scan_start(void); /**@brief Function for handling BLE events. * * @param[in] p_ble_evt Bluetooth stack event. * @param[in] p_context Unused. */ static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) { switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_ADV_REPORT: { NRF_LOG_RAW_HEXDUMP_INFO (m_scan.scan_buffer.p_data, m_scan.scan_buffer.len); NRF_LOG_RAW_INFO ("----------------------------------\r\n"); } default: break; } } /** * @brief SoftDevice SoC event handler. * * @param[in] evt_id SoC event. * @param[in] p_context Context. */ static void soc_evt_handler(uint32_t evt_id, void * p_context) { switch (evt_id) { case NRF_EVT_FLASH_OPERATION_SUCCESS: /* fall through */ case NRF_EVT_FLASH_OPERATION_ERROR: if (m_memory_access_in_progress) { m_memory_access_in_progress = false; scan_start(); } break; default: // No implementation needed. break; } } /**@brief Function for initializing the BLE stack. * * @details Initializes the SoftDevice and the BLE event interrupt. */ static void ble_stack_init(void) { ret_code_t err_code; err_code = nrf_sdh_enable_request(); APP_ERROR_CHECK(err_code); // Configure the BLE stack using the default settings. // Fetch the start address of the application RAM. uint32_t ram_start = 0; err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start); APP_ERROR_CHECK(err_code); // Enable BLE stack. err_code = nrf_sdh_ble_enable(&ram_start); APP_ERROR_CHECK(err_code); // Register handlers for BLE and SoC events. NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL); NRF_SDH_SOC_OBSERVER(m_soc_observer, APP_SOC_OBSERVER_PRIO, soc_evt_handler, NULL); } /**@brief Function for handling Scanning Module events. */ static void scan_evt_handler(scan_evt_t const * p_scan_evt) { switch(p_scan_evt->scan_evt_id) { case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT: { NRF_LOG_INFO("Scan timed out."); scan_start(); } break; default: break; } } /**@brief Function for initializing the scanning and setting the filters. */ static void scan_init(void) { ret_code_t err_code; nrf_ble_scan_init_t init_scan; memset(&init_scan, 0, sizeof(init_scan)); init_scan.connect_if_match = false; init_scan.conn_cfg_tag = APP_BLE_CONN_CFG_TAG; init_scan.p_scan_param = &m_scan_param; err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler); APP_ERROR_CHECK(err_code); } /**@brief Function for starting scanning. */ static void scan_start(void) { ret_code_t err_code; // If there is any pending write to flash, defer scanning until it completes. if (nrf_fstorage_is_busy(NULL)) { m_memory_access_in_progress = true; return; } err_code = nrf_ble_scan_start(&m_scan); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing logging. */ static void log_init(void) { ret_code_t err_code = NRF_LOG_INIT(NULL); APP_ERROR_CHECK(err_code); NRF_LOG_DEFAULT_BACKENDS_INIT(); } /**@brief Function for initializing the timer. */ static void timer_init(void) { ret_code_t err_code = app_timer_init(); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing power management. */ static void power_management_init(void) { ret_code_t err_code; err_code = nrf_pwr_mgmt_init(); APP_ERROR_CHECK(err_code); } /**@brief Function for handling the idle state (main loop). * * @details Handles any pending log operations, then sleeps until the next event occurs. */ static void idle_state_handle(void) { if (NRF_LOG_PROCESS() == false) { nrf_pwr_mgmt_run(); } } int main(void) { // Initialize. log_init(); timer_init(); power_management_init(); ble_stack_init(); scan_init(); // Start execution. NRF_LOG_RAW_INFO( " ----------------\r\n"); NRF_LOG_RAW_INFO( "| Beacon scanner |"); NRF_LOG_RAW_INFO("\r\n ----------------\r\n"); scan_start(); // Enter main loop. for (;;) { idle_state_handle(); } }
Also I'm using two nRF52840 DKs with nrf SDK 16.
I appreciate any advise anyone can give me.
Thanks in advance and best regards.
Gabriel