nRF_SDK_17.1.0 s140 pca10056 BLE_UART

Hello all,

I am trying to develop an application where the user will input some specific commands i.e hex value of 0x01 via a mobile application and then via bluetooth this command will be passed to the computer using UART.

I have compiled the ble app uart on my nrf52840 but i am struggling to modify the code for my application.

Could someone help me with this ? 

Thanks

Kleanthis

  • Thank you now when i send the command 0x01 via nrf connect from my phone i can see on termite that the device is activated. Now regarding the second part of my previous question. I would like when the user inputs that command (0x01 via BLE) to transfer it via UART to my computer. I have studied the app_uart function but i could not find any information on how i can transfer that command to UART.

    Could it be possible to help me with that ? I am guessing i shall introduce the m_device_state inside that function and when is set to 1 then it will transfer the data through the data_array ? 

    /**@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.
     */
    /**@snippet [Handling the data received over UART] */
    void uart_event_handle(app_uart_evt_t * p_event)
    {
        static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
        static uint8_t index = 0;
        uint32_t       err_code;
    
        switch (p_event->evt_type)
        {
            case APP_UART_DATA_READY:
                UNUSED_VARIABLE(app_uart_get(&data_array[index]));
                index++;
    
                if ((data_array[index - 1] == '\n') ||
                    (data_array[index - 1] == '\r') ||
                    (index >= m_ble_nus_max_data_len))
                {
                    if (index > 1)
                    {
                        NRF_LOG_DEBUG("Ready to send data over BLE NUS");
                        NRF_LOG_HEXDUMP_DEBUG(data_array, index);
    
                        do
                        {
                            uint16_t length = (uint16_t)index;
                            err_code = ble_nus_data_send(&m_nus, data_array, &length, m_conn_handle);
                            if ((err_code != NRF_ERROR_INVALID_STATE) &&
                                (err_code != NRF_ERROR_RESOURCES) &&
                                (err_code != NRF_ERROR_NOT_FOUND))
                            {
                                APP_ERROR_CHECK(err_code);
                            }
                        } while (err_code == NRF_ERROR_RESOURCES);
                    }
    
                    index = 0;
                }
                break;
    
            case APP_UART_COMMUNICATION_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_communication);
                break;
    
            case APP_UART_FIFO_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_code);
                break;
    
            default:
                break;
        }
    }

  • kleanthise said:
    Could it be possible to help me with that ? I am guessing i shall introduce the m_device_state inside that function and when is set to 1 then it will transfer the data through the data_array ? 

    Yes, but you are looking in the wrong function it seems - the uart_event_handle is used to handle the UART events, which primarily is used to handle the messages received / incoming over UART by forwarding them over the BLE link. You can see that in the uart_event_handle function it only really handles data in the APP_UART_DATA_READY event, which is generated whenever data is received over UART.

    You should instead add this in the nus_evt_handler, in the handling of the BLE_NUS_EVT_RX_DATA event (which is generated whenever data is received over BLE).
    You are on the right path - the approach you describe is correct for the functionality you are after - but you will need to add the app_uart_put function at the right place to implement it.

    Best regards,
    Karl

  • static void nus_data_handler(ble_nus_evt_t *p_evt) {
      if (p_evt->type == BLE_NUS_EVT_RX_DATA) {
        uint32_t err_code;
    
        NRF_LOG_DEBUG("Received data from BLE NUS. Writing data on UART.");
        NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
    
        if (p_evt->params.rx_data.p_data[0] == COMMAND_ACTIVATION) {
          m_device_state = 1;
        }
    
        if (m_device_state ==1 ) {
          NRF_LOG_INFO("Device is activated.");
          app_uart_put(COMMAND_ACTIVATION);
        } else {
          NRF_LOG_INFO("Device not activated.");
        }
      } else if (p_evt->type == BLE_NUS_EVT_TX_RDY) {
        NRF_LOG_DEBUG(" Service is ready to accept new data to be transmitted..");
      } else if (p_evt->type == BLE_NUS_EVT_COMM_STARTED) {
        NRF_LOG_DEBUG("NUS Notification Enable.");
        //app_timer_start(m_timer_nus, APP_TIMER_TICKS(10), NULL);
      } else if (p_evt->type == BLE_NUS_EVT_COMM_STOPPED) {
        NRF_LOG_DEBUG("NUS Notification Disable.");
      }
    }
    
    Thanks a lot for clarifying this. Following your advice and after checking what the app_uart_put gets which if i am not mistaken it just generates a buffer that will send the data via UART correct ? 

    I have modified my code and added the app_uart_put command. It seems that the command needs to be in a loop to get update every transmission correct? How shall i  modify my code to make this happen ? 

    Thank you very much for your time.

  • Hello again, Kleanthis

    kleanthise said:
    Thanks a lot for clarifying this.
    kleanthise said:
    Thank you very much for your time.

    No problem at all, I am happy to help!

    kleanthise said:
    Following your advice and after checking what the app_uart_put gets which if i am not mistaken it just generates a buffer that will send the data via UART correct ? 

    No this is not quite correct - the app_uart_put function takes a single byte as its argument, and places it in the hardware UART peripheral's TX buffer which will then be transfer over the hardware UART lines.

    kleanthise said:
    I have modified my code and added the app_uart_put command. It seems that the command needs to be in a loop to get update every transmission correct? How shall i  modify my code to make this happen ? 

    What do you mean when you say that it must be in a loop?
    There might be some confusion here between the hardware UART peripheral's RX and TX, and the emulated UART over BLE (NUS).
    The app_uart_put is strictly working with the hardware UART peripheral of the nRF device. It has nothing to do with BLE, and will only output the byte it is given on the hardware UART lines.
    The nus_data_handle handles NUS related events, i.e when data is received over the emulated BLE UART, such as the reception of data over the emulated BLE UART (NUS) which generates the BLE_NUS_EVT_RX_DATA event.

    Best regards,
    Karl

  • main code
    
    
    #include <stdint.h>
    #include <string.h>
    #include "nordic_common.h"
    #include "nrf.h"
    #include "ble_hci.h"
    #include "ble_advdata.h"
    #include "ble_advertising.h"
    #include "ble_conn_params.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_soc.h"
    #include "nrf_sdh_ble.h"
    #include "nrf_ble_gatt.h"
    #include "nrf_ble_qwr.h"
    #include "app_timer.h"
    #include "ble_nus_custom.h"
    #include "app_uart.h"
    #include "app_util_platform.h"
    #include "bsp_btn_ble.h"
    #include "nrf_pwr_mgmt.h"
    
    #if defined (UART_PRESENT)
    #include "nrf_uart.h"
    #endif
    #if defined (UARTE_PRESENT)
    #include "nrf_uarte.h"
    #endif
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #define APP_BLE_CONN_CFG_TAG            1                                           /**< A tag identifying the SoftDevice BLE configuration. */
    
    #define DEVICE_NAME                     "GRACED_BLE"                               /**< Name of device. Will be included in the advertising data. */
    #define NUS_SERVICE_UUID_TYPE           BLE_UUID_TYPE_VENDOR_BEGIN                  /**< UUID type for the Nordic UART Service (vendor specific). */
    
    #define APP_BLE_OBSERVER_PRIO           3                                           /**< Application's BLE observer priority. You shouldn't need to modify this value. */
    
    #define APP_ADV_INTERVAL                64                                          /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */
    
    #define APP_ADV_DURATION                18000                                       /**< The advertising duration (180 seconds) in units of 10 milliseconds. */
    
    #define MIN_CONN_INTERVAL               MSEC_TO_UNITS(20, UNIT_1_25_MS)             /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
    #define MAX_CONN_INTERVAL               MSEC_TO_UNITS(75, UNIT_1_25_MS)             /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */
    #define SLAVE_LATENCY                   0                                           /**< Slave latency. */
    #define CONN_SUP_TIMEOUT                MSEC_TO_UNITS(4000, UNIT_10_MS)             /**< Connection supervisory timeout (4 seconds), Supervision Timeout uses 10 ms units. */
    #define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(5000)                       /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
    #define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(30000)                      /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
    #define MAX_CONN_PARAMS_UPDATE_COUNT    3                                           /**< Number of attempts before giving up the connection parameter negotiation. */
    
    #define DEAD_BEEF                       0xDEADBEEF                                  /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
    
    #define UART_TX_BUF_SIZE                256                                         /**< UART TX buffer size. */
    #define UART_RX_BUF_SIZE                256                                         /**< UART RX buffer size. */
    
    #define COMMAND_ACTIVATION 0x01
    static uint8_t m_device_state = 0; 
    
    BLE_NUS_DEF(m_cus);                                   /**< BLE NUS service instance. */
    NRF_BLE_GATT_DEF(m_gatt);                                                           /**< GATT module instance. */
    NRF_BLE_QWR_DEF(m_qwr);                                                             /**< Context for the Queued Write module.*/
    BLE_ADVERTISING_DEF(m_advertising);                                                 /**< Advertising module instance. */
    
    
    
    
    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. */
    static ble_uuid_t m_adv_uuids[]          =                                          /**< Universally unique service identifier. */
    {
        {BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}
    };
    
    
    /**@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);
    }
    
    /**@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 the GAP initialization.
     *
     * @details This function will set up all the necessary GAP (Generic Access Profile) parameters of
     *          the device. It also sets the permissions and appearance.
     */
    static void gap_params_init(void)
    {
        uint32_t                err_code;
        ble_gap_conn_params_t   gap_conn_params;
        ble_gap_conn_sec_mode_t sec_mode;
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
    
        err_code = sd_ble_gap_device_name_set(&sec_mode,
                                              (const uint8_t *) DEVICE_NAME,
                                              strlen(DEVICE_NAME));
        APP_ERROR_CHECK(err_code);
    
        memset(&gap_conn_params, 0, sizeof(gap_conn_params));
    
        gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
        gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
        gap_conn_params.slave_latency     = SLAVE_LATENCY;
        gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;
    
        err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling Queued Write Module errors.
     *
     * @details A pointer to this function will be passed to each service which may need to inform the
     *          application about an error.
     *
     * @param[in]   nrf_error   Error code containing information about what went wrong.
     */
    static void nrf_qwr_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    
    /**@brief Function for handling the data from the Nordic UART Service.
     *
     * @details This function will process the data received from the Nordic UART BLE Service and send
     *          it to the UART module.
     *
     * @param[in] p_evt       Nordic UART Service event.
     */
    /**@snippet [Handling the data received over BLE] */
    static void nus_data_handler(ble_cus_evt_t *p_evt) {
      if (p_evt->evt_type == BLE_NUS_EVT_RX_DATA) {
        uint32_t err_code;
    
        NRF_LOG_DEBUG("Received data from BLE NUS. Writing data on UART.");
        NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
        NRF_LOG_INFO("p_data = %d",p_evt->params.rx_data.p_data[0]);
    
        if (p_evt->params.rx_data.p_data[0] == COMMAND_ACTIVATION) {
          m_device_state = 1;
        }   
    
        if (m_device_state == 1 ) {
          NRF_LOG_INFO("Device is activated.");
          while(app_uart_put(COMMAND_ACTIVATION)!= NRF_SUCCESS);
          NRF_LOG_INFO("Data transferred to UART");
          m_device_state = 0;
        } else {
    
          NRF_LOG_INFO("Device not activated.");
        }
      } else if (p_evt->evt_type == BLE_NUS_EVT_TX_RDY) {
        NRF_LOG_DEBUG(" Service is ready to accept new data to be transmitted..");
      } else if (p_evt->evt_type == BLE_NUS_EVT_COMM_STARTED) {
        NRF_LOG_DEBUG("NUS Notification Enable.");
        //app_timer_start(m_timer_nus, APP_TIMER_TICKS(10), NULL);
      } else if (p_evt->evt_type == BLE_NUS_EVT_COMM_STOPPED) {
        NRF_LOG_DEBUG("NUS Notification Disable.");
      }
    }
    
    /**@snippet [Handling the data received over BLE] */
    
    
    /**@brief Function for initializing services that will be used by the application.
     */
    static void services_init(void)
    {
        uint32_t           err_code;
        ble_cus_init_t     nus_init;
        nrf_ble_qwr_init_t qwr_init = {0};
    
        // Initialize Queued Write Module.
        qwr_init.error_handler = nrf_qwr_error_handler;
    
        err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
        APP_ERROR_CHECK(err_code);
    
        // Initialize NUS.
        memset(&nus_init, 0, sizeof(nus_init));
    
        nus_init.evt_handler = nus_data_handler;
    
        err_code = ble_cus_init(&m_cus, &nus_init);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling an event from the Connection Parameters Module.
     *
     * @details This function will be called for all events in the Connection Parameters Module
     *          which are passed to the application.
     *
     * @note All this function does is to disconnect. This could have been done by simply setting
     *       the disconnect_on_fail config parameter, but instead we use the event handler
     *       mechanism to demonstrate its use.
     *
     * @param[in] p_evt  Event received from the Connection Parameters Module.
     */
    static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
    {
        uint32_t err_code;
    
        if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
        {
            err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
            APP_ERROR_CHECK(err_code);
        }
    }
    
    
    /**@brief Function for handling errors from the Connection Parameters module.
     *
     * @param[in] nrf_error  Error code containing information about what went wrong.
     */
    static void conn_params_error_handler(uint32_t nrf_error)
    {
        APP_ERROR_HANDLER(nrf_error);
    }
    
    
    /**@brief Function for initializing the Connection Parameters module.
     */
    static void conn_params_init(void)
    {
        uint32_t               err_code;
        ble_conn_params_init_t cp_init;
    
        memset(&cp_init, 0, sizeof(cp_init));
    
        cp_init.p_conn_params                  = NULL;
        cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
        cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
        cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
        cp_init.start_on_notify_cccd_handle    = BLE_GATT_HANDLE_INVALID;
        cp_init.disconnect_on_fail             = false;
        cp_init.evt_handler                    = on_conn_params_evt;
        cp_init.error_handler                  = conn_params_error_handler;
    
        err_code = ble_conn_params_init(&cp_init);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for putting the chip into sleep mode.
     *
     * @note This function will not return.
     */
    static void sleep_mode_enter(void)
    {
        uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);
    
        // Prepare wakeup buttons.
        err_code = bsp_btn_ble_sleep_mode_prepare();
        APP_ERROR_CHECK(err_code);
    
        // Go to system-off mode (this function will not return; wakeup will cause a reset).
        err_code = sd_power_system_off();
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Function for handling advertising events.
     *
     * @details This function will be called for advertising events which are passed to the application.
     *
     * @param[in] ble_adv_evt  Advertising event.
     */
    static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
    {
        uint32_t err_code;
    
        switch (ble_adv_evt)
        {
            case BLE_ADV_EVT_FAST:
                err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
                APP_ERROR_CHECK(err_code);
                break;
            case BLE_ADV_EVT_IDLE:
                sleep_mode_enter();
                break;
            default:
                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)
    {
        uint32_t err_code;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                NRF_LOG_INFO("Connected");
                err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
                APP_ERROR_CHECK(err_code);
                m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
                err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                NRF_LOG_INFO("Disconnected");
                // LED indication will be changed when advertising starts.
                m_conn_handle = BLE_CONN_HANDLE_INVALID;
                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_GAP_EVT_SEC_PARAMS_REQUEST:
                // Pairing not supported
                err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GATTS_EVT_SYS_ATTR_MISSING:
                // No system attributes have been stored.
                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.
                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.
                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 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 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("Data len is set to 0x%X(%d)", m_ble_nus_max_data_len, m_ble_nus_max_data_len);
        }
        NRF_LOG_DEBUG("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 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);
    
        err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@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:
                sleep_mode_enter();
                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 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.
     */
    /**@snippet [Handling the data received over UART] */
    void uart_event_handle(app_uart_evt_t * p_event)
    {
        static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
        static uint8_t index = 0;
        uint32_t       err_code;
    
        switch (p_event->evt_type)
        {
            case APP_UART_DATA_READY:
                UNUSED_VARIABLE(app_uart_get(&data_array[index]));
                index++;
    
                if ((data_array[index - 1] == '\n') ||
                    (data_array[index - 1] == '\r') ||
                    (index >= m_ble_nus_max_data_len))
                {
                    if (index > 1)
                    {
                        NRF_LOG_DEBUG("Ready to send data over BLE NUS");
                        NRF_LOG_HEXDUMP_DEBUG(data_array, index);
    
                        do
                        {
                            uint16_t length = (uint16_t)index;
                            err_code = ble_cus_data_send(&m_cus, data_array);                        
                            if (err_code != NRF_ERROR_INVALID_STATE && err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING && err_code != NRF_ERROR_RESOURCES && err_code != NRF_ERROR_BUSY)
                            {
                                APP_ERROR_CHECK(err_code);
                            }
                        } while (err_code == NRF_ERROR_RESOURCES);
                    }
    
                    index = 0;
                }
                break;
    
            case APP_UART_COMMUNICATION_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_communication);
                break;
    
            case APP_UART_FIFO_ERROR:
                APP_ERROR_HANDLER(p_event->data.error_code);
                break;
    
            default:
                break;
        }
    }
    /**@snippet [Handling the data received over UART] */
    
    
    /**@brief  Function for initializing the UART module.
     */
    /**@snippet [UART Initialization] */
    static void uart_init(void)
    {
        uint32_t                     err_code;
        app_uart_comm_params_t const comm_params =
        {
            .rx_pin_no    = 11,
            .tx_pin_no    = 12,
            .rts_pin_no   = RTS_PIN_NUMBER,
            .cts_pin_no   = CTS_PIN_NUMBER,
            .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
            .use_parity   = false,
    #if defined (UART_PRESENT)
            .baud_rate    = NRF_UART_BAUDRATE_115200
    #else
            .baud_rate    = NRF_UARTE_BAUDRATE_115200
    #endif
        };
    
        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);
    }
    /**@snippet [UART Initialization] */
    
    
    /**@brief Function for initializing the Advertising functionality.
     */
    static void advertising_init(void)
    {
        uint32_t               err_code;
        ble_advertising_init_t init;
    
        memset(&init, 0, sizeof(init));
    
        init.advdata.name_type          = BLE_ADVDATA_FULL_NAME;
        init.advdata.include_appearance = false;
        init.advdata.flags              = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
    
        init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
        init.srdata.uuids_complete.p_uuids  = m_adv_uuids;
    
        init.config.ble_adv_fast_enabled  = true;
        init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
        init.config.ble_adv_fast_timeout  = APP_ADV_DURATION;
        init.evt_handler = on_adv_evt;
    
        err_code = ble_advertising_init(&m_advertising, &init);
        APP_ERROR_CHECK(err_code);
    
        ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
    }
    
    
    /**@brief Function for initializing buttons and leds.
     *
     * @param[out] p_erase_bonds  Will be true if the clear bonding button was pressed to wake the application up.
     */
    static void buttons_leds_init(bool * p_erase_bonds)
    {
        bsp_event_t startup_event;
    
        uint32_t err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = bsp_btn_ble_init(NULL, &startup_event);
        APP_ERROR_CHECK(err_code);
    
        *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
    }
    
    
    /**@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)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            nrf_pwr_mgmt_run();
        }
    }
    
    
    /**@brief Function for starting advertising.
     */
    static void advertising_start(void)
    {
        uint32_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
        APP_ERROR_CHECK(err_code);
    }
    
    
    /**@brief Application main function.
     */
    int main(void)
    {
        bool erase_bonds;
    
        // Initialize.
        uart_init();
        log_init();
        timers_init();
        buttons_leds_init(&erase_bonds);
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        services_init();
        advertising_init();
        conn_params_init();
    
        // Start execution.
        printf("\r\nUART started.\r\n");
        NRF_LOG_INFO("Debug logging for UART over RTT started.");
        advertising_start();
    
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
        }
    }
    
    
    /**
     * @}
     */
    ble_nus_custom.c
    
    
    #include "sdk_common.h"
    #if NRF_MODULE_ENABLED(BLE_NUS)
    #include "ble.h"
    #include "ble_nus_custom.h"
    #include "ble_srv_common.h"
    
    #define NRF_LOG_MODULE_NAME ble_nus
    #if BLE_NUS_CONFIG_LOG_ENABLED
    #define NRF_LOG_LEVEL       BLE_NUS_CONFIG_LOG_LEVEL
    #define NRF_LOG_INFO_COLOR  BLE_NUS_CONFIG_INFO_COLOR
    #define NRF_LOG_DEBUG_COLOR BLE_NUS_CONFIG_DEBUG_COLOR
    #else // BLE_NUS_CONFIG_LOG_ENABLED
    #define NRF_LOG_LEVEL       0
    #endif // BLE_NUS_CONFIG_LOG_ENABLED
    #include "nrf_log.h"
    NRF_LOG_MODULE_REGISTER();
    
    
    #define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0003               /**< The UUID of the TX Characteristic. */
    #define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0002               /**< The UUID of the RX Characteristic. */
    
    #define BLE_NUS_MAX_RX_CHAR_LEN        BLE_NUS_MAX_DATA_LEN /**< Maximum length of the RX Characteristic (in bytes). */
    #define BLE_NUS_MAX_TX_CHAR_LEN        BLE_NUS_MAX_DATA_LEN /**< Maximum length of the TX Characteristic (in bytes). */
    
    #define NUS_BASE_UUID                  {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */
    
    
    /**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the SoftDevice.
     *
     * @param[in] p_nus     Custom Service structure.
     * @param[in] p_ble_evt Pointer to the event received from BLE stack.
     */
    static void on_connect(ble_cus_t * p_cus, ble_evt_t const * p_ble_evt)
    {
      p_cus->conn_handle = p_ble_evt->evt.gap_evt.conn_handle; // During connection the conn_handle will be assigned a value (e.g in case of four connection we could have had four handles 0x0, 0x1, 0x2 and 0x3 respectively)
    
      ble_cus_evt_t evt;
      enum gatt_handles gatt_handle;
    
      evt.evt_type = BLE_CUS_EVT_CONNECTED;
    
      p_cus->evt_handler(p_cus, &evt, gatt_handle);
    }
    
     /**@brief Function for handling the Disconnect event.
     *
     * @param[in]   p_cus       Custom Service structure.
     * @param[in]   p_ble_evt   Event received from the BLE stack.
     */
    static void on_disconnect(ble_cus_t *p_cus, ble_evt_t const *p_ble_evt) {
      UNUSED_PARAMETER(p_ble_evt);
      p_cus->conn_handle = BLE_CONN_HANDLE_INVALID; // The connection handle if it is initialized but not associated with a connected device, then it is assigned the value 0xFFFF (BLE_CONN_HANDLE_INVALID).
      enum gatt_handles gatt_handle;
      ble_cus_evt_t evt;
    
      evt.evt_type = BLE_CUS_EVT_DISCONNECTED;
    
      p_cus->evt_handler(p_cus, &evt, gatt_handle);
    }
    
    
    /**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the SoftDevice.
     *
     * @param[in] p_nus     Nordic UART Service structure.
     * @param[in] p_ble_evt Pointer to the event received from BLE stack.
     */
    static void on_write(ble_cus_t * p_cus, ble_evt_t const * p_ble_evt)
    {
        ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write; // When the central do a write command a BLE_GATTS_EVT_WRITE event is received and we assing this event to p_evt_write variable
        static ble_cus_evt_t evt;
        enum gatt_handles gatt_handle; // create an instance of gatt handles
    
       //*****BLE_NUS_EVT_RX_DATA_Characteristic*****
      // Here we check if the handle that has been written matches the handle of the CCCD and that the value has the correct length (2bytes). For indications and notifications len must be 2
      if ((p_evt_write->handle == p_cus->custom_value_handles.cccd_handle) && (p_evt_write->len == 2)) {
    
        // CCCD written, call application event handler
        if (p_cus->evt_handler != NULL) { // na - check that the event handler function is pointing somewhere (in our case on on_cus_evt function, see main.c)
    
          gatt_handle = BLE_NUS_EVT_RX_DATA; // na - assign the CCCD_HANDLE value
    
          NRF_LOG_INFO("Write: %d", p_evt_write->data[0]);
          // Here we need to check if the notification enabled or disabled
          if (p_evt_write->data[0] == 0x01) {
            evt.evt_type = BLE_CUS_EVT_NOTIFICATION_ENABLED;
          } else if (p_evt_write->data[0] == 0x00) {
            evt.evt_type = BLE_CUS_EVT_NOTIFICATION_DISABLED;
          } else {
            evt.evt_type = BLE_CUS_EVT_INVALID_INPUT;
            NRF_LOG_INFO("Invalid State");
          }
          p_cus->evt_handler(p_cus, &evt, gatt_handle); // na - Call the application event handler.
        }
      }
      }
    
    void ble_cus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ble_cus_t * p_cus = (ble_cus_t *)p_context;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                on_connect(p_cus, p_ble_evt);
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                on_connect(p_cus, p_ble_evt);
                break;
    
            case BLE_GATTS_EVT_WRITE:
                on_write(p_cus, p_ble_evt);
                break;
    
            case BLE_GATTS_EVT_HVN_TX_COMPLETE:
                on_hvx_tx_complete(p_cus, p_ble_evt);
                break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    //Initialize our service passing as parameter an instance of our service's structure
    uint32_t ble_cus_init(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
    { if (p_cus == NULL || p_cus_init == NULL) {
        return NRF_ERROR_NULL;
      }
    
        uint32_t            err_code;
        ble_uuid_t            ble_uuid;
        ble_uuid128_t         nus_base_uuid = NUS_BASE_UUID;
        ble_add_char_params_t add_char_params;
    
        // Initialize the service structure.
        p_cus->evt_handler = p_cus_init->evt_handler;
        p_cus->conn_handle = BLE_CONN_HANDLE_INVALID; // Give our service connection handle a default value
    
        /**@snippet [Adding proprietary Service to the SoftDevice] */
        // Add a custom base UUID.
        err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_cus->uuid_type);
        VERIFY_SUCCESS(err_code);
    
        ble_uuid.type = p_cus->uuid_type;
        ble_uuid.uuid = BLE_UUID_NUS_SERVICE;
    
        // Add the service.
        err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_cus->service_handle);
        if (err_code != NRF_SUCCESS) {
        return err_code;
        }
    
        // Add the RX Characteristic.
        memset(&add_char_params, 0, sizeof(add_char_params));
        add_char_params.uuid                     = BLE_UUID_NUS_RX_CHARACTERISTIC;
        add_char_params.uuid_type                = p_cus->uuid_type;
        add_char_params.max_len                  = BLE_NUS_MAX_RX_CHAR_LEN;
        add_char_params.init_len                 = sizeof(uint8_t);
        add_char_params.is_var_len               = true;
        add_char_params.char_props.write         = 1;
        add_char_params.char_props.write_wo_resp = 1;
    
        add_char_params.read_access  = SEC_OPEN;
        add_char_params.write_access = SEC_OPEN;
    
        err_code = characteristic_add(p_cus->service_handle, &add_char_params, &p_cus->rx_handles);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    
        // Add the TX Characteristic.
        /**@snippet [Adding proprietary characteristic to the SoftDevice] */
        memset(&add_char_params, 0, sizeof(add_char_params));
        add_char_params.uuid              = BLE_UUID_NUS_TX_CHARACTERISTIC;
        add_char_params.uuid_type         = p_cus->uuid_type;
        add_char_params.max_len           = BLE_NUS_MAX_TX_CHAR_LEN;
        add_char_params.init_len          = sizeof(uint8_t);
        add_char_params.is_var_len        = true;
        add_char_params.char_props.notify = 1;
    
        add_char_params.read_access       = SEC_OPEN;
        add_char_params.write_access      = SEC_OPEN;
        add_char_params.cccd_write_access = SEC_OPEN;
    
        return characteristic_add(p_cus->service_handle, &add_char_params, &p_cus->tx_handles);
        /**@snippet [Adding proprietary characteristic to the SoftDevice] */
    }
    
    
    
    //This is where we will implement the notification
    
    uint32_t ble_cus_data_send(ble_cus_t * p_cus, int16_t custom_value[]){
        //uint32_t                 err_code;
        //ble_gatts_hvx_params_t     hvx_params;
        //ble_cus_client_context_t * p_client;
    
        if (p_cus == NULL) {
        return NRF_ERROR_NULL;
        }
    
        uint32_t err_code = NRF_SUCCESS;
    
       /** Send value if connected and notifying using sd_ble_gatts_hvx
       *  Verify that we have a valid connection handle, i.e. that we're actually connected to a peer, 
       *  if not we should return an error indicating that we're in an invalid state
       */
    if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
     {
        ble_gatts_hvx_params_t hvx_params; // We declare a variable, hvx_params, of type ble_gatts_hvx_params_t
                                           // This will hold the necessary parameters to do a notification and provide them to the sd_ble_gatts_hvx()
                                           // hvx stands for Handle Value X where X symbolize either notification of indication
        memset(&hvx_params, 0, sizeof(hvx_params));
        uint16_t len = 32; // Set the length of bytes to be written. Remember that you must set the same len size for the characteristic attribute
    
        hvx_params.handle = p_cus->custom_value_handles.value_handle;
        hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
        hvx_params.offset = 0;
        hvx_params.p_len  = &len;
        hvx_params.p_data = custom_value;
    
      /*
            After setting the hvx_params, we notify the peer by calling sd_ble_gatts_hvx()
            Parameters
            [in]         conn_handle	Connection handle.
            [in,out]     p_hvx_params	Pointer to an HVx parameters structure. If ble_gatts_hvx_params_t::p_data contains a non-NULL pointer 
                                            the attribute value will be updated with the contents pointed by it before sending the notification or indication. 
                                            If the attribute value is updated, ble_gatts_hvx_params_t::p_len is updated by the SoftDevice to contain the number 
                                            of actual bytes written, else it will be set to 0.
    
             sd_ble_gatts_hvx() not-only can change the internal value of the characteristic, but also sends it out as a notification/indication 
             to the other side which is subscribed to the characteristic
    
        */
    
        err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params); // Notify the peer by passing the connection handle as well as the hvx_params structure
      } else {
        err_code = NRF_ERROR_INVALID_STATE;
        //NRF_LOG_INFO("sd_ble_gatts_hvx result: NRF_ERROR_INVALID_STATE. \r\n");
      }
    
      return err_code;
    }
    
    #endif // NRF_MODULE_ENABLED(BLE_NUS)
     ble_nus_custom.h
     
     
     /**@file
     *
     * @defgroup ble_nus Nordic UART Service
     * @{
     * @ingroup  ble_sdk_srv
     * @brief    Nordic UART Service implementation.
     *
     * @details The Nordic UART Service is a simple GATT-based service with TX and RX characteristics.
     *          Data received from the peer is passed to the application, and the data received
     *          from the application of this service is sent to the peer as Handle Value
     *          Notifications. This module demonstrates how to implement a custom GATT-based
     *          service and characteristics using the SoftDevice. The service
     *          is used by the application to send and receive ASCII text strings to and from the
     *          peer.
     *
     * @note    The application must register this module as BLE event observer using the
     *          NRF_SDH_BLE_OBSERVER macro. Example:
     *          @code
     *              ble_nus_t instance;
     *              NRF_SDH_BLE_OBSERVER(anything, BLE_NUS_BLE_OBSERVER_PRIO,
     *                                   ble_nus_on_ble_evt, &instance);
     *          @endcode
     */
    #ifndef BLE_NUS_H__
    #define BLE_NUS_H__
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "sdk_config.h"
    #include "ble.h"
    #include "ble_srv_common.h"
    #include "nrf_sdh_ble.h"
    #include "ble_link_ctx_manager.h"
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    /**@brief   Macro for defining a ble_nus instance.
     *
     * @param     _name            Name of the instance.
     * @param[in] _nus_max_clients Maximum number of NUS clients connected at a time.
     * @hideinitializer
     */
    #define BLE_NUS_DEF(_name)                       \
        static ble_cus_t _name;                      \                 
        NRF_SDH_BLE_OBSERVER(_name ## _obs,          \                   
             BLE_NUS_BLE_OBSERVER_PRIO,              \
             ble_cus_on_ble_evt, &_name)
    
    #define BLE_UUID_NUS_SERVICE 0x0001 /**< The UUID of the Nordic UART Service. */
    
    #define OPCODE_LENGTH        1
    #define HANDLE_LENGTH        2
    
    /**@brief   Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
    #if defined(NRF_SDH_BLE_GATT_MAX_MTU_SIZE) && (NRF_SDH_BLE_GATT_MAX_MTU_SIZE != 0)
        #define BLE_NUS_MAX_DATA_LEN (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - OPCODE_LENGTH - HANDLE_LENGTH)
    #else
        #define BLE_NUS_MAX_DATA_LEN (BLE_GATT_MTU_SIZE_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH)
        #warning NRF_SDH_BLE_GATT_MAX_MTU_SIZE is not defined.
    #endif
    
    #define ENUM_BASE 0x00
    
    /**@brief handler enum. */
    enum gatt_handles {
    
        BLE_NUS_EVT_RX_DATA,      /**< Data received. */
        BLE_NUS_EVT_TX_RDY,       /**< Service is ready to accept new data to be transmitted. */
        BLE_NUS_EVT_COMM_STARTED, /**< Notification has been enabled. */
        BLE_NUS_EVT_COMM_STOPPED, /**< Notification has been disabled. */
    }; 
    
    /**@brief Raw Data notification enum */
    enum notify {
      DISABLE,
      ENABLE
    };
    
    /**@brief Custom Service event type. */
    typedef enum {
      //DEFAULT = ENUM_BASE,
      BLE_CUS_EVT_NOTIFICATION_DISABLED = ENUM_BASE + 0x01, /**< Custom value notification disabled event. */
      BLE_CUS_EVT_NOTIFICATION_ENABLED = ENUM_BASE + 0x02,  /**< Custom value notification enabled event. */
      BLE_RSSI_NOTIFICATION_DISABLED = ENUM_BASE + 0x03,    /**< Custom value notification disabled event. */
      BLE_RSSI_NOTIFICATION_ENABLED = ENUM_BASE + 0x04,     /**< Custom value notification enabled event. */
      BLE_CUS_EVT_DISCONNECTED = ENUM_BASE + 0x05,          /**< BLE disconnection event. */
      BLE_CUS_EVT_CONNECTED = ENUM_BASE + 0x06,             /**< BLE connection event. */
      BLE_CUS_EVT_INVALID_INPUT = ENUM_BASE + 0x07          /**< Invalid input for enabling notifications. */
    } ble_cus_evt_type_t;
    
    /**@brief   Nordic UART Service @ref BLE_NUS_EVT_RX_DATA event data.
     *
     * @details This structure is passed to an event when @ref BLE_NUS_EVT_RX_DATA occurs.
     */
    typedef struct
    {
        uint8_t const * p_data; /**< A pointer to the buffer with received data. */
        uint16_t        length; /**< Length of received data. */
    } ble_cus_evt_rx_data_t;
    
    
    /**@brief Custom Service event. */
    typedef struct
    {
      ble_cus_evt_type_t evt_type;       /**< Type of event. */
       union
        {
            ble_cus_evt_rx_data_t rx_data; /**< @ref BLE_NUS_EVT_RX_DATA event data. */
        } params;
      } ble_cus_evt_t;
    
    /* Forward declaration of the ble_cus_t type. */
    typedef struct ble_cus_s ble_cus_t;
    
    
    
    /**@brief Custom Service event handler type. */
    typedef void (* ble_cus_evt_handler_t) (ble_cus_evt_t * p_cus, ble_cus_evt_t *p_evt, int gatt_handler);
    
    
    /**@brief This contains all options and data needed for initialization of the service.*/
    typedef struct
    {
      ble_cus_evt_handler_t evt_handler;                      /**< Event handler to be called for handling events in the Custom Service. */
      uint8_t initial_custom_value;                           /**< Initial custom value */
      ble_srv_cccd_security_mode_t custom_value_char_attr_md; /**< Initial security level for Custom characteristics attribute */
      ble_srv_cccd_security_mode_t rssi_char_attr_md;         /**< Initial security level for RSSI characteristics attribute */
    } ble_cus_init_t;
    
    
    
    /**@brief Custom Service structure. This contains various status information for the service that provided from the BLE struct. */
    struct ble_cus_s {
      ble_cus_evt_handler_t evt_handler;              /**< Event handler to be called for handling events in the Custom Service. */
      uint16_t service_handle;                        /**< Handle of Custom Service (as provided by the BLE stack). */
      uint16_t conn_handle;                           /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
      ble_gatts_char_handles_t custom_value_handles;  /**< Handles related to the Custom Value characteristic (as provided by the BLE stack). */
      blcm_link_ctx_storage_t * const p_link_ctx_storage; /**< Pointer to link context storage with handles of all current connections and its context. */
      ble_gatts_char_handles_t tx_handles;    /**< Handles related to the UN Command characteristic (as provided by the BLE stack). */
      ble_gatts_char_handles_t rx_handles;          /**< Handles related to the RSSI characteristic (as provided by the BLE stack). */
      uint8_t uuid_type;                              /**< Type of the uuid - as provided by the BLE stack. */
    
    };
    
    /**@brief Function for initializing the Custom Service.
     *
     * @param[out]  p_cus       Custom Service structure. This structure will have to be supplied by
     *                          the application. It will be initialized by this function, and will later
     *                          be used to identify this particular service instance.
     * @param[in]   p_cus_init  Information needed to initialize the service.
     *
     * @return      NRF_SUCCESS on successful initialization of service, otherwise an error code.
     */
    uint32_t ble_cus_init(ble_cus_t *p_cus, const ble_cus_init_t *p_cus_init);
    
    
    
    /**@brief Function for handling the Application's BLE Stack events.
     *
     * @details Handles all events from the BLE stack of interest to the Battery Service.
     *
     * @note 
     *
     * @param[in]   p_ble_evt      Event received from the BLE stack.
     * @param[in]   p_context      Custom Service structure.
     */
    void ble_cus_on_ble_evt(ble_evt_t const *p_ble_evt, void *p_context);
    
    
    /**@brief   Function for sending a data to the peer.
     *
     * @details This function sends the input string as an RX characteristic notification to the
     *          peer.
     *
     * @param[in]     p_nus       Pointer to the Nordic UART Service structure.
     * @param[in]     p_data      String to be sent.
     * @param[in,out] p_length    Pointer Length of the string. Amount of sent bytes.
     * @param[in]     conn_handle Connection Handle of the destination client.
     *
     * @retval NRF_SUCCESS If the string was sent successfully. Otherwise, an error code is returned.
     */
    uint32_t ble_cus_data_send(ble_cus_t * p_cus, int16_t custom_value[]);
    
    
    
    #endif // BLE_NUS_H__
    
    /** 
    @} 
    */

    Dear Karl,

    Thanks a lot for your helpful guidance. I have tried once more to write my own services and characteristics based on UART to BLE example as you can see in the attached codes above. But now getting the following errors.

    I do not understand what creates this issue. Could you help me to troubleshoot it ? 

Related