BLE battery level server(peripheral)

Hi,

currently I am working for a ble battery level indication server. For that I followed one example called ble_app_bps.

And I configured  for battery level simulation. My question here is how can I send a battery level counter value(for example 0% to 20%) to the nrf connect app in smartphone?

means the real sensor(or battery level) value ,not the simulated value Please help me in this case.

//ble peripheral as advertiser/battery level Indication server


//header files
#include <stdbool.h>
#include <stdint.h>
#include <string.h>

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#include "app_timer.h"
#include "bsp_btn_ble.h"

#include "nrf_pwr_mgmt.h"

#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "nrf_sdh_soc.h"

#include "nrf_ble_qwr.h"
#include "nrf_ble_gatt.h"

#include "ble_advdata.h"
#include "ble_advertising.h"

#include "ble_bas.h"
#include "sensorsim.h"
#include "ble_srv_common.h"
#include "ble_conn_params.h"

//macros
#define APP_BLE_CONN_CFG_TAG  1
#define APP_BLE_OBSERVER_PRIO 3

#define DEVICE_NAME         "Satyabrata_BLE"
#define MIN_CON_INTERVAL    MSEC_TO_UNITS(100,UNIT_1_25_MS)//minimum conn interval(7.5ms to 4.0 secs)
#define MAX_CON_INTERVAL    MSEC_TO_UNITS(200,UNIT_1_25_MS)//maximum conn interval(7.5 ms to 4.0 secs)
#define SLAVE_LATENCY       0                              //no of times the slave skips the conn interval
#define CONN_SUP_TIMEOUT    MSEC_TO_UNITS(2000,UNIT_10_MS)//time between two succsessful conn events(100ms to 32s)

#define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(5000)  
#define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(30000)
#define MAX_CONN_PARAMS_UPDATE_COUNT    3

#define APP_ADV_INTERVAL    300
#define APP_ADV_DURATION    0

#define BATTERY_LEVEL_MEAS_INTERVAL     APP_TIMER_TICKS(2000)                   /**< Battery level measurement interval (ticks). */
#define MIN_BATTERY_LEVEL               81                                      /**< Minimum battery level as returned by the simulated measurement function. */
#define MAX_BATTERY_LEVEL               100                                     /**< Maximum battery level as returned by the simulated measurement function. */
#define BATTERY_LEVEL_INCREMENT         1                                       /**< Value by which the battery level is incremented/decremented for each call to the simulated measurement function. */




NRF_BLE_QWR_DEF(m_qwr);
NRF_BLE_GATT_DEF(m_gatt);
BLE_ADVERTISING_DEF(m_advertising);

APP_TIMER_DEF(m_battery_timer_id);                                      /**< Battery timer. */
BLE_BAS_DEF(m_bas);                                                     /**< Structure used to identify the battery service. */




//private variables
static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;
static sensorsim_cfg_t      m_battery_sim_cfg;                          /**< Battery Level sensor simulator configuration. */
static sensorsim_state_t    m_battery_sim_state;                        /**< Battery Level sensor simulator state. */



static ble_uuid_t m_adv_uuids[] =                                       /**< Universally unique service identifiers. */
{
    
    {BLE_UUID_BATTERY_SERVICE,            BLE_UUID_TYPE_BLE}
};




//private functions

//step-9 gatt initialization
static void gatt_init()
{
ret_code_t err_code = nrf_ble_gatt_init(&m_gatt,NULL);
APP_ERROR_CHECK(err_code);
}



//step-8 gap initialization
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_CON_INTERVAL;
gap_conn_params.max_conn_interval = MAX_CON_INTERVAL;
gap_conn_params.slave_latency     = SLAVE_LATENCY;
gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;

err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
APP_ERROR_CHECK(err_code);


}



//step-13 error handler for queue writer
static void nrf_qwr_error_handler(uint32_t nrf_error)
{

APP_ERROR_HANDLER(nrf_error);

}


