This blog is to show how to get the RSSI (Radio Signal Strength Indicator) on the nRF52 chipset.
RSSI
In telecommunications, received signal strength indicator (RSSI) is a measurement of the power present in a received radio signal.
RSSI is usually invisible to a user of a receiving device. However, because signal strength can vary greatly and affect functionality in wireless networking, IEEE 802.11 devices often make the measurement available to users.
RSSI is often derived in the intermediate frequency (IF) stage before the IF amplifier. In zero-IF systems, it is derived in the baseband signal chain, before the baseband amplifier.
Product Specification on the nRF52832
It has the RSSISAMPLE to read the rssi value (1 byte).

For the Bluetooth Low Energy, there are two difference modes to get the RSSI value.
- Broadcast / Scanning mode (Advertising / Observer role)
- Connected Mode (Central / Peripheral role)
Broadcast / Scanning mode
The advertiser is kept to broadcaster the advertising packet on each interval as below.

Advertiser would sometimes get the scan request from central. Advertiser would get the peer address and rssi on such central.
SoftDevices up to versions 5.x you need to enable the option for BLE_GAP_OPT_SCAN_REQ_REPORT in order for the SoftDevice to generate those events.
For SoftDevices versions 6.x this was changed and there is now a flag scan_req_notification in ble_gap_adv_params_t that you must set in order to get the BLE_GAP_EVT_SCAN_REQ_REPORTs.

Softdevice v6.x

When the device (advertiser) gets the scan request event ( BLE_GAP_EVT_SCAN_REQ_REPORT), it would get RSSI, peer_address and advertising handle number.

