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

scan filters for custom uuid is not matching

hi attached code for below requirement:

command: scan on - scan devices

command: devices - display filtered devices .

Filters set are for : thermometer, NUS and custom service for nonin sensor.

but i could able to get only thermometer in peripheral device list.

please check and let me know what is wrong with the code.

i am using : SDK 15.02 nRF52832

/**
 * 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 "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_backend_flash.h"
#include "ble_nus.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. */

#ifdef RK_CLI
   
//Added custom service 
#include "ble_cus.h"
#include "ble_hts.h"
#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;

//Added HTS service
BLE_HTS_DEF(m_hts);
static void on_hts_evt(ble_hts_t * p_hts, ble_hts_evt_t * p_evt);
#define TEMP_TYPE_AS_CHARACTERISTIC     0                                           /**< Determines if temperature type is given as characteristic (1) or as a field of measurement (0). */
static bool              m_hts_meas_ind_conf_pending = false;                       /**< Flag to keep track of when an indication confirmation is pending. */
static sensorsim_cfg_t   m_temp_celcius_sim_cfg;                                    /**< Temperature simulator configuration. */
static sensorsim_state_t m_temp_celcius_sim_state;                                  /**< Temperature simulator state. */

#define ADDR_STRING_LEN         (2 * (BLE_GAP_ADDR_LEN)+6)

NRF_BLE_SCAN_DEF(m_scan);


/* array of Scan filters */
static ble_uuid_t const m_scan_uuid[] =  { {BLE_UUID_NUS_SERVICE,BLE_UUID_TYPE_VENDOR_BEGIN},
                                          {BLE_UUID_HEALTH_THERMOMETER_SERVICE,BLE_UUID_TYPE_BLE},
                                          {BLE_UUID_NONIN_SENSOR_SERVICE,BLE_UUID_TYPE_VENDOR_BEGIN}};


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;                   /**< RSSI value. */
}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;
}
static void device_to_list_add(ble_gap_evt_adv_report_t const * p_adv_report);
void scan_start(void);
//void address_to_cmd_add(ble_gap_addr_t const * p_connected_addr); to add devices to "known devices" list
#endif

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};
    ble_hts_init_t     hts_init;
     
     
    // 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.*/

         // Initialize CUS Service init structure to zero.
        memset(&cus_init, 0, sizeof(cus_init));
        cus_init.evt_handler = on_cus_evt;
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cus_init.custom_value_char_attr_md.cccd_write_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cus_init.custom_value_char_attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cus_init.custom_value_char_attr_md.write_perm);

        err_code = ble_cus_init(&m_cus, &cus_init);
         
        APP_ERROR_CHECK(err_code);
        
         // Initialize Health Thermometer Service
    memset(&hts_init, 0, sizeof(hts_init));

    hts_init.evt_handler                 = on_hts_evt;
    hts_init.temp_type_as_characteristic = TEMP_TYPE_AS_CHARACTERISTIC;
    hts_init.temp_type                   = BLE_HTS_TEMP_TYPE_BODY;

    // Here the sec level for the Health Thermometer Service can be changed/increased.
    hts_init.ht_meas_cccd_wr_sec = SEC_JUST_WORKS;
    hts_init.ht_type_rd_sec      = SEC_OPEN;

    err_code = ble_hts_init(&m_hts, &hts_init);
    APP_ERROR_CHECK(err_code);
}

/**@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;
     
    switch (p_ble_evt->header.evt_id)
    {
        #ifdef RK_CLI
      
          case BLE_GAP_EVT_ADV_REPORT:
          {           
            // add all scanned devices without filter 
            //device_to_list_add(&p_gap_evt->params.adv_report); 
            
          }
          break;
      
        #endif
        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);
        } break;

        case BLE_GAP_EVT_DISCONNECTED:
            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);
            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_DEBUG("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_DEBUG("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;
  
        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_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);
}

#ifdef RK_CLI
/**@brief Function for populating simulated health thermometer measurement.
 */
