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

Multi-peripheral, bonding and whitelisting

Hi,

I need a way to have a concurrent connection (multi-peripheral), with whitelisting and bonding. Is there any example of this?

I found an example for multi-peripherals, but this is not for concurrent connections. I also found the HID-Mouse example which uses whitelisting and bonding, but it's only supporting single links (because it uses the advertising module).

I some sort of managed to include those two together, but then sometimes the softdevice asserts. So I was wondering if there are any other examples of doing this?

Parents
  •  That is not true. You can support multiple connections when the advertising module is used. Just look at the multiperipheral example.

    The advertising API notes: "Note: The Advertising Module supports only applications with a single peripheral link."

    The multiperipheral example doesn't use the advertising module if I understand correctly. It uses the Advertising and Scan Response Data Encoder

    Or am I confusing things?

    What did that look like? What happened when the "softdevice asserted"? Can you show me a screenshot, or any other observation you did to conclude with that?

    For instance, when I disconnect, I get:

    00> <info> app: Connection with link 0x0 established.
    00> <debug> nrf_ble_gatt: Peer on connection 0x0 requested a data length of 27 bytes.
    00> <debug> nrf_ble_gatt: Updating data length to 27 on connection 0x0.
    00> <debug> nrf_ble_gatt: Data length updated to 27 on connection 0x0.
    00> <debug> nrf_ble_gatt: max_rx_octets: 27
    00> <debug> nrf_ble_gatt: max_tx_octets: 27
    00> <debug> nrf_ble_gatt: max_rx_time: 328
    00> <debug> nrf_ble_gatt: max_tx_time: 2120
    00> <debug> app: PHY update request.
    00> <error> app: Fatal error

    But it doesn't happen always, but the fact that it happens makes it unreliable. 

    So probably something is wrong in my code. 

    I can send you my code, how can I do that?

  • Gueston said:

    The multiperipheral example doesn't use the advertising module if I understand correctly. It uses the Advertising and Scan Response Data Encoder

    Or am I confusing things?

     You are absolutely correct. I didn't realize this before. 

     

    Gueston said:

    So probably something is wrong in my code. 

    I can send you my code, how can I do that?

     The log is a good thing. It is probably something you can fix. 

    Whenever you see "Fatal error" in the log, it means that one of your APP_ERROR_CHECK(err_code); has received an err_code != 0.

    To find out which one that triggered it, add "DEBUG" to your preprocessor definitions. Let me know what IDE you are using if you are not sure how to do this. 

    When you added this, the log should point to an APP_ERROR_CHECK(err_code) in your project, and a value for err_code. Which one does it point to, and what function returned that err_code, and what value did err_code have?

    BR,
    Edvin

Reply
  • Gueston said:

    The multiperipheral example doesn't use the advertising module if I understand correctly. It uses the Advertising and Scan Response Data Encoder

    Or am I confusing things?

     You are absolutely correct. I didn't realize this before. 

     

    Gueston said:

    So probably something is wrong in my code. 

    I can send you my code, how can I do that?

     The log is a good thing. It is probably something you can fix. 

    Whenever you see "Fatal error" in the log, it means that one of your APP_ERROR_CHECK(err_code); has received an err_code != 0.

    To find out which one that triggered it, add "DEBUG" to your preprocessor definitions. Let me know what IDE you are using if you are not sure how to do this. 

    When you added this, the log should point to an APP_ERROR_CHECK(err_code) in your project, and a value for err_code. Which one does it point to, and what function returned that err_code, and what value did err_code have?

    BR,
    Edvin

