/** 
* Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
*    list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
*    Semiconductor ASA integrated circuit in a product or a software update for
*    such product, must reproduce the above copyright notice, this list of
*    conditions and the following disclaimer in the documentation and/or other
*    materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
*    contributors may be used to endorse or promote products derived from this
*    software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
*    Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
*    engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @example examples/ble_peripheral/ble_app_hrs/main.c
*
* @brief Heart Rate Service Sample Application main file.
*
* This file contains the source code for a sample application using the Heart Rate service
* (and also Battery and Device Information services). This application uses the
* @ref srvlib_conn_params module.
*/

#include <stdint.h>
#include <string.h>
#include "nordic_common.h"
#include "nrf.h"
#include "ble.h"
#include "ble_hci.h"
#include "ble_srv_common.h"
#include "ble_advdata.h"
#include "ble_advertising.h"
#include "ble_dis.h"
#include "boards.h"
#include "sensorsim.h"
#include "nrf_sdh.h"
#include "nrf_sdh_soc.h"
#include "nrf_sdh_ble.h"
#include "bsp.h"
#include "bsp_btn_ble.h"
#include "peer_manager.h"
#include "peer_manager_handler.h"
#include "fds.h"
#include "nrf_ble_gatt.h"
#include "nrf_ble_qwr.h"
#include "ble_conn_state.h"

#include "app_error.h"
#include "app_timer.h"
#include "task_manager.h"
#include "nrf_cli.h"
#include "nrf_cli_rtt.h"
#include "nrf_cli_uart.h"
#include "nrf_cli_ble_uart.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_drv_clock.h"
#include "nrf_stack_guard.h"
#include "nrf_fstorage_sd.h"
#include "nrf_ble_scan.h"
#include "ble_db_discovery.h"
#include "ble_nus.h"
#include "ble_cus.h"
//#include "ble_hts.h"
#include "ble_conn_params.h"
#include "flash_write.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_backend_flash.h"


#define DEVICE_NAME                     "Nordic_CLI"                                /**< Name of device. Will be included in the advertising data. */
#define MANUFACTURER_NAME               "NordicSemiconductor"                       /**< Manufacturer. Will be passed to Device Information Service. */
#define APP_ADV_INTERVAL                300                                         /**< The advertising interval (in units of 0.625 ms. This value corresponds to 187.5 ms). */

#define APP_ADV_DURATION                18000                                       /**< The advertising duration (180 seconds) in units of 10 milliseconds. */

#define APP_BLE_OBSERVER_PRIO           3                                           /**< Application's BLE observer priority. You shouldn't need to modify this value. */
#define APP_BLE_CONN_CFG_TAG            1                                           /**< A tag identifying the SoftDevice BLE configuration. */

#define BATTERY_LEVEL_MEAS_INTERVAL      APP_TIMER_TICKS(2000)                      /**< Battery level measurement interval (ticks). */
#define MIN_BATTERY_LEVEL                81                                         /**< Minimum simulated battery level. */
#define MAX_BATTERY_LEVEL                100                                        /**< Maximum simulated 7battery level. */
#define BATTERY_LEVEL_INCREMENT          1                                          /**< Increment between each simulated battery level measurement. */

#define MIN_CONN_INTERVAL                MSEC_TO_UNITS(400, UNIT_1_25_MS)           /**< Minimum acceptable connection interval (0.4 seconds). */
#define MAX_CONN_INTERVAL                MSEC_TO_UNITS(650, UNIT_1_25_MS)           /**< Maximum acceptable connection interval (0.65 second). */
#define SLAVE_LATENCY                    0                                          /**< Slave latency. */
#define CONN_SUP_TIMEOUT                 MSEC_TO_UNITS(4000, UNIT_10_MS)            /**< Connection supervisory timeout (4 seconds). */

#define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(5000)                       /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
#define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(30000)                      /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
#define MAX_CONN_PARAMS_UPDATE_COUNT    3                                           /**< Number of attempts before giving up the connection parameter negotiation. */

#define SEC_PARAM_BOND                  1                                           /**< Perform bonding. */
#define SEC_PARAM_MITM                  0                                           /**< Man In The Middle protection not required. */
#define SEC_PARAM_LESC                  0                                           /**< LE Secure Connections not enabled. */
#define SEC_PARAM_KEYPRESS              0                                           /**< Keypress notifications not enabled. */
#define SEC_PARAM_IO_CAPABILITIES       BLE_GAP_IO_CAPS_NONE                        /**< No I/O capabilities. */
#define SEC_PARAM_OOB                   0                                           /**< Out Of Band data not available. */
#define SEC_PARAM_MIN_KEY_SIZE          7                                           /**< Minimum encryption key size. */
#define SEC_PARAM_MAX_KEY_SIZE          16                                          /**< Maximum encryption key size. */

#define DEAD_BEEF                       0xDEADBEEF                                  /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */

#define ADDR_STRING_LEN         (2 * (BLE_GAP_ADDR_LEN)+6)
#define BLE_UUID_NUS_SERVICE            0x0001                      /**< The UUID of the Nordic UART Service. */
#define NUS_SERVICE_UUID_TYPE   BLE_UUID_TYPE_VENDOR_BEGIN              /**< UUID type for the Nordic UART Service (vendor specific). */
NRF_BLE_SCAN_DEF(m_scan);
#define N_AD_TYPES 4
#define UUID128_SIZE    16  /**< Size of 128 bit UUID. */
#define UUID16_SIZE 2
typedef struct
{
  bool    is_not_empty;                   /**< Indicates that the structure is not empty. */
  uint8_t addr[BLE_GAP_ADDR_LEN];         /**< Device address. */
  char    dev_name[DEVICE_NAME_MAX_SIZE]; /**< Device name. */
  int8_t  RSSI_value_RK;   
  uint8_t uuid_buffer_1[UUID128_SIZE];        /**< Buffer for storing an  UUID128. */
  uint16_t uuid_len;
  uint8_t uuid_type;
  
}scanned_device_t;