static void hts_sim_measurement(ble_hts_meas_t * p_meas)
{
    static ble_date_time_t time_stamp = { 2012, 12, 5, 11, 50, 0 };

    uint32_t celciusX100;

    p_meas->temp_in_fahr_units = false;
    p_meas->time_stamp_present = true;
    p_meas->temp_type_present  = (TEMP_TYPE_AS_CHARACTERISTIC ? false : true);

    celciusX100 = sensorsim_measure(&m_temp_celcius_sim_state, &m_temp_celcius_sim_cfg);

    p_meas->temp_in_celcius.exponent = -2;
    p_meas->temp_in_celcius.mantissa = celciusX100;
    p_meas->temp_in_fahr.exponent    = -2;
    p_meas->temp_in_fahr.mantissa    = (32 * 100) + ((celciusX100 * 9) / 5);
    p_meas->time_stamp               = time_stamp;
    p_meas->temp_type                = BLE_HTS_TEMP_TYPE_FINGER;

    // update simulated time stamp
    time_stamp.seconds += 27;
    if (time_stamp.seconds > 59)
    {
        time_stamp.seconds -= 60;
        time_stamp.minutes++;
        if (time_stamp.minutes > 59)
        {
            time_stamp.minutes = 0;
        }
    }
}

/**@brief Function for simulating and sending one Temperature Measurement.
 */
static void temperature_measurement_send(void)
{
    ble_hts_meas_t simulated_meas;
    ret_code_t     err_code;

    if (!m_hts_meas_ind_conf_pending)
    {
        hts_sim_measurement(&simulated_meas);

        err_code = ble_hts_measurement_send(&m_hts, &simulated_meas);

        switch (err_code)
        {
            case NRF_SUCCESS:
                // Measurement was successfully sent, wait for confirmation.
                m_hts_meas_ind_conf_pending = true;
                break;

            case NRF_ERROR_INVALID_STATE:
                // Ignore error.
                break;

            default:
                APP_ERROR_HANDLER(err_code);
                break;
        }
    }
}


/**@brief Function for handling the Health Thermometer Service events.
 *
 * @details This function will be called for all Health Thermometer Service events which are passed
 *          to the application.
 *
 * @param[in] p_hts  Health Thermometer Service structure.
 * @param[in] p_evt  Event received from the Health Thermometer Service.
 */
static void on_hts_evt(ble_hts_t * p_hts, ble_hts_evt_t * p_evt)
{
    switch (p_evt->evt_type)
    {
        case BLE_HTS_EVT_INDICATION_ENABLED:
            // Indication has been enabled, send a single temperature measurement
            temperature_measurement_send();
            break;

        case BLE_HTS_EVT_INDICATION_CONFIRMED:
            m_hts_meas_ind_conf_pending = false;
            break;

        default:
            // No implementation needed.
            break;
    }
}


/**@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;
    }
}


/**@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, uint16_t const *p_gatts_uuid)
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;
  
    // 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)
        {
          /* 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;

            // 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)
    {
      
#ifdef RK_CLI //test scan filters
   
       case NRF_BLE_SCAN_EVT_FILTER_MATCH:
        {
            //Add devices to the list if the scan filter is matched
            device_to_list_add(p_scan_evt->params.filter_match.p_adv_report);
        }break;
//      case NRF_BLE_SCAN_EVT_NOT_FOUND:
//         {
//           if (p_scan_evt->params.filter_match.p_adv_report->peer_addr.addr[0] == 0x88)
//           NRF_LOG_RAW_INFO("Filter not found\r\n");
//          }break;
#endif //RK_CLI //test scan filters
        
         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[0],
                      p_connected->peer_addr.addr[1],
                      p_connected->peer_addr.addr[2],
                      p_connected->peer_addr.addr[3],
                      p_connected->peer_addr.addr[4],
                      p_connected->peer_addr.addr[5]
                      );
         } 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.connect_if_match = false;
    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);
    
    //add 'NRF_BLE_SCAN_UUID_CNT' filters
    for(int n_count = 0; n_count < NRF_BLE_SCAN_UUID_CNT; n_count++)
    {
      err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_UUID_FILTER, &m_scan_uuid[n_count]);
      APP_ERROR_CHECK(err_code);
    }

    err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_UUID_FILTER, false);
    APP_ERROR_CHECK(err_code);
}
#endif

/** @brief Function for initializing BLE components.
 */
void ble_init(void)
{

    ble_stack_init();
    gap_params_init();
    gatt_init();
    advertising_init();
    services_init();
    APP_ERROR_CHECK(nrf_cli_ble_uart_service_init());
    peer_manager_init();
    
#ifdef RK_CLI
    scan_init();
#endif
}


