Hi everyone,
I changed the example ble_app_beacon from sdk 15.0.0 sd132 to be able to scan beacon besides transmit. It works well to scan beacons and I can get their UUID's. But I need to read the tx power reference at 1 meter sended by the Smartphone that I believe is the tx_power from p_gap_evt->params.adv_report.tx_power. I tryied to change this value even in nRF Connect app, but the value is fixed at 0x7F.
I found this from ble_gap.h:
at line 232:
/** @brief Invalid power level. */
#define BLE_GAP_POWER_LEVEL_INVALID 127
at line 1260:
int8_t tx_power /**< TX Power reported by the advertiser in the last packet header received. This field is set to @ref BLE_GAP_POWER_LEVEL_INVALID if the last received packet did not contain the Tx Power field. @note TX Power is only included in extended advertising packets. */
I know that the value is being sended because I already tested in other hardware from other manufacturer many times. So I think I forgot some configuration in my code.
I attached my code to help you help me ;)
Any help will be appreciate.
#include <stdbool.h> #include <stdint.h> #include <string.h> #include "nordic_common.h" #include "bsp.h" #include "nrf_soc.h" #include "nrf_sdh.h" #include "nrf_sdh_ble.h" #include "ble_advdata.h" #include "app_timer.h" #include "nrf_pwr_mgmt.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #include "ble_conn_state.h" #include "nrf_gpio.h" #include "nrf_delay.h" static ble_gap_adv_params_t m_adv_params; /**< 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_MAX]; /**< 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 = m_enc_advdata, .len = BLE_GAP_ADV_SET_DATA_SIZE_MAX }, .scan_rsp_data = { .p_data = NULL, .len = 0 } }; 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. APP_MAJOR_VALUE, // Major arbitrary value that can be used to distinguish between Beacons. APP_MINOR_VALUE, // Minor arbitrary value that can be used to distinguish between Beacons. APP_MEASURED_RSSI // Manufacturer specific information. The Beacon's measured TX power in // this implementation. }; /**@brief Parameters used when scanning. */ static ble_gap_scan_params_t const m_scan_params = { .extended = 1, .active = 0, .interval = SCAN_INTERVAL, .window = SCAN_WINDOW, .timeout = SCAN_DURATION, .scan_phys = BLE_GAP_PHY_1MBPS, .filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL, }; static uint8_t m_scan_buffer_data[BLE_GAP_SCAN_BUFFER_EXTENDED_MIN]; /**< buffer where advertising reports will be stored by the SoftDevice. */ /**@brief Pointer to the buffer where advertising reports will be stored by the SoftDevice. */ static ble_data_t m_scan_buffer = { m_scan_buffer_data, BLE_GAP_SCAN_BUFFER_EXTENDED_MIN }; /**@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); } /**@brief Function for initializing the Advertising functionality. * * @details Encodes the required advertising data and passes it to the stack. * Also builds a structure to be passed to the stack when starting advertising. */ static void advertising_init(void) { uint32_t err_code; ble_advdata_t advdata; uint8_t flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED; ble_advdata_manuf_data_t manuf_specific_data; 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.flags = flags; 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_NONCONNECTABLE_NONSCANNABLE_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. err_code = ble_advdata_encode(&advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_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); } static void advertising_stop(void) { ret_code_t err_code; err_code = sd_ble_gap_adv_stop(m_adv_handle); APP_ERROR_CHECK(err_code); } /**@brief Function for initiating scanning. */ static void scan_start(void) { ret_code_t err_code; (void) sd_ble_gap_scan_stop(); err_code = sd_ble_gap_scan_start(&m_scan_params, &m_scan_buffer); // It is okay to ignore this error since we are stopping the scan anyway. if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } } static void scan_stop(void) { ret_code_t err_code; err_code = sd_ble_gap_scan_stop(); APP_ERROR_CHECK(err_code); } /**@brief Function for handling BLE events from central applications. * * @details This function parses scanning reports and initiates a connection to peripherals when a * target UUID is found. It updates the status of LEDs used to report central applications * activity. * * @param[in] p_ble_evt Bluetooth stack event. */ static void on_ble_central_evt(ble_evt_t const * p_ble_evt) { ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt; uint8_t uuid[26]; switch (p_ble_evt->header.evt_id) { // Upon connection, check which peripheral has connected (HR or RSC), initiate DB // discovery, update LEDs status and resume scanning if necessary. case BLE_GAP_EVT_CONNECTED: { NRF_LOG_INFO("Central connected"); } break; // BLE_GAP_EVT_CONNECTED case BLE_GAP_EVT_DISCONNECTED: { NRF_LOG_INFO("Central disconnected"); } break; // BLE_GAP_EVT_DISCONNECTED case BLE_GAP_EVT_ADV_REPORT: { NRF_LOG_INFO("Advertise received"); scan_start(); nrf_gpio_pin_toggle(LED1_PIN); memmove(uuid, p_gap_evt->params.adv_report.data.p_data, p_gap_evt->params.adv_report.data.len); NRF_LOG_INFO("UUID: %02x%02x%02x%02x%02x%02x", uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5]); NRF_LOG_INFO("TX_POWER: %02x", p_gap_evt->params.adv_report.tx_power); NRF_LOG_INFO("RSSI: %02x", p_gap_evt->params.adv_report.rssi); } break; // BLE_GAP_ADV_REPORT default: // No implementation needed. break; } } /**@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) { uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle; uint16_t role = ble_conn_state_role(conn_handle); if ((role == BLE_GAP_ROLE_CENTRAL) || (p_ble_evt->header.evt_id == BLE_GAP_EVT_ADV_REPORT)) { on_ble_central_evt(p_ble_evt); } } /**@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 a handler for BLE events. NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL); } /**@brief Function for the GAP initialization. * * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the * device including the device name, appearance, and the preferred connection parameters. */ static void gap_params_init(void) { ret_code_t err_code; ble_gap_conn_params_t gap_conn_params; ble_gap_conn_sec_mode_t sec_mode; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME, strlen(DEVICE_NAME)); APP_ERROR_CHECK(err_code); memset(&gap_conn_params, 0, sizeof(gap_conn_params)); gap_conn_params.min_conn_interval = MIN_CONNECTION_INTERVAL; gap_conn_params.max_conn_interval = MAX_CONNECTION_INTERVAL; gap_conn_params.slave_latency = SLAVE_LATENCY; gap_conn_params.conn_sup_timeout = SUPERVISION_TIMEOUT; err_code = sd_ble_gap_ppcp_set(&gap_conn_params); 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 timers. */ static void timers_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 If there is no pending log operation, then sleep until next the next event occurs. */ static void idle_state_handle(void) { if (NRF_LOG_PROCESS() == false) { nrf_pwr_mgmt_run(); } } /** * @brief Function for application main entry. */ int main(void) { /* Configure board. */ nrf_gpio_cfg_output(LED1_PIN); nrf_gpio_cfg_output(LED2_PIN); // Initialize. log_init(); timers_init(); power_management_init(); nrf_gpio_pin_set(LED1_PIN); nrf_gpio_pin_set(LED2_PIN); ble_stack_init(); gap_params_init(); advertising_init(); scan_start(); sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_SCAN_INIT, BLE_GAP_TX_POWER_ROLE_ADV, 4); NRF_LOG_INFO("Beacon example started."); // Enter main loop. while(true) { idle_state_handle(); } }