typedef struct
{
  uint8_t * p_data;   /**< Pointer to data. */
  uint16_t  data_len; /**< Length of data. */
} data_t;

scanned_device_t   m_device[DEVICE_TO_FIND_MAX];                 /**< Stores device info from scan data. */

scanned_device_t * scan_device_info_get(void)
{
  return m_device;
}

void scan_device_info_clear(void)
{
  memset(m_device, 0, sizeof(m_device));
}
static void device_to_list_add(ble_gap_evt_adv_report_t const * p_adv_report);
void scan_start(void);
void int_addr_to_hex_str(char * p_result, uint8_t result_len, uint8_t const * const p_addr);

#define RSSI_THRESHOLD -70
static void adv_list_timer_handle(void * p_context);
static bool               m_scanning = false;                           /**< Variable that informs about the ongoing scanning. True when scan is ON. */
#define FOUND_DEVICE_REFRESH_TIME APP_TIMER_TICKS(SCAN_LIST_REFRESH_INTERVAL) /**< Time after which the device list is clean and refreshed. */

BLE_DB_DISCOVERY_ARRAY_DEF(m_db_disc, NRF_SDH_BLE_CENTRAL_LINK_COUNT);  /**< Database discovery module instances. */
#define CENTRAL_SCANNING_LED      BSP_BOARD_LED_0
#define CENTRAL_CONNECTED_LED     BSP_BOARD_LED_1
static void db_discovery_init(void);
static void db_disc_handler(ble_db_discovery_evt_t * p_evt);
void ble_serv_on_db_disc_evt(ble_db_discovery_evt_t const * p_evt);
void print_uuid(char * p_result, uint8_t result_len, uint8_t const * const p_uuid, uint8_t size);

typedef struct 
{
  uint32_t addr[BLE_GAP_ADDR_LEN];         /**< Device address. */
  char    dev_name[DEVICE_NAME_MAX_SIZE]; /**< Device name. */
  int8_t RSSI_value_RK;
  uint16_t uuid;
}known_list_t;
#define MAX_DEVICE 8
extern known_list_t k_device[MAX_DEVICE];

known_list_t temp_device;

extern uint8_t k_count = 0;

/* Thermometer UUID = 0x1809 
  NUS UUID = {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E};{0x6E400001B5A3F393E0A9E50E24DCCA9E} 
  NONIN UUID = {0x1B, 0xC5, 0xD5, 0xA5, 0x02, 0x00, 0x5E, 0x8B, 0xE2, 0x11, 0x5F, 0x0D, 0x00, 0x00, 0xA9, 0x46}
  static ble_uuid_t m_uuid16[] = {{0x1809,BLE_UUID_TYPE_BLE }, {0xFEE0, BLE_UUID_TYPE_BLE}, {0x180A, BLE_UUID_TYPE_BLE}}; */

#define SCAN_INTERVAL             0x00A0                                     /**< Determines scan interval in units of 0.625 millisecond. */
#define SCAN_WINDOW               0x0050                                     /**< Determines scan window in units of 0.625 millisecond. */
#define SCAN_TIMEOUT              0x0000                                     /**< Timout when scanning. 0x0000 disables timeout. */
#define SCAN_REQUEST              0                                          /**< Active scannin is not set. */
#define SCAN_WHITELIST_ONLY       0                                          /**< We will not ignore unknown devices. */

static const ble_gap_scan_params_t m_scan_param =
{
  .extended = 1,
  .report_incomplete_evts = 1,
  .active = SCAN_REQUEST,
  .filter_policy = SCAN_WHITELIST_ONLY,
  .scan_phys = NULL,
  .interval = (uint16_t)SCAN_INTERVAL,
  .window = (uint16_t)SCAN_WINDOW,
  .timeout = SCAN_TIMEOUT
};

static const ble_gap_conn_params_t m_connection_param =
{
  (uint16_t)MIN_CONN_INTERVAL,
  (uint16_t)MAX_CONN_INTERVAL,
  (uint16_t)SLAVE_LATENCY,
  (uint16_t)CONN_SUP_TIMEOUT
};

//Added custom service 

#define NOTIFICATION_INTERVAL           APP_TIMER_TICKS(1000) 
static void on_cus_evt(ble_cus_t     * p_cus_service, ble_cus_evt_t * p_evt);
BLE_CUS_DEF(m_cus);
APP_TIMER_DEF(m_notification_timer_id);
ble_cus_init_t   cus_init;

/* array of UUID to be filtered */
static ble_uuid_t const m_scan_uuid[] =  {{BLE_UUID_NUS_SERVICE,0x03},
{BLE_UUID_HEALTH_THERMOMETER_SERVICE,BLE_UUID_TYPE_BLE},
{BLE_UUID_NONIN_SENSOR_SERVICE,BLE_UUID_TYPE_VENDOR_BEGIN}};


static void connect_to_target(ble_gap_evt_adv_report_t const * p_adv_report);
static bool connect = false;
static void conn_params_init(void);
static void conn_params_error_handler(uint32_t nrf_error);
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt);

bool normal_mode_on = true;
bool next_conn = false;

NRF_BLE_GATT_DEF(m_gatt);                                                           /**< GATT module instance. */
NRF_BLE_QWR_DEF(m_qwr);                                                             /**< Context for the Queued Write module.*/
BLE_ADVERTISING_DEF(m_advertising);                                                 /**< Advertising module instance. */


NRF_CLI_UART_DEF(cli_uart,0 , 256, 16);
NRF_CLI_BLE_UART_DEF(cli_ble_uart, &m_gatt, 64, 32);
NRF_CLI_DEF(m_cli_uart, "uart_cli:~$ ", &cli_uart.transport,'\r', 4);
NRF_CLI_DEF(m_ble_cli, "ble_cli:~$ ", &cli_ble_uart.transport,'\r', 8);

