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

Handling data two times from one of the peripherals

Hello,

I have been struggling with multilink uart example for a while. I have done 3 peripherals and one central communication but still I have some problems. I am using SDK 14.2.0 and 4 EYSHSNZWZ modules from Taiyo Yuden.

Central side sends data to peripherals that I send from computer via RS232 correctly, however when I send data from peripherals continuously, one of the peripherals sends the data two times. I think it is because of the central code, not the peripherals because I use same code for peripherals. I think that central shows the data two times. For example for handle 2, peripheral sends 5 bytes but central shows 10 bytes. For the other connection handles, central shows what is send from peripherals.

The main code for central is here:

/**
 * Copyright (c) 2014 - 2017, 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 "app_error.h"
#include "app_uart.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "app_timer.h"
#include "app_util.h"
#include "bsp_btn_ble.h"
#include "ble.h"
#include "ble_hci.h"
#include "ble_advdata.h"
#include "ble_advertising.h"
#include "ble_conn_params.h"
#include "ble_db_discovery.h"
#include "ble_conn_state.h"
#include "ble_nus_c.h"
#include "nrf_ble_gatt.h"
#include "nrf_delay.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"


#define APP_BLE_CONN_CFG_TAG      1                                     /**< A tag that refers to the BLE stack configuration we set with @ref sd_ble_cfg_set. Default tag is @ref APP_BLE_CONN_CFG_TAG. */
#define APP_BLE_OBSERVER_PRIO     3                                     /**< Application's BLE observer priority. You shouldn't need to modify this value. */

#define UART_TX_BUF_SIZE        256                                     /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE        256                                     /**< UART RX buffer size. */

#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 the Button characteristic on the peer. */

#define LEDBUTTON_BUTTON          BSP_BUTTON_0                          /**< Button that will write 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). */

#define SCAN_INTERVAL             0x00A0                                /**< Determines scan interval in units of 0.625 millisecond. */
#define SCAN_WINDOW               0x0050                                /**< Determines scan window in units of 0.625 millisecond. */
#define SCAN_TIMEOUT              0x0000                                /**< Timout when scanning. 0x0000 disables timeout. */

#define MIN_CONNECTION_INTERVAL   MSEC_TO_UNITS(7.5, UNIT_1_25_MS)      /**< Determines minimum connection interval in milliseconds. */
#define MAX_CONNECTION_INTERVAL   MSEC_TO_UNITS(30, UNIT_1_25_MS)       /**< Determines maximum connection interval in milliseconds. */
#define SLAVE_LATENCY             0                                     /**< Determines slave latency in terms of connection events. */
#define SUPERVISION_TIMEOUT       MSEC_TO_UNITS(4000, UNIT_10_MS)       /**< Determines supervision time-out in units of 10 milliseconds. */

#define UUID16_SIZE             2                                       /**< Size of 16 bit UUID */
#define UUID32_SIZE             4                                       /**< Size of 32 bit UUID */
#define UUID128_SIZE            16                                      /**< Size of 128 bit UUID */

#define ECHOBACK_BLE_UART_DATA  1                                       /**< Echo the UART data that is received over the Nordic UART Service back to the sender. */

NRF_BLE_GATT_DEF(m_gatt);                                               /**< GATT module instance. */
BLE_NUS_C_ARRAY_DEF(m_ble_nus_c, NRF_SDH_BLE_CENTRAL_LINK_COUNT);                                             /**< BLE NUS service client instance. */
BLE_DB_DISCOVERY_DEF(m_db_disc);  /**< Database discovery module instances. */

static char const m_target_periph_name[] = "Nordic_Blinky";             /**< Name of the device we try to connect to. This name is searched for in the scan report data*/
static uint16_t m_ble_nus_max_data_len = BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH; /**< Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */


/**@brief Scan parameters requested for scanning and connection. */
static ble_gap_scan_params_t const m_scan_params =
{
    .active   = 0,
    .interval = SCAN_INTERVAL,
    .window   = SCAN_WINDOW,
    .timeout  = SCAN_TIMEOUT,
    #if (NRF_SD_BLE_API_VERSION <= 2)
        .selective   = 0,
        .p_whitelist = NULL,
    #endif
    #if (NRF_SD_BLE_API_VERSION >= 3)
        .use_whitelist  = 0,
        .adv_dir_report = 0,
    #endif
};

