Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Nus client and write to secure characteristic

Hi,

I have modified the nus service and added two new characteristics called txs and rxs which support read and write protection.

on the peripheral i have set BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM for txs and rxs

The service is working as expected from NRF connect for android.

Now I have modified the nus client service as well and implemented my own ble_nus_c_string_send_secure, which writes to the secure characteristic.

I have bonded the central device with nus client to peripheral with nus service.

the ble_nus_c_string_send command works and peripheral receives the string, but ble_nus_c_string_send_secure command returns NRF_SUCCESS but peripheral does not receive the string.

Am I missing something?

for writing to a secured characteristic, do I have to pass more to the sd_ble_gattc_write function?

Thanks,

Raghav

Parents
  • Hello,

    So, what does your implementation look like? What is the difference between ble_nus_c_string_send and ble_nus_c_string_send_secure? Do they write to the same characteristic, or does it write to the new characteristics, rxs? Is the rxs set up properly on the peripheral?

     

    It is a bit difficult to say what the issue may be only with a brief description of your implementation. Could you upload at least the implementation of ble_nus_c_string_send_secure()?

     

    Best regards,

    Edvin

Reply
  • Hello,

    So, what does your implementation look like? What is the difference between ble_nus_c_string_send and ble_nus_c_string_send_secure? Do they write to the same characteristic, or does it write to the new characteristics, rxs? Is the rxs set up properly on the peripheral?

     

    It is a bit difficult to say what the issue may be only with a brief description of your implementation. Could you upload at least the implementation of ble_nus_c_string_send_secure()?

     

    Best regards,

    Edvin