//step-12 initialize services
static void services_init(void)
{

ret_code_t err_code;
ble_bas_init_t     bas_init;
nrf_ble_qwr_init_t qwr_init = {0};

qwr_init.error_handler = nrf_qwr_error_handler;
err_code = nrf_ble_qwr_init(&m_qwr,&qwr_init);
APP_ERROR_CHECK(err_code);

  // Initialize Battery Service.
    memset(&bas_init, 0, sizeof(bas_init));

    // Here the sec level for the Battery Service can be changed/increased.
    bas_init.bl_rd_sec        = SEC_OPEN;
    bas_init.bl_cccd_wr_sec   = SEC_OPEN;
    bas_init.bl_report_rd_sec = SEC_OPEN;

    bas_init.evt_handler          = NULL;
    bas_init.support_notification = true;
    bas_init.p_report_ref         = NULL;
    bas_init.initial_batt_level   = 100;

    err_code = ble_bas_init(&m_bas, &bas_init);
    APP_ERROR_CHECK(err_code);


}


//step-16 create an event handler for connection parameters update
static void on_conn_params_evt(ble_conn_params_evt_t *p_evt)
{
ret_code_t err_code;
if(p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
{
err_code = sd_ble_gap_disconnect(m_conn_handle,BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
APP_ERROR_CHECK(err_code);
}

if(p_evt->evt_type == BLE_CONN_PARAMS_EVT_SUCCEEDED)
{

}

}

//step-15 create an error handler for connection parameters update

static void conn_params_error_handler(uint32_t nrf_error)
{

APP_ERROR_HANDLER(nrf_error);
}





//step-14 connection params init
static void conn_params_init(void)
{
ret_code_t err_code;

ble_conn_params_init_t cp_init;
memset(&cp_init,0,sizeof(cp_init));
cp_init.p_conn_params  = NULL;
cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
cp_init.start_on_notify_cccd_handle    = BLE_GATT_HANDLE_INVALID;
cp_init.disconnect_on_fail             = false;
cp_init.error_handler = conn_params_error_handler;
cp_init.evt_handler   = on_conn_params_evt;

err_code = ble_conn_params_init(&cp_init);
APP_ERROR_CHECK(err_code);


}


//step-11 create advertisement event handler
static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
{
ret_code_t err_code;

switch(ble_adv_evt)
{
case BLE_ADV_EVT_FAST:
NRF_LOG_INFO("fast advertising....");
err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
APP_ERROR_CHECK(err_code);
break;

case BLE_ADV_EVT_IDLE:
err_code = bsp_indication_set(BSP_INDICATE_IDLE);
APP_ERROR_CHECK(err_code);

break;

default:
break;

}

}




//step-10 advertising init
static void advertising_init(void)
{
ret_code_t err_code;
ble_advertising_init_t init;


memset(&init,0,sizeof(init));

init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
init.advdata.include_appearance = true;
init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;

init.advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
init.advdata.uuids_complete.p_uuids  = m_adv_uuids;

init.config.ble_adv_fast_enabled = true;
init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
init.config.ble_adv_fast_timeout  = APP_ADV_DURATION;
init.evt_handler = on_adv_evt;

err_code = ble_advertising_init(&m_advertising,&init);
APP_ERROR_CHECK(err_code);

ble_advertising_conn_cfg_tag_set(&m_advertising,APP_BLE_CONN_CFG_TAG);
}



//step-7 ble event handler
static void ble_evt_handler(ble_evt_t const *p_ble_evt,void *p_context)
{
ret_code_t err_code = NRF_SUCCESS;
switch(p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_DISCONNECTED:
NRF_LOG_INFO("device is disconnected");
break;

case BLE_GAP_EVT_CONNECTED:
NRF_LOG_INFO("device is connected");
err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
APP_ERROR_CHECK(err_code);

m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr,m_conn_handle);
APP_ERROR_CHECK(err_code);
break;



case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
NRF_LOG_DEBUG("phy update request");
ble_gap_phys_t const phys = 
{
.rx_phys = BLE_GAP_PHY_AUTO,
.tx_phys = BLE_GAP_PHY_AUTO,
};

err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle,&phys);
APP_ERROR_CHECK(err_code);

break;



}//switch case end

}