static uint16_t  m_conn_handle = BLE_CONN_HANDLE_INVALID;                           /**< Handle of the current connection. */

task_id_t m_ble_console_task_id;

static ble_uuid_t m_adv_uuids[] =                                                   /**< Universally unique service identifiers. */
{
  {BLE_UUID_NUS_SERVICE,            BLE_UUID_TYPE_BLE},
  {BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE},
  
};

/**@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 Clear bond information from persistent storage.
*/
static void delete_bonds(void)
{
  ret_code_t err_code;
  
  NRF_LOG_INFO("Erase bonds!");
  
  err_code = pm_peers_delete();
  APP_ERROR_CHECK(err_code);
}


/**@brief Function for starting advertising.
*/
void advertising_start(bool erase_bonds)
{
  if (erase_bonds == true)
  {
    delete_bonds();
    // Advertising is started by PM_EVT_PEERS_DELETE_SUCCEEDED event.
  }
  else
  {
    ret_code_t err_code;
    
    err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
    APP_ERROR_CHECK(err_code);
  }
}


/**@brief Function for handling Peer Manager events.
*
* @param[in] p_evt  Peer Manager event.
*/
static void pm_evt_handler(pm_evt_t const * p_evt)
{
  pm_handler_on_pm_evt(p_evt);
  pm_handler_flash_clean(p_evt);
  
  switch (p_evt->evt_id)
  {
  case PM_EVT_PEERS_DELETE_SUCCEEDED:
    advertising_start(false);
    break;
    
  default:
    break;
  }
}

/**@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_CONN_INTERVAL;
  gap_conn_params.max_conn_interval = MAX_CONN_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);
}

/**@brief Function for handling events from the GATT library. */
void gatt_evt_handler(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt)
{
  NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x",
                p_gatt->att_mtu_desired_central,
                p_gatt->att_mtu_desired_periph);
}


/**@brief Function for initializing the GATT module.
*/
static void gatt_init(void)
{
  ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
  APP_ERROR_CHECK(err_code);
}


/**@brief Function for handling Queued Write Module errors.
*
* @details A pointer to this function will be passed to each service which may need to inform the
*          application about an error.
*
* @param[in]   nrf_error   Error code containing information about what went wrong.
*/
static void nrf_qwr_error_handler(uint32_t nrf_error)
{
  APP_ERROR_HANDLER(nrf_error);
}


/**@brief Function for initializing services that will be used by the application.
*
* @details Initialize the Heart Rate, Battery and Device Information services.
*/
static void services_init(void)
{
  ret_code_t         err_code;
  ble_dis_init_t     dis_init;
  nrf_ble_qwr_init_t qwr_init = {0};
 
  // Initialize Queued Write Module.
  qwr_init.error_handler = nrf_qwr_error_handler;
  
  err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
  APP_ERROR_CHECK(err_code);
  
  // Initialize Device Information Service.
  memset(&dis_init, 0, sizeof(dis_init));
  
  ble_srv_ascii_to_utf8(&dis_init.manufact_name_str, (char *)MANUFACTURER_NAME);
  
  dis_init.dis_char_rd_sec = SEC_OPEN;
  
  err_code = ble_dis_init(&dis_init);
  APP_ERROR_CHECK(err_code);
  
  /*  RK code to initialize the nonin services used by the application.*/
  ble_uuid_t            ble_uuid;
  BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HEALTH_THERMOMETER_SERVICE);
 
  err_code = ble_db_discovery_evt_register(&ble_uuid);
  if (err_code == NRF_SUCCESS)
  {
    APP_ERROR_CHECK(err_code);
  }
  if(err_code == NRF_ERROR_NULL)
  {
    NRF_LOG_INFO("error null pointer supplied\n\r");
  }
  if(err_code == NRF_ERROR_INVALID_STATE)
  {
    NRF_LOG_INFO("error NRF_ERROR_INVALID_STATE\n\r");
  }
  if(err_code == NRF_ERROR_NO_MEM)
  {
    NRF_LOG_INFO("error NRF_ERROR_NO_MEM\n\r");
  }
    
  // Add Nonin Oxy sensor Service UUID BASE
  ble_uuid128_t base_uuid = BLE_UUID_NONIN_SENSOR_SERVICE_BASE;
  
  // Initialize CUS Service init structure to zero.
  memset(&cus_init, 0, sizeof(cus_init));
  cus_init.evt_handler = on_cus_evt;
  
  if (&m_cus == NULL || &cus_init == NULL)
  {
    NRF_LOG_INFO("NRF_ERROR_NULL");
  }

  // Initialize service structure
  m_cus.evt_handler               = cus_init.evt_handler;
  m_cus.conn_handle               = BLE_CONN_HANDLE_INVALID;
  
  err_code =  sd_ble_uuid_vs_add(&base_uuid,  &m_cus.uuid_type);
  if (err_code == NRF_ERROR_INVALID_ADDR)
  {
    NRF_LOG_INFO("error = NRF_ERROR_INVALID_ADDR\n\r");
  }
  if (err_code == NRF_ERROR_NO_MEM)
  {
    NRF_LOG_INFO("error = NRF_ERROR_NO_MEM\n\r");
  }
  
  ble_uuid.uuid = BLE_UUID_NONIN_SENSOR_SERVICE;
  ble_uuid.type = m_cus.uuid_type;
  err_code = ble_db_discovery_evt_register(&ble_uuid);
  if (err_code == NRF_SUCCESS)
  {
    APP_ERROR_CHECK(err_code);
  }
  if(err_code == NRF_ERROR_NULL)
  {
    NRF_LOG_INFO("error null pointer supplied\n\r");
  }
  if(err_code == NRF_ERROR_INVALID_STATE)
  {
    NRF_LOG_INFO("error NRF_ERROR_INVALID_STATE\n\r");
  }
  if(err_code == NRF_ERROR_NO_MEM)
  {
    NRF_LOG_INFO("error NRF_ERROR_NO_MEM\n\r");
  }
 
}