Children
  • See the log below:

    00> <info> app: Connection with link 0x0 established.
    00> <info> app:   m_whitelist_peer_cnt 1, MAX_PEERS_WLIST 8
    00> <info> app: Fast advertising.
    00> <debug> nrf_ble_gatt: Peer on connection 0x0 requested a data length of 27 bytes.
    00> <debug> nrf_ble_gatt: Updating data length to 27 on connection 0x0.
    00> <debug> nrf_ble_gatt: Data length updated to 27 on connection 0x0.
    00> <debug> nrf_ble_gatt: max_rx_octets: 27
    00> <debug> nrf_ble_gatt: max_tx_octets: 27
    00> <debug> nrf_ble_gatt: max_rx_time: 328
    00> <debug> app: PHY update request.
    00> <debug> app: pm_whitelist_get returns 0 addr in whitelist and 0 irk whitelist
    00> <error> app: ERROR 12804 [Unknown error code] at ../../../main.c:252
    00> PC at: 0x00032B87

    The code at line 252 (and 251 which is the function it checks):

        err_code = pm_device_identities_list_set(peer_ids, peer_id_count);
        APP_ERROR_CHECK(err_code);

    This only happens when the central disconnects. 

  • Hello,

    Thank you. Just to show you how I usually look up these values:

    The error handler prints a decimal number, but the SDK return values are typically hexadecimal (at least the large ones). Decimal 12804 = hecadecimal 0x3204.

    The error codes are usually divided into groups based on the first and second integer. To explain, look at the file nrf_error.h. In that file, all the common error codes are listed. That is, 0-19 (decimal). Above that, you can see:

    #define NRF_ERROR_BASE_NUM      (0x0)       ///< Global error base
    #define NRF_ERROR_SDM_BASE_NUM  (0x1000)    ///< SDM error base
    #define NRF_ERROR_SOC_BASE_NUM  (0x2000)    ///< SoC error base
    #define NRF_ERROR_STK_BASE_NUM  (0x3000)    ///< STK error base

    So since your error code is starting with 3, it is probably using the STK base, NRF_ERROR_STK_BASE_NUM.

    If you search your project for this name (NRF_ERROR_STK_BASE_NUM), you will see a couple of hits in the file ble_err.h. When you open that file, you will see:

    #define NRF_L2CAP_ERR_BASE             (NRF_ERROR_STK_BASE_NUM+0x100) /**< L2CAP specific errors. */
    #define NRF_GAP_ERR_BASE               (NRF_ERROR_STK_BASE_NUM+0x200) /**< GAP specific errors. */
    #define NRF_GATTC_ERR_BASE             (NRF_ERROR_STK_BASE_NUM+0x300) /**< GATT client specific errors. */
    #define NRF_GATTS_ERR_BASE             (NRF_ERROR_STK_BASE_NUM+0x400) /**< GATT server specific errors. */

    Since your error code starts with 0x32... it is coming from the NRF_GAP_ERR_BASE. Searching for this macro, you will find some hits in ble_gap.h, and there it is:

    BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE  = (NRF_GAP_ERR_BASE + 0x004) = 0x3204.

    If you search for BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE in your project, you will see that it is used in peer_manager.h, specifically in the description for pm_device_identities_list_set():

    * @retval BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE   If the device identities list is in use and
     *                                                  cannot be set.

    So this means that the device identities list is currently in use, and can't be changed. If you at that point in time is scanning or advertising, this return value is expected. To work around this, you need to stop scanning and advertising, then call pm_device_identities_list_set(), and then resume scanning or advertising. 

    The reason you are seeing this error is probably because the hids keyboard example only supports one connection, and will not be advertising or scanning when it tries to edit the device identities list. 

  • Thank you for your answer. I didn't know to look on those error codes like that.

    But how do I disable advertising with the advertising module? I only found the method to directly use the softdevice

    sd_ble_gap_adv_stop(m_advertising.adv_handle);

    But then the device is not starting at all (I don't even get a log). But probably this is not the way to go because I use the advertising module.

    And another thing. Why can I connect more centrals while I use the advertising module, but the advertising module is only made for one link? 
  • I don't know what your application looks like, and where the pm_device_identities_list_set() was called from. Is it triggered from an event in main.c?

    If so, you can try to use some functions like this:

    static void custom_adv_stop(void)
    {
        NRF_LOG_INFO("stop advertising");
        ret_code_t err_code;
        
        uint8_t my_adv_handle = m_advertising.adv_handle;
        err_code = sd_ble_gap_adv_stop(my_adv_handle);
        APP_ERROR_CHECK(err_code);
        
        err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);
    }
    
    static void custom_adv_start(void)
    {
        NRF_LOG_INFO("start advertising");
        uint32_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
        APP_ERROR_CHECK(err_code);
    }

    custom_adv_start() is actually exactly the same as advertising_start() found in most BLE examples, so just use the default advertising_start() function.

    In case this doesn't work, it may be because the peer manager's event handler is called before the main file's event handler. 

    E.g, make sure that the custom_advertising_stop() is called before pm_handler_secure_on_connection(p_ble_evt);

    Best regards,

    Edvin

  • I put custom_advertising_stop() before pm_device_identities_list_set() and then start advertising.

    If I'm not bonded, I can disconnect and the peripheral doesn't crash. But as soon as I bond it crashes, as in that it's not advertising anymore and I get "00> <error> app: End of error report" as log info. So that's not that helpfull.

    Below the relevant code. On line 268 and 281 I respectively stop and start advertising.

    /**@brief Function for setting filtered whitelist.
     *
     * @param[in] skip  Filter passed to @ref pm_peer_id_list.
     */
    static void whitelist_set(pm_peer_id_list_skip_t skip) {
        pm_peer_id_t peer_ids[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
        uint32_t peer_id_count = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
    
        ret_code_t err_code = pm_peer_id_list(peer_ids, &peer_id_count, PM_PEER_ID_INVALID, skip);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_INFO("\tm_whitelist_peer_cnt %d, MAX_PEERS_WLIST %d",
                     peer_id_count + 1,
                     BLE_GAP_WHITELIST_ADDR_MAX_COUNT);
    
        err_code = pm_whitelist_set(peer_ids, peer_id_count);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@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);
    }
    
    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_DEBUG("PM_EVT_BONDED_PEER_CONNECTED");
                // Update the rank of the peer.
                err_code = pm_peer_rank_highest(p_evt->peer_id);
                break;
            case PM_EVT_CONN_SEC_START:
                NRF_LOG_DEBUG("PM_EVT_CONN_SEC_START");
                break;
            case PM_EVT_CONN_SEC_SUCCEEDED:
                NRF_LOG_DEBUG("PM_EVT_CONN_SEC_SUCCEEDED");
                // Update the rank of the peer.
                err_code = pm_peer_rank_highest(p_evt->peer_id);
                break;
            case PM_EVT_CONN_SEC_FAILED:
                NRF_LOG_DEBUG("PM_EVT_CONN_SEC_FAILED");
                // In some cases, when securing fails, 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.
                //            NRF_LOG_INFO("Failed to secure connection. Disconnecting.");
                //            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);
                //            }
                //            m_conn_handle = BLE_CONN_HANDLE_INVALID;
    
                break;
            case PM_EVT_CONN_SEC_CONFIG_REQ: {
                NRF_LOG_DEBUG("PM_EVT_CONN_SEC_CONFIG_REQ");
                // A connected peer (central) is trying to pair, but the Peer Manager already has a bond
                // for that peer. Setting allow_repairing to false rejects the pairing request.
                // If this event is ignored (pm_conn_sec_config_reply is not called in the event
                // handler), the Peer Manager assumes allow_repairing to be false.
                pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false};
                pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
            } break;
            case PM_EVT_CONN_SEC_PARAMS_REQ: {
                NRF_LOG_DEBUG("PM_EVT_CONN_SEC_PARAMS_REQ");
                // If you want to set different security parameters for particular peers, you can do
                // so here. Pass the desired security parameters to pm_conn_sec_params_reply().
                //            err_code = pm_conn_sec_params_reply(p_evt->conn_handle,
                //                                               &sec_param,
                //                                                p_evt->params.conn_sec_params_req.p_context);
                //            APP_ERROR_CHECK(err_code);
            } break;
            case PM_EVT_STORAGE_FULL:
                NRF_LOG_DEBUG("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;
            case PM_EVT_ERROR_UNEXPECTED:
                NRF_LOG_DEBUG("PM_EVT_ERROR_UNEXPECTED");
                // Assert.
                APP_ERROR_CHECK(p_evt->params.error_unexpected.error);
                break;
            case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
                NRF_LOG_DEBUG("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");
                    // Note: You should check on what kind of white list policy your application should use.
    
                    whitelist_set(PM_PEER_ID_LIST_SKIP_NO_ID_ADDR);
                }
                break;
            case PM_EVT_PEER_DATA_UPDATE_FAILED:
                NRF_LOG_DEBUG("PM_EVT_PEER_DATA_UPDATE_SUCCEEDED");
                // Assert.
                APP_ERROR_CHECK_BOOL(false);
                break;
            case PM_EVT_PEER_DELETE_SUCCEEDED:
                NRF_LOG_DEBUG("PM_EVT_PEER_DELETE_SUCCEEDED");
                break;
            case PM_EVT_PEER_DELETE_FAILED:
                NRF_LOG_DEBUG("PM_EVT_PEER_DELETE_FAILED");
                // Assert.
                APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error);
                break;
            case PM_EVT_PEERS_DELETE_SUCCEEDED:
                NRF_LOG_DEBUG("PM_EVT_PEERS_DELETE_SUCCEEDED");
                // At this point it is safe to start advertising or scanning.
                break;
            case PM_EVT_PEERS_DELETE_FAILED:
                NRF_LOG_DEBUG("PM_EVT_PEERS_DELETE_FAILED");
                // Assert.
                APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error);
                break;
            case PM_EVT_LOCAL_DB_CACHE_APPLIED:
                NRF_LOG_DEBUG("PM_EVT_LOCAL_DB_CACHE_APPLIED");
                break;
            case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED:
                NRF_LOG_DEBUG("PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED");
                // The local database has likely changed, send service changed indications.
                pm_local_database_has_changed();
                break;
            case PM_EVT_SERVICE_CHANGED_IND_SENT:
                NRF_LOG_DEBUG("PM_EVT_SERVICE_CHANGED_IND_SENT");
                break;
            case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED:
                NRF_LOG_DEBUG("PM_EVT_SERVICE_CHANGED_IND_CONFIRMED");
                break;
        }
    }
    
    /**@brief Function for starting advertising.
     */
    static void advertising_start(bool erase_bonds) {
        NRF_LOG_INFO("start advertising");
        if (erase_bonds == true) {
            delete_bonds();
            // Advertising is started by PM_EVT_PEERS_DELETE_SUCCEEDED event.
        } else {
            whitelist_set(PM_PEER_ID_LIST_SKIP_NO_ID_ADDR);
            bsp_board_led_on(ADVERTISING_LED);
            ret_code_t ret = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
            APP_ERROR_CHECK(ret);
        }
    }
    
    static void custom_adv_stop(void) {
        NRF_LOG_INFO("stop advertising");
        ret_code_t err_code;
    
        uint8_t my_adv_handle = m_advertising.adv_handle;
        err_code = sd_ble_gap_adv_stop(my_adv_handle);
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for setting filtered device identities.
     *
     * @param[in] skip  Filter passed to @ref pm_peer_id_list.
     */
    static void identities_set(pm_peer_id_list_skip_t skip) {
        pm_peer_id_t peer_ids[BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT];
        uint32_t peer_id_count = BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT;
    
        ret_code_t err_code = pm_peer_id_list(peer_ids, &peer_id_count, PM_PEER_ID_INVALID, skip);
        APP_ERROR_CHECK(err_code);
    
        err_code = pm_device_identities_list_set(peer_ids, peer_id_count);
        APP_ERROR_CHECK(err_code);
    
        // Advertising is not running when all connections are taken, and must therefore be started.
        //   advertising_start(false);
    }
    
    /**@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_HIGH_DUTY:
                NRF_LOG_INFO("High Duty Directed advertising.");
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_DIRECTED);
                APP_ERROR_CHECK(err_code);
                break;
    
            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);
                break;
    
            case BLE_ADV_EVT_IDLE:
                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);
    
                // Set the correct identities list (no excluding peers with no Central Address Resolution).
    
                identities_set(PM_PEER_ID_LIST_SKIP_NO_IRK);
    
                // 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;  //BLE_ADV_EVT_WHITELIST_REQUEST
    
            case BLE_ADV_EVT_PEER_ADDR_REQUEST: {
                pm_peer_data_bonding_t peer_bonding_data;
                custom_adv_stop();
                // 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);
    
                        // Manipulate identities to exclude peers with no Central Address Resolution.
                        identities_set(PM_PEER_ID_LIST_SKIP_ALL);
    
                        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);
                        advertising_start(false);
                    }
                }
    
            }
    
            break;  //BLE_ADV_EVT_PEER_ADDR_REQUEST
    
            default:
                break;
        }
    }
    
    /**@brief Function for initializing the Advertising functionality.
     */
    static void advertising_init(void) {
        uint32_t err_code;
        uint8_t adv_flags;
        ble_advertising_init_t init;
    
        memset(&init, 0, sizeof(init));
    
        adv_flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
        init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
        init.advdata.include_appearance = true;
        init.advdata.flags = adv_flags;
        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_high_duty_enabled = true;
        init.config.ble_adv_directed_enabled = false;
        init.config.ble_adv_directed_interval = 0;
        init.config.ble_adv_directed_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_DURATION;
        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_DURATION;
    
        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);
    }

Related