Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

ble_app_uart Tx Characteristics - Read property

Hi, I am using nRF52832 module as connectivity chip (GAP peripheral, GATT server) with ble_app_uart_pca10040_s112 as source.

I am using nRF connect app to test data communication.

  • The data sent from App is received in my Application chip, I have no issues w.r.t to NUS Rx GATT characteristics (0002).
  • With NUS Tx GATT characteristics (0003), I would like to use Read property instead of Notify property. 

    After enabling Read in ble_nus_init(), I am not seeing any response in Read value in the nRF connect App. However, with Notify property, I'm getting the desired response.

I have found similar discussion here. My question is, is it mandatory to use Notify property in order to get received data?

If not, how can I get data using only the Read property(as my application demands this way), disabling the Notify property?

Please help. Thank you in advance.

Parents
  • Hi,

    My question is, is it mandatory to use Notify property in order to get received data?

    it is not mandatory to use notify in order to receive data, but if you use Notify,  it permits notification on characteristic value without acknowledgment. To make it simple in the nRF Connect app if you allowed Notify option for this characteristic whenever you update characteristics from your Nordic device, the new value can be seen in nRF connect app also, that how the notify works, the peripheral can notify master without requiring any acknowledgment. If you use just Read property, which means the master needs to exclusively read it if it wants to get the new data. In nordic SDK5, this reading procedure is handled by softdevice so we won't get any special events on reading. In your nRF connect app try to read it again manually and you will get the latest characteristic value. If your application doesn't want to use notify or indication property just set it to read property and exclusively read that particular characteristic when needed, this should work for you, hope everything is clear. 

  • Thank you very much for the precise information!

    kindly let me know what are you referring as master here.

    What I am able to understand is, after setting Read property in Tx characteristics, if I attempt to read data(from read value of that particular characteristics) from a GATT client, it will work fine with no issues. Please correct me if I'm wrong.

    Also, while testing with Notify property, the data I received has "0x0A" at the end, representing "\n". How can I get rid of it as I suspect my peer device is discarding the packet because of it.

  • Hi,

    kindly let me know what are you referring as master here.

    I was referring to the device in BLE central role in your case, the PC/Android device that's run the nRF connect application.

    What I am able to understand is, after setting Read property in Tx characteristics, if I attempt to read data(from read value of that particular characteristics) from a GATT client, it will work fine with no issues. Please correct me if I'm wrong.

    You're correct!

    Also, while testing with Notify property, the data I received has "0x0A" at the end, representing "\n". How can I get rid of it as I suspect my peer device is discarding the packet because of it.

    You need to get rid of this at the application level, I will give you hint, 

    /**@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;
        }
    }
     

    this is the uart event handler in the example, you can see that only after 'new line' '\n' (hex 0x0A) or if the string has reached the maximum data length the "ble_nus_send" is called, just alter that in a way that fit your need

  • Thank you so much for your response. I am able to remove "0x0A" with the hint you have provided. 

    However, I'm still facing issue with read property,  even after manual read there is no data seen in Read value.

  • Hi,

    Thank you so much for your response. I am able to remove "0x0A" with the hint you have provided. 

    However, I'm still facing issue with read property,  even after manual read there is no data seen in Read value.

    I think I got your problem, correct me if i am wrong.

    It seems that on the example "ble_app_uart_pca10040_s112" you only  changed "add_char_params.char_props.read = 1" in the  "ble_nus_init" function, right?

    if this is the case please understand that the example "ble_app_uart_pca10040_s112" was written to update characterestic value using Notify property, so you need to change this to suit your method.

    step 1

    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;
        ble_add_char_params_t add_char_params;
    
        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.
        memset(&add_char_params, 0, sizeof(add_char_params));
        add_char_params.uuid                     = BLE_UUID_NUS_RX_CHARACTERISTIC;
        add_char_params.uuid_type                = p_nus->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_nus->service_handle, &add_char_params, &p_nus->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_nus->uuid_type;
        add_char_params.max_len           = BLE_NUS_MAX_TX_CHAR_LEN;
        add_char_params.init_len          = 3;//sizeof(uint8_t);
        add_char_params.is_var_len        = true;
        add_char_params.char_props.read = 1;
        uint8_t value[3];
        value[0] = 'h';
        value[1] = 'a';
        value[2] = 'i';
        add_char_params.p_init_value = value;
        add_char_params.is_value_user = 0;
    
        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_nus->service_handle, &add_char_params, &p_nus->tx_handles);
        ///**@snippet [Adding proprietary characteristic to the SoftDevice] */
        
    }

    please change your "ble_nus_init" function  in ble_nus.c to this , please notice the changes in adding the second characterestic, also i set the initial value as 'hai' so when you first read it, you will see that 

    step 2

    go to ble_nus_data_send function  in ble_nus.c, right now this is only tailored to send new data as Notificaiton, change this to the following.

    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_gatts_value_t  gatts_value;
        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));
        memset(&gatts_value,0,sizeof(gatts_value));
        //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;
        gatts_value.len = *p_length;
        gatts_value.offset = 0;
        gatts_value.p_value = p_data;
    
        return sd_ble_gatts_value_set(conn_handle, p_nus->tx_handles.value_handle, &gatts_value);
        //return sd_ble_gatts_hvx(conn_handle, &hvx_params);
    }

    now after sending new data from serial terminal, upon reading the characteristic  you will get the new values in nRF connect app, if any issue persist let me Know!

  • Yes, you got that right. Thank you for the insight on ble_nus functions, now my peer device communicates with nRF module successfully.  

    Thank you very much for your time and support!

Reply Children
No Data
Related