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

ble_nus_data_send returns 0x5 error code

Hello,

I wanted to send data over peripheral device to the central device by using ble UART example. I used ble_nus_data_send() function in main(void) function. I have checked if the data was sent or not . ble_nus_data_send() returned 0x5 instead of NRF_SUCCESS. I also tried to use it in main() function, but nothing changed.

My ultimate goal is to send data when peripheral and central device pair each other.

Best Regards

Parents
  • I am sorry for the delayThe staffing is reduced during easter due to holidays and I will be gone this week, but I will be back Tuesday next week and will look at your ticket then.

    Best regards,

    Simon

  • Hello Simon,

    I am still having this problem. I tried with this basic function:

    static void send_data(void)
    {
        uint32_t err_code;
        uint16_t length = 6;
        NRF_LOG_INFO("Start");
        uint8_t array[6];
        array[0] = 'h';
        array[1] = 'e';
        array[2] = 'l';
        array[3] = 'l';
        array[4] = 'o';
        array[5] = '\n';
    
        err_code = ble_nus_data_send(&m_nus, array, &length, m_conn_handle);
        NRF_LOG_INFO ("ble_nus_data_send returned 0x%x", err_code)
        
    } 
    


    I calIed this function in BLE_GAP_EVT_CONNECTED case, but got same error (0x8). I think it is a mistake calling this function in BLE_GAP_EVT_CONNECTED.
    I tought that maybe I should create function in uart_event_handle() function, but this function is about receiving data, isn't it ?
    I also checked if my notifications are enabled or not. I followed instructions from: https://devzone.nordicsemi.com/f/nordic-q-a/42244/nrf_error_invalid_state-when-calling-ble_nus_data_send-after-connection-is-established
    I can see that notifications are enabled.
    I would try send data with button action in bsp_event_handler() function, but I just want to send data after connection.
    I hope that I specified my problem clearly. If my function has no error, I would like to know that where should I call my function or create in somewhere else.

    Best Regards

  • The reason it is failing is that the client (often the central) hasn't enabled notifications yet. In order to send data from the server (the device where the services and characteristics are stored and it is often the peripheral device) to the client, notifications need to be enabled, which is done by writing to the CCCD

    I assume you are using the ble_app_uart central and the ble_app_uart peripheral examples. In that case, the ble_app_uart central example will enable notifications after service discovery is completed. Look at 

    \nRF5_SDK_16.0.0\examples\ble_central\ble_app_uart_c\main.c-->ble_nus_c_evt_handler()-->BLE_NUS_C_EVT_DISCOVERY_COMPLETE-->ble_nus_c_tx_notif_enable()

    static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt)
    {
        ret_code_t err_code;
    
        switch (p_ble_nus_evt->evt_type)
        {
            case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
                NRF_LOG_INFO("Discovery complete.");
                err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
                APP_ERROR_CHECK(err_code);
    
                err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
                APP_ERROR_CHECK(err_code);
                NRF_LOG_INFO("Connected to device with Nordic UART Service.");
                break;

    When the ble_app_uart peripheral device receives this write, the function on_write() in \nRF5_SDK_16.0.0\components\ble\ble_services\ble_nus\ble_nus.c will get triggered, and  p_client->is_notification_enabled is  set to "true":

    static void on_write(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
    {
        .
        .
        .
    
        if ((p_evt_write->handle == p_nus->tx_handles.cccd_handle) &&
            (p_evt_write->len == 2))
        {
            if (p_client != NULL)
            {
                if (ble_srv_is_notification_enabled(p_evt_write->data))
                {
                    p_client->is_notification_enabled = true;
                    evt.type                          = BLE_NUS_EVT_COMM_STARTED;
                }

    After this happens, you can send data from the server (ble_app_uart peripheral) to the client (ble_app_uart central).

    Best regards,

    Simon

Reply
  • The reason it is failing is that the client (often the central) hasn't enabled notifications yet. In order to send data from the server (the device where the services and characteristics are stored and it is often the peripheral device) to the client, notifications need to be enabled, which is done by writing to the CCCD

    I assume you are using the ble_app_uart central and the ble_app_uart peripheral examples. In that case, the ble_app_uart central example will enable notifications after service discovery is completed. Look at 

    \nRF5_SDK_16.0.0\examples\ble_central\ble_app_uart_c\main.c-->ble_nus_c_evt_handler()-->BLE_NUS_C_EVT_DISCOVERY_COMPLETE-->ble_nus_c_tx_notif_enable()

    static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt)
    {
        ret_code_t err_code;
    
        switch (p_ble_nus_evt->evt_type)
        {
            case BLE_NUS_C_EVT_DISCOVERY_COMPLETE:
                NRF_LOG_INFO("Discovery complete.");
                err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles);
                APP_ERROR_CHECK(err_code);
    
                err_code = ble_nus_c_tx_notif_enable(p_ble_nus_c);
                APP_ERROR_CHECK(err_code);
                NRF_LOG_INFO("Connected to device with Nordic UART Service.");
                break;

    When the ble_app_uart peripheral device receives this write, the function on_write() in \nRF5_SDK_16.0.0\components\ble\ble_services\ble_nus\ble_nus.c will get triggered, and  p_client->is_notification_enabled is  set to "true":

    static void on_write(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
    {
        .
        .
        .
    
        if ((p_evt_write->handle == p_nus->tx_handles.cccd_handle) &&
            (p_evt_write->len == 2))
        {
            if (p_client != NULL)
            {
                if (ble_srv_is_notification_enabled(p_evt_write->data))
                {
                    p_client->is_notification_enabled = true;
                    evt.type                          = BLE_NUS_EVT_COMM_STARTED;
                }

    After this happens, you can send data from the server (ble_app_uart peripheral) to the client (ble_app_uart central).

    Best regards,

    Simon

Children
  • Thanks for explanation. Yes, I am using ble_app_c_uart. I can say that notification is enabled.

    if (ble_srv_is_notification_enabled(p_evt_write->data))
                {
                    NRF_LOG_INFO("Notification enabled.");
                    p_client->is_notification_enabled = true;
                    evt.type                          = BLE_NUS_EVT_COMM_STARTED;
                }

    After this, I get the info below in RTT viewer from the central side when I power the peripheral device:

    00> <info> app: BLE UART central example started.
    00> <info> app: Connecting to target 893473D394EE
    00> <info> app: ATT MTU exchange completed.
    00> <info> app: Ble NUS max data length set to 0x14(20)
    00> <info> app: Discovery complete.
    00> <info> app: Connected to device with Nordic UART Service.

    And this is the info from peripheral side when I call my function in BLE_GAP_EVT_CONNECTED

    00> <info> app: Debug logging for UART over RTT started.
    00> <info> app: Connected
    00> <info> app: ble_nus_data_send returned 0x8
    00> <info> app: Data len is set to 0x14(20)
    00> <info> ble_nus: Notification enabled.

    I know that if ble_nus_data_send() function returns NRF_SUCCESS, it means data is sent.
    My question is that where should I call send_data function I mentioned. ( if I wrote send_data function correctly ). I tried calling it in main() function in a while loop and in  BLE_GAP_EVT_CONNECTED, but both of them didn't work.

    Best Regards

  • The question is not where you call it, the question is when you call it. You should call it after p_client->is_notification_enabled = true runs (after the log "Notification enabled")

    Here is one approach:

    • Utilize the event type BLE_NUS_EVT_COMM_STARTED, which shows that notifications has been enabled:

    /**@brief   Nordic UART Service event types. */
    typedef enum
    {
        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. */
    } ble_nus_evt_type_t;
    

    • In nus_data_handler() add the following piece of code:

    static void nus_data_handler(ble_nus_evt_t * p_evt)
    {
    
        if (p_evt->type == BLE_NUS_EVT_COMM_STARTED)  //Add this
        {                                             //Add this
    
            
            //Call ble_nus_data_send() here
    
        }
        
    
        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_ev...
            .
            .
            .

  • Now I get the logic. Thank you Simon, it worked ! Now ble_nus_data_send returns 0x0.
    Could you please tell me that how I can see the data I sent in central side ?

Related