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

Not receiving tx notification (NUS service) from second peripheral.

I have a central device (nRF52832/Soft device s132) that connects to two peripherals. Both peripherals send data to the central via NUS. I have incorporated the required changes for the NUS_C by refering to the LBS_C service from multi-link central example.

Declaration:

BLE_NUS_C_ARRAY_DEF(m_ble_nus_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT);
BLE_DB_DISCOVERY_ARRAY_DEF(m_db_disc, NRF_SDH_BLE_CENTRAL_LINK_COUNT);

Initialization:

static void nus_c_init(void) {
  ret_code_t err_code;
  ble_nus_c_init_t init;

  init.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_ble_nus_c[i], &init);
        APP_ERROR_CHECK(err_code);
    }
}

static void db_disc_handler(ble_db_discovery_evt_t *p_evt) {
  ble_nus_c_on_db_disc_evt(&m_ble_nus_c[p_evt->conn_handle], p_evt);
}

Handler function:

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) {
  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:
    ble_nus_chars_received_uart_print(p_ble_nus_evt->p_data, p_ble_nus_evt->data_len);
    break;

  case BLE_NUS_C_EVT_DISCONNECTED:
    NRF_LOG_INFO("Disconnected.");
    break;

  default:
    break;
  }
}

The snippet from the ble_evt_handler:

case BLE_GAP_EVT_CONNECTED:
    // Discover peer's services.
      err_code = ble_nus_c_handles_assign(&m_ble_nus_c[p_gap_evt->conn_handle], p_ble_evt->evt.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_ble_evt->evt.gap_evt.conn_handle);
      APP_ERROR_CHECK(err_code);
      break;
    }

I can see both the peripherals getting connected. Both peripherals stream data from on-board sensors distinguishable from the sensor Id. The issue is, I see the data only from the peripheral that connects first. If peripheral 1 connects first, i only see the data from peripheral 1. If peripheral 2 connects first then I see the data only from peripheral 2. In the function:

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)

I am printing the address of the p_ble_nus_c using:

NRF_LOG_INFO("nus instance = %u.", p_ble_nus_c);

When the nus handler runs for the case BLE_NUS_C_EVT_DISCOVERY_COMPLETE,  I see two different instances, like these - 

nus instance = 536900620 - from peripheral1, and

nus instance = 536900636 - from peripheral2

But when the nus handler runs for the case BLE_NUS_C_EVT_NUS_TX_EVT, I only see 

