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

sd_ble_gatts_hvx NRF_ERROR_RESOURCES in do while loop

After a few notifications in short succession this code will reliably get stuck in an infinite loop (15.2.0). Can sd_ble_gatts_hvx not be used in this way? Do you have to wait for BLE_GATTS_EVT_HVN_TX_COMPLETE? This makes things more difficult as you then have to queue the notifications in the application.

do {
    err_code = sd_ble_gatts_hvx(conn_handle, &params);
} while (err_code == NRF_ERROR_RESOURCES);

Parents
  • Hi Nick, 

    sd_ble_gatts_hvx() is a synchronous API call so it should return NRF_ERROR_RESOURCES as long as the notification queue is full and should not halt if called in a loop. 

    Yes, the recommended and most power-efficient approach is to call sd_ble_gatts_hvx untill you get the NRF_ERROR_RESOURCES return code and then wait until you get the BLE_GATTS_EVT_HVN_TX_COMPLETE before you call sd_ble_gatts_hvx again. 

    Note: The number of Handle Value Notifications that can be queued is configured by ble_gatts_conn_cfg_t::hvn_tx_queue_size.

    Best regards

    Bjørn 

  • Thanks for your response but the code does not halt on sd_ble_gatts_hvx, just the loop continues indefinitely i.e. sd_ble_gatts_hvx continues to return NRF_ERROR_RESOURCES forever. So perhaps the function does not work correctly, as I assume it shouldn't return NRF_ERROR_RESOURCES forever as the queue will become free at some point.

  • Ok, and you're not getting the BLE_GATTS_EVT_HVN_TX_COMPLETE either? Are you able to capture a sniffer trace of the on air packets with the nRF Sniffer v2 ? It would be interesting to see if the notification packets are actually sent or not. 

    Btw, which SDK and SoftDevice version are you using? And which IC?

    Best regards

    Bjørn 

  • SDK 15.2.0 SoftDevice S132 6.1.0. on NRF52832

    It seems calling either sd_ble_gatts_hvx or nrf_pwr_mgmt_run (as below) in a loop prevents HVN_TX_COMPLETE occurring. If I use either to attempt to wait for the HVN_TX_COMPLETE it never occurs and the loop gets stuck.

    static volatile bool m_notifications_queue_full = false;
    
    void ble_blister_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ble_blister_t * p_blister = (ble_blister_t *)p_context;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GATTS_EVT_HVN_TX_COMPLETE:
                NRF_LOG_DEBUG("HVN_TX_COMPLETE: %d", p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count);
                m_notifications_queue_full = false;
                break;
            default:
                break;
        }
    }
    
    void send() {
    do {
    err_code = sd_ble_gatts_hvx(conn_handle, &params);
    if(err_code == NRF_ERROR_RESOURCES) {
        NRF_LOG_WARNING("Queue full, waiting");
        NRF_LOG_FLUSH();
        m_notifications_queue_full = true;
        while(m_notifications_queue_full) {
            nrf_pwr_mgmt_run();
        }
    }
    } while (err_code == NRF_ERROR_RESOURCES);
    }

    5 notifications are sent and received by the connected device. The firmware gets stuck sending the 6th.

    I should probably note that 1 notification is being sent on GPIO interrupt, and this is occurring when many interrupts occur at the same time.

  • Hmm, calling nrf_pwr_mgmt_run to sleep the device while waiting for the HVN_TX_COMPLETE event should not lead to the behaviour you're describing. WHen you call send, how many HVN_TX_COMPLETE events do you get before the code is deadlocked? And which .hvn_tx_complete.count is passed in the event?

  • I get zero HVN_TX_COMPLETE unless I omit the loop and just ignore the return error. Perhaps the interrupt handling queue is full and interrupts from the radio can't be handled or something? I'm not sure of the detail of how things work in that respect, just guessing.

  • Are you running the loop at an interrupt context?  It could sound like thee loop is blocking the SD events from being handled in the application. I think this could happen if the loop is running in an interrupt context with priority 6.

    Best regards

    Bjørn

Reply Children
Related