/**@brief Function for handling advertising events.
*
* @details This function will be called for advertising events which are passed to the application.
*
* @param[in] ble_adv_evt  Advertising event.
*/
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_RAW_INFO("Fast advertising.\r");
    err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
    APP_ERROR_CHECK(err_code);
    break;
    
  case BLE_ADV_EVT_IDLE:
    nrf_pwr_mgmt_run();
    break;
    
  default:
    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)
{
  ret_code_t err_code;
  
  // For readability
  ble_gap_evt_t const        * p_gap_evt   = &p_ble_evt->evt.gap_evt;
  
//   ble_gap_addr_t caddr = p_ble_evt->evt.gap_evt.params.scan_req_report.peer_addr;
   
  switch (p_ble_evt->header.evt_id)
  {
  case BLE_GAP_EVT_ADV_REPORT:
    { 
      device_to_list_add(&p_gap_evt->params.adv_report);         
    } break;
    
  case BLE_GAP_EVT_CONNECTED:
    {
      NRF_LOG_INFO("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);
      
      nrf_cli_ble_uart_config_t config = { .conn_handle = m_conn_handle };
      
      err_code = nrf_cli_init(&m_ble_cli, &config, true, true, NRF_LOG_SEVERITY_INFO);
      APP_ERROR_CHECK(nrf_cli_task_create(&m_ble_cli));
      APP_ERROR_CHECK(err_code);
      
       //Find device role in connection
//   uint16_t   role = ble_conn_state_role(m_conn_handle);
//   if (role == BLE_GAP_ROLE_PERIPH)
//   {
//     
//     NRF_LOG_INFO("Do you want to add connected device to Known device list cmd: connect (Y/N) ?\n\r");
//     
//   }
   
      if (normal_mode_on == false)
      {
        do 
        {
          err_code = ble_db_discovery_start(&m_db_disc[p_gap_evt->conn_handle],p_gap_evt->conn_handle);
          if (err_code == NRF_SUCCESS)
          {
            NRF_LOG_INFO("discovery started :busy status\n");
            APP_ERROR_CHECK(err_code);
          }
          
        }while(err_code == NRF_ERROR_BUSY);
        
        // Update LEDs status and check whether it is needed to look for more
        // peripherals to connect to.
        bsp_board_led_on(CENTRAL_CONNECTED_LED);
        if (ble_conn_state_central_conn_count() == NRF_SDH_BLE_CENTRAL_LINK_COUNT)
        {
          bsp_board_led_off(CENTRAL_SCANNING_LED);
        }
        else
        {
          // Resume scanning.
          bsp_board_led_on(CENTRAL_SCANNING_LED);
          scan_start();
        }
      }
      else
      {
        next_conn = true;
      }
      
    } break;
    
  case BLE_GAP_EVT_DISCONNECTED:
    {
      connect = false;
      NRF_LOG_INFO("Disconnected, reason %d.",
                   p_ble_evt->evt.gap_evt.params.disconnected.reason);
      m_conn_handle = BLE_CONN_HANDLE_INVALID;
      (void)nrf_cli_uninit(&m_ble_cli);
      
      if (ble_conn_state_central_conn_count() == 0)
      {
        // Turn off the LED that indicates the connection.
        bsp_board_led_off(CENTRAL_CONNECTED_LED);
      }
      
      // Start scanning.
      if (m_scanning)
      {
        scan_start();
      }
      
      // Turn on the LED for indicating scanning.
      bsp_board_led_on(CENTRAL_SCANNING_LED);
    }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;
    
  case BLE_GATTC_EVT_TIMEOUT:
    // Disconnect on GATT Client timeout event.
    NRF_LOG_INFO("GATT Client Timeout.");
    err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                     BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
    APP_ERROR_CHECK(err_code);
    break;
    
  case BLE_GATTS_EVT_TIMEOUT:
    // Disconnect on GATT Server timeout event.
    NRF_LOG_INFO("GATT Server Timeout.");
    err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                     BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
    APP_ERROR_CHECK(err_code);
    break;
    
  case BLE_GAP_EVT_TIMEOUT:
    NRF_LOG_INFO("Timeout error\n\r");
    sd_ble_gap_connect_cancel();
    next_conn = true;
    break;
    
  case BLE_GAP_EVT_SCAN_REQ_REPORT:
//    NRF_LOG_INFO("central address = %x:%x:%x:%x:%x:%x\n\r", caddr.addr[5], caddr.addr[4], caddr.addr[3], caddr.addr[2], caddr.addr[1], caddr.addr[0]);
//    NRF_LOG_INFO("rssi central = %d\n\r", p_ble_evt->evt.gap_evt.params.scan_req_report.rssi);
    break;
  default:
    // No implementation needed.
    break;
  }
}

/**@brief Function for the SoftDevice initialization.
*
* @details This function 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 handling events from the BSP module.
*
* @param[in]   event   Event generated by button press.
*/
void bsp_event_handler(bsp_event_t event)
{
  ret_code_t err_code;
  
  switch (event)
  {
  case BSP_EVENT_SLEEP:
    nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
    break;
    
  case BSP_EVENT_DISCONNECT:
    err_code = sd_ble_gap_disconnect(m_conn_handle,
                                     BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
    if (err_code != NRF_ERROR_INVALID_STATE)
    {
      APP_ERROR_CHECK(err_code);
    }
    break;
    
  case BSP_EVENT_WHITELIST_OFF:
    if (m_conn_handle == BLE_CONN_HANDLE_INVALID)
    {
      err_code = ble_advertising_restart_without_whitelist(&m_advertising);
      if (err_code != NRF_ERROR_INVALID_STATE)
      {
        APP_ERROR_CHECK(err_code);
      }
    }
    break;
    
  default:
    break;
  }
}


/**@brief Function for the Peer Manager initialization.
*/
static void peer_manager_init(void)
{
  ble_gap_sec_params_t sec_param;
  ret_code_t           err_code;
  
  err_code = pm_init();
  APP_ERROR_CHECK(err_code);
  
  memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
  
  // Security parameters to be used for all security procedures.
  sec_param.bond           = SEC_PARAM_BOND;
  sec_param.mitm           = SEC_PARAM_MITM;
  sec_param.io_caps        = SEC_PARAM_IO_CAPABILITIES;
  sec_param.oob            = SEC_PARAM_OOB;
  sec_param.min_key_size   = SEC_PARAM_MIN_KEY_SIZE;
  sec_param.max_key_size   = SEC_PARAM_MAX_KEY_SIZE;
  sec_param.kdist_own.enc  = 1;
  sec_param.kdist_own.id   = 1;
  sec_param.kdist_peer.enc = 1;
  sec_param.kdist_peer.id  = 1;
  
  err_code = pm_sec_params_set(&sec_param);
  APP_ERROR_CHECK(err_code);
  
  err_code = pm_register(pm_evt_handler);
  APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing the Advertising functionality.
*/
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_directed_enabled = true;
 
  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);
}

/**@brief Function for handling an event from the Connection Parameters Module.
*
* @details This function will be called for all events in the Connection Parameters Module
*          which are passed to the application.
*
* @note All this function does is to disconnect. This could have been done by simply setting
*       the disconnect_on_fail config parameter, but instead we use the event handler
*       mechanism to demonstrate its use.
*
* @param[in] p_evt  Event received from the Connection Parameters Module.
*/
static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
{
  uint32_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);
  }
}