/**@brief Connection parameters requested for connection. */
static ble_gap_conn_params_t const m_connection_param =
{
    (uint16_t)MIN_CONNECTION_INTERVAL,
    (uint16_t)MAX_CONNECTION_INTERVAL,
    (uint16_t)SLAVE_LATENCY,
    (uint16_t)SUPERVISION_TIMEOUT
};


/**@brief Function to handle asserts in the SoftDevice.
 *
 * @details This function will be called in case of an assert in the SoftDevice.
 *
 * @warning This handler is an example only and does not fit a final product. You need to analyze
 *          how your product is supposed to react in case of Assert.
 * @warning On assert from the SoftDevice, the system can only recover on reset.
 *
 * @param[in] line_num     Line number of the failing ASSERT call.
 * @param[in] 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 the LEDs initialization.
 *
 * @details Initializes all LEDs used by the application.
 */
static void leds_init(void)
{
    bsp_board_leds_init();
}


/**
 * @brief Parses advertisement data, providing length and location of the field in case
 *        matching data is found.
 *
 * @param[in]  type       Type of data to be looked for in advertisement data.
 * @param[in]  p_advdata  Advertisement report length and pointer to report.
 * @param[out] p_typedata If data type requested is found in the data report, type data length and
 *                        pointer to data will be populated here.
 *
 * @retval NRF_SUCCESS if the data type is found in the report.
 * @retval NRF_ERROR_NOT_FOUND if the data type could not be found.
 */
static uint32_t adv_report_parse(uint8_t type, uint8_array_t * p_advdata, uint8_array_t * p_typedata)
{
    uint32_t  index = 0;
    uint8_t * p_data;

    p_data = p_advdata->p_data;

    while (index < p_advdata->size)
    {
        uint8_t field_length = p_data[index];
        uint8_t field_type   = p_data[index + 1];

        if (field_type == type)
        {
            p_typedata->p_data = &p_data[index + 2];
            p_typedata->size   = field_length - 1;
            return NRF_SUCCESS;
        }
        index += field_length + 1;
    }
    return NRF_ERROR_NOT_FOUND;
}


