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

How to deal with [NRF_ERROR_RESOURCES]

Hello
If "NRF_ERROR_RESOURCES" occurs, does the set transmission data not be transmitted? Will it be sent partway? I do not know either.
If "NRF_ERROR_RESOURCES" is returned when executing [ble_nus_data_send ()], can I freeze the time and execute [ble_nus_data_send ()] again?
Thanking you in advance
 
Parents
  • Hi,

    If ble_nus_data_send() returns NRF_ERROR_RESOURCES, it means that too many notifications are queued. All the BLE buffers in the SoftDevice are full, and you can not upload any more notifications until the BLE_GATTS_EVT_HVN_TX_COMPLETE event occurs. You will need to call ble_nus_data_send() again when that happens.

    You have 2 options, either call ble_nus_data_send() in a loop until the function returns NRF_SUCCESS, or wait for the BLE_GATTS_EVT_HVN_TX_COMPLETE and then send the packet. Waiting in a loop is how it’s implemented in ble_app_uart, but there is a small bug in SDK 15.0, where the wrong error-code is tested. NRF_ERROR_BUSY is tested, but it should be NRF_ERROR_RESOURCES.

    Here is the uart_event_handle() for SDK 15.0 with the bug fixed:

    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') || (index >= (m_ble_nus_max_data_len)))
                {
                    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;
        }
    }

  • Hi Sigurd,

    I'm programming an app based on the blinky example from SDK 15.1.0 on the nRF52 development kit. I've managed to modify the example to send and receive multiple bytes per packet, but when I try to send more packets, I get the NRF_ERROR_RESOURCES error. For me, the BLE_GATTS_EVT_HVN_TX_COMPLETE event never seems to occur, although packets are sent to the central. I have a case for it in ble_event_handler:

    case BLE_GATTS_EVT_HVN_TX_COMPLETE:
        NRF_LOG_DEBUG("BLE_GATTS_EVT_HVN_TX_COMPLETE");
        break;

    That line never gets printed. Am I doing something wrong here?

    Also, when I send the packets, I always wait for NRF_SUCCESS before sending the next one, but I still get the error after a few packets. I don't know, what am I missing?

    Thank you in advance!

  • That line never gets printed. Am I doing something wrong here?

    Could you try NRF_LOG_INFO instead of NRF_LOG_DEBUG ?

  • Thanks a lot for your answer, it does work with NRF_LOG_INFO. Sending over 30 notifications in a row also works, if I wait for the BLE_GATTS_EVT_HVN_TX_COMPLETE event. Shouldn't NRF_SUCCESS be enough to look for?

    uint32_t ble_dev_send_data(uint16_t conn_handle, ble_dev_t * p_dev, uint8_t *data, uint16_t len)
    {
    	ret_code_t err_code;
    
    	ble_gatts_hvx_params_t params;
    
    	memset(&params, 0, sizeof(params));
    	params.type   = BLE_GATT_HVX_NOTIFICATION;
    	params.handle = p_dev->read_char_handles.value_handle;
    	params.p_len = &len;
    	params.p_data = data;
    					
    	err_code = sd_ble_gatts_hvx(conn_handle, &params);	
    	
        return err_code;
    }

    If I keep trying to send in a while loop until the above method returns NRF_SUCCESS, it fails with NRF_ERROR_RESOURCES after the 5th or 6th packet anyways.

    case BLE_GATTS_EVT_HVN_TX_COMPLETE:
    	NRF_LOG_INFO("BLE_GATTS_EVT_HVN_TX_COMPLETE");
        ble_tx_complete = 1;
    	break;

    If I set a flag when BLE_GATTS_EVT_HVN_TX_COMPLETE occurs (like in the above snippet) and wait, it works:

    for (uint8_t i = 0; i < noOfPkts; i++)
    {	
        /* other code */
        
    	while(ble_tx_complete == 0);
    	ble_dev_send(m_conn_handle, &m_dev, (uint8_t*)&report, (uint16_t)sizeof(report));
    	ble_tx_complete = 0;												
    }

    Isn't there a better way of doing this? Do you always have to wait for this event before sending more packets?

    By the way, increasing NRF_SDH_BLE_GAP_EVENT_LENGTH in sdk_config.h had no effect.

Reply
  • Thanks a lot for your answer, it does work with NRF_LOG_INFO. Sending over 30 notifications in a row also works, if I wait for the BLE_GATTS_EVT_HVN_TX_COMPLETE event. Shouldn't NRF_SUCCESS be enough to look for?

    uint32_t ble_dev_send_data(uint16_t conn_handle, ble_dev_t * p_dev, uint8_t *data, uint16_t len)
    {
    	ret_code_t err_code;
    
    	ble_gatts_hvx_params_t params;
    
    	memset(&params, 0, sizeof(params));
    	params.type   = BLE_GATT_HVX_NOTIFICATION;
    	params.handle = p_dev->read_char_handles.value_handle;
    	params.p_len = &len;
    	params.p_data = data;
    					
    	err_code = sd_ble_gatts_hvx(conn_handle, &params);	
    	
        return err_code;
    }

    If I keep trying to send in a while loop until the above method returns NRF_SUCCESS, it fails with NRF_ERROR_RESOURCES after the 5th or 6th packet anyways.

    case BLE_GATTS_EVT_HVN_TX_COMPLETE:
    	NRF_LOG_INFO("BLE_GATTS_EVT_HVN_TX_COMPLETE");
        ble_tx_complete = 1;
    	break;

    If I set a flag when BLE_GATTS_EVT_HVN_TX_COMPLETE occurs (like in the above snippet) and wait, it works:

    for (uint8_t i = 0; i < noOfPkts; i++)
    {	
        /* other code */
        
    	while(ble_tx_complete == 0);
    	ble_dev_send(m_conn_handle, &m_dev, (uint8_t*)&report, (uint16_t)sizeof(report));
    	ble_tx_complete = 0;												
    }

    Isn't there a better way of doing this? Do you always have to wait for this event before sending more packets?

    By the way, increasing NRF_SDH_BLE_GAP_EVENT_LENGTH in sdk_config.h had no effect.

Children
Related