/**@brief Function for handling errors from the Connection Parameters module.
*
* @param[in] nrf_error  Error code containing information about what went wrong.
*/
static void conn_params_error_handler(uint32_t nrf_error)
{
  APP_ERROR_HANDLER(nrf_error);
}


/**@brief Function for initializing the Connection Parameters module.
*/
static void conn_params_init(void)
{
  uint32_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.evt_handler                    = on_conn_params_evt;
  cp_init.error_handler                  = conn_params_error_handler;
  
  err_code = ble_conn_params_init(&cp_init);
  APP_ERROR_CHECK(err_code);
}

static void connect_to_target(ble_gap_evt_adv_report_t const * p_adv_report)
{
  // For readability.
  ble_gap_addr_t const        * p_addr        = &p_adv_report->peer_addr;
  ret_code_t             err_code;
  scan_evt_t scan_evt;
  
  nrf_ble_scan_stop();
  
  memset(&scan_evt, 0, sizeof(scan_evt));
  
  // Establish connection.
  err_code = sd_ble_gap_connect(p_addr,
                                &m_scan_param,
                                &m_connection_param,
                                APP_BLE_CONN_CFG_TAG);
  
  if (err_code == NRF_SUCCESS)
  {
    connect = true;
  }
  else if(err_code == NRF_ERROR_INVALID_ADDR)
  {
    NRF_LOG_INFO("NRF_ERROR_INVALID_ADDR failed\n\r");
  }
  else if(err_code == NRF_ERROR_INVALID_PARAM)
  {
    NRF_LOG_INFO("NRF_ERROR_INVALID_PARAM failed\n\r");
  }
  else if(err_code == NRF_ERROR_NOT_FOUND)
  {
    NRF_LOG_INFO("NRF_ERROR_NOT_FOUND failed\n\r");
  }
  else if (err_code == NRF_ERROR_INVALID_STATE)
  {
    NRF_LOG_INFO("NRF_ERROR_INVALID_STATE failed\n\r");
  }
  else if (err_code == BLE_ERROR_GAP_INVALID_BLE_ADDR)
  {
    NRF_LOG_INFO("BLE_ERROR_GAP_INVALID_BLE_ADDR failed\n\r");
  }
  else if (err_code == NRF_ERROR_CONN_COUNT)
  {
    NRF_LOG_INFO("NRF_ERROR_CONN_COUNT failed\n\r");
  }
  else if (err_code == NRF_ERROR_RESOURCES)
  {
    NRF_LOG_INFO("NRF_ERROR_RESOURCES failed\n\r");
  }
  else if (err_code == NRF_ERROR_NOT_SUPPORTED)
  {
    NRF_LOG_INFO("NRF_ERROR_NOT_SUPPORTED failed\n\r");
  }
  
  scan_evt.scan_evt_id                    = NRF_BLE_SCAN_EVT_CONNECTING_ERROR;
  scan_evt.params.connecting_err.err_code = err_code;
  
  NRF_LOG_DEBUG("Connection status: %d", err_code);
  nrf_ble_scan_start(&m_scan);    
}


/**@brief Function for handling the Custom Service Service events.
*
* @details This function will be called for all Custom Service events which are passed to
*          the application.
*
* @param[in]   p_cus_service  Custom Service structure.
* @param[in]   p_evt          Event received from the Custom Service.
*
*/
static void on_cus_evt(ble_cus_t     * p_cus_service,
                       ble_cus_evt_t * p_evt)
{
  ret_code_t err_code;
  
  switch(p_evt->evt_type)
  {
  case BLE_CUS_EVT_NOTIFICATION_ENABLED:
    
    err_code = app_timer_start(m_notification_timer_id, NOTIFICATION_INTERVAL, NULL);
    APP_ERROR_CHECK(err_code);
    break;
    
  case BLE_CUS_EVT_NOTIFICATION_DISABLED:
    // Stop the application timer that is triggering the notifications
    err_code = app_timer_stop(m_notification_timer_id);
    APP_ERROR_CHECK(err_code);
    break;
    
  case BLE_CUS_EVT_CONNECTED:
    break;
    
  case BLE_CUS_EVT_DISCONNECTED:
    break;
  case BLE_CUS_EVT_SERVO_CTR_VALUE_RECEIVED:
    break;    
    
  default:
    // No implementation needed.
    break;
  }
}