/**@brief Function to start scanning. */
static void scan_start(void)
{
    ret_code_t ret;

    (void) sd_ble_gap_scan_stop();

    NRF_LOG_INFO("Start scanning for device name %s.", (uint32_t)m_target_periph_name);
    ret = sd_ble_gap_scan_start(&m_scan_params);
    APP_ERROR_CHECK(ret);

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



/**@brief Function for handling the advertising report BLE event.
 *
 * @param[in] p_ble_evt  Bluetooth stack event.
 */
static void on_adv_report(ble_evt_t const * p_ble_evt)
{
    uint32_t      err_code;
    uint8_array_t adv_data;
    uint8_array_t dev_name;
    bool          do_connect = false;

    // For readibility.
    ble_gap_evt_t  const * p_gap_evt  = &p_ble_evt->evt.gap_evt;
    ble_gap_addr_t const * peer_addr  = &p_gap_evt->params.adv_report.peer_addr;

    // Prepare advertisement report for parsing.
    adv_data.p_data = (uint8_t *)p_gap_evt->params.adv_report.data;
    adv_data.size   = p_gap_evt->params.adv_report.dlen;

    // Search for advertising names.
    bool found_name = false;
    err_code = adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME,
                                &adv_data,
                                &dev_name);
    if (err_code != NRF_SUCCESS)
    {
        // Look for the short local name if it was not found as complete.
        err_code = adv_report_parse(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME, &adv_data, &dev_name);
        if (err_code != NRF_SUCCESS)
        {
            // If we can't parse the data, then exit.
            return;
        }
        else
        {
            found_name = true;
        }
    }
    else
    {
        found_name = true;
    }

    if (found_name)
    {
        if (strlen(m_target_periph_name) != 0)
        {
            if (memcmp(m_target_periph_name, dev_name.p_data, dev_name.size) == 0)
            {
                do_connect = true;
            }
        }
    }

    if (do_connect)
    {
        // Initiate connection.
        err_code = sd_ble_gap_connect(peer_addr, &m_scan_params, &m_connection_param, APP_BLE_CONN_CFG_TAG);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Connection Request Failed, reason %d", 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)
{
    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 has 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_ble_nus_c[p_gap_evt->conn_handle], p_gap_evt->conn_handle, NULL);
            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);
            
            NRF_LOG_INFO("m_ble_nus_c[0x%x]: conn_handle = 0x%x, rx = 0x%x, tx = 0x%x, cccd = 0x%x",
                p_gap_evt->conn_handle,
                m_ble_nus_c[p_gap_evt->conn_handle].conn_handle,
                m_ble_nus_c[p_gap_evt->conn_handle].handles.nus_rx_handle,
                m_ble_nus_c[p_gap_evt->conn_handle].handles.nus_tx_handle,
                m_ble_nus_c[p_gap_evt->conn_handle].handles.nus_tx_cccd_handle);
            
            
            APP_ERROR_CHECK(err_code);

            //err_code = ble_db_discovery_start(&m_db_disc, p_ble_evt->evt.gap_evt.conn_handle);

          //err_code = ble_db_discovery_start(&m_db_disc, p_gap_evt->conn_handle);
          err_code = ble_db_discovery_start(&m_db_disc, p_ble_evt->evt.gap_evt.conn_handle);

            if (err_code != NRF_ERROR_BUSY)
            {
                APP_ERROR_CHECK(err_code);
            }

            // Update LEDs status, and check if we should be looking for more
            // peripherals to connect to.
            bsp_board_led_on(CENTRAL_CONNECTED_LED);
            if (ble_conn_state_n_centrals() == 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 which disconnected, update
        // the LEDs status and start scanning again.
        case BLE_GAP_EVT_DISCONNECTED:
        {
            NRF_LOG_INFO("Central link 0x%x disconnected (reason: 0x%x)",
                         p_gap_evt->conn_handle,
                         p_gap_evt->params.disconnected.reason);

            if (ble_conn_state_n_centrals() == 0)
            {
                //err_code = app_button_disable();
                //APP_ERROR_CHECK(err_code);

                // Turn off connection indication LED
                bsp_board_led_off(CENTRAL_CONNECTED_LED);
            }

            // Start scanning
            scan_start();

            // Turn on LED for indicating scanning
            bsp_board_led_on(CENTRAL_SCANNING_LED);

        } break;

        case BLE_GAP_EVT_ADV_REPORT:
            on_adv_report(p_ble_evt);
            break;

        case BLE_GAP_EVT_TIMEOUT:
        {
            // We have not specified a timeout for scanning, so only connection attemps can timeout.
            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;

#ifndef S140
        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;
#endif

        case BLE_GATTC_EVT_TIMEOUT:
        {
            // Disconnect on GATT Client timeout event.
            NRF_LOG_DEBUG("GATT Client Timeout.");
            err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            APP_ERROR_CHECK(err_code);
        } break;

        case BLE_GATTS_EVT_TIMEOUT:
        {
            // Disconnect on GATT Server timeout event.
            NRF_LOG_DEBUG("GATT Server Timeout.");
            err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            APP_ERROR_CHECK(err_code);
        } break;

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



/**@brief Function for 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 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)
{
    NRF_LOG_DEBUG("call to ble_lbs_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_ble_nus_c[p_evt->conn_handle], p_evt);
}

/**@brief Function for handling characters received by the Nordic UART Service.
 *
 * @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)
{
    ret_code_t ret_val;

    NRF_LOG_DEBUG("Receiving data.");
    NRF_LOG_HEXDUMP_DEBUG(p_data, data_len);

    for (uint32_t i = 0; i < data_len; i++)
    {
        do
        {
            ret_val = app_uart_put(p_data[i]);
            if ((ret_val != NRF_SUCCESS) && (ret_val != NRF_ERROR_BUSY))
            {
                NRF_LOG_ERROR("app_uart_put failed for index 0x%04x.", i);
                APP_ERROR_CHECK(ret_val);
            }
        } while (ret_val == NRF_ERROR_BUSY);
    }
    if (p_data[data_len-1] == '\r')
    {
        while (app_uart_put('\n') == NRF_ERROR_BUSY);
    }
   /* if (ECHOBACK_BLE_UART_DATA)
    {
        // Send data back to peripheral.

        do
        {   
        for(uint32_t i = 0; i< NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++)
        {
            ret_val = ble_nus_c_string_send(&m_ble_nus_c[i], p_data, data_len);
            if ((ret_val != NRF_SUCCESS) && (ret_val != NRF_ERROR_BUSY))
            {
                NRF_LOG_ERROR("Failed sending NUS message. Error 0x%x. ", ret_val);
                APP_ERROR_CHECK(ret_val);
            }
            }
        } while (ret_val == NRF_ERROR_BUSY);

    }
    */
}


/**@brief   Function for handling app_uart events.
 *
 * @details This function will receive a single character from the app_uart module and append it to
 *          a string. The string will be be sent over BLE when the last character received was a
 *          'new line' '\n' (hex 0x0A) or if the string has reached the maximum data length.
 */
void uart_event_handle(app_uart_evt_t * p_event)
{
    uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
    uint16_t index = 0;
    uint32_t ret_val = NRF_ERROR_INVALID_STATE;

    switch (p_event->evt_type)
    {
        /**@snippet [Handling data from UART] */
        case APP_UART_DATA_READY:
            UNUSED_VARIABLE(app_uart_get(&data_array[index]));
            index++;

            if ((data_array[index - 1] == '\n') || (index >= (m_ble_nus_max_data_len)))
            {
                //NRF_LOG_DEBUG("Ready to send data over BLE NUS");
               // NRF_LOG_INFO("Ready to send data over BLE NUS");
                NRF_LOG_HEXDUMP_DEBUG(data_array, index);

                for (uint32_t i = 0; i < NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++) {
                  if (m_ble_nus_c[i].conn_handle != BLE_CONN_HANDLE_INVALID && 
                    0 != m_ble_nus_c[i].handles.nus_tx_handle && 
                    0 != m_ble_nus_c[i].handles.nus_rx_handle )
                  {
                    ret_val = ble_nus_c_string_send(&m_ble_nus_c[i], data_array, index);

                    if ((ret_val != NRF_ERROR_INVALID_STATE) && (ret_val != NRF_ERROR_BUSY)) {
                      NRF_LOG_ERROR("CON HND id is %d, UUID %d, Tx %d, Rx %d, RETVAL %d",
                          m_ble_nus_c[i].conn_handle,
                          m_ble_nus_c[i].uuid_type,
                          m_ble_nus_c[i].handles.nus_tx_handle,
                          m_ble_nus_c[i].handles.nus_rx_handle,
                          ret_val);
                      //APP_ERROR_CHECK(ret_val);
                    }
                  }
                }

                index = 0;
            }
            break;

        /**@snippet [Handling data from UART] */
        case APP_UART_COMMUNICATION_ERROR:
            NRF_LOG_ERROR("Communication error occurred while handling UART.");
            APP_ERROR_HANDLER(p_event->data.error_communication);
            break;

        case APP_UART_FIFO_ERROR:
            NRF_LOG_ERROR("Error occurred in FIFO module used by UART.");
            APP_ERROR_HANDLER(p_event->data.error_code);
            break;

        default:
            break;
    }
}


/**@brief Callback handling 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;

    switch (p_ble_nus_evt->evt_type)
    {
        case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
            NRF_LOG_INFO("Discovery on handle %d complete.", p_ble_nus_evt->conn_handle);

            //  Burasi GAP event, discovery event degil. Burayý deðiþtirmek lazým

            err_code = ble_nus_c_handles_assign(&p_ble_nus_c[p_ble_nus_evt->conn_handle], p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
            APP_ERROR_CHECK(err_code);

            NRF_LOG_INFO("m_ble_nus_c[0x%x]: conn_handle = 0x%x, rx = 0x%x, tx = 0x%x, cccd = 0x%x",
                                p_ble_nus_evt->conn_handle,
                                m_ble_nus_c[p_ble_nus_evt->conn_handle].conn_handle,
                                m_ble_nus_c[p_ble_nus_evt->conn_handle].handles.nus_rx_handle,
                                m_ble_nus_c[p_ble_nus_evt->conn_handle].handles.nus_tx_handle,
                                m_ble_nus_c[p_ble_nus_evt->conn_handle].handles.nus_tx_cccd_handle);
            

            err_code = ble_nus_c_tx_notif_enable(&p_ble_nus_c[p_ble_nus_evt->conn_handle]);
            
            //err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
            if (err_code != NRF_ERROR_BUSY)
             {
                 APP_ERROR_CHECK(err_code);                                         
             }
            NRF_LOG_INFO("Connected to device with Nordic UART Service on handle %d.", p_ble_nus_evt->conn_handle);

            break;
        case BLE_NUS_C_EVT_NUS_TX_EVT:
            NRF_LOG_INFO("Uartttan data alindi.");
            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.");
          
          if( NULL == p_ble_nus_evt ) {
            NRF_LOG_INFO( "ple_ble_nus_evt is null" );
          }
          /*
          else if( BLE_CONN_HANDLE_INVALID != p_ble_nus_evt->conn_handle ) {
            NRF_LOG_INFO("m_ble_nus_c[0x%x]: DISCONNECTED = 0x%x, rx = 0x%x, tx = 0x%x, cccd = 0x%x",
                p_ble_nus_evt->conn_handle,
                m_ble_nus_c[p_ble_nus_evt->conn_handle].conn_handle,
                m_ble_nus_c[p_ble_nus_evt->conn_handle].handles.nus_rx_handle,
                m_ble_nus_c[p_ble_nus_evt->conn_handle].handles.nus_tx_handle,
                m_ble_nus_c[p_ble_nus_evt->conn_handle].handles.nus_tx_cccd_handle);
           }
           */
           else {
            NRF_LOG_INFO( "Event Handler connection pointer is null: conn_handle: %d", p_ble_nus_evt->conn_handle );
          }
          

          scan_start();
          break;
    }
}

