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

BLE_GATTS_EVT_HVN_TX_COMPLETE is never called

Hello, I have a bit of a weird case. I'm sending data over Bluetooth. In the begging, I wrote whole data handling in the main.c main loop. everything worked nicely, so I have decided to move all data handling to the new c file (MLX.c). Data is handling correctly, I have tested that using nrf_log, however sending it over Bluetooth I have an issue. it sends only 15 samples and stops while through nrf log I can see that data is still being handled.

Data sampling in MLX

      case MLX_step:
        nrf_gpio_pin_clear(LED_1);
          sample = sample + 1;
          data_length = Data_length_setup(sample);
          sprintf(csample1,"s%d, \r",sample);
          BLT_data_send(csample1,data_length);      // Data send over bluetooth

          for (int32_t a = 0; a<10  ;a++)
          {             
            int16_t test = MLX_read();

            if (test < 0)
            {test = test*(-1);}

            data_length = Data_length_setup(test);

            sprintf(mybuf,"%d,  \r",test);
            BLT_data_send(mybuf,data_length);      // Data send over bluetooth                                    
            nrf_delay_ms(10);
          }
         nrf_gpio_pin_set(LED_1);
      break;

BLT_data_send(); function is in the main.c

void BLT_data_send(char *data, int16_t data_l)
{  
  uint32_t err_code = ble_nus_data_send(&m_nus, data,&data_l, m_conn_handle);
  //while (err_code == NRF_ERROR_RESOURCES);
}

I have figured out that I have issues with NRF_ERROR_RESOURCES, so I have added a new case in the "ble_evt_handler", however, I never seen "send" in the terminal. So I guess BLE_GATTS_EVT_HVN_TX_COMPLETE never occurs? 

        case BLE_GATTS_EVT_HVN_TX_COMPLETE:
            NRF_LOG_INFO("send");
            NRF_LOG_FLUSH(); 
            break;

I'm quite new with NRF and software and I can't really figure what's going on, especially then data handling is done in main.c file is all good. I assume some kind of Bluetooth buffer getting full or something. Any help would be appreciated, thanks!

I'm working on a custom-made board with the nrf52 module and Bluetooth is sent to the PCA10056 development kit. 

Regards,
Jonas G

