This was a quick and un-optimized test done to observe how proximity and range approximation can be done based on the Bluetooth Low Energy module’s RSSI(Received Signal Strength Indicator). We have utilized NRF52 SoC and ESP32 SoC for this test where NRF52 is in Central Role and ESP32 is in the Peripheral BLE role. in this test we do not care about what profile, or services there have or offer.

In this post you will find:

  • Quick Set-Up ESP32 Development Environment on Linux Platform.
  • Compiling gatt_server project for ESP32 and uploading gatt_server to ESP32 WROOM32 Module.
  • Setting Up the SDK, SoftDevice for NRF52.
    • Uploading Softdevice S132 and then the App-Hex.
  • Testing NRF52, Adv Report, RSSI.
    • Testing with ESP32 and NRF52 and tweaking the logic.

ESP32 Linux Development Environment Setup

ESP32 WROOM32
ESP32 WROOM32 MODULE

This is for debian-flavoured linux platforms, make sure you have python 3.7 or higher:

~>sudo apt-get install git wget flex bison gperf python python-pip python-setuptools cmake ninja-build ccache libffi-dev libssl-dev dfu-util
~>mkdir platforms_sdk
~>cd platforms_sdk
~/platforms_sdk>git clone --recursive https://github.com/espressif/esp-idf.git
~/platforms_sdk>cd esp-idf
~/platforms_sdk/esp-idf>./install.sh
~/platforms_sdk/esp-idf>. ./export.sh

After executing the export.sh script, your terminal is now ready with esp-idf environment variables. But you need to run export.sh every time when you launch a new terminal instance.

Compiling ESP32 Project and Uploading

In this session, we are using gatt_server project which is out of the box from the example folder of the esp-idf bundle.

// Putting the gatt_server project folder to the level of esp-idf folder
// Set the target and default configs
~/platforms_sdk/gatt_server>idf.py set-target esp32
//Run menuconfig if you want to set or enable other features and libraries etc.
~/platforms_sdk/gatt_server>idf.py menuconfig
// Now build the project, this below command will noly generate the application bin file.
~/platforms_sdk/gatt_server>idf.py build
// Assuming your COM PORT is on /dev/ttyUSB0, this will build, flash over ttyUSB0 and the open the console based serial monitor at 115200 baud rate by default.
~/platforms_sdk/gatt_server>idf.py flash monitor

Setting Up the SDK, SoftDevice for NRF52.

Some Specs of NRF52 Preview DK board which is been used fo this test:

  • NRF52832 QFAABA | Central Role | So we downloaded the following from NordicSemi’s website, and also matching the IROM and RAM.
    • nRF5 SDK 17.0.2
    • S132 SoftDevice
nRF52 Preview DK Image
nRF52 Preview DK(Old Version)

The general upload sequence in the Nordic Semi’s BLE SoC ecosystems (without bootloader) is:

  • Soft Device Hex file to be uploaded using nRFStudio.(S132 in our case)
  • Then, upload the application hex file so compiled by the IDE, by nRFStudio, and this will auto-reset the SoC after upload.

REMEMBER to search for IRAM and ROM addresses for your respective nRF5X SoC, and I am not mentioning here, because the link may get updated by Nordic Semi. hence please look for the latest values at the time you want to have these details.

Testing the whole rig-setup

Testing the nRF52 and ESP32 Rig.
Testing the nRF52 and ESP32 Rig.
ESP32 and nRF52 Preview DK Kit
ESP32 and nRF52 Preview DK Kit

nRF52 Source Code Edited Section from the template project ble_uart_app out of the box from SDK bundle. In this template, we have removed the NRFLog library and also omitted the UUID Filter from the scan_init() procedure.

Github Gist Link: https://gist.github.com/pixma/3cab61902dbe9b0e430db06c6286cbe7

// File: main.c or the main entry point of the application.
////////////////
// added which comes along with SDK bundle so provided by Keil for ARM. 
#include "math.h"
//If you are using GCC, you may have to provide flag options in compilation phase.
///////////
// Only edited portions are mentioned here for main.c from template project to make/customize
// for scanning without filter, also NRFLog removed to pack it within 32K limit of Keil for now.
//