/** @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 to sleep until a BLE event is received by the application.
 */
static void power_manage(void)
{
    ret_code_t err_code = sd_app_evt_wait();
    APP_ERROR_CHECK(err_code);
}


/** @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);
        err_code = nrf_ble_gatt_att_mtu_central_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
    APP_ERROR_CHECK(err_code);
}

/**@brief Function for initializing the UART. */
static void uart_init(void)
{
    ret_code_t err_code;

    app_uart_comm_params_t const comm_params =
    {
        .rx_pin_no    = RX_PIN_NUMBER,
        .tx_pin_no    = TX_PIN_NUMBER,
        .rts_pin_no   = RTS_PIN_NUMBER,
        .cts_pin_no   = CTS_PIN_NUMBER,
        .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
        .use_parity   = false,
        .baud_rate    = UART_BAUDRATE_BAUDRATE_Baud115200
    };

    APP_UART_FIFO_INIT(&comm_params,
                       UART_RX_BUF_SIZE,
                       UART_TX_BUF_SIZE,
                       uart_event_handle,
                       APP_IRQ_PRIORITY_LOWEST,
                       err_code);

    APP_ERROR_CHECK(err_code);
}

/**@brief Function for initializing the 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);
  }

  /*
   ble_nus_c_init_t init[NRF_SDH_BLE_CENTRAL_LINK_COUNT];

  for(uint32_t i = 0; i< NRF_SDH_BLE_CENTRAL_LINK_COUNT; i++)
  {

    init[i].evt_handler = ble_nus_c_evt_handler;
    
    err_code = ble_nus_c_init(&m_ble_nus_c[i], &init[i]);
    APP_ERROR_CHECK(err_code);
    }
    */
}