/**@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);

#ifdef RK_CLI
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);
}

void scan_stop(void)
{
    ret_code_t ret;

    nrf_ble_scan_stop();
    
    ret = bsp_indication_set(BSP_INDICATE_SCANNING);
    APP_ERROR_CHECK(ret);
}

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 buffer[BLE_GAP_ADDR_LEN] = {0};
    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, ":");
        }
    }
}

/* 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);
           
            nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%s %s %d dB\r\n", buffer,  p_device[i].dev_name, p_device[i].RSSI_value_RK);
          
        }
    }
}

static void scan_on_cmd(nrf_cli_t const *p_cli, size_t argc, char **argv)
{
    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)
{
  
    scan_stop();
    nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Scan stopped.\r\n");
}

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

#endif

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

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

   
    
    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);
}
#include "sdk_common.h"
#include "ble_cus.h"
#include <string.h>
#include "ble_srv_common.h"
#include "nrf_gpio.h"
#include "boards.h"
#include "nrf_log.h"
#include "ble_srv_common.h"

/**@brief Function for handling the Connect event.
 *
 * @param[in]   p_cus       Custom Service structure.
 * @param[in]   p_ble_evt   Event received from the BLE stack.
 */
static void on_connect(ble_cus_t * p_cus, ble_evt_t const * p_ble_evt)
{
    p_cus->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;

    ble_cus_evt_t evt;

    evt.evt_type = BLE_CUS_EVT_CONNECTED;

    p_cus->evt_handler(p_cus, &evt);
}

/**@brief Function for handling the Disconnect event.
 *
 * @param[in]   p_cus       Custom Service structure.
 * @param[in]   p_ble_evt   Event received from the BLE stack.
 */
static void on_disconnect(ble_cus_t * p_cus, ble_evt_t const * p_ble_evt)
{
    UNUSED_PARAMETER(p_ble_evt);
    p_cus->conn_handle = BLE_CONN_HANDLE_INVALID;
    
    ble_cus_evt_t evt;

    evt.evt_type = BLE_CUS_EVT_DISCONNECTED;

    p_cus->evt_handler(p_cus, &evt);
}

/**@brief Function for handling the Write event.
 *
 * @param[in]   p_cus       Custom Service structure.
 * @param[in]   p_ble_evt   Event received from the BLE stack.
 */
static void on_write(ble_cus_t * p_cus, ble_evt_t const * p_ble_evt)
{
    ble_cus_evt_t evt;
    ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    
    // Custom Value Characteristic Written to.
    if (p_evt_write->handle == p_cus->oxy_measurement_handles.value_handle)
    {
        nrf_gpio_pin_toggle(LED_4);

    }
    // Check if it is the Servo Control Characteristic that has been written to
    if (p_evt_write->handle == p_cus->nonin_control_point_handles.value_handle)
    {
      nrf_gpio_pin_toggle(LED_4);
      // Set the event type
      evt.evt_type = BLE_CUS_EVT_SERVO_CTR_VALUE_RECEIVED;
      // Assign the written value in the ble_cus_evt_t struct
      evt.servo_ctrl_value = p_evt_write->data[0];
      // Invoke the on_cus_evt event handler in main.c
      p_cus->evt_handler(p_cus, &evt);

    }

    // Check if the Custom value CCCD is written to and that the value is the appropriate length, i.e 2 bytes.
    if ((p_evt_write->handle == p_cus->oxy_measurement_handles.cccd_handle)
        && (p_evt_write->len == 2)
       )
    {
        // CCCD written, call application event handler
        if (p_cus->evt_handler != NULL)
        {
            if (ble_srv_is_notification_enabled(p_evt_write->data))
            {
                evt.evt_type = BLE_CUS_EVT_NOTIFICATION_ENABLED;
            }
            else
            {
                evt.evt_type = BLE_CUS_EVT_NOTIFICATION_DISABLED;
            }
            // Call the application event handler.
            p_cus->evt_handler(p_cus, &evt);
        }
    }

}

void ble_cus_on_ble_evt( ble_evt_t const * p_ble_evt, void * p_context)
{
    ble_cus_t * p_cus = (ble_cus_t *) p_context;
    
   // NRF_LOG_INFO("BLE event received. Event type = %d\r\n", p_ble_evt->header.evt_id); 
    if (p_cus == NULL || p_ble_evt == NULL)
    {
        return;
    }
    
    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            on_connect(p_cus, p_ble_evt);
            break;

        case BLE_GAP_EVT_DISCONNECTED:
            on_disconnect(p_cus, p_ble_evt);
            break;

        case BLE_GATTS_EVT_WRITE:
            on_write(p_cus, p_ble_evt);
            break;

        default:
            // No implementation needed.
            break;
    }
}