nus instance = 536900620 - which is the peripheral that was connected first. Is it possible to stream data from both the peripherals simultaneously? Is there something I am missing?

  • Yes, I confirmed BLE_NUS_C_EVT_DISCOVERY_COMPLETE  and ble_nus_c_tx_notif_enable(p_ble_nus_c) is successful for both the peripherals. Status is returned as NRF_SUCCESS.

  • I assume the service handler must be invoked from the soft device whenever there is an incoming data from the peripheral. It might be that connection handle of the peripheral is being affected somehow. I am not sure. I am posting my source code. I have removed few parts of the code which are irrelevant just for better readability.

    /**
     * This code is based on a sample from Nordic Semiconductor ASA (see license below),
     * with modifications made by Microsoft (see the README.md in this directory).
     *
     * Modified version of ble_peripheral\ble_app_uart example from Nordic nRF5 SDK version 15.2.0
     * (https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/nRF5_SDK_15.2.0_9412b96.zip)
     *
     * Original file: {SDK_ROOT}\examples\ble_peripheral\ble_app_uart\main.c
     **/
    
    /**
     * 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.
     * 
     */
    /** @file
     *
     * @defgroup ble_sdk_uart_over_ble_main main.c
     * @{
     * @ingroup  ble_sdk_app_nus_eval
     * @brief    UART over BLE application main file.
     *
     * This file contains the source code for a sample application that uses the Nordic UART service.
     * This application uses the @ref srvlib_conn_params module.
     */
    
    #include <stdint.h>
    #include <stdio.h>
    #include <string.h>
    #include "nordic_common.h"
    #include "nrf_sdm.h"
    #include "ble.h"
    #include "ble_hci.h"
    #include "ble_db_discovery.h"
    #include "ble_srv_common.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_ble.h"
    #include "nrf_sdh_soc.h"
    #include "nrf_pwr_mgmt.h"
    #include "app_util.h"
    #include "app_error.h"
    #include "peer_manager.h"
    #include "peer_manager_handler.h"
    #include "ble_bas_c.h"
    #include "app_util.h"
    #include "app_timer.h"
    #include "bsp_btn_ble.h"
    #include "fds.h"
    #include "nrf_fstorage.h"
    #include "ble_conn_state.h"
    #include "nrf_ble_gatt.h"
    #include "nrf_ble_lesc.h"
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "nrf_ble_scan.h"
    #include "ble_dis_c.h"
    #include "ble_nus_c.h"
    
    
    #define NUS_SERVICE_UUID_TYPE BLE_UUID_TYPE_VENDOR_BEGIN       /**< UUID type for the Nordic UART Service (vendor specific). */
    #define APP_ADV_INTERVAL 64                                    /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */
    #define APP_ADV_DURATION BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED /**< The advertising duration in units of 10 milliseconds (0 means forever). */
    
    #define SEC_PARAM_BOND 1                                       /**< Perform bonding. */
    #define SEC_PARAM_MITM 1                                       /**< Man In The Middle protection not required. */
    #define SEC_PARAM_LESC 1                                       /**< LE Secure Connections enabled. */
    #define SEC_PARAM_KEYPRESS 0                                   /**< Keypress notifications not enabled. */
    #define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_DISPLAY_ONLY /**< Display I/O capabilities. */
    #define SEC_PARAM_OOB 0                                        /**< Out Of Band data not available. */
    #define SEC_PARAM_MIN_KEY_SIZE 7                               /**< Minimum encryption key size. */
    #define SEC_PARAM_MAX_KEY_SIZE 16                              /**< Maximum encryption key size. */
    #define DEAD_BEEF 0xDEADBEEF                                   /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
    
    #define APP_BLE_CONN_CFG_TAG 1  /**< A tag identifying the SoftDevice BLE configuration. */
    #define APP_BLE_OBSERVER_PRIO 3 /**< Application's BLE observer priority. You shouldn't need to modify this value. */
    
    BLE_NUS_C_ARRAY_DEF(m_ble_nus_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT);
    NRF_BLE_GATT_DEF(m_gatt);                                     /**< GATT module instance. */
    BLE_BAS_C_ARRAY_DEF(m_bas_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT); /**< Structure used to identify the Battery Service client module. */
    NRF_BLE_SCAN_DEF(m_scan);                              /**< Scanning module instance. */
    BLE_DB_DISCOVERY_ARRAY_DEF(m_db_disc, NRF_SDH_BLE_CENTRAL_LINK_COUNT);
    
    static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID;               /**< Handle of the current connection. */
    static uint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - 3; /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
    
    /**@brief Function for assert macro callback.
     *
     * @details This function will be called in case of an assert in the SoftDevice.
     *
     * @warning This handler is an example only and does not fit a final product. You need to analyse
     *          how your product is supposed to react in case of Assert.
     * @warning On assert from the SoftDevice, the system can only recover on reset.
     *
     * @param[in] line_num    Line number of the failing ASSERT call.
     * @param[in] 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(DEAD_BEEF, line_num, p_file_name);
    }
    
    void start_scan(void) {
    
      ret_code_t err_code = nrf_ble_scan_start(&m_scan);
      NRF_LOG_INFO("scanning started");
      APP_ERROR_CHECK(err_code);
      ble_control_message_protocol_send_scan_state_on_notification_event();
    }
    
    /**@brief Function for handling Peer Manager events.
     *
     * @param[in] p_evt  Peer Manager event.
     */
    static void pm_evt_handler(pm_evt_t const *p_evt) {
      pm_handler_on_pm_evt(p_evt);
      pm_handler_flash_clean(p_evt);
    
      switch (p_evt->evt_id) {
      case PM_EVT_BONDED_PEER_CONNECTED:
        break;
    
      case PM_EVT_CONN_SEC_SUCCEEDED:
        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");
          // 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;
    
      default:
        NRF_LOG_INFO("pm_evt_handler: %d", p_evt->evt_id);
        break;
      }
    }
    
    /**@brief Function for initializing the timer module.
     */
    static void timers_init(void) {
      ret_code_t err_code = app_timer_init();
      APP_ERROR_CHECK(err_code);
    }
    
    /**@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) {
      uint32_t err_code;
      uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
      ble_gap_evt_t const *p_gap_evt = &p_ble_evt->evt.gap_evt;
    
      switch (p_ble_evt->header.evt_id) {
      case BLE_GAP_EVT_CONNECTED:
        // Discover peer's services.
           err_code = ble_db_discovery_start(&m_db_disc[p_gap_evt->conn_handle], p_ble_evt->evt.gap_evt.conn_handle);
          APP_ERROR_CHECK(err_code);
          ble_control_message_protocol_send_peripheral_device_connected_event();
        break;
    
      case BLE_GAP_EVT_ADV_REPORT:
        break;
      case BLE_GAP_EVT_DISCONNECTED:
          NRF_LOG_INFO("Peripheral Device Disconnected - reason = %d", p_gap_evt->params.disconnected.reason);
        break;
    
      case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
        NRF_LOG_DEBUG("ble_evt_handler::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_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_GATTS_EVT_SYS_ATTR_MISSING:
        // No system attributes have been stored.
        NRF_LOG_DEBUG("ble_evt_handler::BLE_GATTS_EVT_SYS_ATTR_MISSING");
        err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
        APP_ERROR_CHECK(err_code);
        break;
    
      case BLE_GATTC_EVT_TIMEOUT:
        // Disconnect on GATT Client timeout event.
        NRF_LOG_DEBUG("ble_evt_handler::BLE_GATTC_EVT_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("ble_evt_handler::BLE_GATTS_EVT_TIMEOUT");
        err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
            BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
        APP_ERROR_CHECK(err_code);
        break;
    
      case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
        NRF_LOG_DEBUG("ble_evt_handler::BLE_GAP_EVT_SEC_PARAMS_REQUEST");
        break;
    
      case BLE_GAP_EVT_AUTH_KEY_REQUEST:
        NRF_LOG_INFO("ble_evt_handler::BLE_GAP_EVT_AUTH_KEY_REQUEST");
        break;
    
      case BLE_GAP_EVT_LESC_DHKEY_REQUEST:
        NRF_LOG_INFO("ble_evt_handler::BLE_GAP_EVT_LESC_DHKEY_REQUEST");
        break;
    
      case BLE_GAP_EVT_AUTH_STATUS:
        NRF_LOG_INFO("ble_evt_handler::BLE_GAP_EVT_AUTH_STATUS: status=0x%x bond=0x%x lv4: %d kdist_own:0x%x kdist_peer:0x%x, lesc:%d",
            p_ble_evt->evt.gap_evt.params.auth_status.auth_status,
            p_ble_evt->evt.gap_evt.params.auth_status.bonded,
            p_ble_evt->evt.gap_evt.params.auth_status.sm1_levels.lv4,
            *((uint8_t *)&p_ble_evt->evt.gap_evt.params.auth_status.kdist_own),
            *((uint8_t *)&p_ble_evt->evt.gap_evt.params.auth_status.kdist_peer),
            p_ble_evt->evt.gap_evt.params.auth_status.lesc);
        break;
    
      default:
        // NRF_LOG_INFO("ble_evt_handler::DEFAULT: %X (%d)\n", p_ble_evt->header.evt_id, p_ble_evt->header.evt_id);
        break;
      }
    }
    
    /**@brief Function for handling events from the GATT library. */
    void gatt_evt_handler(nrf_ble_gatt_t *p_gatt, nrf_ble_gatt_evt_t const *p_evt) {
      if ((m_conn_handle == p_evt->conn_handle) && (p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)) {
        m_ble_nus_max_data_len = p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
        NRF_LOG_INFO("gatt_evt_handler::Data len is set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
      }
      NRF_LOG_DEBUG("gatt_evt_handler::ATT MTU exchange completed. central 0x%x peripheral 0x%x",
          p_gatt->att_mtu_desired_central,
          p_gatt->att_mtu_desired_periph);
    }
    
    /**@brief Function for handling events from the BSP module.
     *
     * @param[in]   event   Event generated by button press.
     */
    void bsp_event_handler(bsp_event_t event) {
      uint32_t err_code;
      switch (event) {
      case BSP_EVENT_SLEEP:
        break;
    
      case BSP_EVENT_DISCONNECT:
        err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
        if (err_code != NRF_ERROR_INVALID_STATE) {
          APP_ERROR_CHECK(err_code);
        }
        break;
    
      case BSP_EVENT_WHITELIST_OFF:
        if (m_conn_handle == BLE_CONN_HANDLE_INVALID) {
          err_code = ble_advertising_restart_without_whitelist(&m_advertising);
          if (err_code != NRF_ERROR_INVALID_STATE) {
            APP_ERROR_CHECK(err_code);
          }
        }
        break;
    
      default:
        break;
      }
    }
    
    /**@brief Function for initializing the nrf 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 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 If there is no pending log operation, then sleep until next the next event occurs.
     */
    static void idle_state_handle(void) {
      ret_code_t err_code = nrf_ble_lesc_request_handler();
      APP_ERROR_CHECK(err_code);
    
      UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
      nrf_pwr_mgmt_run();
    }
    
    static uint32_t send_data_to_ble_nus(uint8_t *data, uint16_t length) {
      uint32_t ret;
    
      ret = ble_nus_data_send(&m_nus, data, &length, m_conn_handle);
      //NRF_LOG_INFO("send_data_to_ble_nus: %d", ret);
      return ret;
    }
    
    /**@brief Function for the SoftDevice initialization.
     *
     * @details This function initializes the SoftDevice and the BLE event interrupt.
     */
    static void ble_stack_init(void) {
      ret_code_t err_code;
    
      err_code = nrf_sdh_enable_request();
      APP_ERROR_CHECK(err_code);
    
      // Configure the BLE stack using the default settings.
      // Fetch the start address of the application RAM.
      uint32_t ram_start = 0;
      err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
      APP_ERROR_CHECK(err_code);
    
      // Enable BLE stack.
      err_code = nrf_sdh_ble_enable(&ram_start);
      APP_ERROR_CHECK(err_code);
    
      // Register a handler for BLE events.
      NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }
    
    /**@brief Function for initializing the GATT library. */
    void gatt_init(void) {
      ret_code_t err_code;
    
      err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
      APP_ERROR_CHECK(err_code);
    }
    
    /**@snippet [UART Initialization] */
    
    /**@brief Function for the Peer Manager initialization.
     */
    static void peer_manager_init(void) {
      ble_gap_sec_params_t sec_param;
      ret_code_t err_code;
    
      err_code = pm_init();
      APP_ERROR_CHECK(err_code);
    
      memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
    
      // Security parameters to be used for all security procedures.
      sec_param.bond = SEC_PARAM_BOND;
      sec_param.mitm = SEC_PARAM_MITM;
      sec_param.lesc = SEC_PARAM_LESC;
      sec_param.keypress = SEC_PARAM_KEYPRESS;
      sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES;
      sec_param.oob = SEC_PARAM_OOB;
      sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
      sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
      sec_param.kdist_own.enc = 1;
      sec_param.kdist_own.id = 1;
      sec_param.kdist_peer.enc = 1;
      sec_param.kdist_peer.id = 1;
    
      err_code = pm_sec_params_set(&sec_param);
      APP_ERROR_CHECK(err_code);
    
      err_code = pm_register(pm_evt_handler);
      APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for handling database discovery events.
     *
     * @details This function is callback function to handle events from the database discovery module.
     *          Depending on the UUIDs that are discovered, this function should forward the events
     *          to their respective services.
     *
     * @param[in] p_event  Pointer to the database discovery event.
     */
    static void db_disc_handler(ble_db_discovery_evt_t *p_evt) {
      ble_bas_on_db_disc_evt(&m_bas_c, p_evt);
      ble_nus_c_on_db_disc_evt(&m_ble_nus_c[p_evt->conn_handle], p_evt);
      ble_dis_c_on_db_disc_evt(&m_ble_dis_c, 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 handling Scaning events.
     *
     * @param[in]   p_scan_evt   Scanning event.
     */
    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;
      }
    }
    
    static void scan_init(void) {
      ret_code_t err_code;
      nrf_ble_scan_init_t init_scan;
    
      memset(&init_scan, 0, sizeof(init_scan));
    
      init_scan.connect_if_match = false;
      init_scan.conn_cfg_tag = APP_BLE_CONN_CFG_TAG;
    
      err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
      APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Battery level Collector Handler.
     */
    static void bas_c_evt_handler(ble_bas_c_t *p_bas_c, ble_bas_c_evt_t *p_bas_c_evt) {
      ret_code_t err_code;
    
      switch (p_bas_c_evt->evt_type) {
      case BLE_BAS_C_EVT_DISCOVERY_COMPLETE: {
        err_code = ble_bas_c_handles_assign(p_bas_c, p_bas_c_evt->conn_handle, &p_bas_c_evt->params.bas_db);
        APP_ERROR_CHECK(err_code);
    
        // Battery service discovered. Enable notification of Battery Level.
        NRF_LOG_INFO("Battery Service discovered. Reading battery level.");
    
        err_code = ble_bas_c_bl_read(p_bas_c);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_INFO("Enabling Battery Level Notification.");
        err_code = ble_bas_c_bl_notif_enable(p_bas_c);
        APP_ERROR_CHECK(err_code);
    
      } break;
    
      case BLE_BAS_C_EVT_BATT_NOTIFICATION:
        NRF_LOG_INFO("Battery Level received %d %%.", p_bas_c_evt->params.battery_level);
        break;
    
      case BLE_BAS_C_EVT_BATT_READ_RESP:
        NRF_LOG_INFO("Battery Level Read as %d %%.", p_bas_c_evt->params.battery_level);
        break;
    
      default:
        break;
      }
    }
    
    /**@brief Function for handling characters received by the Nordic UART Service (NUS).
     *
     * @details This function takes a list of characters of length data_len and prints the characters out on UART.
     *          If @ref ECHOBACK_BLE_UART_DATA is set, the data is sent back to sender.
     */
    static void ble_nus_chars_received_uart_print(uint8_t *p_data, uint16_t data_len) {
        NRF_LOG_INFO("nus data: = %s", p_data);
    }
    
    /**@brief Callback handling Nordic UART Service (NUS) client events.
     *
     * @details This function is called to notify the application of NUS client events.
     *
     * @param[in]   p_ble_nus_c   NUS client handle. This identifies the NUS client.
     * @param[in]   p_ble_nus_evt Pointer to the NUS client event.
     */
    
    /**@snippet [Handling events from the ble_nus_c module] */
    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) {
      ret_code_t err_code;
    
      //NRF_LOG_INFO("connection handle: %d", p_ble_nus_evt->conn_handle);
      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:
        ble_nus_chars_received_uart_print(p_ble_nus_evt->p_data, p_ble_nus_evt->data_len);
        break;
    
      case BLE_NUS_C_EVT_DISCONNECTED:
        break;
    
      default:
        break;
      }
    }
    
    /**@brief Function for initializing the Nordic UART Service (NUS) client. */
    static void nus_c_init(void) {
      ret_code_t err_code;
      ble_nus_c_init_t init;
    
      init.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_ble_nus_c[i], &init);
        APP_ERROR_CHECK(err_code);
      }
    
      //err_code = ble_nus_c_init(&m_ble_nus_c, &init);
      //APP_ERROR_CHECK(err_code);
    }
    
    /**
     * @brief Battery level collector initialization.
     */
    static void bas_c_init(void) {
      ret_code_t err_code;
      ble_bas_c_init_t bas_c_init_obj;
    
      bas_c_init_obj.evt_handler = bas_c_evt_handler;
    
      for (uint32_t i = 0; i < NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++) {
        err_code = ble_bas_c_init(&m_bas_c[i], &bas_c_init_obj);
        APP_ERROR_CHECK(err_code);
      }
    
      //  ret_code_t err_code = ble_bas_c_init(&m_bas_c, &bas_c_init_obj);
      //  APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for initializing the Device Information Service client. */
    static void dis_c_init(void) {
      ret_code_t err_code;
      ble_dis_c_init_t init;
    
      memset(&init, 0, sizeof(ble_dis_c_init_t));
      init.evt_handler = ble_dis_c_evt_handler;
    
      err_code = ble_dis_c_init(&m_ble_dis_c, &init);
      APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Application main function.
     */
    int main(void)
    
    {
      // Initialize.
        log_init();
        timer_init();
        power_management_init();
        buttons_leds_init(&erase_bonds);
        ble_stack_init();
        gatt_init();
        peer_manager_init();
        db_discovery_init();
        bas_c_init();
        nus_c_init();
        dis_c_init();
        scan_init();
    
      // Enter main loop.
      for (;;) {
        idle_state_handle();
      }
    }
    
    /**
     * @}
     */

  • Found the issue. A global variable was being updated undesirably. This was supposed to be updated once upon BLE_NUS_C_EVT_DISCOVERY_COMPLETE event. However I was updating it outside of it so for every handler callback this was being updated. Now I see the data from both the NUS peripherals.

  • Good to hear you found the issue. I will close the case then Slight smile

Related