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

send packets continuously in ble_app_uart example

I have to send packages continuously; How can I get feedback on the success of transmission before sending the next package? Which event should I use? and in what callback function?

I'm using SDK 15 and softdevice 6.0. The event BLE_EVT_TX_COMPLETE is missing in ble.h

Thanks

Parents
  • Hi,

     

    You can use the BLE_GATTS_EVT_HVN_TX_COMPLETE event to know that a Handle Value Notification transmission has completed. (This is allready used in the NUS implementation, ble_nus.c). Note that you can queue more than one, but you will get NRF_ERROR_RESOURCES returned when there are too many in the queue. In that case, you have to wait for the BLE_GATTS_EVT_HVN_TX_COMPLETE event before you call ble_nus_data_send() (or sd_ble_gatts_hvx()) again.

  • Hello, I wait the event BLE_GATTS_EVT_HVN_TX_COMPLETE before the next transmission with ble_nus_data_send(). Please see the while loop in the main:

        // Enter main loop.
        for (;;)
        {
            //idle_state_handle();
    
            if ((flag_connected==1)&&(flag_transmitted==1))
            //if (flag_connected==1)
    	{
              flag_transmitted = 0;
              
              //nrf_delay_ms(100);
              nrf_gpio_pin_toggle(OUT_COMP);
              SendData();
    
              num_packets++;
                                               
    	}
    
        }

    the flag_transmitted is asserted in following function handler:

    static void nus_data_handler(ble_nus_evt_t * p_evt)
    {
        int break_point;
        char debug_str[10] = {0};
    
        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_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
    
            break_point = 25;
    
            // **************** ha ricevuto i dati su BLE RX, commentato il blocco inferiore che li rigirava sulla UART fisica
            /*
            for (uint32_t i = 0; i < p_evt->params.rx_data.length; i++)
            {
                do
                {
                    err_code = app_uart_put(p_evt->params.rx_data.p_data[i]);
                    if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY))
                    {
                        NRF_LOG_ERROR("Failed receiving NUS message. Error 0x%x. ", err_code);
                        APP_ERROR_CHECK(err_code);
                    }
                } while (err_code == NRF_ERROR_BUSY);
            }
            if (p_evt->params.rx_data.p_data[p_evt->params.rx_data.length - 1] == '\r')
            {
                while (app_uart_put('\n') == NRF_ERROR_BUSY);
            }
            */
        }
        else if (p_evt->type == BLE_NUS_EVT_TX_RDY)
        {
            flag_transmitted = 1;
    
            NRF_LOG_INFO("TX OK");
            //sprintf(debug_str, "numbers of packets = %d", num_packets);
            //NRF_LOG_INFO("%s",(uint32_t)debug_str);
        }
    
    }

    then, at the connection, the continuous transmission starts. About 6000 packages can be transmitted  before the software goes to the function "__WEAK void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)" with error 19 "NRF_ERROR_RESOURCES".

    Every transmission I toggle a pin, please see the attached image of the monitoring of pin with the scope. Every change of level is a transmission

    A scope division i 5 ms and this is a very strange behaviour because I set the connction interval at 15 ms.

    What do you think?

Reply
  • Hello, I wait the event BLE_GATTS_EVT_HVN_TX_COMPLETE before the next transmission with ble_nus_data_send(). Please see the while loop in the main:

        // Enter main loop.
        for (;;)
        {
            //idle_state_handle();
    
            if ((flag_connected==1)&&(flag_transmitted==1))
            //if (flag_connected==1)
    	{
              flag_transmitted = 0;
              
              //nrf_delay_ms(100);
              nrf_gpio_pin_toggle(OUT_COMP);
              SendData();
    
              num_packets++;
                                               
    	}
    
        }

    the flag_transmitted is asserted in following function handler:

    static void nus_data_handler(ble_nus_evt_t * p_evt)
    {
        int break_point;
        char debug_str[10] = {0};
    
        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_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
    
            break_point = 25;
    
            // **************** ha ricevuto i dati su BLE RX, commentato il blocco inferiore che li rigirava sulla UART fisica
            /*
            for (uint32_t i = 0; i < p_evt->params.rx_data.length; i++)
            {
                do
                {
                    err_code = app_uart_put(p_evt->params.rx_data.p_data[i]);
                    if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY))
                    {
                        NRF_LOG_ERROR("Failed receiving NUS message. Error 0x%x. ", err_code);
                        APP_ERROR_CHECK(err_code);
                    }
                } while (err_code == NRF_ERROR_BUSY);
            }
            if (p_evt->params.rx_data.p_data[p_evt->params.rx_data.length - 1] == '\r')
            {
                while (app_uart_put('\n') == NRF_ERROR_BUSY);
            }
            */
        }
        else if (p_evt->type == BLE_NUS_EVT_TX_RDY)
        {
            flag_transmitted = 1;
    
            NRF_LOG_INFO("TX OK");
            //sprintf(debug_str, "numbers of packets = %d", num_packets);
            //NRF_LOG_INFO("%s",(uint32_t)debug_str);
        }
    
    }

    then, at the connection, the continuous transmission starts. About 6000 packages can be transmitted  before the software goes to the function "__WEAK void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)" with error 19 "NRF_ERROR_RESOURCES".

    Every transmission I toggle a pin, please see the attached image of the monitoring of pin with the scope. Every change of level is a transmission

    A scope division i 5 ms and this is a very strange behaviour because I set the connction interval at 15 ms.

    What do you think?