Parents
  • Hi Simonr,

    I am facing the same problem too. I am calling the sd_ble_gatts_hvx through ble_nus_data_send() in uart_event_handler(). I am trying to implement transparent uart basically sending data from external mcu to nrf52840 at 115200 baudrate/s then send to phone via ble.

    This is what I had in my code :  

    /**@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_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
    {
        nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
        ret_code_t     ret;
        uint16_t index = 0;
    
        switch (p_evt->type)
        {
            case NRF_LIBUARTE_ASYNC_EVT_ERROR:
                break;
            case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
                NRF_LOG_DEBUG("NRF_LIBUARTE_ASYNC_EVT_RX_DATA : Received data from libuarte. Writing data on UART.");
                NRF_LOG_HEXDUMP_DEBUG(p_evt->data.rxtx.p_data,  p_evt->data.rxtx.length);
                
                while (index < p_evt->data.rxtx.length)
                {
                    uint16_t length = (uint16_t)(p_evt->data.rxtx.length - index > BLE_NUS_MAX_DATA_LEN) ? BLE_NUS_MAX_DATA_LEN : p_evt->data.rxtx.length - index;
                    do
                    {
                        ret = ble_nus_data_send(&m_nus, p_evt->data.rxtx.p_data + index, &length, m_conn_handle);
        
                        if ((ret != NRF_ERROR_INVALID_STATE) &&
                            (ret != NRF_ERROR_RESOURCES) &&
                            (ret != NRF_ERROR_NOT_FOUND))
                        {
                            APP_ERROR_CHECK(ret);
                        }
    
                        if (ret == NRF_ERROR_RESOURCES){
                            tx_buffer_is_free = false;
                        }
                        NRF_LOG_INFO("RET | FREE BUFFER TX : %d | %d", ret, tx_buffer_is_free);
                    } while (!tx_buffer_is_free);
    
                    index += length;
                }
    
                if (p_evt->data.rxtx.p_data == NULL){
    
                }
                else {
                   nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
                }
              
                break;
    
            case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
                // NRF_LOG_DEBUG("NRF_LIBUARTE_ASYNC_EVT_TX_DONE : Received data from libuarte. Writing data on UART.");
                // NRF_LOG_HEXDUMP_DEBUG(p_evt->data.rxtx.p_data,  p_evt->data.rxtx.length);
    
                break;
            default:
                break;
        }
    }

    and I added this under ble_evt_handler() :  

    case BLE_GATTS_EVT_HVN_TX_COMPLETE:
                tx_buffer_is_free = true;
                NRF_LOG_INFO("NOTIFICATION TX COMPLETE! - MAIN");
               
                break;

    In my implementation, the tx_buffer_is_free is never changed from BLE_GATTS_EVT_HVN_TX_COMPLETE which didn't get triggered.

    Note that I have assumed that the BLE_GATTS_EVT_HVN_TX_COMPLETE will be fired from the SD interrupt handler after the queued data in ble_nus_data_send() are sent, and set the ret code from 19 (NRF_ERROR_RESOURCES) to 0(NRF_SUCCESS).

    Just want to understand, how do you do "leave the interrupt and set a flag that you can trig the send function from the main IRQ level. " ? (Eg. give an example code)

Reply
  • Hi Simonr,

    I am facing the same problem too. I am calling the sd_ble_gatts_hvx through ble_nus_data_send() in uart_event_handler(). I am trying to implement transparent uart basically sending data from external mcu to nrf52840 at 115200 baudrate/s then send to phone via ble.

    This is what I had in my code :  

    /**@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_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
    {
        nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
        ret_code_t     ret;
        uint16_t index = 0;
    
        switch (p_evt->type)
        {
            case NRF_LIBUARTE_ASYNC_EVT_ERROR:
                break;
            case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
                NRF_LOG_DEBUG("NRF_LIBUARTE_ASYNC_EVT_RX_DATA : Received data from libuarte. Writing data on UART.");
                NRF_LOG_HEXDUMP_DEBUG(p_evt->data.rxtx.p_data,  p_evt->data.rxtx.length);
                
                while (index < p_evt->data.rxtx.length)
                {
                    uint16_t length = (uint16_t)(p_evt->data.rxtx.length - index > BLE_NUS_MAX_DATA_LEN) ? BLE_NUS_MAX_DATA_LEN : p_evt->data.rxtx.length - index;
                    do
                    {
                        ret = ble_nus_data_send(&m_nus, p_evt->data.rxtx.p_data + index, &length, m_conn_handle);
        
                        if ((ret != NRF_ERROR_INVALID_STATE) &&
                            (ret != NRF_ERROR_RESOURCES) &&
                            (ret != NRF_ERROR_NOT_FOUND))
                        {
                            APP_ERROR_CHECK(ret);
                        }
    
                        if (ret == NRF_ERROR_RESOURCES){
                            tx_buffer_is_free = false;
                        }
                        NRF_LOG_INFO("RET | FREE BUFFER TX : %d | %d", ret, tx_buffer_is_free);
                    } while (!tx_buffer_is_free);
    
                    index += length;
                }
    
                if (p_evt->data.rxtx.p_data == NULL){
    
                }
                else {
                   nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
                }
              
                break;
    
            case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
                // NRF_LOG_DEBUG("NRF_LIBUARTE_ASYNC_EVT_TX_DONE : Received data from libuarte. Writing data on UART.");
                // NRF_LOG_HEXDUMP_DEBUG(p_evt->data.rxtx.p_data,  p_evt->data.rxtx.length);
    
                break;
            default:
                break;
        }
    }

    and I added this under ble_evt_handler() :  

    case BLE_GATTS_EVT_HVN_TX_COMPLETE:
                tx_buffer_is_free = true;
                NRF_LOG_INFO("NOTIFICATION TX COMPLETE! - MAIN");
               
                break;

    In my implementation, the tx_buffer_is_free is never changed from BLE_GATTS_EVT_HVN_TX_COMPLETE which didn't get triggered.

    Note that I have assumed that the BLE_GATTS_EVT_HVN_TX_COMPLETE will be fired from the SD interrupt handler after the queued data in ble_nus_data_send() are sent, and set the ret code from 19 (NRF_ERROR_RESOURCES) to 0(NRF_SUCCESS).

    Just want to understand, how do you do "leave the interrupt and set a flag that you can trig the send function from the main IRQ level. " ? (Eg. give an example code)

Children
No Data
Related