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

BLE_NUS_C_EVT_NUS_TX_EVT has handle of 0xffff

Hello,

I have following problem:

I am using a multilink NUS Central. With one peripheral connection everything works fine. But when make a second connection I sometimes get an error when I try to send data back in received event.

In ble_nus_c_evt_handler event with event type BLE_NUS_C_EVT_NUS_TX_EVT the p_ble_nus_c sometimes has an invalid connection handle (0xFFFF).

If I try to send data back I get following warning: <warning> ble_nus_c: Connection handle invalid.

How is this possible? I am assigning the handles with  ble_nus_c_handles_assign on discovery complete.

Does anyone know about this issue?

Thanks (again)...

  • Hello,

    What SDK version do you use?

    Try to add this line in on_hvx() in ble_nus_c.c:

    ble_nus_c_evt.conn_handle = p_ble_evt->evt.gap_evt.conn_handle;

    But only if it is in fact a BLE_NUS_C_EVT_NUS_TX_EVT.

    So something like this:

    static void on_hvx(ble_nus_c_t * p_ble_nus_c, ble_evt_t const * p_ble_evt)
    {
        // HVX can only occur from client sending.
        if (   (p_ble_nus_c->handles.nus_tx_handle != BLE_GATT_HANDLE_INVALID)
            && (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_nus_c->handles.nus_tx_handle)
            && (p_ble_nus_c->evt_handler != NULL))
        {
            ble_nus_c_evt_t ble_nus_c_evt;
    
            ble_nus_c_evt.evt_type = BLE_NUS_C_EVT_NUS_TX_EVT;
            ble_nus_c_evt.p_data   = (uint8_t *)p_ble_evt->evt.gattc_evt.params.hvx.data;
            ble_nus_c_evt.data_len = p_ble_evt->evt.gattc_evt.params.hvx.len;
            ble_nus_c_evt.conn_handle = p_ble_evt->evt.gap_evt.conn_handle; // <-- ADD THIS LINE
    
            p_ble_nus_c->evt_handler(p_ble_nus_c, &ble_nus_c_evt);
            NRF_LOG_DEBUG("Client sending data.");
        }
    }

    Does that change the behavior?

    Best regards,

    Edvin

  • Thanks for the reply. I added the line but it did not change. I am using SDK 15.2

    following a small snippet of my code:

    static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt)
    {
       static uint8_t data_array[sendData_length];
       uint32_t ret_val;
    
        ret_code_t err_code;
        switch (p_ble_nus_evt->evt_type)
        {       
            case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
                err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
                APP_ERROR_CHECK(err_code);
                err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
                APP_ERROR_CHECK(err_code);
                break;
            case BLE_NUS_C_EVT_NUS_TX_EVT:                 
                NRF_LOG_INFO("received data from peripheral %i %i",  p_ble_nus_evt->conn_handle,p_ble_nus_evt->data_len);                       
                // send some data back to client          
                NRF_LOG_INFO("send back data %i, %i", p_ble_nus_evt->conn_handle, p_ble_nus_c->conn_handle);
                ret_val = ble_nus_c_string_send(p_ble_nus_c/*&p_ble_nus_c[ p_ble_nus_evt->conn_handle]*/, data_array, sendData_length);
                if (ret_val == NRF_ERROR_INVALID_STATE)
                {
                    NRF_LOG_INFO("send back break point");
                }
                ...

    It seems that p_ble_nus_evt->conn_handle could be good (0 or 1 if two peripherals are connected, but p_ble_nus_c->conn_handle is sometimes 0xffff)

  • I remember that I did this a while back. You have to be careful when using the handles, so that everything is exactly like it was in the ble_lbs_c.c/h files, and with the conn_handles. 

    Without knowing exactly what the issue is, can you try the attached main.c file, together with the attached ble_nus_c_cust.h and ble_nuc_c_cust.c files, instead of the ble_nuc_c.h/c. 

    I remember that there was some issues regarding the handles. You need to assign handles both in the BLE_NUS_C_DISCOVERY_COMPLETE event, and in the BLE_GAP_EVT_CONNECTED event.

    Try the attached files (they were modified from the default main and ble_nus_c files in SDK15.2.0) 

    /**
     * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    
    #include "sdk_common.h"
    #if NRF_MODULE_ENABLED(BLE_NUS_C)
    #include <stdlib.h>
    
    #include "ble.h"
    #include "ble_nus_c_cust.h"
    #include "ble_gattc.h"
    #include "ble_srv_common.h"
    #include "app_error.h"
    
    #define NRF_LOG_MODULE_NAME ble_nus_c
    #include "nrf_log.h"
    NRF_LOG_MODULE_REGISTER();
    
    void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt)
    {
        ble_nus_c_evt_t nus_c_evt;
        memset(&nus_c_evt,0,sizeof(ble_nus_c_evt_t));
    
        ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
    
        // Check if the NUS was discovered.
        if (    (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
            &&  (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_NUS_SERVICE)
            &&  (p_evt->params.discovered_db.srv_uuid.type == p_ble_nus_c->uuid_type))
        {
            for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
            {
                switch (p_chars[i].characteristic.uuid.uuid)
                {
                    case BLE_UUID_NUS_RX_CHARACTERISTIC:
                        nus_c_evt.handles.nus_rx_handle = p_chars[i].characteristic.handle_value;
                        break;
    
                    case BLE_UUID_NUS_TX_CHARACTERISTIC:
                        nus_c_evt.handles.nus_tx_handle = p_chars[i].characteristic.handle_value;
                        nus_c_evt.handles.nus_tx_cccd_handle = p_chars[i].cccd_handle;
                        break;
    
                    default:
                        break;
                }
            }
            if (p_ble_nus_c->evt_handler != NULL)
            {
                nus_c_evt.conn_handle = p_evt->conn_handle;
                nus_c_evt.evt_type    = BLE_NUS_C_EVT_DISCOVERY_COMPLETE;
                p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
            }
        }
    }
    
    /**@brief     Function for handling Handle Value Notification received from the SoftDevice.
     *
     * @details   This function will uses the Handle Value Notification received from the SoftDevice
     *            and checks if it is a notification of the NUS TX characteristic from the peer. If
     *            it is, this function will decode the data and send it to the
     *            application.
     *
     * @param[in] p_ble_nus_c Pointer to the NUS Client structure.
     * @param[in] p_ble_evt   Pointer to the BLE event received.
     */
    static void on_hvx(ble_nus_c_t * p_ble_nus_c, ble_evt_t const * p_ble_evt)
    {
        if (p_ble_nus_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
        {
            return;
        }
        // HVX can only occur from client sending.
        if (   (p_ble_nus_c->handles.nus_tx_handle != BLE_GATT_HANDLE_INVALID)
            && (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_nus_c->handles.nus_tx_handle)
            && (p_ble_nus_c->evt_handler != NULL))
        {
            ble_nus_c_evt_t ble_nus_c_evt;
            ble_nus_c_evt.conn_handle = p_ble_nus_c->conn_handle;
    
            ble_nus_c_evt.evt_type = BLE_NUS_C_EVT_NUS_TX_EVT;
            ble_nus_c_evt.p_data   = (uint8_t *)p_ble_evt->evt.gattc_evt.params.hvx.data;
            ble_nus_c_evt.data_len = p_ble_evt->evt.gattc_evt.params.hvx.len;
    
            p_ble_nus_c->evt_handler(p_ble_nus_c, &ble_nus_c_evt);
            NRF_LOG_DEBUG("Client sending data.");
        }
    }
    
    uint32_t ble_nus_c_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_c_init)
    {
        uint32_t      err_code;
        ble_uuid_t    uart_uuid;
        ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
    
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init);
    
        err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type);
        VERIFY_SUCCESS(err_code);
    
        uart_uuid.type = p_ble_nus_c->uuid_type;
        uart_uuid.uuid = BLE_UUID_NUS_SERVICE;
    
        p_ble_nus_c->conn_handle           = BLE_CONN_HANDLE_INVALID;
        p_ble_nus_c->evt_handler           = p_ble_nus_c_init->evt_handler;
        p_ble_nus_c->handles.nus_tx_handle = BLE_GATT_HANDLE_INVALID;
        p_ble_nus_c->handles.nus_rx_handle = BLE_GATT_HANDLE_INVALID;
    
        return ble_db_discovery_evt_register(&uart_uuid);
    }
    
    void ble_nus_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ble_nus_c_t * p_ble_nus_c = (ble_nus_c_t *)p_context;
    
        if ((p_ble_nus_c == NULL) || (p_ble_evt == NULL))
        {
            return;
        }
    
        if ( (p_ble_nus_c->conn_handle != BLE_CONN_HANDLE_INVALID)
           &&(p_ble_nus_c->conn_handle != p_ble_evt->evt.gap_evt.conn_handle)
           )
        {
            return;
        }
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GATTC_EVT_HVX:
                on_hvx(p_ble_nus_c, p_ble_evt);
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                if (p_ble_evt->evt.gap_evt.conn_handle == p_ble_nus_c->conn_handle
                        && p_ble_nus_c->evt_handler != NULL)
                {
                    ble_nus_c_evt_t nus_c_evt;
    
                    nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCONNECTED;
    
                    p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID;
                    p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
                }
                break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    /**@brief Function for creating a message for writing to the CCCD. */
    static uint32_t cccd_configure(uint16_t conn_handle, uint16_t cccd_handle, bool enable)
    {
        uint8_t buf[BLE_CCCD_VALUE_LEN];
    
        buf[0] = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
        buf[1] = 0;
    
        ble_gattc_write_params_t const write_params =
        {
            .write_op = BLE_GATT_OP_WRITE_REQ,
            .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
            .handle   = cccd_handle,
            .offset   = 0,
            .len      = sizeof(buf),
            .p_value  = buf
        };
    
        return sd_ble_gattc_write(conn_handle, &write_params);
    }
    
    
    uint32_t ble_nus_c_tx_notif_enable(ble_nus_c_t * p_ble_nus_c)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if ( (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
           ||(p_ble_nus_c->handles.nus_tx_cccd_handle == BLE_GATT_HANDLE_INVALID)
           )
        {
            return NRF_ERROR_INVALID_STATE;
        }
        return cccd_configure(p_ble_nus_c->conn_handle,p_ble_nus_c->handles.nus_tx_cccd_handle, true);
    }
    
    
    uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if (length > BLE_NUS_MAX_DATA_LEN)
        {
            NRF_LOG_WARNING("Content too long.");
            return NRF_ERROR_INVALID_PARAM;
        }
        if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
        {
            NRF_LOG_WARNING("Connection handle invalid.");
            return NRF_ERROR_INVALID_STATE;
        }
    
        ble_gattc_write_params_t const write_params =
        {
            .write_op = BLE_GATT_OP_WRITE_CMD,
            .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
            .handle   = p_ble_nus_c->handles.nus_rx_handle,
            .offset   = 0,
            .len      = length,
            .p_value  = p_string
        };
    
        return sd_ble_gattc_write(p_ble_nus_c->conn_handle, &write_params);
    }
    
    
    uint32_t ble_nus_c_handles_assign(ble_nus_c_t               * p_ble_nus,
                                      uint16_t                    conn_handle,
                                      ble_nus_c_handles_t const * p_peer_handles)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus);
    
        p_ble_nus->conn_handle = conn_handle;
        if (p_peer_handles != NULL)
        {
            p_ble_nus->handles.nus_tx_cccd_handle = p_peer_handles->nus_tx_cccd_handle;
            p_ble_nus->handles.nus_tx_handle      = p_peer_handles->nus_tx_handle;
            p_ble_nus->handles.nus_rx_handle      = p_peer_handles->nus_rx_handle;
        }
        return NRF_SUCCESS;
    }
    #endif // NRF_MODULE_ENABLED(BLE_NUS_C)
    
    ble_nus_c_cust.h
    /**
     * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    /**
     * @brief BLE LED Button Service central and client application main file.
     *
     * This example can be a central for up to 8 peripherals.
     * The peripheral is called ble_app_blinky and can be found in the ble_peripheral
     * folder.
     */
    
    #include <stdint.h>
    #include <stdio.h>
    #include <string.h>
    #include "nordic_common.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_ble.h"
    #include "app_timer.h"
    #include "bsp_btn_ble.h"
    #include "ble.h"
    #include "ble_hci.h"
    #include "ble_advertising.h"
    #include "ble_conn_params.h"
    #include "ble_db_discovery.h"
    //#include "ble_lbs_c.h"
    #include "ble_nus_c_cust.h"
    #include "ble_conn_state.h"
    #include "nrf_ble_gatt.h"
    #include "nrf_pwr_mgmt.h"
    #include "nrf_ble_scan.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    
    #define APP_BLE_CONN_CFG_TAG      1                                     /**< Tag that refers to the BLE stack configuration that is set with @ref sd_ble_cfg_set. The default tag is @ref APP_BLE_CONN_CFG_TAG. */
    #define APP_BLE_OBSERVER_PRIO     3                                     /**< BLE observer priority of the application. There is no need to modify this value. */
    
    #define CENTRAL_SCANNING_LED      BSP_BOARD_LED_0
    #define CENTRAL_CONNECTED_LED     BSP_BOARD_LED_1
    #define LEDBUTTON_LED             BSP_BOARD_LED_2                       /**< LED to indicate a change of state of the Button characteristic on the peer. */
    
    #define LEDBUTTON_BUTTON          BSP_BUTTON_0                          /**< Button that writes to the LED characteristic of the peer. */
    #define BUTTON_DETECTION_DELAY    APP_TIMER_TICKS(50)                   /**< Delay from a GPIOTE event until a button is reported as pushed (in number of timer ticks). */
    
    NRF_BLE_GATT_DEF(m_gatt);                                               /**< GATT module instance. */
    //BLE_LBS_C_ARRAY_DEF(m_lbs_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT);           /**< LED button client instances. */
    BLE_NUS_C_ARRAY_DEF(m_nus_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT);           /**< LED button client instances. */
    BLE_DB_DISCOVERY_ARRAY_DEF(m_db_disc, NRF_SDH_BLE_CENTRAL_LINK_COUNT);  /**< Database discovery module instances. */
    NRF_BLE_SCAN_DEF(m_scan);                                               /**< Scanning Module instance. */
    
    //static char const m_target_periph_name[] = "Nordic_Blinky";             /**< Name of the device to try to connect to. This name is searched for in the scanning report data. */
    static char const m_target_periph_name[] = "Nordic_UART";             /**< Name of the device to try to connect to. This name is searched for in the scanning report data. */
    
    
    /**@brief Function for handling asserts in the SoftDevice.
     *
     * @details This function is called in case of an assert in the SoftDevice.
     *
     * @warning This handler is only an example and is not meant for the final product. You need to analyze
     *          how your product is supposed to react in case of an assert.
     * @warning On assert from the SoftDevice, the system can only recover on reset.
     *
     * @param[in] line_num     Line number of the failing assert call.
     * @param[in] p_file_name  File name of the failing assert call.
     */
    void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
    {
        app_error_handler(0xDEADBEEF, line_num, p_file_name);
    }
    
    
    /**@brief Function for initializing the LEDs.
     *
     * @details Initializes all LEDs used by the application.
     */
    static void leds_init(void)
    {
        bsp_board_init(BSP_INIT_LEDS);
    }
    
    
    static void scan_evt_handler(scan_evt_t const * p_scan_evt)
    {
        ret_code_t err_code;
    
        switch(p_scan_evt->scan_evt_id)
        {
            case NRF_BLE_SCAN_EVT_CONNECTING_ERROR:
            {
                err_code = p_scan_evt->params.connecting_err.err_code;
                APP_ERROR_CHECK(err_code);
            } break;
    
            default:
                break;
        }
    }
    
    
    /**@brief Function for initializing the scanning and setting the filters.
     */
    static void scan_init(void)
    {
        ret_code_t          err_code;
        nrf_ble_scan_init_t init_scan;
    
        memset(&init_scan, 0, sizeof(init_scan));
    
        init_scan.connect_if_match = true;
        init_scan.conn_cfg_tag     = APP_BLE_CONN_CFG_TAG;
    
        err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_scan_filter_set(&m_scan, SCAN_NAME_FILTER, m_target_periph_name);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_scan_filters_enable(&m_scan, NRF_BLE_SCAN_NAME_FILTER, false);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for starting scanning. */
    static void scan_start(void)
    {
        ret_code_t ret;
    
        NRF_LOG_INFO("Start scanning for device name %s.", (uint32_t)m_target_periph_name);
        ret = nrf_ble_scan_start(&m_scan);
        APP_ERROR_CHECK(ret);
        // Turn on the LED to signal scanning.
        bsp_board_led_on(CENTRAL_SCANNING_LED);
    }
    
    
    /**@brief Handles events coming from the LED Button central module.
     *
     * @param[in] p_lbs_c     The instance of LBS_C that triggered the event.
     * @param[in] p_lbs_c_evt The LBS_C event.
     */
    //static void nus_c_evt_handler(ble_nus_c_t * p_nus_c, ble_nus_c_evt_t * p_nus_c_evt)
    static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt)
    {
        switch (p_ble_nus_evt->evt_type)
        {
            case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
            {
                ret_code_t err_code;
    
                NRF_LOG_INFO("Nordic UART Service discovered on conn_handle 0x%x",
                             p_ble_nus_evt->conn_handle);
    
                err_code = app_button_enable();
                APP_ERROR_CHECK(err_code);
                
                err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
                APP_ERROR_CHECK(err_code);
    
                // LED Button Service discovered. Enable notification of Button.
                err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
                APP_ERROR_CHECK(err_code);
            } break; // BLE_LBS_C_EVT_DISCOVERY_COMPLETE
    
            case BLE_NUS_C_EVT_NUS_TX_EVT:
            {
    //            NRF_LOG_INFO("Link 0x%x, Button state changed on peer to 0x%x",
    //                         p_nus_c_evt->conn_handle,
    //                         p_nus_c_evt->params.button.button_state);
    
                NRF_LOG_INFO("notification from conn handle 0x%04x", p_ble_nus_evt->conn_handle);
                NRF_LOG_RAW_INFO("data: ");
                for (int i=0; i<p_ble_nus_evt->data_len; i++)
                {
                    NRF_LOG_RAW_INFO("%c", p_ble_nus_evt->p_data[i]);
                }
                NRF_LOG_RAW_INFO("\r\n");
    //            if (p_nus_c_evt->params.button.button_state)
    //            {
    //                bsp_board_led_on(LEDBUTTON_LED);
    //            }
    //            else
    //            {
    //                bsp_board_led_off(LEDBUTTON_LED);
    //            }
            } break; // BLE_LBS_C_EVT_BUTTON_NOTIFICATION
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    /**@brief Function for handling BLE events.
     *
     * @param[in]   p_ble_evt   Bluetooth stack event.
     * @param[in]   p_context   Unused.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t err_code;
    
        // For readability.
        ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    
        switch (p_ble_evt->header.evt_id)
        {
            // Upon connection, check which peripheral is connected, initiate DB
            // discovery, update LEDs status, and resume scanning, if necessary.
            case BLE_GAP_EVT_CONNECTED:
            {
                NRF_LOG_INFO("Connection 0x%x established, starting DB discovery.",
                             p_gap_evt->conn_handle);
    
                APP_ERROR_CHECK_BOOL(p_gap_evt->conn_handle < NRF_SDH_BLE_CENTRAL_LINK_COUNT);
    
                err_code = ble_nus_c_handles_assign(&m_nus_c[p_gap_evt->conn_handle],
                                                    p_gap_evt->conn_handle,
                                                    NULL);
                APP_ERROR_CHECK(err_code);
    
                err_code = ble_db_discovery_start(&m_db_disc[p_gap_evt->conn_handle],
                                                  p_gap_evt->conn_handle);
                if (err_code != NRF_ERROR_BUSY)
                {
                    APP_ERROR_CHECK(err_code);
                }
    
                // Update LEDs status and check whether it is needed to look for more
                // peripherals to connect to.
                bsp_board_led_on(CENTRAL_CONNECTED_LED);
                if (ble_conn_state_central_conn_count() == NRF_SDH_BLE_CENTRAL_LINK_COUNT)
                {
                    bsp_board_led_off(CENTRAL_SCANNING_LED);
                }
                else
                {
                    // Resume scanning.
                    bsp_board_led_on(CENTRAL_SCANNING_LED);
                    scan_start();
                }
            } break; // BLE_GAP_EVT_CONNECTED
    
            // Upon disconnection, reset the connection handle of the peer that disconnected, update
            // the LEDs status and start scanning again.
            case BLE_GAP_EVT_DISCONNECTED:
            {
                NRF_LOG_INFO("LBS central link 0x%x disconnected (reason: 0x%x)",
                             p_gap_evt->conn_handle,
                             p_gap_evt->params.disconnected.reason);
    
                if (ble_conn_state_central_conn_count() == 0)
                {
                    err_code = app_button_disable();
                    APP_ERROR_CHECK(err_code);
    
                    // Turn off the LED that indicates the connection.
                    bsp_board_led_off(CENTRAL_CONNECTED_LED);
                }
    
                // Start scanning.
                scan_start();
    
                // Turn on the LED for indicating scanning.
                bsp_board_led_on(CENTRAL_SCANNING_LED);
    
            } break;
    
            case BLE_GAP_EVT_TIMEOUT:
            {
                // Timeout for scanning is not specified, so only the connection requests can time out.
                if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
                {
                    NRF_LOG_DEBUG("Connection request timed out.");
                }
            } break;
    
            case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
            {
                NRF_LOG_DEBUG("BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST.");
                // Accept parameters requested by peer.
                err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle,
                                            &p_gap_evt->params.conn_param_update_request.conn_params);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
            {
                NRF_LOG_DEBUG("PHY update request.");
                ble_gap_phys_t const phys =
                {
                    .rx_phys = BLE_GAP_PHY_AUTO,
                    .tx_phys = BLE_GAP_PHY_AUTO,
                };
                err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GATTC_EVT_TIMEOUT:
            {
                // Disconnect on GATT client timeout event.
                NRF_LOG_DEBUG("GATT client timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GATTS_EVT_TIMEOUT:
            {
                // Disconnect on GATT server timeout event.
                NRF_LOG_DEBUG("GATT server timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
            } break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    /**@brief LED Button collector initialization. */
    static void nus_c_init(void)
    {
        ret_code_t       err_code;
        ble_nus_c_init_t nus_c_init_obj;
    
        nus_c_init_obj.evt_handler = ble_nus_c_evt_handler;
    
        for (uint32_t i = 0; i < NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++)
        {
            err_code = ble_nus_c_init(&m_nus_c[i], &nus_c_init_obj);
            APP_ERROR_CHECK(err_code);
        }
    }
    
    
    /**@brief Function for initializing the BLE stack.
     *
     * @details Initializes the SoftDevice and the BLE event interrupts.
     */
    static void ble_stack_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        // Configure the BLE stack using the default settings.
        // Fetch the start address of the application RAM.
        uint32_t ram_start = 0;
        err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Enable BLE stack.
        err_code = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Register a handler for BLE events.
        NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }
    
    
    /**@brief Function for writing to the LED characteristic of all connected clients.
     *
     * @details Based on whether the button is pressed or released, this function writes a high or low
     *          LED status to the server.
     *
     * @param[in] button_action The button action (press or release).
     *            Determines whether the LEDs of the servers are ON or OFF.
     *
     * @return If successful, NRF_SUCCESS is returned. Otherwise, returns the error code from @ref ble_lbs_led_status_send.
     */
    static ret_code_t led_status_send_to_all(uint8_t button_action)
    {
        ret_code_t err_code;
    
        for (uint32_t i = 0; i< NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++)
        {
            //err_code = ble_nus_c_string_send(&m_nus_c[i], button_action);
            err_code = NRF_SUCCESS;
            NRF_LOG_INFO("not actually sending anything");
            if (err_code != NRF_SUCCESS &&
                err_code != BLE_ERROR_INVALID_CONN_HANDLE &&
                err_code != NRF_ERROR_INVALID_STATE)
            {
                return err_code;
            }
        }
            return NRF_SUCCESS;
    }
    
    
    /**@brief Function for handling events from the button handler module.
     *
     * @param[in] pin_no        The pin that the event applies to.
     * @param[in] button_action The button action (press or release).
     */
    static void button_event_handler(uint8_t pin_no, uint8_t button_action)
    {
        ret_code_t err_code;
    
        switch (pin_no)
        {
            case LEDBUTTON_BUTTON:
                err_code = led_status_send_to_all(button_action);
                if (err_code == NRF_SUCCESS)
                {
                    NRF_LOG_INFO("LBS write LED state %d", button_action);
                }
                break;
    
            default:
                APP_ERROR_HANDLER(pin_no);
                break;
        }
    }
    
    
    /**@brief Function for initializing the button handler module.
     */
    static void buttons_init(void)
    {
        ret_code_t err_code;
    
       // The array must be static because a pointer to it is saved in the button handler module.
        static app_button_cfg_t buttons[] =
        {
            {LEDBUTTON_BUTTON, false, BUTTON_PULL, button_event_handler}
        };
    
        err_code = app_button_init(buttons, ARRAY_SIZE(buttons), BUTTON_DETECTION_DELAY);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling database discovery events.
     *
     * @details This function is a callback function to handle events from the database discovery module.
     *          Depending on the UUIDs that are discovered, this function forwards the events
     *          to their respective services.
     *
     * @param[in] p_event  Pointer to the database discovery event.
     */
    static void db_disc_handler(ble_db_discovery_evt_t * p_evt)
    {
        NRF_LOG_DEBUG("call to ble_nus_on_db_disc_evt for instance %d and link 0x%x!",
                      p_evt->conn_handle,
                      p_evt->conn_handle);
    
        ble_nus_c_on_db_disc_evt(&m_nus_c[p_evt->conn_handle], p_evt);
    }
    
    
    /** @brief Database discovery initialization.
     */
    static void db_discovery_init(void)
    {
        ret_code_t err_code = ble_db_discovery_init(db_disc_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing power management.
     */
    static void power_management_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling the idle state (main loop).
     *
     * @details This function handles any pending log operations, then sleeps until the next event occurs.
     */
    static void idle_state_handle(void)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
    
    
    /** @brief Function for initializing the log module.
     */
    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    
    /** @brief Function for initializing the timer.
     */
    static void timer_init(void)
    {
        ret_code_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for initializing the GATT module.
     */
    static void gatt_init(void)
    {
        ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    int main(void)
    {
        // Initialize.
        log_init();
        timer_init();
        leds_init();
        buttons_init();
        power_management_init();
        ble_stack_init();
        gatt_init();
        db_discovery_init();
        nus_c_init();
        ble_conn_state_init();
        scan_init();
    
        // Start execution.
        NRF_LOG_INFO("Multilink example started.");
        scan_start();
    
        for (;;)
        {
            idle_state_handle();
        }
    }
    

    Best regards,

    Edvin

  • For anyone else who comes across this, Edvin's on_hvx() patch resolved the issue for me in SDK 15.2.

  • Assigning the conn_handle to the nus_handle also in the BLE_GAP_EVT_CONNECTED event resolved my issues.

Related