This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Get Tx Power Field NRF52832 Beacon

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();
	}
}

Parents
  • Hi Jeremi,

     

    I'm not sure I fully understand your setup. You mentioned about " tx power reference at 1 meter sended by the Smartphone " Could you clarify what would the smart phone sends here ? What is the smartphone role in your application ? 

    There is a TxPower level inside advertising packet you can add. However, as far as I know, we don't use txpower in our beacon example. You can add the p_tx_power_level of advdata into your advertising packet. 

    When you change txpower, you need to update this value of the advertising data, it doesn't get updated automatically by the softdevice. 

Reply
  • Hi Jeremi,

     

    I'm not sure I fully understand your setup. You mentioned about " tx power reference at 1 meter sended by the Smartphone " Could you clarify what would the smart phone sends here ? What is the smartphone role in your application ? 

    There is a TxPower level inside advertising packet you can add. However, as far as I know, we don't use txpower in our beacon example. You can add the p_tx_power_level of advdata into your advertising packet. 

    When you change txpower, you need to update this value of the advertising data, it doesn't get updated automatically by the softdevice. 

Children
  • Hi Hung Bui,

    Thank you for your quick response.

    The tx power I mentioned is a value sended by a peripheral device (the Smartphone in this case) that is used to calibrate purposes and estimate the distance between a central (NRF52 DK) and peripheral devices. Some beacon apps let you change this value like the picture I attached, but I cant see this value on the central side (NRF52 DK). I can read the UUID, Major and Minor values without problems.

    If you need more information please let me know.

  • Hi folks, I solved my problem.

    The problem was just the size of the buffer I declare: uint8_t uuid[26] at line 191;

    Wen I copy the UUID to the buffer at line 213, the size p_gap_evt->params.adv_report.data.len indicate 27 bytes. But because my buffer have only 26 bytes the last position isn't copied. And this last position have the tx_power value that is exactly I want.

    I hope this help others.

    Thank you!

Related