int main(void)
{
    log_init();
    timer_init();
    leds_init();
    uart_init();
    ble_stack_init();
    gatt_init();
    db_discovery_init();
    //lbs_c_init();
    nus_c_init();
    ble_conn_state_init();
    NRF_LOG_INFO("Multilink example started.");

    // Start scanning for peripherals and initiate connection to devices which  advertise.
    scan_start();

    // Turn on the LED to signal scanning.
    bsp_board_led_on(CENTRAL_SCANNING_LED);

    for (;;)
    {
        if (!NRF_LOG_PROCESS())
        {
            power_manage();
        }
    }
}
 

I get no errors, but I should solve this "two times" problem. There should be a point that I failed to notice. Please help me on this. Thank you in advance.

By the way, same thing happens while sending data from central to peripherals. I mean, data is sent to handle 2, two times. :) but other handles receive the data as is is sent.

Parents
  • Hello,

    Do you get two events, or do you get twice the length on the data?

    e.g.:

    data = 1234512345 or data = 1122334455?

     

    What does the log look like when you send one message from the device with conn handle 2?

    Do you get the line: "Receiving data" two times? 

    Can you also try to add, in your BLE_NUS_C_EVT_NUS_TX_EVT event:

    NRF_LOG_INFO("Uartttan data alindi. conn_handle= %d", p_ble_nus_evt->conn_handle);

    to see that you are not actually connected to the same device twice?

     

    I assume that you have the same project/.hex-file on all the peripherals? Do you? do you have any #define ECHOBACK_BLE_UART_DATA in your peripheral project?

     

    Best regards,

    Edvin

     