The scan request notification should be set in theĀ ble_advertising_start function. The reason is that the parameters in the ble_advertising_init function gets overwritten. You can set it like this:
uint32_t ble_advertising_start(ble_advertising_t * const p_advertising,
ble_adv_mode_t advertising_mode)
{
uint32_t ret;
if (p_advertising->initialized == false)
{
return NRF_ERROR_INVALID_STATE;
}
p_advertising->adv_mode_current = advertising_mode;
memset(&p_advertising->peer_address, 0, sizeof(p_advertising->peer_address));
if ( ((p_advertising->adv_modes_config.ble_adv_directed_high_duty_enabled) && (p_advertising->adv_mode_current == BLE_ADV_MODE_DIRECTED_HIGH_DUTY))
||((p_advertising->adv_modes_config.ble_adv_directed_enabled) && (p_advertising->adv_mode_current == BLE_ADV_MODE_DIRECTED_HIGH_DUTY))
||((p_advertising->adv_modes_config.ble_adv_directed_enabled) && (p_advertising->adv_mode_current == BLE_ADV_MODE_DIRECTED))
)
{
if (p_advertising->evt_handler != NULL)
{
p_advertising->peer_addr_reply_expected = true;
p_advertising->evt_handler(BLE_ADV_EVT_PEER_ADDR_REQUEST);
}
else
{
p_advertising->peer_addr_reply_expected = false;
}
}
p_advertising->adv_mode_current = adv_mode_next_avail_get(p_advertising, advertising_mode);
// Fetch the whitelist.
if ((p_advertising->evt_handler != NULL) &&
(p_advertising->adv_mode_current == BLE_ADV_MODE_FAST || p_advertising->adv_mode_current == BLE_ADV_MODE_SLOW) &&
(p_advertising->adv_modes_config.ble_adv_whitelist_enabled) &&
(!p_advertising->whitelist_temporarily_disabled))
{
p_advertising->whitelist_in_use = false;
p_advertising->whitelist_reply_expected = true;
p_advertising->evt_handler(BLE_ADV_EVT_WHITELIST_REQUEST);
}
else
{
p_advertising->whitelist_reply_expected = false;
}
// Initialize advertising parameters with default values.
memset(&p_advertising->adv_params, 0, sizeof(p_advertising->adv_params));
p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
// Use 1MBIT as primary phy if no phy was selected.
if (phy_is_valid(&p_advertising->adv_modes_config.ble_adv_primary_phy))
{
p_advertising->adv_params.primary_phy = p_advertising->adv_modes_config.ble_adv_primary_phy;
}
else
{
p_advertising->adv_params.primary_phy = BLE_GAP_PHY_1MBPS;
}
if (p_advertising->adv_modes_config.ble_adv_extended_enabled)
{
// Use 1MBIT as secondary phy if no phy was selected.
if (phy_is_valid(&p_advertising->adv_modes_config.ble_adv_secondary_phy))
{
p_advertising->adv_params.secondary_phy = p_advertising->adv_modes_config.ble_adv_secondary_phy;
}
else
{
p_advertising->adv_params.secondary_phy = BLE_GAP_PHY_1MBPS;
}
}
p_advertising->adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
// Set advertising parameters and events according to selected advertising mode.
switch (p_advertising->adv_mode_current)
{
case BLE_ADV_MODE_DIRECTED_HIGH_DUTY:
ret = set_adv_mode_directed_high_duty(p_advertising, &p_advertising->adv_params);
break;
case BLE_ADV_MODE_DIRECTED:
ret = set_adv_mode_directed(p_advertising, &p_advertising->adv_params);
break;
case BLE_ADV_MODE_FAST:
ret = set_adv_mode_fast(p_advertising, &p_advertising->adv_params);
break;
case BLE_ADV_MODE_SLOW:
ret = set_adv_mode_slow(p_advertising, &p_advertising->adv_params);
break;
case BLE_ADV_MODE_IDLE:
p_advertising->adv_evt = BLE_ADV_EVT_IDLE;
break;
default:
break;
}
if (p_advertising->adv_mode_current != BLE_ADV_MODE_IDLE)
{
p_advertising->adv_params.scan_req_notification = 1;
ret = sd_ble_gap_adv_set_configure(&p_advertising->adv_handle, p_advertising->p_adv_data, &p_advertising->adv_params);
if (ret != NRF_SUCCESS)
{
return ret;
}
ret = sd_ble_gap_adv_start(p_advertising->adv_handle, p_advertising->conn_cfg_tag);
if (ret != NRF_SUCCESS)
{
return ret;
}
}
if (p_advertising->evt_handler != NULL)
{
p_advertising->evt_handler(p_advertising->adv_evt);
}
return NRF_SUCCESS;
}

Add the BLE_GAP_EVT_SCAN_REQ_REPORT inside the ble_evt_handler
case BLE_GAP_EVT_SCAN_REQ_REPORT:
NRF_LOG_INFO("BLE_GAP_EVT_SCAN_REQ_REPORT");
{
ble_gap_evt_scan_req_report_t * p_scan_req_report_t = (ble_gap_evt_scan_req_report_t *)&p_ble_evt->evt.gap_evt.params.scan_req_report;
NRF_LOG_INFO("Peer Address = 0x%02x:%02x:%02x:%02x:%02x:%02x", \
p_scan_req_report_t->peer_addr.addr[5], \
p_scan_req_report_t->peer_addr.addr[4], \
p_scan_req_report_t->peer_addr.addr[3], \
p_scan_req_report_t->peer_addr.addr[2], \
p_scan_req_report_t->peer_addr.addr[1], \
p_scan_req_report_t->peer_addr.addr[0]);
NRF_LOG_INFO("RSSI value = %d dBm", p_scan_req_report_t->rssi);
}
Output:

Connected Mode (Central / Peripheral)
How to read the RSSI
You have to call sd_ble_gap_rssi_start() initially so that the SoftDevice will start to report the RSSI. Depending on the parameters, you will get an event every time the RSSI change or if it changes beyond a given threshold. You can also poll by calling sd_ble_gap_rssi_get(). These message sequence charts shows all variants:


Nordic provides the RSSI API to get the value.

After the connection is established, it starts to get RSSI.

Add the routine to print out the RSSI Change inside ble_evt_handler.