/**@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 = true;
    init_scan.conn_cfg_tag     = APP_BLE_CONN_CFG_TAG;

    err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
    APP_ERROR_CHECK(err_code);
  
    // Omitted section to remove filters while scanning.
    //err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_UUID_FILTER, &m_nus_uuid);
    //APP_ERROR_CHECK(err_code);

    // Omitted section to remove filters while scanning.
    //err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_UUID_FILTER, false);
    //APP_ERROR_CHECK(err_code);
}
////////////////
////////////////

/**@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)
{
    ret_code_t            err_code;
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;	

    switch (p_ble_evt->header.evt_id)
    {
	//This below event ID will help you to access MAC ID,
        Complete Name and RSSI of available BLE Device if they are
 
        broadcasting.
        // Add this case if not present in template or
        in example projects
.
        case BLE_GAP_EVT_ADV_REPORT:
	{
	//Edited By Annim Banerjee
        // get a report of the scan
	const ble_gap_evt_adv_report_t *p_adv_report = &p_gap_evt->params.adv_report;			
	compute_is_object_close( p_adv_report );
        // Added this method which returns void.			
        ///////////
	}					
	break;
        // Finsh adding
        case BLE_GAP_EVT_CONNECTED:
            err_code = ble_nus_c_handles_assign(&m_ble_nus_c, p_ble_evt->evt.gap_evt.conn_handle, NULL);
            APP_ERROR_CHECK(err_code);

            err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
            APP_ERROR_CHECK(err_code);

            // start discovery of services. The NUS Client waits for a discovery result
            err_code = ble_db_discovery_start(&m_db_disc, p_ble_evt->evt.gap_evt.conn_handle);
            APP_ERROR_CHECK(err_code);
            break;
.
.
.
.
        default:
            break;
    }
}
///////////
///////////
// Custom function
///////////
static void compute_is_object_close( const  ble_gap_evt_adv_report_t *p_adv_report_data){

    // computing Range approximation based on RSSI
    // Parameters
    // Distance, Measured Power, RSSI and N as a Contant depends on the Env factor from 2-4.
    // Formulae : Distance = 10 ^ ((Measured Power — RSSI)/(10 * N))
    // Using math lib...
    const int nConstant = 2;	
    // Considering low strength from surrounding BLE devices if they are adv-ing.
    const int nMeasuredPower = -69;
    // BLE uses Measured Power is also known as the 1 Meter RSSI. So consider value of Measured Power = -69.
    static double approxDistancef = 0.00;

    // Formulae : Distance = 10 ^ ((Measured Power — RSSI)/(10 * N))

    approxDistancef = pow((double)10, (double)( (double)(nMeasuredPower - ((int)p_adv_report_data->rssi))/(double)(10*nConstant) ));

    if(approxDistancef >= 0.025f ){
        // If anything more than the limit meter approx. range then do not display for now.
    }else{
        // Normal. Other Devices within Approx N m range.
        // else, show that this is under N m range.
        printf("Target : %02x%02x%02x%02x%02x%02x\r\n",
                      p_adv_report_data->peer_addr.addr[0],
                      p_adv_report_data->peer_addr.addr[1],
                      p_adv_report_data->peer_addr.addr[2],
                      p_adv_report_data->peer_addr.addr[3],
                      p_adv_report_data->peer_addr.addr[4],
                      p_adv_report_data->peer_addr.addr[5]
                      );
        printf("This Device RSSI db:%d.\r\n", p_adv_report_data->rssi);
        printf("This Device approx. distance from scanner: %fm . \n\r", approxDistancef );
        printf("\r\n");
    }
}
//End of compute_is_object_close() .
//////////////////
// To remove NRFLog
// Disable them from sdk_config.h via help of wizard from keil IDE, which will help you to pack the output within 32K limit.
// replace NRF_LOG_XXX by printf or remove them if you wish to.
// Clean and then built the project.
int main(void)
{
    // Initialize.
    //log_init();
    timer_init();
    uart_init();
    buttons_leds_init();
    db_discovery_init();
    power_management_init();
    ble_stack_init();
    gatt_init();
    nus_c_init();
    scan_init();

    // Start execution.
    printf("BLE UART central example started.\r\n");
    //NRF_LOG_INFO("BLE UART central example started.");
    scan_start();

    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
    }
}
//
// EOF
//

Do check out the video where the test is been performed.

BLE RSSI Proximity-Range General Test using NRF52(Central) & ESP32(Peripheral)

Services | annimbanerjee.in | on Fiverr.com | https://www.fiverr.com/annimbanerjee
Services | annimbanerjee.in | on Fiverr.com

Author: Annim Banerjee | www.annimbanerjee.in | Services | https://github.com/pixma | Annim Banerjee Fiverr