Reply
  • Hello,

    Do you get two events, or do you get twice the length on the data?

    e.g.:

    data = 1234512345 or data = 1122334455?

     

    What does the log look like when you send one message from the device with conn handle 2?

    Do you get the line: "Receiving data" two times? 

    Can you also try to add, in your BLE_NUS_C_EVT_NUS_TX_EVT event:

    NRF_LOG_INFO("Uartttan data alindi. conn_handle= %d", p_ble_nus_evt->conn_handle);

    to see that you are not actually connected to the same device twice?

     

    I assume that you have the same project/.hex-file on all the peripherals? Do you? do you have any #define ECHOBACK_BLE_UART_DATA in your peripheral project?

     

    Best regards,

    Edvin

     

Children
  • Hi,

    I get the data as 1234512345 while I am sending 12345.

    Only from one connection handle I get this.

    For example:

    From conn handle 0; I send 00 00 00 15 0A, then central gets  00 00 00 15 0A. I see "Uartttan data alindi" part one time. This is OK. 

    From conn handle 2; I send  00 00 00 16 0A, then central gets 00 00 00 16 0A 00 00 00 16 0A. I see "Uartttan data alindi" part two times.

    From conn handle 1; I send 00 00 00 17 0A, then central gets nothing. I don't see "Uartttan data alindi". After I reset conn handle 1, then it becomes conn handle 3, after that I send 00 00 00 17 0A then central get 00 00 00 17 0A. This time I see "Uartttan data alindi" part one time.

    To conclude; handle 1 needs resetting to get data from central, and from conn handle 2, I get always 2 bytes consecutively.

    I didn't use the ECHOBACK_BLE_UART_DATA, I removed it. Both central and peripherals.

    I will consider what you say.

    By the way, I have changed 

    NRF_LOG_INFO("Uartttan data alindi.) part to

    NRF_LOG_INFO("Uartttan data alindi. conn_handle= %d", p_ble_nus_evt->conn_handle); 

    and I always see 

    0> <info> app: Uartttan data alindi.conn_handle= 0
    0> <info> app: Uartttan data alindi.conn_handle= 0


    0> <info> app: Uartttan data alindi.conn_handle= 0


    0> <info> app: Uartttan data alindi.conn_handle= 0


    0> <info> app: Uartttan data alindi.conn_handle= 0

    from every connection handle. I get two times for handle 2, and one time for handle 0. But for every handle it says conn handle 0. I didn't understand. Because at first central assigns handles correctly at the time of connection. 

  • Hello,

     

    Is it possible to send the central project? Do you use any special HW, such as sensors? Or can I replicate this on the regular DK?

     

    Best regards,

    Edvin

  • Hi,

    Link for the central  project file is here. Also I added the .rar file. I use only EYSHSNZWZ board, there isn't any other specific HW. I have only changed the pins for LEDs and there is not any other difference, I think you can use it.

    Thank you.

    0474.ble_app_multilink_central.rar

  • Hello,

    I am not able to compile your project. I get a lot of weird compiling errors, but I suspect that it is because you have modified the ble_nus_c.c and ble_nus_c.h files, which does not originally have BLE_NUS_C_ARRAY_DEF in SDK14.2.0.

     

    Try to compile the project that you sent in a freshly unzipped SDK, and see what files that are missing. These are the files that I would need to compile.

     

    Can you check one thing: Does the same behavior occur if you try to disable optimization? In SES you do this in project settings->code->code generation->optimization level.

     

    It may be that the ble_nus_c.c does not pass the conn_handle correctly, since it is originally intended for only one connection (at least in SDK14.2.0).

     

    Can you try to add the conn_handle in the on_hvx() function in ble_nus_c.c.

    Change from:

    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;
    
            p_ble_nus_c->evt_handler(p_ble_nus_c, &ble_nus_c_evt);
            NRF_LOG_DEBUG("Client sending data.");
        }
    }

    to:

    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.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.");
        }
    }

     

  • Hello Edvin,

    Firstly, thank you for your attention. I am sorry that I didn't send all files that you need. I applied your suggestion about on_hvx part, and now I can see which daha come from which conn handle. But still from  first conn handle (0x1) central can not receive data. From conn handle 0x2, central shows two times the data and conn handle 0x0 is ok. 

    Also I have controlled the code generation optimization settings and I saw that it is already disabled.

    Now I have controlled, compiled and attached the all folder, you can directly use it. 

    In Multilink_Example>examples you can see both peripheral and central that I use.

    File is here.

    Multilink_Example.rar

Related