void ble_serv_on_db_disc_evt(ble_db_discovery_evt_t const * p_evt)
{
  // Check if the Led Button Service was discovered.
  
  ret_code_t err_code;
  
  for (uint8_t i =0; i < sizeof(m_scan_uuid)/sizeof(m_scan_uuid[0]); i++)
  {
    
    if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
        p_evt->params.discovered_db.srv_uuid.uuid == m_scan_uuid[i].uuid &&
          p_evt->params.discovered_db.srv_uuid.type == m_scan_uuid[i].type)
    {
      NRF_LOG_INFO("Service available:%x \n\r", p_evt->params.discovered_db.srv_uuid.uuid);
     
      // move device to known device list - copy MAC ID and UUID 
      if (k_count < DEVICE_TO_FIND_MAX)
      {
        for (uint8_t i = 0; i < k_count; i++)
        {
          if (memcmp(temp_device.addr,k_device[i].addr,sizeof(temp_device.addr)) == 0)
          {
            return;
          }
        }
        memcpy(k_device[k_count].addr, temp_device.addr, sizeof(temp_device.addr));
        memcpy(&k_device[k_count].RSSI_value_RK, &temp_device.RSSI_value_RK,sizeof(temp_device.RSSI_value_RK));
        k_device[k_count].uuid = p_evt->params.discovered_db.srv_uuid.uuid;
        k_count++;
      }
      break;
    }  
  }
  
  if (connect == true)
  {
    err_code = sd_ble_gap_disconnect(m_conn_handle,BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
//    if (err_code != NRF_ERROR_INVALID_STATE)
//    {
      APP_ERROR_CHECK(err_code);
//    }
    if (err_code == NRF_SUCCESS)
    {
      connect = false;
      NRF_LOG_INFO("Disconnected after discovery\n\r");
    }
  }
}
/**@brief Function for handling database discovery events.
*
* @details This function is a callback function to handle events from the database discovery module.
*          Depending on the UUIDs that are discovered, this function forwards the events
*          to their respective services.
*
* @param[in] p_event  Pointer to the database discovery event.
*/
static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
{
  ble_serv_on_db_disc_evt( p_evt);
}


/** @brief Database discovery initialization.
*/
static void db_discovery_init(void)
{
  ret_code_t err_code = ble_db_discovery_init(db_disc_handler);
  APP_ERROR_CHECK(err_code);
}

bool is_scanning(void)
{
  return m_scanning;
}
/**@brief Function for handling the adv_list_timer event, which refreshes the connectable devices.
*/
static void adv_list_timer_handle(void * p_context)
{
  if (is_scanning())
  {
    scan_device_info_clear();
  }
}

