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

s332 advertising whitelist error

Hello Nordic:

I am trying to add advertising with whitelist function to my code which is base on

nrf52832 dk

softdevice s332 5.0.0

SDK 14.2

I use the example code HID MOUSE Application which implement whitelist as reference.

I make functions related to whitelist almost exactly the same as in HID MOUSE Application and copy the missing function like peer_list_get() to my code.

When the first device is bonded and added into whitelist, the function seems to work correctly.

However when the device  disconnected, the device did go to direct advertising but somehow return an error afterwards as below.

0> <info> ant_hrm: ANT HRM channel 0 init
0> <info> ant_hrm: ANT HRM channel 0 open
0> <info> app: Initialization finish entering main loop
0> <info> app: pm_whitelist_get returns 0 addr in whitelist and 0 irk whitelist
0> <info> app: Fast advertising.
0> <info> app: pm_whitelist_get returns 0 addr in whitelist and 0 irk whitelist
0> <info> app: Slow advertising.
0> <info> app: Connected.
0> <info> app: Link secured. Role: 1. conn_handle: 0, Procedure: 1
0> <info> app: New Bond, add the peer to the whitelist if possible
0> <info> app: m_whitelist_peer_cnt 1, MAX_PEERS_WLIST 8
0> <info> app: add 0 to whitelist
0> <info> app: Disconnected
0> <info> app: BLE_ADV_EVT_PEER_ADDR_REQUEST
0> <info> app: Directed advertising.
0> <info> app: pm_whitelist_get returns 1 addr in whitelist and 1 irk whitelist
0> <error> app: ERROR 7 [NRF_ERROR_INVALID_PARAM] at ..\..\..\..\..\..\components\ble\ble_advertising\ble_advertising.c:287

after reset, the error always come up

0> <info> ant_hrm: ANT HRM channel 0 init
0> <info> app: pm_whitelist_get returns 1 addr in whitelist and 1 irk whitelist
0> <error> app: ERROR 7 [NRF_ERROR_INVALID_PARAM] at ..\..\..\..\..\..\components\ble\ble_advertising\ble_advertising.c:287

This erorr was ERROR 12801 [Unknown error code] from ble_advertising_error_handler before i put APP_ERROR_CHECK to advertising.c.

As far as I know from other posts, 12801 stands for "BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST"

which is Use of Whitelist not permitted with discoverable.

It seems that the problem occur because the device is trying to advertise with whitelist.

I did set BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE in advertising_init() but the example code also do so which seems like it will switch automatically the flag to BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED before switching to advertising with whitelist from the code below, am i correct?

static ret_code_t set_adv_mode_fast(ble_advertising_t * const p_advertising,
                                    ble_gap_adv_params_t    * p_adv_params)
{
    ret_code_t ret;

    p_adv_params->interval = p_advertising->adv_modes_config.ble_adv_fast_interval;
    p_adv_params->timeout  = p_advertising->adv_modes_config.ble_adv_fast_timeout;

    if ((p_advertising->adv_modes_config.ble_adv_whitelist_enabled) &&
        (!p_advertising->whitelist_temporarily_disabled) &&
        (whitelist_has_entries(p_advertising)))
    {
        #if (NRF_SD_BLE_API_VERSION <= 2)
            p_adv_params->p_whitelist = &m_whitelist;
        #endif

        p_adv_params->fp = BLE_GAP_ADV_FP_FILTER_CONNREQ;
        p_advertising->advdata.flags  = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;

        ret = ble_advdata_set(&(p_advertising->advdata), NULL);
        if (ret != NRF_SUCCESS)
        {
						APP_ERROR_CHECK(ret);
            return ret;
        }

        p_advertising->adv_evt = BLE_ADV_EVT_FAST_WHITELIST;
    }
    else
    {
        p_advertising->adv_evt = BLE_ADV_EVT_FAST;
    }

    return NRF_SUCCESS;
}

I also try to switch the flag in advertising_init() directly to BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED however the advertising mode seems to go to IDLE directly which result in sleep mode enter.

Since I am new to Bluetooth and embedded system. This might be a stupid question. but Could you kindly let me know how to fix this problem?