/**@brief Function for adding the Custom Value characteristic.
 *
 * @param[in]   p_cus        Battery Service structure.
 * @param[in]   p_cus_init   Information needed to initialize the service.
 *
 * @return      NRF_SUCCESS on success, otherwise an error code.
 */
//static uint32_t custom_value_char_add(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
//{
//    uint32_t            err_code;
//    ble_gatts_char_md_t char_md;
//    ble_gatts_attr_md_t cccd_md;
//    ble_gatts_attr_t    attr_char_value;
//    ble_uuid_t          ble_uuid;
//    ble_gatts_attr_md_t attr_md;
//
//    // Add Custom Value characteristic
//    memset(&cccd_md, 0, sizeof(cccd_md));
//
//    //  Read  operation on cccd should be possible without authentication.
//    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
//    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
//    
//    cccd_md.write_perm = p_cus_init->custom_value_char_attr_md.cccd_write_perm;
//    cccd_md.vloc       = BLE_GATTS_VLOC_STACK;
//
//    memset(&char_md, 0, sizeof(char_md));
//
//    char_md.char_props.read   = 1;
//    char_md.char_props.write  = 1;
//    char_md.char_props.notify = 1; 
//    char_md.p_char_user_desc  = NULL;
//    char_md.p_char_pf         = NULL;
//    char_md.p_user_desc_md    = NULL;
//    char_md.p_cccd_md         = &cccd_md; 
//    char_md.p_sccd_md         = NULL;
//		
//    ble_uuid.type = p_cus->uuid_type;
//    ble_uuid.uuid = CUSTOM_VALUE_CHAR_UUID;
//
//    memset(&attr_md, 0, sizeof(attr_md));
//
//    attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
//    attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
//    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
//    attr_md.rd_auth    = 0;
//    attr_md.wr_auth    = 0;
//    attr_md.vlen       = 0;
//
//    memset(&attr_char_value, 0, sizeof(attr_char_value));
//
//    attr_char_value.p_uuid    = &ble_uuid;
//    attr_char_value.p_attr_md = &attr_md;
//    attr_char_value.init_len  = sizeof(uint8_t);
//    attr_char_value.init_offs = 0;
//    attr_char_value.max_len   = sizeof(uint8_t);
//
//    err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
//                                               &attr_char_value,
//                                               &p_cus->custom_value_handles);
//    if (err_code != NRF_SUCCESS)
//    {
//        return err_code;
//    }
//
//    return NRF_SUCCESS;
//}
//
///**@brief Function for adding the Custom Value characteristic.
// *
// * @param[in]   p_cus        Battery Service structure.
// * @param[in]   p_cus_init   Information needed to initialize the service.
// *
// * @return      NRF_SUCCESS on success, otherwise an error code.
// */
//static uint32_t servo_ctrl_char_add(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
//{
//    uint32_t            err_code;
//    ble_gatts_char_md_t char_md;
//    ble_gatts_attr_md_t cccd_md;
//    ble_gatts_attr_t    attr_char_value;
//    ble_uuid_t          ble_uuid;
//    ble_gatts_attr_md_t attr_md;
//
//    // Add Custom Value characteristic
//    memset(&cccd_md, 0, sizeof(cccd_md));
//
//    //  Read  operation on cccd should be possible without authentication.
//    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
//    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
//    
//    cccd_md.write_perm = p_cus_init->custom_value_char_attr_md.cccd_write_perm;
//    cccd_md.vloc       = BLE_GATTS_VLOC_STACK;
//
//    memset(&char_md, 0, sizeof(char_md));
//
//    char_md.char_props.read   = 1;
//    char_md.char_props.write  = 1;
//    char_md.char_props.notify = 0; 
//    char_md.p_char_user_desc  = NULL;
//    char_md.p_char_pf         = NULL;
//    char_md.p_user_desc_md    = NULL;
//    char_md.p_cccd_md         = &cccd_md; 
//    char_md.p_sccd_md         = NULL;
//
//    memset(&ble_uuid, 0, sizeof(ble_uuid));
///*
//    ble_uuid128_t base_uuid_2 = {CUSTOM_SERVICE_UUID_BASE_2};
//    err_code =  sd_ble_uuid_vs_add(&base_uuid_2, &p_cus->uuid_type_2);
//    VERIFY_SUCCESS(err_code);
//*/
//    ble_uuid.type = p_cus->uuid_type_2;
//    ble_uuid.uuid = SERVO_CTRL_CHAR_UUID;
//
//    memset(&attr_md, 0, sizeof(attr_md));
//
//    attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
//    attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
//    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
//    attr_md.rd_auth    = 0;
//    attr_md.wr_auth    = 0;
//    attr_md.vlen       = 0;
//
//    memset(&attr_char_value, 0, sizeof(attr_char_value));
//
//    attr_char_value.p_uuid    = &ble_uuid;
//    attr_char_value.p_attr_md = &attr_md;
//    attr_char_value.init_len  = sizeof(uint8_t);
//    attr_char_value.init_offs = 0;
//    attr_char_value.max_len   = sizeof(uint8_t);
//
//    err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
//                                               &attr_char_value,
//                                               &p_cus->servo_control_handles);
//    if (err_code != NRF_SUCCESS)
//    {
//        return err_code;
//    }
//
//    return NRF_SUCCESS;
//}