/**@brief Function for searching for a device name and adding it to a dynamic command.
*
* @details Use this function to parse the received advertising data and to find a given
* name in them either as 'complete_local_name' or as 'short_local_name'.
*
* @param[in]   p_adv_report   Advertising data to parse.
*/
static void device_to_list_add(ble_gap_evt_adv_report_t const * p_adv_report)
{
  uint8_t  idx             = 0;
  uint16_t dev_name_offset = 0;
  uint16_t field_len;
  data_t   adv_data;
  int8_t peripheral_rssi = p_adv_report->rssi;
  // Initialize advertisement report for parsing
  adv_data.p_data   = (uint8_t *)p_adv_report->data.p_data;
  adv_data.data_len = p_adv_report->data.len;
  
  
  for ( idx = 0; idx < DEVICE_TO_FIND_MAX; idx++)
  {
    // If address is duplicated, then return.
    if (memcmp(p_adv_report->peer_addr.addr,
               m_device[idx].addr,
               sizeof(p_adv_report->peer_addr.addr)) == 0)
    {
      /* update rssi value */
      memcpy(&m_device[idx].RSSI_value_RK, 
             &p_adv_report->rssi, 
             sizeof(p_adv_report->rssi));
      return;
    }
  }
  
  // Add device data if an empty record is found.
  for (idx = 0; idx < DEVICE_TO_FIND_MAX; idx++)
  {
    if (!m_device[idx].is_not_empty)
    {
      if (peripheral_rssi > RSSI_THRESHOLD)
      {
        /* store peer address */
        memcpy(m_device[idx].addr,
               p_adv_report->peer_addr.addr,
               sizeof(p_adv_report->peer_addr.addr));
        
        /* store rssi value */
        memcpy(&m_device[idx].RSSI_value_RK, 
               &p_adv_report->rssi, 
               sizeof(p_adv_report->rssi));
        
        m_device[idx].is_not_empty = true;
        
        //connect to target
        bool d_found = false;
        if (p_adv_report->type.connectable && connect == false )
        {
          for (idx = 0; idx <= k_count; idx++)
          {
            if (memcmp(p_adv_report->peer_addr.addr,k_device[idx].addr, sizeof(p_adv_report->peer_addr.addr)) == 0)
            {
//              NRF_LOG_INFO("device address matched\n\r");
              d_found = true;
            }
            
          }
          if (!d_found)
          {
            connect_to_target(p_adv_report);
            /* Copy MAC ID and RSSI to known device list */
            memcpy(temp_device.addr,
                   p_adv_report->peer_addr.addr,
                   sizeof(p_adv_report->peer_addr.addr));
            
            memcpy(&temp_device.RSSI_value_RK,
                   &p_adv_report->rssi,
                   sizeof(p_adv_report->rssi));
            
          }
          
        }
        // Search for advertising names.
        field_len = ble_advdata_search(adv_data.p_data,
                                       adv_data.data_len,
                                       &dev_name_offset,
                                       BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
        
        if (field_len == 0)
        {
          field_len = ble_advdata_search(adv_data.p_data,
                                         adv_data.data_len,
                                         &dev_name_offset,
                                         BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME);
          // If name is not found, then return.
          if (field_len == 0) 
          {
            return;
          }
        }
        
        memcpy(m_device[idx].dev_name, &adv_data.p_data[dev_name_offset], field_len);         
        m_device[idx].dev_name[field_len] = 0;
        
      }
      return;
      
    }
    
  }
}


/**@brief Function for handling Scanning Module events.
*/
static void scan_evt_handler(scan_evt_t const * p_scan_evt)
{
  ret_code_t err_code;
  
  switch(p_scan_evt->scan_evt_id)
  {
  case NRF_BLE_SCAN_EVT_CONNECTING_ERROR:
    {
      err_code = p_scan_evt->params.connecting_err.err_code;
      APP_ERROR_CHECK(err_code);
    } break;
    
  case NRF_BLE_SCAN_EVT_CONNECTED:
    {
      ble_gap_evt_connected_t const * p_connected =
        p_scan_evt->params.connected.p_connected;
      // Scan is automatically stopped by the connection.
      NRF_LOG_INFO("Connecting to target %02x:%02x:%02x:%02x:%02x:%02x",
                   p_connected->peer_addr.addr[5],
                   p_connected->peer_addr.addr[4],
                   p_connected->peer_addr.addr[3],
                   p_connected->peer_addr.addr[2],
                   p_connected->peer_addr.addr[1],
                   p_connected->peer_addr.addr[0]
                     );
    } break;
    
  case NRF_BLE_SCAN_EVT_SCAN_TIMEOUT:
    {
      NRF_LOG_INFO("Scan timed out.");
      scan_start();
      ret_code_t ret;
      
      ret = nrf_ble_scan_start(&m_scan);
      APP_ERROR_CHECK(ret);
      
      ret = bsp_indication_set(BSP_INDICATE_SCANNING);
      APP_ERROR_CHECK(ret);
    } break;
    
    
    
  default:
    break;
  }
}
/**@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.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);
  
}


/** @brief Function for initializing BLE components.
*/
void ble_init(void)
{
  ble_stack_init();
  gap_params_init();
  gatt_init();
  db_discovery_init();
  services_init();
  advertising_init();
  peer_manager_init();
  scan_init();
}


/**@brief Function for initializing buttons and leds.
*
* @param[out] p_erase_bonds  Will be true if the clear bonding button was pressed to wake the application up.
*/
static void buttons_leds_init(bool * p_erase_bonds)
{
  ret_code_t err_code;
  bsp_event_t startup_event;
  
  err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
  APP_ERROR_CHECK(err_code);
  
  err_code = bsp_btn_ble_init(NULL, &startup_event);
  APP_ERROR_CHECK(err_code);
  
  *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
}

/**
* @brief Function for shutdown events.
*
* @param[in]   event       Shutdown type.
*/
static bool shutdown_handler(nrf_pwr_mgmt_evt_t event)
{
  ret_code_t err_code;
  
  err_code = bsp_indication_set(BSP_INDICATE_IDLE);
  APP_ERROR_CHECK(err_code);
  
  switch (event)
  {
  case NRF_PWR_MGMT_EVT_PREPARE_WAKEUP:
    // Prepare wakeup buttons.
    err_code = bsp_btn_ble_sleep_mode_prepare();
    APP_ERROR_CHECK(err_code);
    break;
  default:
    break;
  }
  
  return true;
}

NRF_PWR_MGMT_HANDLER_REGISTER(shutdown_handler, 0);

void scan_start(void)
{
  ret_code_t ret;
  ret = nrf_ble_scan_start(&m_scan);
  APP_ERROR_CHECK(ret);
  
  ret = bsp_indication_set(BSP_INDICATE_SCANNING);
  APP_ERROR_CHECK(ret);
  
  m_scanning = true;
}

void scan_stop(void)
{
  ret_code_t ret;
  
  nrf_ble_scan_stop();
  
  ret = bsp_indication_set(BSP_INDICATE_SCANNING);
  APP_ERROR_CHECK(ret);
  
  m_scanning = false;
}

void int_addr_to_hex_str(char * p_result, uint8_t result_len, uint8_t const * const p_addr)
{
  ASSERT(p_result);
  ASSERT(p_addr);
  
  if (result_len > BLE_GAP_ADDR_LEN)
  {
    return;
  }
  
  char tempbuffer = '\0';
  
  memset(p_result, 0, result_len);
  
  for (uint8_t i = 0; i < result_len; ++i)
  {
    sprintf(&tempbuffer, "%.2X", p_addr[result_len - (i+1)]);
    strcat(p_result, &tempbuffer);
    
    if (i < (result_len - 1))
    {
      strcat(p_result, ":");
    }
  }
}

void print_uuid(char * p_result, uint8_t result_len, uint8_t const * const p_uuid, uint8_t size)
{
  ASSERT(p_result);
  ASSERT(p_uuid);
  
  if (result_len > 100)
  {
    return;
  }			 
  //Printing UUID in "8-4-4-4-12" format
  char buffer[100] = {0};
  
  memset(p_result, 0, result_len);
  memset(buffer, 0, 100);
  
  for (uint8_t j = size; j >= 1; --j)
  {
    sprintf(buffer, "%.2X", p_uuid[j-1]);
    
    strcat(p_result, buffer);
    if ( size < UUID128_SIZE && (j == 3 || j == 5 || j == 7))
    {
      strcat(p_result, ",");
    }
    
    if (j ==13 || j ==11 || j==9 || j==7)
    {
      strcat(p_result, "-");
    }
  }
  
}

/* Below funciton displays the scanned device list */
void device_list(nrf_cli_t const *p_cli, scanned_device_t * p_device )
{
  for (uint8_t i = 0; i < DEVICE_TO_FIND_MAX; i++)
  {
    if (p_device[i].is_not_empty)
    {
      nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Device ");
      
      char buffer[ADDR_STRING_LEN];
      int_addr_to_hex_str(buffer, BLE_GAP_ADDR_LEN, p_device[i].addr);
      char ubuffer[100]={0};
      print_uuid(ubuffer, 100, p_device[i].uuid_buffer_1, p_device[i].uuid_len);
      
      nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%s %s %ddB\r\n", buffer,  p_device[i].dev_name, p_device[i].RSSI_value_RK);
    }
    
  }
  nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Known Device List:\n\r");
  //print known device list
  for (uint8_t i = 0; i < k_count; i++)
  {
    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "K Device ");
    
    char buffer[ADDR_STRING_LEN];
    int_addr_to_hex_str(buffer, BLE_GAP_ADDR_LEN, (uint8_t *)k_device[i].addr);
    
    
    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%s %ddB uuid = %x\r\n", buffer, k_device[i].RSSI_value_RK, k_device[i].uuid);
  }
  
}