Children
  • Hello,

    Einar is currently out of office, so I have taken this case, and will follow it up.

     

    I see that the BLE_NUS_EVT_TX_RDY is called on the BLE_EVT_TX_COMPLETE event, so it should be fine.

     

    What does your SendData() function look like?

     

    Can you please try the following:

    define "DEBUG" in your preprocessor defines, and disable optimization (set it to -O0). Then you should be able to find out what function that returns NRF_ERROR_RESOURCES. Set a breakpoint on line 90 in app_error_weak.c, and it should break there when you receive the error. Check what file name and line number that is stored in p_info. Is this within your SendData() function?

     

    Best regards,

    Edvin

  • Hello,

    following the function SendData()

    void SendData(void)
    {
    
        static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
        static uint8_t index = 0;
        uint32_t       err_code;
        uint16_t length;
    
        for (index=0; index<18; index++)
        {
          data_array[index] =  (unsigned char)tempo_IC1;//index+1;
        }
    
        length = 18;
    
        do
        {
          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_BUSY) && (err_code != NRF_ERROR_NOT_FOUND))
          {
            APP_ERROR_CHECK(err_code);
          }
        } while (err_code == NRF_ERROR_BUSY);
    
    }
    

    The file name in p_info is main.c where there is the function SendData and the line number is "APP_ERROR_CHECK(err_code)" always in function SendData

  • Hello,

    ble_nus_data_send() returns NRF_ERROR_RESOURCES this means that the sending buffer for this characteristic is full. Please see the description in ble_gatts.h, on line 632.

     

    Do you use notification or indication?

     

    I don't see why you use the NRF_ERROR_BUSY return value.

     

    if you want to send more packets you should do something like:

    err_code = NRF_SUCCESS;
    while (err_code == NRF_SUCCESS)
    {
        err_code = ble_nus_data_send()
    }
    if (err_code != NRF_ERROR_RESOURCES (or anything else you want to filter out...)
    {
        APP_ERROR_CHECK(err_code)
    }

     

    When you receive an err_code = NRF_ERROR_RESOURCES, you should wait for the BLE_GATTS_EVT_HVN_TX_COMPLETE event, which means that some buffer space is free, and do the same until you are done sending data.

     

    Best regards,

    Edvin

  • Hello, I changed the function void SendData(void) as follows:

    void SendData(void)
    {
    
        static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
        static uint8_t index = 0;
        uint32_t       err_code;
        uint16_t length;
    
        for (index=0; index<18; index++)
        {
          data_array[index] =  (unsigned char)tempo_IC1;//index+1;
        }
    
        length = 18;
    
        err_code = ble_nus_data_send(&m_nus, data_array, &length, m_conn_handle);
        
    
        if ((err_code != NRF_ERROR_RESOURCES)&&(err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_BUSY) && (err_code != NRF_ERROR_NOT_FOUND))// (or anything else you want to filter out...)
        {
            APP_ERROR_CHECK(err_code);
        }
    
    }
    

    and now I have not the NRF_ERROR_RESOURCES. Pratically I send a packet of 18 bytes only if I sure that is set the flag BLE_GATTS_EVT_HVN_TX_COMPLETE. However I have the same timing transmission on the oscilloscope. That is the transmission of 7 packets of 18 bytes every connection interval that I set to 15 ms. This behaviour "freezes" the app on IOS ( I use IOS 11.4). How I can send one packet of 18 bytes every connection interva continuously?

    best regards

    Mario

  • Oh, so you want to lower the transmission rate, is that correct?

     

    Unfortunately, you can't read out how many packets you have queued up, but there are some viable workarounds if you want to only send one packet per connection interval:

     

    1: Not the best solution, but maybe the easiest. You can use a timer, and send a packet in the timeout handler. This may not be synced up with the connection interval, but if that is ok for your application, that is fine.

     

    2: You can keep track of the number of packets that you have queued. That is, every time ble_nus_data_send, increment the counter, and everytime you get the tx complete event, decrement the counter. And then you only queue a packet when the counter is 0. This is basically what you did with the flag_transmitted implementation.

     

    3: If you want to queue a packet every connection interval, this might be the most reliable solution. You can enable the radio notification. Please see this guide.  That way you can get an interrupt on a given time before the connection interval event. In that interrupt you can queue one packet. 

     

    I am a bit confused. The description from Einar is suited if you want to queue several packets, which is the correct way of doing it. But do you want to only queue one packet at the time? Do you want to increase the throughput? If the phone freezes it's probably because the app can't handle the incoming packets fast enough.

     

    Best regards,

    Edvin

Related