uint32_t ble_cus_init(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
{
    if (p_cus == NULL || p_cus_init == NULL)
    {
        return NRF_ERROR_NULL;
    }

    uint32_t   err_code;
    ble_uuid_t ble_uuid;
    ble_add_char_params_t add_char_params;
   
    // Initialize service structure
    p_cus->evt_handler               = p_cus_init->evt_handler;
    p_cus->conn_handle               = BLE_CONN_HANDLE_INVALID;

    // Add Nonin Oxy sensor Service UUID BASE
    ble_uuid128_t base_uuid = BLE_UUID_NONIN_SENSOR_SERVICE_BASE;
    err_code =  sd_ble_uuid_vs_add(&base_uuid, &p_cus->uuid_type);
    VERIFY_SUCCESS(err_code);

    ble_uuid.type = p_cus->uuid_type;
    ble_uuid.uuid = BLE_UUID_NONIN_SENSOR_SERVICE;

    // Add the Custom Service
    err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_cus->service_handle);
    if (err_code != NRF_SUCCESS)
    {
        
        return err_code;
    }
    
    
    // Add UUID BASE for the Oxy measurement characteristic
    ble_uuid128_t base_uuid_oxy_measurement = BLE_UUID_OXY_MEASUREMENT_CHARACTERISTIC_BASE;
    err_code =  sd_ble_uuid_vs_add(&base_uuid_oxy_measurement, &p_cus->uuid_type_oxy_measurement);
    VERIFY_SUCCESS(err_code);
    
    //Add the oxymetry measurement Characteristic.
    memset(&add_char_params, 0, sizeof(add_char_params));
    add_char_params.uuid                     = BLE_UUID_OXY_MEASUREMENT_CHARACTERISTIC;
    add_char_params.uuid_type                = p_cus->uuid_type_oxy_measurement;
    add_char_params.max_len                  = sizeof(uint8_t);
    add_char_params.init_len                 = sizeof(uint8_t);
    add_char_params.is_var_len               = true;
    add_char_params.char_props.write         = 1;
    add_char_params.char_props.write_wo_resp = 1;

    add_char_params.read_access  = SEC_OPEN;
    add_char_params.write_access = SEC_OPEN;

    err_code = characteristic_add(p_cus->service_handle, &add_char_params, &p_cus->oxy_measurement_handles);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    
    
    // Add UUID BASE for Nonin control point characteristic
    ble_uuid128_t base_uuid_nonin_control_point = BLE_UUID_NONIN_CONTROL_POINT_CHARACTERISTIC_BASE;
    err_code =  sd_ble_uuid_vs_add(&base_uuid_nonin_control_point, &p_cus->uuid_type_nonin_control_point);
    VERIFY_SUCCESS(err_code);
    
    // Add the Nonin control point Characteristic.
    /**@snippet [Adding proprietary characteristic to the SoftDevice] */
    memset(&add_char_params, 0, sizeof(add_char_params));
    add_char_params.uuid              = BLE_UUID_NONIN_CONTROL_POINT_CHARACTERISTIC;
    add_char_params.uuid_type         = p_cus->uuid_type;
    add_char_params.max_len           = sizeof(uint8_t);
    add_char_params.init_len          = sizeof(uint8_t);
    add_char_params.is_var_len        = true;
    add_char_params.char_props.notify = 1;

    add_char_params.read_access       = SEC_OPEN;
    add_char_params.write_access      = SEC_OPEN;
    add_char_params.cccd_write_access = SEC_OPEN;

    return characteristic_add(p_cus->service_handle, &add_char_params, &p_cus->nonin_control_point_handles);
    /**@snippet [Adding proprietary characteristic to the SoftDevice] */
    
}