//step-6 ble stack init
static void ble_stack_init()
{
ret_code_t err_code;
err_code = nrf_sdh_enable_request();
APP_ERROR_CHECK(err_code);


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

err_code = nrf_sdh_ble_enable(&ram_start);
APP_ERROR_CHECK(err_code);

NRF_SDH_BLE_OBSERVER(m_ble_observer,APP_BLE_OBSERVER_PRIO,ble_evt_handler,NULL);

}





//step-4 init power management
static void pwr_management_init(void)
{
ret_code_t err_code = nrf_pwr_mgmt_init();
APP_ERROR_CHECK(err_code);

}




//step-3 init bsp leds for ble 
static void leds_init(void)
{
ret_code_t err_code = bsp_init(BSP_INIT_LEDS,NULL);
APP_ERROR_CHECK(err_code);
}



/**@brief Function for performing battery measurement and updating the Battery Level characteristic
 *        in Battery Service.
 */
static void battery_level_update(void)
{
    ret_code_t err_code;
    uint8_t  battery_level=0;

   // battery_level = (uint8_t)sensorsim_measure(&m_battery_sim_state, &m_battery_sim_cfg);
      battery_level = battery_level + 1;
      if(battery_level == 8) battery_level = 0;
    err_code = ble_bas_battery_level_update(&m_bas, battery_level, BLE_CONN_HANDLE_ALL);
    if ((err_code != NRF_SUCCESS) &&
        (err_code != NRF_ERROR_INVALID_STATE) &&
        (err_code != NRF_ERROR_RESOURCES) &&
        (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
       )
    {
        APP_ERROR_HANDLER(err_code);
    }
}




/**@brief Function for handling the Battery measurement timer timeout.
 *
 * @details This function will be called each time the battery level measurement timer expires.
 *
 * @param[in]   p_context   Pointer used for passing some arbitrary information (context) from the
 *                          app_start_timer() call to the timeout handler.
 */
static void battery_level_meas_timeout_handler(void * p_context)
{
    UNUSED_PARAMETER(p_context);
    battery_level_update();
}



//step-2 init app timer
static void timers_init(void)
{
ret_code_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code);

 // Create timers.
    err_code = app_timer_create(&m_battery_timer_id,
                                APP_TIMER_MODE_REPEATED,
                                battery_level_meas_timeout_handler);
    APP_ERROR_CHECK(err_code);

}




//1st step initialize the logger
static void log_init()
{
ret_code_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
}


//step-5 idle state handle
static void idle_state_handle(void)
{
if(NRF_LOG_PROCESS() == false)
{
   nrf_pwr_mgmt_run();
}

}


//step-17 start the advertisement
static void advertising_start(void)
{

ret_code_t err_code = ble_advertising_start(&m_advertising,BLE_ADV_MODE_FAST);
APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing the sensor simulators.
 */
static void sensor_simulator_init(void)
{
    m_battery_sim_cfg.min          = MIN_BATTERY_LEVEL;
    m_battery_sim_cfg.max          = MAX_BATTERY_LEVEL;
    m_battery_sim_cfg.incr         = BATTERY_LEVEL_INCREMENT;
    m_battery_sim_cfg.start_at_max = true;

    sensorsim_init(&m_battery_sim_state, &m_battery_sim_cfg);


}





/**@brief Function for starting application timers.
 */
static void application_timers_start(void)
{
    ret_code_t err_code;

    // Start application timers.
    err_code = app_timer_start(m_battery_timer_id, BATTERY_LEVEL_MEAS_INTERVAL, NULL);
    APP_ERROR_CHECK(err_code);
}

/**@brief Function for application main entry.
 */
int main(void)
{
   log_init();//done
   timers_init();//done
   //leds_init();//done

  pwr_management_init();//done

  ble_stack_init();//done
  gap_params_init();//done
  gatt_init();//done
  advertising_init();//done
  services_init();//done
  //sensor_simulator_init();//done
  conn_params_init();//done

  NRF_LOG_INFO("Battery Level Server application started.....");
  application_timers_start();//done
  advertising_start();//done


 //enter main loop  
for(;;)
{
    idle_state_handle();
}
}



Here is the main.c file attached.

SDK - nrf5_SDK_17.1.0

DK - nrf52840

IDE - Segger embedded studio

Thanks & Regards

Satyabrata Senapati

Related