Parents
  • Thank you Håvard for the fast response and the note about direct advertising. My code uses ble_ant_app_hrm example as a template. I separate  BLE part to be BLE Agent which is as below. I also change quit a lot of initial settings while trying to make bonding and dfu works. It is quit messy since I am still just testing on it ><"

    #include <stdint.h>
    #include <string.h>
    #include "BLE_Agent.h"
    #include "nordic_common.h"
    #include "app_error.h"
    #include "ble_hci.h"
    #include "ble_conn_state.h"
    #include "ble_conn_params.h"
    #include "ble_srv_common.h"
    #include "ble_dfu.h"
    #include "nrf_gpio.h" 
    #include "drv_acc.h"
    
    #include "nrf_dfu_svci.h"
    #include "nrf_svci_async_function.h"
    #include "nrf_svci_async_handler.h"
    
    #include "ble_advdata.h"
    #include "ble_advertising.h"
    #include "ble_hrs.h"
    #include "ble_dis.h"
    #include "ble_ipd.h"
    
    #include "nrf_sdh.h"
    #include "nrf_sdh_ble.h"
    #include "nrf_sdh_soc.h"
    
    #include "ant_interface.h"
    #include "ANT_Agent.h"
    #include "fds.h"
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "peer_manager.h"
    
    static pm_peer_id_t      								m_peer_id;                                   /**< Device reference handle to the current bonded central. */
    static volatile uint16_t                m_conn_handle = BLE_CONN_HANDLE_INVALID;     /**< Handle of the current connection. */
    static pm_peer_id_t      m_whitelist_peers[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];       /**< List of peers currently in the whitelist. */
    static uint32_t          m_whitelist_peer_cnt;                                      /**< Number of peers currently in the whitelist. */
    
    BLE_HRS_DEF(m_hrs);                                                                  /**< Heart rate service instance. */
    BLE_IPD_DEF(m_ipd);																																	 /**< Intelligent Pedal service instance. */
    BLE_ADVERTISING_DEF(m_advertising);                                 								/**< Advertising module instance. */
    NRF_BLE_GATT_DEF(m_gatt);                                                           /**< GATT module instance. */
    #define NOTIFICATION_INTERVAL           APP_TIMER_TICKS(1000)
    APP_TIMER_DEF(m_notification_timer_id); //timer for ble notification
    static uint8_t m_ipd_value = 0;    //testing ble notification
    
    
    
    #ifdef BLE_DFU_APP_SUPPORT
    /**@brief Function for handling dfu events from the Buttonless Secure DFU service
     *
     * @param[in]   event   Event from the Buttonless Secure DFU service.
     */
    static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event)
    {
        switch (event)
        {
            case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE:
                NRF_LOG_INFO("Device is preparing to enter bootloader mode.");
                // YOUR_JOB: Disconnect all bonded devices that currently are connected.
                //           This is required to receive a service changed indication
                //           on bootup after a successful (or aborted) Device Firmware Update.
                break;
    
            case BLE_DFU_EVT_BOOTLOADER_ENTER:
                // YOUR_JOB: Write app-specific unwritten data to FLASH, control finalization of this
                //           by delaying reset by reporting false in app_shutdown_handler
                NRF_LOG_INFO("Device will enter bootloader mode.");
                break;
    
            case BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED:
                NRF_LOG_ERROR("Request to enter bootloader mode failed asynchroneously.");
                // YOUR_JOB: Take corrective measures to resolve the issue
                //           like calling APP_ERROR_CHECK to reset the device.
                break;
    
            case BLE_DFU_EVT_RESPONSE_SEND_ERROR:
                NRF_LOG_ERROR("Request to send a response to client failed.");
                // YOUR_JOB: Take corrective measures to resolve the issue
                //           like calling APP_ERROR_CHECK to reset the device.
                APP_ERROR_CHECK(false);
                break;
    
            default:
                NRF_LOG_ERROR("Unknown event from ble_dfu_buttonless.");
                break;
        }
    }
    #endif // BLE_DFU_APP_SUPPORT
    
    /**@brief 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)
    {
        uint32_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);
    
        err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_CYCLING_POWER_SENSOR);
        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 putting the chip into sleep mode.
     *
     * @note This function will not return.
     */
    static void sleep_mode_enter(void)
    {
    		uint32_t err_code;
    		// Enable wake on low power accelerometer.
        nrf_gpio_cfg_sense_input(LIS3DH_INT1, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); //NRF_GPIO_PIN_NOPULL NRF_GPIO_PIN_SENSE_HIGH for real use
        // Prepare wakeup buttons.
        //uint32_t err_code = drv_acc_wakeup_prepare(true);
        //APP_ERROR_CHECK(err_code);
    	
    		NRF_LOG_FLUSH();
        // Go to system-off mode (this function will not return; wakeup will cause a reset).
        err_code = sd_power_system_off();
    		NRF_LOG_WARNING("BLE timeout system off return. Perhaps due to debug mode");
        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_DIRECTED:
                NRF_LOG_INFO("Directed advertising.");
    //            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_DIRECTED);
    //            APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_FAST:
                NRF_LOG_INFO("Fast advertising.");
    //            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
    //            APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_SLOW:
                NRF_LOG_INFO("Slow advertising.");
    //            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_SLOW);
    //            APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_FAST_WHITELIST:
                NRF_LOG_INFO("Fast advertising with whitelist.");
    //            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_WHITELIST);
    //            APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_SLOW_WHITELIST:
                NRF_LOG_INFO("Slow advertising with whitelist.");
    //            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_WHITELIST);
    //            APP_ERROR_CHECK(err_code);
                err_code = ble_advertising_restart_without_whitelist(&m_advertising);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_IDLE:
    //            err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    //            APP_ERROR_CHECK(err_code);
                sleep_mode_enter();
                break;
    
            case BLE_ADV_EVT_WHITELIST_REQUEST:
            {
                ble_gap_addr_t whitelist_addrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
                ble_gap_irk_t  whitelist_irks[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
                uint32_t       addr_cnt = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
                uint32_t       irk_cnt  = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
    
                err_code = pm_whitelist_get(whitelist_addrs, &addr_cnt,
                                            whitelist_irks,  &irk_cnt);
                APP_ERROR_CHECK(err_code);
                NRF_LOG_INFO("pm_whitelist_get returns %d addr in whitelist and %d irk whitelist",
                               addr_cnt,
                               irk_cnt);
    
                // Apply the whitelist.
                err_code = ble_advertising_whitelist_reply(&m_advertising,
                                                           whitelist_addrs,
                                                           addr_cnt,
                                                           whitelist_irks,
                                                           irk_cnt);
                APP_ERROR_CHECK(err_code);
            }
            break;
    
            case BLE_ADV_EVT_PEER_ADDR_REQUEST:
            {
    					NRF_LOG_INFO("BLE_ADV_EVT_PEER_ADDR_REQUEST");
                pm_peer_data_bonding_t peer_bonding_data;
    
                // Only Give peer address if we have a handle to the bonded peer.
                if (m_peer_id != PM_PEER_ID_INVALID)
                {
    
                    err_code = pm_peer_data_bonding_load(m_peer_id, &peer_bonding_data);
                    if (err_code != NRF_ERROR_NOT_FOUND)
                    {
                        APP_ERROR_CHECK(err_code);
    
                        ble_gap_addr_t * p_peer_addr = &(peer_bonding_data.peer_ble_id.id_addr_info);
                        err_code = ble_advertising_peer_addr_reply(&m_advertising, p_peer_addr);
                        APP_ERROR_CHECK(err_code);
                    }
    
                }
                break;
            }
    
            default:
                break;
        }
    }
    
    /**@brief Function for handling advertising errors.
     *
     * @param[in] nrf_error  Error code containing information about what went wrong.
     */
    static void ble_advertising_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    /**@brief Function for initializing the Advertising functionality.
     */
    static void advertising_init(void)
    {
        ret_code_t             err_code;
        ble_advertising_init_t init;
    	
        ble_uuid_t m_adv_uuids[] =
        {
            {BLE_UUID_CYCLING_POWER,         BLE_UUID_TYPE_BLE},
            {BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE}
        };
    
        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_LIMITED_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_whitelist_enabled      = true;
        init.config.ble_adv_directed_enabled       = true;
        init.config.ble_adv_directed_slow_enabled  = false;
        init.config.ble_adv_directed_slow_interval = 0;
        init.config.ble_adv_directed_slow_timeout  = 0;
        init.config.ble_adv_fast_enabled					 = true;
        init.config.ble_adv_fast_interval					 = APP_ADV_FAST_INTERVAL;
        init.config.ble_adv_fast_timeout 					 = APP_ADV_FAST_TIMEOUT_IN_SECONDS;
    		init.config.ble_adv_slow_enabled           = true;
        init.config.ble_adv_slow_interval          = APP_ADV_SLOW_INTERVAL;
        init.config.ble_adv_slow_timeout           = APP_ADV_SLOW_TIMEOUT;
    
        init.evt_handler = on_adv_evt;
    		init.error_handler = ble_advertising_error_handler;
    
        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 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_ipd_evt(ble_ipd_t     * p_ipd_service,
                           ble_ipd_evt_t * p_evt)
    {
    		uint32_t      err_code;
        switch(p_evt->evt_type)
        {
            case BLE_IPD_EVT_NOTIFICATION_ENABLED:
    	   err_code = app_timer_start(m_notification_timer_id, NOTIFICATION_INTERVAL, NULL);
               APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_IPD_EVT_NOTIFICATION_DISABLED:
    	   err_code = app_timer_stop(m_notification_timer_id);
               APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_IPD_EVT_CONNECTED:
                break;
    
            case BLE_IPD_EVT_DISCONNECTED:
                  break;
    
            default:
                  // No implementation needed.
                  break;
        }
    }
    
    
    /**@brief Initialize services that will be used by the application.
     *
     * @details Initialize the Heart Rate and Device Information services.
     */
    static void services_init(void)
    {
        uint32_t       err_code;
        ble_hrs_init_t hrs_init;
        ble_dis_init_t dis_init;
    		ble_ipd_init_t ipd_init;
        uint8_t        body_sensor_location;
    	
    #ifdef BLE_DFU_APP_SUPPORT		
    		// Initialize the dfu module
    		 ble_dfu_buttonless_init_t dfus_init =
        {
            .evt_handler = ble_dfu_evt_handler
        };
    		
        // Initialize the async SVCI interface to bootloader.
        err_code = ble_dfu_buttonless_async_svci_init();
        APP_ERROR_CHECK(err_code);
        
        err_code = ble_dfu_buttonless_init(&dfus_init);
        APP_ERROR_CHECK(err_code);
    #endif //BLE_DFU_APP_SUPPORT
    	
    		// Initialize Intelligent Pedal Service.
        memset(&ipd_init, 0, sizeof(ipd_init));
    	
    		// Here the sec level for the IPD Service can be changed/increased.
    		BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&ipd_init.ipd_value_char_attr_md.read_perm);
    		BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&ipd_init.ipd_value_char_attr_md.write_perm);
    		
    		// Set the ipd event handler
        ipd_init.evt_handler  = on_ipd_evt;
    		
        err_code = ble_ipd_init(&m_ipd, &ipd_init);
        APP_ERROR_CHECK(err_code);
    
        // Initialize Heart Rate Service.
        body_sensor_location = BLE_HRS_BODY_SENSOR_LOCATION_FINGER;
    
        memset(&hrs_init, 0, sizeof(hrs_init));
    
        hrs_init.evt_handler                 = NULL;
        hrs_init.is_sensor_contact_supported = false;
        hrs_init.p_body_sensor_location      = &body_sensor_location;
    
        // Here the sec level for the Heart Rate Service can be changed/increased.
        BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hrs_init.hrs_hrm_attr_md.cccd_write_perm);
        BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_hrm_attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_hrm_attr_md.write_perm);
    
        BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hrs_init.hrs_bsl_attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_bsl_attr_md.write_perm);
    
        err_code = ble_hrs_init(&m_hrs, &hrs_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, MANUFACTURER_NAME);
    
        BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&dis_init.dis_attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm);
    
        err_code = ble_dis_init(&dis_init);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Connection Parameters Module handler.
     *
     * @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;
    
    //    switch (p_evt->evt_type)
    //    {
    //        case BLE_CONN_PARAMS_EVT_FAILED:
    ////            err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
    ////            APP_ERROR_CHECK(err_code);
    //            break;
    
    //        default:
    //            // No implementation needed.
    //            break;
    //    }
    //}
    
    
    /**@brief Connection Parameters module error handler.
     *
     * @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 Initialize 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    = m_hrs.hrm_handles.cccd_handle;
        cp_init.disconnect_on_fail             = false;
        cp_init.evt_handler                    = NULL;//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);
    }
    
    
    /**@brief Function for dispatching a BLE stack event to all modules with a BLE stack event handler.
     *
     * @param[in] p_ble_evt  Bluetooth stack event.
     * @param[in] p_context  Context.
     */
    void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t err_code = NRF_SUCCESS;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_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;
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
    //            err_code = bsp_indication_set(BSP_INDICATE_IDLE);
                //APP_ERROR_CHECK(err_code);
                NRF_LOG_INFO("Disconnected");
                m_conn_handle = BLE_CONN_HANDLE_INVALID;
                // Need to close the ANT channel to make it safe to write bonding information to flash
                //err_code = sd_ant_channel_close(ANT_HRMRX_ANT_CHANNEL);
                //APP_ERROR_CHECK(err_code);
    
                // Note: Bonding information will be stored, advertising will be restarted and the
                //       ANT channel will be reopened when ANT event CHANNEL_CLOSED is received.
                break;
    
    //        case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:   //citty fix 20180511 ios send mtu while connecting solved by adding gatt init()
    //						err_code=sd_ble_gatts_exchange_mtu_reply(p_ble_evt->evt.gatts_evt.conn_handle, 23);
    //						APP_ERROR_CHECK(err_code);
    //            break;
    
    
    #ifndef BONDING_ENABLE
    //        case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
    //            err_code = sd_ble_gap_sec_params_reply(m_conn_handle,
    //                                                   BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP,
    //                                                   NULL,
    //                                                   NULL);
    //            APP_ERROR_CHECK(err_code);
    //            break;
    #endif // BONDING_ENABLE
    				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;
    				
    				case BLE_EVT_USER_MEM_REQUEST:
                err_code = sd_ble_user_mem_reply(p_ble_evt->evt.gattc_evt.conn_handle, NULL);
                APP_ERROR_CHECK(err_code);
                break;
    				
    //        case BLE_GAP_EVT_TIMEOUT:
    //            if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISING)
    //            {
    //                //err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    //                APP_ERROR_CHECK(err_code);
    //                // Go to system-off mode (this function will not return; wakeup will cause a reset)
    //                err_code = sd_power_system_off();
    //                NRF_LOG_WARNING("BLE timeout system off return. Perhaps due to debug mode");
    //                APP_ERROR_CHECK(err_code);
    //            }
    //            break;
    
    #ifndef BONDING_ENABLE
                case BLE_GATTS_EVT_SYS_ATTR_MISSING:
                    err_code = sd_ble_gatts_sys_attr_set(m_conn_handle,
                                                         NULL,
                                                         0,
                                                         BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS);
                    APP_ERROR_CHECK(err_code);
                    break;
    #endif // BONDING_ENABLE
    
    			 case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            {
                ble_gatts_evt_rw_authorize_request_t  req;
                ble_gatts_rw_authorize_reply_params_t auth_reply;
    
                req = p_ble_evt->evt.gatts_evt.params.authorize_request;
    
                if (req.type != BLE_GATTS_AUTHORIZE_TYPE_INVALID)
                {
                    if ((req.request.write.op == BLE_GATTS_OP_PREP_WRITE_REQ)     ||
                        (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) ||
                        (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL))
                    {
                        if (req.type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
                        {
                            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
                        }
                        else
                        {
                            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
                        }
                        auth_reply.params.write.gatt_status = APP_FEATURE_NOT_SUPPORTED;
                        err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle,
                                                                   &auth_reply);
                        APP_ERROR_CHECK(err_code);
                    }
                }
            } break; // BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST
            default:
                //NRF_LOG_ERROR("BLE_GATTS_EVT NOT SUPPORT %x",p_ble_evt->header.evt_id);
                // No implementation needed.
                break;
        }
    }
    
    #ifdef BONDING_ENABLE
    
    /**@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)
    {
        ret_code_t err_code;
    
        switch (p_evt->evt_id)
        {
            case PM_EVT_BONDED_PEER_CONNECTED:
                NRF_LOG_INFO("Connected to previously bonded device");
    //            err_code = pm_peer_rank_highest(p_evt->peer_id);
    //            if (err_code != NRF_ERROR_BUSY)
    //            {
    //                APP_ERROR_CHECK(err_code);
    //            }
                break; // PM_EVT_BONDED_PEER_CONNECTED
    
            case PM_EVT_CONN_SEC_START:
                break; // PM_EVT_CONN_SEC_START
    
            case PM_EVT_CONN_SEC_SUCCEEDED:
                NRF_LOG_INFO("Link secured. Role: %d. conn_handle: %d, Procedure: %d",
                                     ble_conn_state_role(p_evt->conn_handle),
                                     p_evt->conn_handle,
                                     p_evt->params.conn_sec_succeeded.procedure);
    
    //            if (p_evt->params.conn_sec_succeeded.procedure == PM_LINK_SECURED_PROCEDURE_BONDING)
    //            {
    //                err_code = pm_peer_rank_highest(p_evt->peer_id);
    //                if (err_code != NRF_ERROR_BUSY)
    //                {
    //                    APP_ERROR_CHECK(err_code);
    //                }
    //            }
    						m_peer_id = p_evt->peer_id;
                break;  // PM_EVT_CONN_SEC_SUCCEEDED
    
            case PM_EVT_CONN_SEC_FAILED:
    						NRF_LOG_INFO("Failed to secure connection.");
                /** Often, when securing fails, it shouldn't be restarted, for security reasons.
                 *  Other times, it can be restarted directly.
                 *  Sometimes it can be restarted, but only after changing some Security Parameters.
                 *  Sometimes, it cannot be restarted until the link is disconnected and reconnected.
                 *  Sometimes it is impossible, to secure the link, or the peer device does not support it.
                 *  How to handle this error is highly application dependent. */
                break; // PM_EVT_CONN_SEC_FAILED
    
            case PM_EVT_CONN_SEC_CONFIG_REQ:
            {
                // Reject pairing request from an already bonded peer.
                pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false};
                pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
            } break; // PM_EVT_CONN_SEC_CONFIG_REQ
    
            case PM_EVT_STORAGE_FULL:
                // Run garbage collection on the flash.
    						err_code = fds_gc();
                if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES)
                {
                    // Retry.
                }
                else
                {
                    APP_ERROR_CHECK(err_code);
                }
                break; // PM_EVT_STORAGE_FULL
    
            case PM_EVT_ERROR_UNEXPECTED:
                // A likely fatal error occurred. Assert.
                APP_ERROR_CHECK(p_evt->params.error_unexpected.error);
                break;
    
            case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
            {
                if (     p_evt->params.peer_data_update_succeeded.flash_changed
                     && (p_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_BONDING))
                {
                    NRF_LOG_INFO("New Bond, add the peer to the whitelist if possible");
                    NRF_LOG_INFO("\tm_whitelist_peer_cnt %d, MAX_PEERS_WLIST %d",
                                   m_whitelist_peer_cnt + 1,
                                   BLE_GAP_WHITELIST_ADDR_MAX_COUNT);
                    // Note: You should check on what kind of white list policy your application should use.
    
                    if (m_whitelist_peer_cnt < BLE_GAP_WHITELIST_ADDR_MAX_COUNT)
                    {
                        // Bonded to a new peer, add it to the whitelist.
                        m_whitelist_peers[m_whitelist_peer_cnt++] = m_peer_id;
    										NRF_LOG_INFO("add %d to whitelist",m_peer_id);
    
                        // The whitelist has been modified, update it in the Peer Manager.
                        err_code = pm_whitelist_set(m_whitelist_peers, m_whitelist_peer_cnt);
                        APP_ERROR_CHECK(err_code);
    
                        err_code = pm_device_identities_list_set(m_whitelist_peers, m_whitelist_peer_cnt);
                        if (err_code != NRF_ERROR_NOT_SUPPORTED)
                        {
                            APP_ERROR_CHECK(err_code);
                        }
                    }
                }
            } break;
    
            case PM_EVT_PEER_DATA_UPDATE_FAILED:
                // Assert.
                APP_ERROR_CHECK_BOOL(false);
                break; // PM_EVT_ERROR_UNEXPECTED
    
            case PM_EVT_PEER_DELETE_SUCCEEDED:
    						NRF_LOG_INFO("Peer delete succeeded");
                break; // PM_EVT_PEER_DELETE_SUCCEEDED
    
            case PM_EVT_PEER_DELETE_FAILED:
                // Assert.
                APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error);
                break; // PM_EVT_PEER_DELETE_FAILED
    
            case PM_EVT_PEERS_DELETE_SUCCEEDED:
                NRF_LOG_INFO("Peers delete succeeded");
    						advertising_start(false);
                break; // PM_EVT_PEERS_DELETE_SUCCEEDED
    
            case PM_EVT_PEERS_DELETE_FAILED:
                // Assert.
                APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error);
                break; // PM_EVT_PEERS_DELETE_FAILED
    
            case PM_EVT_LOCAL_DB_CACHE_APPLIED:
                break; // PM_EVT_LOCAL_DB_CACHE_APPLIED
    
            case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED:
                // The local database has likely changed, send service changed indications.
                pm_local_database_has_changed();
                break; // PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED
    
            case PM_EVT_SERVICE_CHANGED_IND_SENT:
                break; // PM_EVT_SERVICE_CHANGED_IND_SENT
    
            case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED:
                break; // PM_EVT_SERVICE_CHANGED_IND_SENT
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    /**@brief Fetch the list of peer manager peer IDs.
     *
     * @param[inout] p_peers   The buffer where to store the list of peer IDs.
     * @param[inout] p_size    In: The size of the @p p_peers buffer.
     *                         Out: The number of peers copied in the buffer.
     */
    static void peer_list_get(pm_peer_id_t * p_peers, uint32_t * p_size)
    {
        pm_peer_id_t peer_id;
        uint32_t     peers_to_copy;
    
        peers_to_copy = (*p_size < BLE_GAP_WHITELIST_ADDR_MAX_COUNT) ?
                         *p_size : BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
    
        peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);
        *p_size = 0;
    
        while ((peer_id != PM_PEER_ID_INVALID) && (peers_to_copy--))
        {
            p_peers[(*p_size)++] = peer_id;
            peer_id = pm_next_peer_id_get(peer_id);
        }
    }
    
    /**@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 ret;
    
    //        memset(m_whitelist_peers, PM_PEER_ID_INVALID, sizeof(m_whitelist_peers));
    //        m_whitelist_peer_cnt = (sizeof(m_whitelist_peers) / sizeof(pm_peer_id_t));
    
    //        peer_list_get(m_whitelist_peers, &m_whitelist_peer_cnt);
    
    //        ret = pm_whitelist_set(m_whitelist_peers, m_whitelist_peer_cnt);
    //        APP_ERROR_CHECK(ret);
    
    //        // Setup the device identies list.
    //        // Some SoftDevices do not support this feature.
    //        ret = pm_device_identities_list_set(m_whitelist_peers, m_whitelist_peer_cnt);
    //        if (ret != NRF_ERROR_NOT_SUPPORTED)
    //        {
    //            APP_ERROR_CHECK(ret);
    //        }
    
            ret = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
            APP_ERROR_CHECK(ret);
        }
    }
    
    
    /**@brief Function for the Peer Manager initialization.
     *
     * @param[in] erase_bonds  Indicates whether bonding information should be cleared from
     *                         persistent storage during initialization of the Peer Manager.
     */
    /**@brief Function for the Peer Manager initialization.
     */
    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);
    
    //    err_code = fds_register(fds_evt_handler);
    //    APP_ERROR_CHECK(err_code);
    }
    #endif // BONDING_ENABLE
    
    /**@brief   Function for initializing the GATT module.
     * @details The GATT module handles ATT_MTU and Data Length update procedures automatically.
     */
    static void gatt_init(void)
    {
        ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief BLE Agent initialized
     */
    void BLE_Agent_init(void)
    {
        gap_params_init();
    		services_init();
        advertising_init();
        conn_params_init();
    		gatt_init();
    	
    		nrf_gpio_cfg_output(20); //TESTING ON LED4
    }
    
    /**@brief Timer initialization.
     *
     * @details Initializes the timer module. This creates and starts application timers.
     */
    void ble_timers_init(void)
    {
    		uint32_t err_code = app_timer_create(&m_notification_timer_id, APP_TIMER_MODE_REPEATED, notification_timeout_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief 
     *
     * @details 
     *
     * @param[in] 
     *                       
     */
    void notification_timeout_handler(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        ret_code_t err_code;
        
        // Increment the value of m_ipd_value before nortifing it.
        m_ipd_value++;
        
        err_code = ble_ipd_value_update(&m_ipd, m_ipd_value);
        APP_ERROR_CHECK(err_code);
    }

    I call softdevice_setup, BLE_Agent_init, peer_manager_init and advertising_start(false) in main before the main loop. The softdevice_setup is exactly the same as in the ble_ant_app_hrm example as below.

    static void softdevice_setup(void)
    {
        ret_code_t err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        ASSERT(nrf_sdh_is_enabled());
    
        // 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);
    
        err_code = nrf_sdh_ant_enable();
        APP_ERROR_CHECK(err_code);
    
        err_code = ant_plus_key_set(ANTPLUS_NETWORK_NUMBER);
        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);
        NRF_SDH_ANT_OBSERVER(m_ant_observer, APP_ANT_OBSERVER_PRIO, ant_evt_handler, NULL);
    }

    Once again thank you for helping

Reply
  • Thank you Håvard for the fast response and the note about direct advertising. My code uses ble_ant_app_hrm example as a template. I separate  BLE part to be BLE Agent which is as below. I also change quit a lot of initial settings while trying to make bonding and dfu works. It is quit messy since I am still just testing on it ><"

    #include <stdint.h>
    #include <string.h>
    #include "BLE_Agent.h"
    #include "nordic_common.h"
    #include "app_error.h"
    #include "ble_hci.h"
    #include "ble_conn_state.h"
    #include "ble_conn_params.h"
    #include "ble_srv_common.h"
    #include "ble_dfu.h"
    #include "nrf_gpio.h" 
    #include "drv_acc.h"
    
    #include "nrf_dfu_svci.h"
    #include "nrf_svci_async_function.h"
    #include "nrf_svci_async_handler.h"
    
    #include "ble_advdata.h"
    #include "ble_advertising.h"
    #include "ble_hrs.h"
    #include "ble_dis.h"
    #include "ble_ipd.h"
    
    #include "nrf_sdh.h"
    #include "nrf_sdh_ble.h"
    #include "nrf_sdh_soc.h"
    
    #include "ant_interface.h"
    #include "ANT_Agent.h"
    #include "fds.h"
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "peer_manager.h"
    
    static pm_peer_id_t      								m_peer_id;                                   /**< Device reference handle to the current bonded central. */
    static volatile uint16_t                m_conn_handle = BLE_CONN_HANDLE_INVALID;     /**< Handle of the current connection. */
    static pm_peer_id_t      m_whitelist_peers[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];       /**< List of peers currently in the whitelist. */
    static uint32_t          m_whitelist_peer_cnt;                                      /**< Number of peers currently in the whitelist. */
    
    BLE_HRS_DEF(m_hrs);                                                                  /**< Heart rate service instance. */
    BLE_IPD_DEF(m_ipd);																																	 /**< Intelligent Pedal service instance. */
    BLE_ADVERTISING_DEF(m_advertising);                                 								/**< Advertising module instance. */
    NRF_BLE_GATT_DEF(m_gatt);                                                           /**< GATT module instance. */
    #define NOTIFICATION_INTERVAL           APP_TIMER_TICKS(1000)
    APP_TIMER_DEF(m_notification_timer_id); //timer for ble notification
    static uint8_t m_ipd_value = 0;    //testing ble notification
    
    
    
    #ifdef BLE_DFU_APP_SUPPORT
    /**@brief Function for handling dfu events from the Buttonless Secure DFU service
     *
     * @param[in]   event   Event from the Buttonless Secure DFU service.
     */
    static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event)
    {
        switch (event)
        {
            case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE:
                NRF_LOG_INFO("Device is preparing to enter bootloader mode.");
                // YOUR_JOB: Disconnect all bonded devices that currently are connected.
                //           This is required to receive a service changed indication
                //           on bootup after a successful (or aborted) Device Firmware Update.
                break;
    
            case BLE_DFU_EVT_BOOTLOADER_ENTER:
                // YOUR_JOB: Write app-specific unwritten data to FLASH, control finalization of this
                //           by delaying reset by reporting false in app_shutdown_handler
                NRF_LOG_INFO("Device will enter bootloader mode.");
                break;
    
            case BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED:
                NRF_LOG_ERROR("Request to enter bootloader mode failed asynchroneously.");
                // YOUR_JOB: Take corrective measures to resolve the issue
                //           like calling APP_ERROR_CHECK to reset the device.
                break;
    
            case BLE_DFU_EVT_RESPONSE_SEND_ERROR:
                NRF_LOG_ERROR("Request to send a response to client failed.");
                // YOUR_JOB: Take corrective measures to resolve the issue
                //           like calling APP_ERROR_CHECK to reset the device.
                APP_ERROR_CHECK(false);
                break;
    
            default:
                NRF_LOG_ERROR("Unknown event from ble_dfu_buttonless.");
                break;
        }
    }
    #endif // BLE_DFU_APP_SUPPORT
    
    /**@brief 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)
    {
        uint32_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);
    
        err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_CYCLING_POWER_SENSOR);
        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 putting the chip into sleep mode.
     *
     * @note This function will not return.
     */
    static void sleep_mode_enter(void)
    {
    		uint32_t err_code;
    		// Enable wake on low power accelerometer.
        nrf_gpio_cfg_sense_input(LIS3DH_INT1, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); //NRF_GPIO_PIN_NOPULL NRF_GPIO_PIN_SENSE_HIGH for real use
        // Prepare wakeup buttons.
        //uint32_t err_code = drv_acc_wakeup_prepare(true);
        //APP_ERROR_CHECK(err_code);
    	
    		NRF_LOG_FLUSH();
        // Go to system-off mode (this function will not return; wakeup will cause a reset).
        err_code = sd_power_system_off();
    		NRF_LOG_WARNING("BLE timeout system off return. Perhaps due to debug mode");
        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_DIRECTED:
                NRF_LOG_INFO("Directed advertising.");
    //            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_DIRECTED);
    //            APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_FAST:
                NRF_LOG_INFO("Fast advertising.");
    //            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
    //            APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_SLOW:
                NRF_LOG_INFO("Slow advertising.");
    //            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_SLOW);
    //            APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_FAST_WHITELIST:
                NRF_LOG_INFO("Fast advertising with whitelist.");
    //            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_WHITELIST);
    //            APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_SLOW_WHITELIST:
                NRF_LOG_INFO("Slow advertising with whitelist.");
    //            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_WHITELIST);
    //            APP_ERROR_CHECK(err_code);
                err_code = ble_advertising_restart_without_whitelist(&m_advertising);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_ADV_EVT_IDLE:
    //            err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    //            APP_ERROR_CHECK(err_code);
                sleep_mode_enter();
                break;
    
            case BLE_ADV_EVT_WHITELIST_REQUEST:
            {
                ble_gap_addr_t whitelist_addrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
                ble_gap_irk_t  whitelist_irks[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
                uint32_t       addr_cnt = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
                uint32_t       irk_cnt  = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
    
                err_code = pm_whitelist_get(whitelist_addrs, &addr_cnt,
                                            whitelist_irks,  &irk_cnt);
                APP_ERROR_CHECK(err_code);
                NRF_LOG_INFO("pm_whitelist_get returns %d addr in whitelist and %d irk whitelist",
                               addr_cnt,
                               irk_cnt);
    
                // Apply the whitelist.
                err_code = ble_advertising_whitelist_reply(&m_advertising,
                                                           whitelist_addrs,
                                                           addr_cnt,
                                                           whitelist_irks,
                                                           irk_cnt);
                APP_ERROR_CHECK(err_code);
            }
            break;
    
            case BLE_ADV_EVT_PEER_ADDR_REQUEST:
            {
    					NRF_LOG_INFO("BLE_ADV_EVT_PEER_ADDR_REQUEST");
                pm_peer_data_bonding_t peer_bonding_data;
    
                // Only Give peer address if we have a handle to the bonded peer.
                if (m_peer_id != PM_PEER_ID_INVALID)
                {
    
                    err_code = pm_peer_data_bonding_load(m_peer_id, &peer_bonding_data);
                    if (err_code != NRF_ERROR_NOT_FOUND)
                    {
                        APP_ERROR_CHECK(err_code);
    
                        ble_gap_addr_t * p_peer_addr = &(peer_bonding_data.peer_ble_id.id_addr_info);
                        err_code = ble_advertising_peer_addr_reply(&m_advertising, p_peer_addr);
                        APP_ERROR_CHECK(err_code);
                    }
    
                }
                break;
            }
    
            default:
                break;
        }
    }
    
    /**@brief Function for handling advertising errors.
     *
     * @param[in] nrf_error  Error code containing information about what went wrong.
     */
    static void ble_advertising_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    /**@brief Function for initializing the Advertising functionality.
     */
    static void advertising_init(void)
    {
        ret_code_t             err_code;
        ble_advertising_init_t init;
    	
        ble_uuid_t m_adv_uuids[] =
        {
            {BLE_UUID_CYCLING_POWER,         BLE_UUID_TYPE_BLE},
            {BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE}
        };
    
        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_LIMITED_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_whitelist_enabled      = true;
        init.config.ble_adv_directed_enabled       = true;
        init.config.ble_adv_directed_slow_enabled  = false;
        init.config.ble_adv_directed_slow_interval = 0;
        init.config.ble_adv_directed_slow_timeout  = 0;
        init.config.ble_adv_fast_enabled					 = true;
        init.config.ble_adv_fast_interval					 = APP_ADV_FAST_INTERVAL;
        init.config.ble_adv_fast_timeout 					 = APP_ADV_FAST_TIMEOUT_IN_SECONDS;
    		init.config.ble_adv_slow_enabled           = true;
        init.config.ble_adv_slow_interval          = APP_ADV_SLOW_INTERVAL;
        init.config.ble_adv_slow_timeout           = APP_ADV_SLOW_TIMEOUT;
    
        init.evt_handler = on_adv_evt;
    		init.error_handler = ble_advertising_error_handler;
    
        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 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_ipd_evt(ble_ipd_t     * p_ipd_service,
                           ble_ipd_evt_t * p_evt)
    {
    		uint32_t      err_code;
        switch(p_evt->evt_type)
        {
            case BLE_IPD_EVT_NOTIFICATION_ENABLED:
    	   err_code = app_timer_start(m_notification_timer_id, NOTIFICATION_INTERVAL, NULL);
               APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_IPD_EVT_NOTIFICATION_DISABLED:
    	   err_code = app_timer_stop(m_notification_timer_id);
               APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_IPD_EVT_CONNECTED:
                break;
    
            case BLE_IPD_EVT_DISCONNECTED:
                  break;
    
            default:
                  // No implementation needed.
                  break;
        }
    }
    
    
    /**@brief Initialize services that will be used by the application.
     *
     * @details Initialize the Heart Rate and Device Information services.
     */
    static void services_init(void)
    {
        uint32_t       err_code;
        ble_hrs_init_t hrs_init;
        ble_dis_init_t dis_init;
    		ble_ipd_init_t ipd_init;
        uint8_t        body_sensor_location;
    	
    #ifdef BLE_DFU_APP_SUPPORT		
    		// Initialize the dfu module
    		 ble_dfu_buttonless_init_t dfus_init =
        {
            .evt_handler = ble_dfu_evt_handler
        };
    		
        // Initialize the async SVCI interface to bootloader.
        err_code = ble_dfu_buttonless_async_svci_init();
        APP_ERROR_CHECK(err_code);
        
        err_code = ble_dfu_buttonless_init(&dfus_init);
        APP_ERROR_CHECK(err_code);
    #endif //BLE_DFU_APP_SUPPORT
    	
    		// Initialize Intelligent Pedal Service.
        memset(&ipd_init, 0, sizeof(ipd_init));
    	
    		// Here the sec level for the IPD Service can be changed/increased.
    		BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&ipd_init.ipd_value_char_attr_md.read_perm);
    		BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&ipd_init.ipd_value_char_attr_md.write_perm);
    		
    		// Set the ipd event handler
        ipd_init.evt_handler  = on_ipd_evt;
    		
        err_code = ble_ipd_init(&m_ipd, &ipd_init);
        APP_ERROR_CHECK(err_code);
    
        // Initialize Heart Rate Service.
        body_sensor_location = BLE_HRS_BODY_SENSOR_LOCATION_FINGER;
    
        memset(&hrs_init, 0, sizeof(hrs_init));
    
        hrs_init.evt_handler                 = NULL;
        hrs_init.is_sensor_contact_supported = false;
        hrs_init.p_body_sensor_location      = &body_sensor_location;
    
        // Here the sec level for the Heart Rate Service can be changed/increased.
        BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hrs_init.hrs_hrm_attr_md.cccd_write_perm);
        BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_hrm_attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_hrm_attr_md.write_perm);
    
        BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hrs_init.hrs_bsl_attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_bsl_attr_md.write_perm);
    
        err_code = ble_hrs_init(&m_hrs, &hrs_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, MANUFACTURER_NAME);
    
        BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&dis_init.dis_attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm);
    
        err_code = ble_dis_init(&dis_init);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Connection Parameters Module handler.
     *
     * @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;
    
    //    switch (p_evt->evt_type)
    //    {
    //        case BLE_CONN_PARAMS_EVT_FAILED:
    ////            err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
    ////            APP_ERROR_CHECK(err_code);
    //            break;
    
    //        default:
    //            // No implementation needed.
    //            break;
    //    }
    //}
    
    
    /**@brief Connection Parameters module error handler.
     *
     * @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 Initialize 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    = m_hrs.hrm_handles.cccd_handle;
        cp_init.disconnect_on_fail             = false;
        cp_init.evt_handler                    = NULL;//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);
    }
    
    
    /**@brief Function for dispatching a BLE stack event to all modules with a BLE stack event handler.
     *
     * @param[in] p_ble_evt  Bluetooth stack event.
     * @param[in] p_context  Context.
     */
    void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t err_code = NRF_SUCCESS;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_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;
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
    //            err_code = bsp_indication_set(BSP_INDICATE_IDLE);
                //APP_ERROR_CHECK(err_code);
                NRF_LOG_INFO("Disconnected");
                m_conn_handle = BLE_CONN_HANDLE_INVALID;
                // Need to close the ANT channel to make it safe to write bonding information to flash
                //err_code = sd_ant_channel_close(ANT_HRMRX_ANT_CHANNEL);
                //APP_ERROR_CHECK(err_code);
    
                // Note: Bonding information will be stored, advertising will be restarted and the
                //       ANT channel will be reopened when ANT event CHANNEL_CLOSED is received.
                break;
    
    //        case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:   //citty fix 20180511 ios send mtu while connecting solved by adding gatt init()
    //						err_code=sd_ble_gatts_exchange_mtu_reply(p_ble_evt->evt.gatts_evt.conn_handle, 23);
    //						APP_ERROR_CHECK(err_code);
    //            break;
    
    
    #ifndef BONDING_ENABLE
    //        case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
    //            err_code = sd_ble_gap_sec_params_reply(m_conn_handle,
    //                                                   BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP,
    //                                                   NULL,
    //                                                   NULL);
    //            APP_ERROR_CHECK(err_code);
    //            break;
    #endif // BONDING_ENABLE
    				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;
    				
    				case BLE_EVT_USER_MEM_REQUEST:
                err_code = sd_ble_user_mem_reply(p_ble_evt->evt.gattc_evt.conn_handle, NULL);
                APP_ERROR_CHECK(err_code);
                break;
    				
    //        case BLE_GAP_EVT_TIMEOUT:
    //            if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISING)
    //            {
    //                //err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    //                APP_ERROR_CHECK(err_code);
    //                // Go to system-off mode (this function will not return; wakeup will cause a reset)
    //                err_code = sd_power_system_off();
    //                NRF_LOG_WARNING("BLE timeout system off return. Perhaps due to debug mode");
    //                APP_ERROR_CHECK(err_code);
    //            }
    //            break;
    
    #ifndef BONDING_ENABLE
                case BLE_GATTS_EVT_SYS_ATTR_MISSING:
                    err_code = sd_ble_gatts_sys_attr_set(m_conn_handle,
                                                         NULL,
                                                         0,
                                                         BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS);
                    APP_ERROR_CHECK(err_code);
                    break;
    #endif // BONDING_ENABLE
    
    			 case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            {
                ble_gatts_evt_rw_authorize_request_t  req;
                ble_gatts_rw_authorize_reply_params_t auth_reply;
    
                req = p_ble_evt->evt.gatts_evt.params.authorize_request;
    
                if (req.type != BLE_GATTS_AUTHORIZE_TYPE_INVALID)
                {
                    if ((req.request.write.op == BLE_GATTS_OP_PREP_WRITE_REQ)     ||
                        (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) ||
                        (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL))
                    {
                        if (req.type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
                        {
                            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
                        }
                        else
                        {
                            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
                        }
                        auth_reply.params.write.gatt_status = APP_FEATURE_NOT_SUPPORTED;
                        err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle,
                                                                   &auth_reply);
                        APP_ERROR_CHECK(err_code);
                    }
                }
            } break; // BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST
            default:
                //NRF_LOG_ERROR("BLE_GATTS_EVT NOT SUPPORT %x",p_ble_evt->header.evt_id);
                // No implementation needed.
                break;
        }
    }
    
    #ifdef BONDING_ENABLE
    
    /**@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)
    {
        ret_code_t err_code;
    
        switch (p_evt->evt_id)
        {
            case PM_EVT_BONDED_PEER_CONNECTED:
                NRF_LOG_INFO("Connected to previously bonded device");
    //            err_code = pm_peer_rank_highest(p_evt->peer_id);
    //            if (err_code != NRF_ERROR_BUSY)
    //            {
    //                APP_ERROR_CHECK(err_code);
    //            }
                break; // PM_EVT_BONDED_PEER_CONNECTED
    
            case PM_EVT_CONN_SEC_START:
                break; // PM_EVT_CONN_SEC_START
    
            case PM_EVT_CONN_SEC_SUCCEEDED:
                NRF_LOG_INFO("Link secured. Role: %d. conn_handle: %d, Procedure: %d",
                                     ble_conn_state_role(p_evt->conn_handle),
                                     p_evt->conn_handle,
                                     p_evt->params.conn_sec_succeeded.procedure);
    
    //            if (p_evt->params.conn_sec_succeeded.procedure == PM_LINK_SECURED_PROCEDURE_BONDING)
    //            {
    //                err_code = pm_peer_rank_highest(p_evt->peer_id);
    //                if (err_code != NRF_ERROR_BUSY)
    //                {
    //                    APP_ERROR_CHECK(err_code);
    //                }
    //            }
    						m_peer_id = p_evt->peer_id;
                break;  // PM_EVT_CONN_SEC_SUCCEEDED
    
            case PM_EVT_CONN_SEC_FAILED:
    						NRF_LOG_INFO("Failed to secure connection.");
                /** Often, when securing fails, it shouldn't be restarted, for security reasons.
                 *  Other times, it can be restarted directly.
                 *  Sometimes it can be restarted, but only after changing some Security Parameters.
                 *  Sometimes, it cannot be restarted until the link is disconnected and reconnected.
                 *  Sometimes it is impossible, to secure the link, or the peer device does not support it.
                 *  How to handle this error is highly application dependent. */
                break; // PM_EVT_CONN_SEC_FAILED
    
            case PM_EVT_CONN_SEC_CONFIG_REQ:
            {
                // Reject pairing request from an already bonded peer.
                pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false};
                pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
            } break; // PM_EVT_CONN_SEC_CONFIG_REQ
    
            case PM_EVT_STORAGE_FULL:
                // Run garbage collection on the flash.
    						err_code = fds_gc();
                if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES)
                {
                    // Retry.
                }
                else
                {
                    APP_ERROR_CHECK(err_code);
                }
                break; // PM_EVT_STORAGE_FULL
    
            case PM_EVT_ERROR_UNEXPECTED:
                // A likely fatal error occurred. Assert.
                APP_ERROR_CHECK(p_evt->params.error_unexpected.error);
                break;
    
            case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
            {
                if (     p_evt->params.peer_data_update_succeeded.flash_changed
                     && (p_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_BONDING))
                {
                    NRF_LOG_INFO("New Bond, add the peer to the whitelist if possible");
                    NRF_LOG_INFO("\tm_whitelist_peer_cnt %d, MAX_PEERS_WLIST %d",
                                   m_whitelist_peer_cnt + 1,
                                   BLE_GAP_WHITELIST_ADDR_MAX_COUNT);
                    // Note: You should check on what kind of white list policy your application should use.
    
                    if (m_whitelist_peer_cnt < BLE_GAP_WHITELIST_ADDR_MAX_COUNT)
                    {
                        // Bonded to a new peer, add it to the whitelist.
                        m_whitelist_peers[m_whitelist_peer_cnt++] = m_peer_id;
    										NRF_LOG_INFO("add %d to whitelist",m_peer_id);
    
                        // The whitelist has been modified, update it in the Peer Manager.
                        err_code = pm_whitelist_set(m_whitelist_peers, m_whitelist_peer_cnt);
                        APP_ERROR_CHECK(err_code);
    
                        err_code = pm_device_identities_list_set(m_whitelist_peers, m_whitelist_peer_cnt);
                        if (err_code != NRF_ERROR_NOT_SUPPORTED)
                        {
                            APP_ERROR_CHECK(err_code);
                        }
                    }
                }
            } break;
    
            case PM_EVT_PEER_DATA_UPDATE_FAILED:
                // Assert.
                APP_ERROR_CHECK_BOOL(false);
                break; // PM_EVT_ERROR_UNEXPECTED
    
            case PM_EVT_PEER_DELETE_SUCCEEDED:
    						NRF_LOG_INFO("Peer delete succeeded");
                break; // PM_EVT_PEER_DELETE_SUCCEEDED
    
            case PM_EVT_PEER_DELETE_FAILED:
                // Assert.
                APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error);
                break; // PM_EVT_PEER_DELETE_FAILED
    
            case PM_EVT_PEERS_DELETE_SUCCEEDED:
                NRF_LOG_INFO("Peers delete succeeded");
    						advertising_start(false);
                break; // PM_EVT_PEERS_DELETE_SUCCEEDED
    
            case PM_EVT_PEERS_DELETE_FAILED:
                // Assert.
                APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error);
                break; // PM_EVT_PEERS_DELETE_FAILED
    
            case PM_EVT_LOCAL_DB_CACHE_APPLIED:
                break; // PM_EVT_LOCAL_DB_CACHE_APPLIED
    
            case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED:
                // The local database has likely changed, send service changed indications.
                pm_local_database_has_changed();
                break; // PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED
    
            case PM_EVT_SERVICE_CHANGED_IND_SENT:
                break; // PM_EVT_SERVICE_CHANGED_IND_SENT
    
            case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED:
                break; // PM_EVT_SERVICE_CHANGED_IND_SENT
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    /**@brief Fetch the list of peer manager peer IDs.
     *
     * @param[inout] p_peers   The buffer where to store the list of peer IDs.
     * @param[inout] p_size    In: The size of the @p p_peers buffer.
     *                         Out: The number of peers copied in the buffer.
     */
    static void peer_list_get(pm_peer_id_t * p_peers, uint32_t * p_size)
    {
        pm_peer_id_t peer_id;
        uint32_t     peers_to_copy;
    
        peers_to_copy = (*p_size < BLE_GAP_WHITELIST_ADDR_MAX_COUNT) ?
                         *p_size : BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
    
        peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);
        *p_size = 0;
    
        while ((peer_id != PM_PEER_ID_INVALID) && (peers_to_copy--))
        {
            p_peers[(*p_size)++] = peer_id;
            peer_id = pm_next_peer_id_get(peer_id);
        }
    }
    
    /**@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 ret;
    
    //        memset(m_whitelist_peers, PM_PEER_ID_INVALID, sizeof(m_whitelist_peers));
    //        m_whitelist_peer_cnt = (sizeof(m_whitelist_peers) / sizeof(pm_peer_id_t));
    
    //        peer_list_get(m_whitelist_peers, &m_whitelist_peer_cnt);
    
    //        ret = pm_whitelist_set(m_whitelist_peers, m_whitelist_peer_cnt);
    //        APP_ERROR_CHECK(ret);
    
    //        // Setup the device identies list.
    //        // Some SoftDevices do not support this feature.
    //        ret = pm_device_identities_list_set(m_whitelist_peers, m_whitelist_peer_cnt);
    //        if (ret != NRF_ERROR_NOT_SUPPORTED)
    //        {
    //            APP_ERROR_CHECK(ret);
    //        }
    
            ret = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
            APP_ERROR_CHECK(ret);
        }
    }
    
    
    /**@brief Function for the Peer Manager initialization.
     *
     * @param[in] erase_bonds  Indicates whether bonding information should be cleared from
     *                         persistent storage during initialization of the Peer Manager.
     */
    /**@brief Function for the Peer Manager initialization.
     */
    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);
    
    //    err_code = fds_register(fds_evt_handler);
    //    APP_ERROR_CHECK(err_code);
    }
    #endif // BONDING_ENABLE
    
    /**@brief   Function for initializing the GATT module.
     * @details The GATT module handles ATT_MTU and Data Length update procedures automatically.
     */
    static void gatt_init(void)
    {
        ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief BLE Agent initialized
     */
    void BLE_Agent_init(void)
    {
        gap_params_init();
    		services_init();
        advertising_init();
        conn_params_init();
    		gatt_init();
    	
    		nrf_gpio_cfg_output(20); //TESTING ON LED4
    }
    
    /**@brief Timer initialization.
     *
     * @details Initializes the timer module. This creates and starts application timers.
     */
    void ble_timers_init(void)
    {
    		uint32_t err_code = app_timer_create(&m_notification_timer_id, APP_TIMER_MODE_REPEATED, notification_timeout_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief 
     *
     * @details 
     *
     * @param[in] 
     *                       
     */
    void notification_timeout_handler(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        ret_code_t err_code;
        
        // Increment the value of m_ipd_value before nortifing it.
        m_ipd_value++;
        
        err_code = ble_ipd_value_update(&m_ipd, m_ipd_value);
        APP_ERROR_CHECK(err_code);
    }

    I call softdevice_setup, BLE_Agent_init, peer_manager_init and advertising_start(false) in main before the main loop. The softdevice_setup is exactly the same as in the ble_ant_app_hrm example as below.

    static void softdevice_setup(void)
    {
        ret_code_t err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        ASSERT(nrf_sdh_is_enabled());
    
        // 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);
    
        err_code = nrf_sdh_ant_enable();
        APP_ERROR_CHECK(err_code);
    
        err_code = ant_plus_key_set(ANTPLUS_NETWORK_NUMBER);
        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);
        NRF_SDH_ANT_OBSERVER(m_ant_observer, APP_ANT_OBSERVER_PRIO, ant_evt_handler, NULL);
    }

    Once again thank you for helping

Children
No Data
Related