Children
  • Hi Edvin,

    I will attach files that I have changed and this is how I have configured the NUS service on the peripheral

    BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&nus_init.nus_rxs_attr_md.cccd_write_perm);
    BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&nus_init.nus_rxs_attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&nus_init.nus_rxs_attr_md.write_perm);
    
    BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&nus_init.nus_txs_attr_md.cccd_write_perm);
    BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&nus_init.nus_txs_attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&nus_init.nus_txs_attr_md.write_perm);


    Please check the function ble_nus_c_string_send_secure in the nus client
  • /**
     * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
     * 
     * All rights reserved.
     * 
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     * 
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     * 
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     * 
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     * 
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     * 
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     * 
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * 
     */
    #include "sdk_common.h"
    #if NRF_MODULE_ENABLED(BLE_NUS)
    #include "ble.h"
    #include "ble_nus.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_UUID_NUS_TXS_CHARACTERISTIC 0x0005               /**< The UUID of the TXS Characteristic. */
    #define BLE_UUID_NUS_RXS_CHARACTERISTIC 0x0004               /**< The UUID of the RXS 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     Nordic UART Service structure.
     * @param[in] p_ble_evt Pointer to the event received from BLE stack.
     */
    static void on_connect(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
    {
        ret_code_t                 err_code;
        ble_nus_evt_t              evt;
        ble_gatts_value_t          gatts_val;
        uint8_t                    cccd_value[2];
        ble_nus_client_context_t * p_client = NULL;
    
        err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
                                     p_ble_evt->evt.gap_evt.conn_handle,
                                     (void *) &p_client);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
                          p_ble_evt->evt.gap_evt.conn_handle);
        }
    
        uint8_t send_comm_started_event = 0;
    
        /* Check the hosts CCCD value to inform of readiness to send data using the RX characteristic */
        memset(&gatts_val, 0, sizeof(ble_gatts_value_t));
        gatts_val.p_value = cccd_value;
        gatts_val.len     = sizeof(cccd_value);
        gatts_val.offset  = 0;
    
        err_code = sd_ble_gatts_value_get(p_ble_evt->evt.gap_evt.conn_handle,
                                          p_nus->tx_handles.cccd_handle,
                                          &gatts_val);
    
        if ((err_code == NRF_SUCCESS)     &&
            (p_nus->data_handler != NULL) &&
            ble_srv_is_notification_enabled(gatts_val.p_value))
        {
            if (p_client != NULL)
            {
                p_client->is_notification_enabled = true;
            }
            send_comm_started_event = 1;
        }
    
        /* Check the hosts CCCD value to inform of readiness to send data using the RX characteristic */
        memset(&gatts_val, 0, sizeof(ble_gatts_value_t));
        gatts_val.p_value = cccd_value;
        gatts_val.len     = sizeof(cccd_value);
        gatts_val.offset  = 0;
    
        err_code = sd_ble_gatts_value_get(p_ble_evt->evt.gap_evt.conn_handle,
                                          p_nus->txs_handles.cccd_handle,
                                          &gatts_val);
    
        if ((err_code == NRF_SUCCESS)     &&
            (p_nus->data_handler != NULL) &&
            ble_srv_is_notification_enabled(gatts_val.p_value))
        {
            if (p_client != NULL)
            {
                p_client->is_secure_notification_enabled = true;
            }
            send_comm_started_event = 1;
        }
    
        if(send_comm_started_event) 
        {
            memset(&evt, 0, sizeof(ble_nus_evt_t));
            evt.type        = BLE_NUS_EVT_COMM_STARTED;
            evt.p_nus       = p_nus;
            evt.conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
            evt.p_link_ctx  = p_client;
    
            p_nus->data_handler(&evt);
        }
    
    }
    
    
    /**@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_nus_t * p_nus, ble_evt_t const * p_ble_evt)
    {
        ret_code_t                    err_code;
        ble_nus_evt_t                 evt;
        ble_nus_client_context_t    * p_client;
        ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    
        err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
                                     p_ble_evt->evt.gatts_evt.conn_handle,
                                     (void *) &p_client);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
                          p_ble_evt->evt.gatts_evt.conn_handle);
        }
    
        memset(&evt, 0, sizeof(ble_nus_evt_t));
        evt.p_nus       = p_nus;
        evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
        evt.p_link_ctx  = p_client;
    
        if ((p_evt_write->handle == p_nus->tx_handles.cccd_handle || p_evt_write->handle == p_nus->txs_handles.cccd_handle) &&
            (p_evt_write->len == 2))
        {
            if (p_client != NULL)
            {
                if(p_evt_write->handle == p_nus->tx_handles.cccd_handle) {
                  if (ble_srv_is_notification_enabled(p_evt_write->data))
                  {
                      p_client->is_notification_enabled = true;
                      evt.type                          = BLE_NUS_EVT_COMM_STARTED;
                  }
                  else
                  {
                      p_client->is_notification_enabled = false;
                      evt.type                          = BLE_NUS_EVT_COMM_STOPPED;
                  }
                } else {
                  if (ble_srv_is_notification_enabled(p_evt_write->data))
                  {
                      p_client->is_secure_notification_enabled = true;
                      evt.type                          = BLE_NUS_EVT_COMM_STARTED;
                  }
                  else
                  {
                      p_client->is_secure_notification_enabled = false;
                      evt.type                          = BLE_NUS_EVT_COMM_STOPPED;
                  }
                }
                
                if (p_nus->data_handler != NULL)
                {
                    p_nus->data_handler(&evt);
                }
    
            }
        }
        else if ((p_evt_write->handle == p_nus->rx_handles.value_handle || p_evt_write->handle == p_nus->rxs_handles.value_handle) &&
                 (p_nus->data_handler != NULL))
        {
            if(p_evt_write->handle == p_nus->rxs_handles.value_handle) 
            {
              evt.type                = BLE_NUS_EVT_RXS_DATA;
            } 
            else 
            {
              evt.type                = BLE_NUS_EVT_RX_DATA;
            }
            evt.params.rx_data.p_data = p_evt_write->data;
            evt.params.rx_data.length = p_evt_write->len;
    
            p_nus->data_handler(&evt);
        }
        else
        {
            // Do Nothing. This event is not relevant for this service.
        }
    }
    
    
    /**@brief Function for handling the @ref BLE_GATTS_EVT_HVN_TX_COMPLETE 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_hvx_tx_complete(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
    {
        ret_code_t                 err_code;
        ble_nus_evt_t              evt;
        ble_nus_client_context_t * p_client;
    
        err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
                                     p_ble_evt->evt.gatts_evt.conn_handle,
                                     (void *) &p_client);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
                          p_ble_evt->evt.gatts_evt.conn_handle);
            return;
        }
    
        if (p_client->is_notification_enabled)
        {
            memset(&evt, 0, sizeof(ble_nus_evt_t));
            evt.type        = BLE_NUS_EVT_TX_RDY;
            evt.p_nus       = p_nus;
            evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
            evt.p_link_ctx  = p_client;
    
            p_nus->data_handler(&evt);
        } else if (p_client->is_secure_notification_enabled)
        {
            memset(&evt, 0, sizeof(ble_nus_evt_t));
            evt.type        = BLE_NUS_EVT_TXS_RDY;
            evt.p_nus       = p_nus;
            evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
            evt.p_link_ctx  = p_client;
    
            p_nus->data_handler(&evt);
        }
    }
    
    
    /**@brief Function for adding TX characteristic.
     *
     * @param[in] p_nus       Nordic UART Service structure.
     * @param[in] p_nus_init  Information needed to initialize the service.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static uint32_t tx_char_add(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
    {
        /**@snippet [Adding proprietary characteristic to the SoftDevice] */
        ble_gatts_char_md_t char_md;
        ble_gatts_attr_md_t cccd_md;
        ble_gatts_attr_t    attr_char_value;
        ble_uuid_t          ble_uuid;
        ble_gatts_attr_md_t attr_md;
    
        memset(&cccd_md, 0, sizeof(cccd_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
    
        cccd_md.vloc = BLE_GATTS_VLOC_STACK;
    
        memset(&char_md, 0, sizeof(char_md));
    
        char_md.char_props.notify = 1;
        char_md.p_char_user_desc  = NULL;
        char_md.p_char_pf         = NULL;
        char_md.p_user_desc_md    = NULL;
        char_md.p_cccd_md         = &cccd_md;
        char_md.p_sccd_md         = NULL;
    
        ble_uuid.type = p_nus->uuid_type;
        ble_uuid.uuid = BLE_UUID_NUS_TX_CHARACTERISTIC;
    
        memset(&attr_md, 0, sizeof(attr_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
    
        attr_md.vloc    = BLE_GATTS_VLOC_STACK;
        attr_md.rd_auth = 0;
        attr_md.wr_auth = 0;
        attr_md.vlen    = 1;
    
        memset(&attr_char_value, 0, sizeof(attr_char_value));
    
        attr_char_value.p_uuid    = &ble_uuid;
        attr_char_value.p_attr_md = &attr_md;
        attr_char_value.init_len  = sizeof(uint8_t);
        attr_char_value.init_offs = 0;
        attr_char_value.max_len   = BLE_NUS_MAX_TX_CHAR_LEN;
    
        return sd_ble_gatts_characteristic_add(p_nus->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_nus->tx_handles);
        /**@snippet [Adding proprietary characteristic to the SoftDevice] */
    }
    
    /**@brief Function for adding TXS characteristic.
     *
     * @param[in] p_nus       Nordic UART Service structure.
     * @param[in] p_nus_init  Information needed to initialize the service.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static uint32_t txs_char_add(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
    {
        /**@snippet [Adding proprietary characteristic to the SoftDevice] */
        ble_gatts_char_md_t char_md;
        ble_gatts_attr_md_t cccd_md;
        ble_gatts_attr_t    attr_char_value;
        ble_uuid_t          ble_uuid;
        ble_gatts_attr_md_t attr_md;
    
        memset(&cccd_md, 0, sizeof(cccd_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
        cccd_md.write_perm = p_nus_init->nus_txs_attr_md.cccd_write_perm;
    
        cccd_md.vloc = BLE_GATTS_VLOC_STACK;
    
        memset(&char_md, 0, sizeof(char_md));
    
        char_md.char_props.notify = 1;
        char_md.p_char_user_desc  = NULL;
        char_md.p_char_pf         = NULL;
        char_md.p_user_desc_md    = NULL;
        char_md.p_cccd_md         = &cccd_md;
        char_md.p_sccd_md         = NULL;
    
        ble_uuid.type = p_nus->uuid_type;
        ble_uuid.uuid = BLE_UUID_NUS_TXS_CHARACTERISTIC;
    
        memset(&attr_md, 0, sizeof(attr_md));
    
        attr_md.read_perm  = p_nus_init->nus_txs_attr_md.read_perm;
        attr_md.write_perm = p_nus_init->nus_txs_attr_md.write_perm;
    
        attr_md.vloc    = BLE_GATTS_VLOC_STACK;
        attr_md.rd_auth = 0;
        attr_md.wr_auth = 0;
        attr_md.vlen    = 1;
    
        memset(&attr_char_value, 0, sizeof(attr_char_value));
    
        attr_char_value.p_uuid    = &ble_uuid;
        attr_char_value.p_attr_md = &attr_md;
        attr_char_value.init_len  = sizeof(uint8_t);
        attr_char_value.init_offs = 0;
        attr_char_value.max_len   = BLE_NUS_MAX_TX_CHAR_LEN;
    
        return sd_ble_gatts_characteristic_add(p_nus->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_nus->txs_handles);
        /**@snippet [Adding proprietary characteristic to the SoftDevice] */
    }
    
    /**@brief Function for adding RX characteristic.
     *
     * @param[in] p_nus       Nordic UART Service structure.
     * @param[in] p_nus_init  Information needed to initialize the service.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static uint32_t rx_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
    {
        ble_gatts_char_md_t char_md;
        ble_gatts_attr_t    attr_char_value;
        ble_uuid_t          ble_uuid;
        ble_gatts_attr_md_t attr_md;
    
        memset(&char_md, 0, sizeof(char_md));
    
        char_md.char_props.write         = 1;
        char_md.char_props.write_wo_resp = 1;
        char_md.p_char_user_desc         = NULL;
        char_md.p_char_pf                = NULL;
        char_md.p_user_desc_md           = NULL;
        char_md.p_cccd_md                = NULL;
        char_md.p_sccd_md                = NULL;
    
        ble_uuid.type = p_nus->uuid_type;
        ble_uuid.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC;
    
        memset(&attr_md, 0, sizeof(attr_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
    
        attr_md.vloc    = BLE_GATTS_VLOC_STACK;
        attr_md.rd_auth = 0;
        attr_md.wr_auth = 0;
        attr_md.vlen    = 1;
    
        memset(&attr_char_value, 0, sizeof(attr_char_value));
    
        attr_char_value.p_uuid    = &ble_uuid;
        attr_char_value.p_attr_md = &attr_md;
        attr_char_value.init_len  = 1;
        attr_char_value.init_offs = 0;
        attr_char_value.max_len   = BLE_NUS_MAX_RX_CHAR_LEN;
    
        return sd_ble_gatts_characteristic_add(p_nus->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_nus->rx_handles);
    }
    
    /**@brief Function for adding RXS characteristic.
     *
     * @param[in] p_nus       Nordic UART Service structure.
     * @param[in] p_nus_init  Information needed to initialize the service.
     *
     * @return NRF_SUCCESS on success, otherwise an error code.
     */
    static uint32_t rxs_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
    {
        ble_gatts_char_md_t char_md;
        ble_gatts_attr_md_t cccd_md;
        ble_gatts_attr_t    attr_char_value;
        ble_uuid_t          ble_uuid;
        ble_gatts_attr_md_t attr_md;
    
        memset(&cccd_md, 0, sizeof(cccd_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
        cccd_md.write_perm = p_nus_init->nus_rxs_attr_md.cccd_write_perm;
        cccd_md.vloc       = BLE_GATTS_VLOC_STACK;
    
        memset(&char_md, 0, sizeof(char_md));
    
        char_md.char_props.write         = 1;
        char_md.char_props.write_wo_resp = 1;
        char_md.p_char_user_desc         = NULL;
        char_md.p_char_pf                = NULL;
        char_md.p_user_desc_md           = NULL;
        char_md.p_cccd_md                = &cccd_md;
        char_md.p_sccd_md                = NULL;
    
        ble_uuid.type = p_nus->uuid_type;
        ble_uuid.uuid = BLE_UUID_NUS_RXS_CHARACTERISTIC;
    
        memset(&attr_md, 0, sizeof(attr_md));
    
        attr_md.read_perm  = p_nus_init->nus_rxs_attr_md.read_perm;
        attr_md.write_perm = p_nus_init->nus_rxs_attr_md.write_perm;
    
        attr_md.vloc    = BLE_GATTS_VLOC_STACK;
        attr_md.rd_auth = 0;
        attr_md.wr_auth = 0;
        attr_md.vlen    = 1;
    
        memset(&attr_char_value, 0, sizeof(attr_char_value));
    
        attr_char_value.p_uuid    = &ble_uuid;
        attr_char_value.p_attr_md = &attr_md;
        attr_char_value.init_len  = 1;
        attr_char_value.init_offs = 0;
        attr_char_value.max_len   = BLE_NUS_MAX_RX_CHAR_LEN;
    
        return sd_ble_gatts_characteristic_add(p_nus->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_nus->rxs_handles);
    }
    
    void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
    {
        if ((p_context == NULL) || (p_ble_evt == NULL))
        {
            return;
        }
    
        ble_nus_t * p_nus = (ble_nus_t *)p_context;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                on_connect(p_nus, p_ble_evt);
                break;
    
            case BLE_GATTS_EVT_WRITE:
                on_write(p_nus, p_ble_evt);
                break;
    
            case BLE_GATTS_EVT_HVN_TX_COMPLETE:
                on_hvx_tx_complete(p_nus, p_ble_evt);
                break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
    {
        ret_code_t    err_code;
        ble_uuid_t    ble_uuid;
        ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
    
        VERIFY_PARAM_NOT_NULL(p_nus);
        VERIFY_PARAM_NOT_NULL(p_nus_init);
    
        // Initialize the service structure.
        p_nus->data_handler = p_nus_init->data_handler;
    
        /**@snippet [Adding proprietary Service to the SoftDevice] */
        // Add a custom base UUID.
        err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
        VERIFY_SUCCESS(err_code);
    
        ble_uuid.type = p_nus->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_nus->service_handle);
        /**@snippet [Adding proprietary Service to the SoftDevice] */
        VERIFY_SUCCESS(err_code);
    
        // Add the RX Characteristic.
        err_code = rx_char_add(p_nus, p_nus_init);
        VERIFY_SUCCESS(err_code);
    
        // Add the TX Characteristic.
        err_code = tx_char_add(p_nus, p_nus_init);
        VERIFY_SUCCESS(err_code);
    
        // Add the RXS Characteristic.
        err_code = rxs_char_add(p_nus, p_nus_init);
        VERIFY_SUCCESS(err_code);
    
        // Add the TXS Characteristic.
        err_code = txs_char_add(p_nus, p_nus_init);
        VERIFY_SUCCESS(err_code);
    
        return NRF_SUCCESS;
    }
    
    
    uint32_t ble_nus_data_send(ble_nus_t * p_nus,
                               uint8_t   * p_data,
                               uint16_t  * p_length,
                               uint16_t    conn_handle)
    {
        ret_code_t                 err_code;
        ble_gatts_hvx_params_t     hvx_params;
        ble_nus_client_context_t * p_client;
    
        VERIFY_PARAM_NOT_NULL(p_nus);
    
        err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage, conn_handle, (void *) &p_client);
        VERIFY_SUCCESS(err_code);
    
        if ((conn_handle == BLE_CONN_HANDLE_INVALID) || (p_client == NULL))
        {
            return NRF_ERROR_NOT_FOUND;
        }
    
        if (!p_client->is_notification_enabled)
        {
            return NRF_ERROR_INVALID_STATE;
        }
    
        if (*p_length > BLE_NUS_MAX_DATA_LEN)
        {
            return NRF_ERROR_INVALID_PARAM;
        }
    
        memset(&hvx_params, 0, sizeof(hvx_params));
    
        hvx_params.handle = p_nus->tx_handles.value_handle;
        hvx_params.p_data = p_data;
        hvx_params.p_len  = p_length;
        hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
    
        return sd_ble_gatts_hvx(conn_handle, &hvx_params);
    }
    
    uint32_t ble_nus_data_send_secure(ble_nus_t * p_nus,
                               uint8_t   * p_data,
                               uint16_t  * p_length,
                               uint16_t    conn_handle)
    {
        ret_code_t                 err_code;
        ble_gatts_hvx_params_t     hvx_params;
        ble_nus_client_context_t * p_client;
    
        VERIFY_PARAM_NOT_NULL(p_nus);
    
        err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage, conn_handle, (void *) &p_client);
        VERIFY_SUCCESS(err_code);
    
        if ((conn_handle == BLE_CONN_HANDLE_INVALID) || (p_client == NULL))
        {
            return NRF_ERROR_NOT_FOUND;
        }
    
        if (!p_client->is_secure_notification_enabled)
        {
            return NRF_ERROR_INVALID_STATE;
        }
    
        if (*p_length > BLE_NUS_MAX_DATA_LEN)
        {
            return NRF_ERROR_INVALID_PARAM;
        }
    
        memset(&hvx_params, 0, sizeof(hvx_params));
    
        hvx_params.handle = p_nus->txs_handles.value_handle;
        hvx_params.p_data = p_data;
        hvx_params.p_len  = p_length;
        hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
    
        return sd_ble_gatts_hvx(conn_handle, &hvx_params);
    }
    
    #endif // NRF_MODULE_ENABLED(BLE_NUS)
    

  • /**
     * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
     * 
     * All rights reserved.
     * 
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     * 
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     * 
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     * 
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     * 
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     * 
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     * 
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * 
     */
    
    #include "sdk_common.h"
    #if NRF_MODULE_ENABLED(BLE_NUS_C)
    #include <stdlib.h>
    
    #include "ble.h"
    #include "ble_nus_c.h"
    #include "ble_gattc.h"
    #include "ble_srv_common.h"
    #include "app_error.h"
    
    #define NRF_LOG_MODULE_NAME ble_nus_c
    #include "nrf_log.h"
    NRF_LOG_MODULE_REGISTER();
    
    void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt)
    {
        ble_nus_c_evt_t nus_c_evt;
        memset(&nus_c_evt,0,sizeof(ble_nus_c_evt_t));
    
        ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
    
        // Check if the NUS was discovered.
        if (    (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
            &&  (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_NUS_SERVICE)
            &&  (p_evt->params.discovered_db.srv_uuid.type == p_ble_nus_c->uuid_type))
        {
            for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
            {
                switch (p_chars[i].characteristic.uuid.uuid)
                {
                    case BLE_UUID_NUS_RX_CHARACTERISTIC:
                        nus_c_evt.handles.nus_rx_handle = p_chars[i].characteristic.handle_value;
                        break;
    
                    case BLE_UUID_NUS_TX_CHARACTERISTIC:
                        nus_c_evt.handles.nus_tx_handle = p_chars[i].characteristic.handle_value;
                        nus_c_evt.handles.nus_tx_cccd_handle = p_chars[i].cccd_handle;
                        break;
    
                    case BLE_UUID_NUS_RXS_CHARACTERISTIC:
                        nus_c_evt.handles.nus_rxs_handle = p_chars[i].characteristic.handle_value;
                        break;
    
                    case BLE_UUID_NUS_TXS_CHARACTERISTIC:
                        nus_c_evt.handles.nus_txs_handle = p_chars[i].characteristic.handle_value;
                        nus_c_evt.handles.nus_txs_cccd_handle = p_chars[i].cccd_handle;
                        break;
    
                    default:
                        break;
                }
            }
            if (p_ble_nus_c->evt_handler != NULL)
            {
                nus_c_evt.conn_handle = p_evt->conn_handle;
                nus_c_evt.evt_type    = BLE_NUS_C_EVT_DISCOVERY_COMPLETE;
                p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
            }
        }
    }
    
    /**@brief     Function for handling Handle Value Notification received from the SoftDevice.
     *
     * @details   This function will uses the Handle Value Notification received from the SoftDevice
     *            and checks if it is a notification of the NUS TX characteristic from the peer. If
     *            it is, this function will decode the data and send it to the
     *            application.
     *
     * @param[in] p_ble_nus_c Pointer to the NUS Client structure.
     * @param[in] p_ble_evt   Pointer to the BLE event received.
     */
    static void on_hvx(ble_nus_c_t * p_ble_nus_c, ble_evt_t const * p_ble_evt)
    {
        // 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_evt->evt.gattc_evt.params.hvx.handle == p_ble_nus_c->handles.nus_txs_handle)
            && (p_ble_nus_c->evt_handler != NULL))
        {
            ble_nus_c_evt_t ble_nus_c_evt;
            if(p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_nus_c->handles.nus_txs_handle) {
              ble_nus_c_evt.evt_type = BLE_NUS_C_EVT_NUS_TXS_EVT;
            } else {
              ble_nus_c_evt.evt_type = BLE_NUS_C_EVT_NUS_TX_EVT;
            }
            ble_nus_c_evt.p_data   = (uint8_t *)p_ble_evt->evt.gattc_evt.params.hvx.data;
            ble_nus_c_evt.data_len = p_ble_evt->evt.gattc_evt.params.hvx.len;
    
            p_ble_nus_c->evt_handler(p_ble_nus_c, &ble_nus_c_evt);
            NRF_LOG_DEBUG("Client sending data.");
        }
    }
    
    uint32_t ble_nus_c_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_c_init)
    {
        uint32_t      err_code;
        ble_uuid_t    uart_uuid;
        ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
    
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init);
    
        err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type);
        VERIFY_SUCCESS(err_code);
    
        uart_uuid.type = p_ble_nus_c->uuid_type;
        uart_uuid.uuid = BLE_UUID_NUS_SERVICE;
    
        p_ble_nus_c->conn_handle           = BLE_CONN_HANDLE_INVALID;
        p_ble_nus_c->evt_handler           = p_ble_nus_c_init->evt_handler;
        p_ble_nus_c->handles.nus_tx_handle = BLE_GATT_HANDLE_INVALID;
        p_ble_nus_c->handles.nus_rx_handle = BLE_GATT_HANDLE_INVALID;
        p_ble_nus_c->handles.nus_txs_handle = BLE_GATT_HANDLE_INVALID;
        p_ble_nus_c->handles.nus_rxs_handle = BLE_GATT_HANDLE_INVALID;
    
        return ble_db_discovery_evt_register(&uart_uuid);
    }
    
    void ble_nus_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ble_nus_c_t * p_ble_nus_c = (ble_nus_c_t *)p_context;
    
        if ((p_ble_nus_c == NULL) || (p_ble_evt == NULL))
        {
            return;
        }
    
        if ( (p_ble_nus_c->conn_handle != BLE_CONN_HANDLE_INVALID)
           &&(p_ble_nus_c->conn_handle != p_ble_evt->evt.gap_evt.conn_handle)
           )
        {
            return;
        }
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GATTC_EVT_HVX:
                on_hvx(p_ble_nus_c, p_ble_evt);
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                if (p_ble_evt->evt.gap_evt.conn_handle == p_ble_nus_c->conn_handle
                        && p_ble_nus_c->evt_handler != NULL)
                {
                    ble_nus_c_evt_t nus_c_evt;
    
                    nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCONNECTED;
    
                    p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID;
                    p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
                }
                break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    /**@brief Function for creating a message for writing to the CCCD. */
    static uint32_t cccd_configure(uint16_t conn_handle, uint16_t cccd_handle, bool enable)
    {
        uint8_t buf[BLE_CCCD_VALUE_LEN];
    
        buf[0] = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
        buf[1] = 0;
    
        ble_gattc_write_params_t const write_params =
        {
            .write_op = BLE_GATT_OP_WRITE_REQ,
            .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
            .handle   = cccd_handle,
            .offset   = 0,
            .len      = sizeof(buf),
            .p_value  = buf
        };
    
        return sd_ble_gattc_write(conn_handle, &write_params);
    }
    
    
    uint32_t ble_nus_c_tx_notif_enable(ble_nus_c_t * p_ble_nus_c)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if ( (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
           ||(p_ble_nus_c->handles.nus_tx_cccd_handle == BLE_GATT_HANDLE_INVALID)
           )
        {
            return NRF_ERROR_INVALID_STATE;
        }
        return cccd_configure(p_ble_nus_c->conn_handle,p_ble_nus_c->handles.nus_tx_cccd_handle, true);
    }
    
    uint32_t ble_nus_c_txs_notif_enable(ble_nus_c_t * p_ble_nus_c)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if ( (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
           ||(p_ble_nus_c->handles.nus_txs_cccd_handle == BLE_GATT_HANDLE_INVALID)
           )
        {
            return NRF_ERROR_INVALID_STATE;
        }
        return cccd_configure(p_ble_nus_c->conn_handle,p_ble_nus_c->handles.nus_txs_cccd_handle, true);
    }
    
    uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if (length > BLE_NUS_MAX_DATA_LEN)
        {
            NRF_LOG_WARNING("Content too long.");
            return NRF_ERROR_INVALID_PARAM;
        }
        if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
        {
            NRF_LOG_WARNING("Connection handle invalid.");
            return NRF_ERROR_INVALID_STATE;
        }
    
        ble_gattc_write_params_t const write_params =
        {
            .write_op = BLE_GATT_OP_WRITE_CMD,
            .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
            .handle   = p_ble_nus_c->handles.nus_rx_handle,
            .offset   = 0,
            .len      = length,
            .p_value  = p_string
        };
    
        return sd_ble_gattc_write(p_ble_nus_c->conn_handle, &write_params);
    }
    
    uint32_t ble_nus_c_string_send_secure(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if (length > BLE_NUS_MAX_DATA_LEN)
        {
            NRF_LOG_WARNING("Content too long.");
            return NRF_ERROR_INVALID_PARAM;
        }
        if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
        {
            NRF_LOG_WARNING("Connection handle invalid.");
            return NRF_ERROR_INVALID_STATE;
        }
    
        ble_gattc_write_params_t const write_params =
        {
            .write_op = BLE_GATT_OP_WRITE_CMD,
            .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
            .handle   = p_ble_nus_c->handles.nus_rxs_handle,
            .offset   = 0,
            .len      = length,
            .p_value  = p_string
        };
    
        return sd_ble_gattc_write(p_ble_nus_c->conn_handle, &write_params);
    }
    
    uint32_t ble_nus_c_handles_assign(ble_nus_c_t               * p_ble_nus,
                                      uint16_t                    conn_handle,
                                      ble_nus_c_handles_t const * p_peer_handles)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus);
    
        p_ble_nus->conn_handle = conn_handle;
        if (p_peer_handles != NULL)
        {
            p_ble_nus->handles.nus_tx_cccd_handle = p_peer_handles->nus_tx_cccd_handle;
            p_ble_nus->handles.nus_tx_handle      = p_peer_handles->nus_tx_handle;
            p_ble_nus->handles.nus_rx_handle      = p_peer_handles->nus_rx_handle;
            p_ble_nus->handles.nus_txs_cccd_handle = p_peer_handles->nus_txs_cccd_handle;
            p_ble_nus->handles.nus_txs_handle      = p_peer_handles->nus_txs_handle;
            p_ble_nus->handles.nus_rxs_handle      = p_peer_handles->nus_rxs_handle;
        }
        return NRF_SUCCESS;
    }
    #endif // NRF_MODULE_ENABLED(BLE_NUS_C)
    

  • Hello,

    I wasn't able to compile with your ble_nus_c and ble_nus files, until I moved the BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM to inside the ble_nus.c file. Where did you place them?

     

     

    Did you actually encrypt the link? Does any of the devices initiate encryption, and do you respond to it in the other device?

     

    Best regards,

    Edvin

Related