uint32_t ble_cus_custom_value_update(ble_cus_t * p_cus, uint8_t custom_value)
{
    NRF_LOG_INFO("In ble_cus_custom_value_update. \r\n"); 
    if (p_cus == NULL)
    {
        return NRF_ERROR_NULL;
    }

    uint32_t err_code = NRF_SUCCESS;
    ble_gatts_value_t gatts_value;

    // Initialize value struct.
    memset(&gatts_value, 0, sizeof(gatts_value));

    gatts_value.len     = sizeof(uint8_t);
    gatts_value.offset  = 0;
    gatts_value.p_value = &custom_value;

    // Update database.
    err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                      p_cus->oxy_measurement_handles.value_handle,
                                      &gatts_value);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    // Send value if connected and notifying.
    if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
    {
        ble_gatts_hvx_params_t hvx_params;

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

        hvx_params.handle = p_cus->oxy_measurement_handles.value_handle;
        hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
        hvx_params.offset = gatts_value.offset;
        hvx_params.p_len  = &gatts_value.len;
        hvx_params.p_data = gatts_value.p_value;

        err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
        NRF_LOG_INFO("sd_ble_gatts_hvx result: %x. \r\n", err_code); 
    }
    else
    {
        err_code = NRF_ERROR_INVALID_STATE;
        NRF_LOG_INFO("sd_ble_gatts_hvx result: NRF_ERROR_INVALID_STATE. \r\n"); 
    }


    return err_code;
}
ble_cus.hsdk_config.h\

i have modified ble_app_cli example code to achieve my requirements. attached files main.c, sdk_config.h, ble_cus.c(custom service), ble_cus.h

  • just giving some details : 

    if there are 3 peripheral devices with all 3 uuid's only HTS(Thermometer) service is getting detected.

    in the output devices: i able to get only HTS device.

    other two devices are not shown in device list .

    i have set scan filter for all 3 UUID's. even-though the expected devices are in vicinity , my application is not able to match filter for other two UUID's.

    Please suggest what is wrong the code???

    Thanks in advance... 

  • Rekha said:
    i have set scan filter for all 3 UUID's

     How did you do this? I assume it involves nrf_ble_scan_uuid_filter_add() from the file nrf_ble_scan.c at some point. Can you try to set your logging level to "Debug" in sdk_config.h, and see f all filters are added? You should see 3 entries of "Added filter on UUID n" in your log. If you don't, are you receiving the error NRF_ERROR_NO_MEM at any point?

    Best regards,

    Edvin

  • there are no such errors, i got that error before and I resolved it by allocating more memory.

    right now i am not getting any errors. 

    I have added filters using  nrf_ble_scan_uuid_filter_add() from the file nrf_ble_scan.c.

    i tried debugging it i was able to see 3 filters being added in the array.

  • Hello,

    If you look into nrf_ble_scan.c:

    I assume you have NRF_BLE_SCAN_UUID_CNT > 0 (probably 3). 

    If so, the device will enter adv_uuid_compare() on line 962 in nrf_ble_scan.c.

    • Can you see whether you have all_filters_mode = true or false?
      If set to true, yo need to match all 3 UUIDs to connect. If set to false, it is enough to match with one UUID. Is this what you mean? That you will match on only one UUID, and it ignores the rest? If so, try to set all_filters_mode to true.

    • If the issue is that you don't see the two last UUIDs, are you sure that you are actually advertising with all 3 UUIDs? My suspicion is no, since 3 UUIDs will take up a lot of space, and you only have 31 advertising bytes.

    I am still not sure I understand your issue correctly, but can you see if it is any of the two above?

  • Can you see whether you have all_filters_mode = true or false?

    it is set true. Because there might be different central devices with any one of these UUID's so i just want to check whether atleast one UUID is present or not. if yes then move to matched list and display in device list.

    since 3 UUIDs will take up a lot of space, and you only have 31 advertising bytes.

    But the issue is with scan filter not advertising. because i have 3 different device each advertises with one UUID. so i want to list all these 3 devices.

    Thanks

    Rekha

Related