static void scan_on_cmd(nrf_cli_t const *p_cli, size_t argc, char **argv)
{
  normal_mode_on = false;
  scan_start(); 
  nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Scanning...\r\n");
}

static void scan_off_cmd(nrf_cli_t const *p_cli, size_t argc, char **argv)
{
  normal_mode_on = true;
  scan_stop();
  nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Scan stopped.\r\n");
}

void display_device_list_cmd(nrf_cli_t const *p_cli, size_t argc, char **argv)
{
  if (argc >= 2)
  {
    if (nrf_cli_help_requested(p_cli))
    {
      nrf_cli_help_print(p_cli, NULL, 0);
      return;
    }
    else
    {
      nrf_cli_fprintf(p_cli,
                      NRF_CLI_ERROR,
                      "%s:%s%s\r\n",
                      argv[0],
                      " bad parameter ",
                      argv[1]);
      return;
    }
  }
  /* Print connectable devices from scan data.*/
  scanned_device_t * p_device_list = scan_device_info_get();
  device_list(p_cli, p_device_list);
}


static void default_cmd(nrf_cli_t const *p_cli, size_t argc, char **argv)
{
  if (argc >= 2)
  {
    if (nrf_cli_help_requested(p_cli))
    {
      nrf_cli_help_print(p_cli, NULL, 0);
      return;
    }
    else
    {
      nrf_cli_fprintf(p_cli,
                      NRF_CLI_ERROR,
                      "%s:%s%s\r\n",
                      argv[0],
                      " bad parameter ",
                      argv[1]);
      return;
    }
  }
}

// Register "mpu" command and it's subcommands in CLI.
NRF_CLI_CREATE_STATIC_SUBCMD_SET(scan_commands)
{
  NRF_CLI_CMD(on, NULL, "Scan on.", scan_on_cmd),
  NRF_CLI_CMD(off, NULL, "Scan off.", scan_off_cmd),
  NRF_CLI_SUBCMD_SET_END
};


NRF_CLI_CMD_REGISTER(scan, &scan_commands, "Commands for scan control", default_cmd);
NRF_CLI_CMD_REGISTER(devices, NULL, "print device list", display_device_list_cmd);

void idle_task(void * p_context)
{
  
  bool erase_bonds = (bool)p_context;
  
  advertising_start(erase_bonds);
  
  // Enter main loop.
  for (;;)
  {
    if (NRF_LOG_PROCESS() == false)
    {
      nrf_pwr_mgmt_run();
    }
    task_yield();
  }
  
}

static void core_init(void)
{
  APP_ERROR_CHECK(NRF_LOG_INIT(app_timer_cnt_get));
  
  nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;
  uart_config.pseltxd = TX_PIN_NUMBER;
  uart_config.pselrxd = RX_PIN_NUMBER;
  uart_config.hwfc    = NRF_UART_HWFC_DISABLED;
  APP_ERROR_CHECK(nrf_cli_init(&m_cli_uart, &uart_config, true, true, NRF_LOG_SEVERITY_INFO));
  
  APP_ERROR_CHECK(nrf_drv_clock_init());
  
  nrf_drv_clock_lfclk_request(NULL);
  
  APP_ERROR_CHECK(app_timer_init());
  // Timer for refreshing scanned devices data.
  APP_TIMER_DEF(adv_list_timer);
  APP_ERROR_CHECK(app_timer_create(&adv_list_timer, APP_TIMER_MODE_REPEATED, adv_list_timer_handle));
  APP_ERROR_CHECK(app_timer_start(adv_list_timer, FOUND_DEVICE_REFRESH_TIME, NULL));
  
  
  APP_ERROR_CHECK(nrf_pwr_mgmt_init());
  
  APP_ERROR_CHECK(nrf_cli_task_create(&m_cli_uart));
}


/**@brief Function for application main entry.
*/
int main(void)

{
  bool erase_bonds;
  
  core_init();
  
  buttons_leds_init(&erase_bonds);
  
  ble_init();
  conn_params_init();
  
  fds_test_init();
  
  APP_ERROR_CHECK(nrf_cli_ble_uart_service_init());
  
  NRF_LOG_RAW_INFO("BLE Nordic Uart Service started\r\n");
  NRF_LOG_RAW_INFO("Press Tab to view all available commands.\r\n");
  task_manager_start(idle_task, (void *)erase_bonds);
  
  while (true)
  {
    UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
    nrf_cli_process(&m_cli_uart);
  }
  
}
