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

Sending a CSV File over ble Gatt connection

Hi,

I need to send data from a CSV file on the nordic board(Via fatfs library). I have presently gotten a Gatt service up and running.

I have a mobile application which, can see the gatt service and write to the characteristics. From a specific write command from the mobile device I want the nordic board to send the CSV file over.

I can presently read a single line of the CSV file formatted like this: (Time stamp, data1, data 2, data3, data 4, data 5).

What I need to implement is:

  • Reading the whole file but, one or multiple lines at a time due to the size of the CSV
  • Changing the read pointer of the SD card (So I know where to continue to read from)
  • Send this data to the characteristic
  • Read this characteristic data.

My code is based upon :  https://github.com/bjornspockeli/custom_ble_service_example

My CSV file size depends on the length of time I have been storing data from. It could be upto around 1-2mbytes. I beleive I need to set up some kind of notification service. Where I read a line(or several) of the SD card, set the GATT characteristic value to this. Then change the SD card pointer. Wait till the data is received by the mobile application. Then repeat until the file is read full.y

Note I am using SDK 16 NRF52840-dk PCA 10056 S140.

This post is similar and mentions using two characteristics one from commication from the mobile app and, one for receiving the data.

https://devzone.nordicsemi.com/f/nordic-q-a/53987/nrf52840-file-transfer-via-ble

Parents
  • Hello,

    So you want to send a CSV file rom the SD card to the connected mobile phone, right?

    If I were you, I would start with the ble_app_uart example, and use ble_nus_data_send() to send your notifications. You can probably do it in the application you have started developing now. Just send the data using notifications.

    I didn't really see any questions in your post. Have you attempted this? Did you get stuck somewhere?

    Best regards,

    Edvin

  • Yes I want to send a CSV file from the SD card on the nordic board to a mobile phone. 

    Is there an example of this?

    I have not used the ble_app_uart example for this. However I do have my own custom service and Gatt connection working. My question is

    • How do I change the pointer location for the SD card?
    • How do I setup the notifications? As in how do I get them to work and change the value to be sent via this notification to the value of the CSV data?

    Also does with ble_app_uart example have a custom service? As I will need to move alot of my functionality too it.

    Also how does ble_nus_data_send work?

    Is there some guidance for how to setup notifications?

    Thanks

  • I tried to point to the app_uart_evt_t->data.error_communication, which is an uint32_t, but I wanted you to check the description of this event in app_uart.h line 117.

    Does it say anything about the value of the error_communication?

    From app_uart.h:

    uint32_t error_communication; /**< Field used if evt_type is: APP_UART_COMMUNICATION_ERROR. This field contains the value in the ERRORSRC register for the UART peripheral. The UART_ERRORSRC_x defines from nrf5x_bitfields.h can be used to parse the error code. See also the \nRFXX Series Reference Manual for specification. */

    You are using the nRF52840, so I suggest you check the ERRORSRC register for the UART on the nRF52840:
    https://infocenter.nordicsemi.com/topic/ps_nrf52840/uart.html?cp=4_0_0_5_32_9#topic

    A value of 1 means OVERRUN. Perhaps this is to be expected when you disable and/or enable the UART when there is UART data traffic ongoing? Have you tried to ignore the APP_UART_COMMUNICATION_ERROR when you are enabling and disabling the UART?

  • How would I go about ignoring it. Or better yet how do I prevent the overrun? This crash occurs seemingly around a couple of minutes after i disconnect.

  • Don't pass it into the error handler by commenting out the line saying APP_ERROR_HANDLER(...): 

            case APP_UART_COMMUNICATION_ERROR:
                //APP_ERROR_HANDLER(p_event->data.error_communication);
                break;

  • Thanks, that did seem to fix it. I have another question. I am now reading my CSV file by manually each time calling my function send CSV. This is working however, I want it to be automatic. 

    Therefore I presume I can loop this until all my data is sent. My question is: Is there a way to confirm each time data is sent it is received before sending the next data?

    I need this as I want to send my full log of data. This will be done using the notifications and, checking for a notification value change.

  • If you want this to happen fast, you can just queue up as many packets as you like. Queue one using the sd_ble_gatts_hvx function, which you already do, and if that returns NRF_SUCCESS, try to queue another one immediately. Do this as long as it returns NRF_SUCCESS. Eventually, it will return NRF_ERROR_RESOURCES, which means that the buffer is full. When this happens, you must wait for the BLE_GATTS_EVT_HVN_TX_COMPLETE event (add this to your ble_evt_handler()). When you receive this event, you can continue to queue packets until it returns NRF_ERROR_RESOURCES.

    Remember that the packet you queue that returns NRF_ERROR_RESOURCES isn't queued, so this would be the first packet you try to queue after the BLE_GATTS_EVT_HVN_TX_COMPLETE event.

Reply
  • If you want this to happen fast, you can just queue up as many packets as you like. Queue one using the sd_ble_gatts_hvx function, which you already do, and if that returns NRF_SUCCESS, try to queue another one immediately. Do this as long as it returns NRF_SUCCESS. Eventually, it will return NRF_ERROR_RESOURCES, which means that the buffer is full. When this happens, you must wait for the BLE_GATTS_EVT_HVN_TX_COMPLETE event (add this to your ble_evt_handler()). When you receive this event, you can continue to queue packets until it returns NRF_ERROR_RESOURCES.

    Remember that the packet you queue that returns NRF_ERROR_RESOURCES isn't queued, so this would be the first packet you try to queue after the BLE_GATTS_EVT_HVN_TX_COMPLETE event.

Children
  • I am not quite sure what you mean by queue. Presently I am sending all my data (10 CSV lines for testing like below)

    • Receive notification command
    • Loop
      • If flag = true(set by notification timer 10 times a second)
      • Read sd card line
      • send data (ble_cus_send)
      • Check error
      • reset flag
      • Exit condition is all CSV read

    This works but is this queuing? If so how can I speed it up atm its 510bytes per second.

  • Your function ble_cus_send() is calling sd_ble_gatts_hvx(). This is what I mean by queuing. ble_cus_send() = queuing.

  • So therefore, My bullet point code shown above works via queuing?

    This means then I don't need a flag to make it loop 10 times a second.

    Therefore, I just need to queue up all my data?

  • I have tried adding the parts for BLE_GATTS_EVT_HVN_TX_COMPLETE and setting a volatile bool to true when this event runs. However, I then try to queue up another packet and it still returns NRF_ERROR_RESOURCES.

    When I store this data to my phone I receive 533 data out of 600 in my CSV file. Below is my loop code. What is incorrect here. Not my notifyflag runs once every 10ms. Without it I store 524 data.

    Note I terminate the reading with an end of file packet.(Just an X)

    void SEND_CSV()//Send the CSV file chop off when it gets to \r\n
    {
        ret_code_t err_code;
        uint16_t data_length = 0;
        uint16_t offset_length = 11;
        data_length =(sizeof(ble_csv_data)-offset_length);//Only send 40 bytes
    
        if(End_of_file == 1)//End of the file
        {
            uint8_t End_of_file_data[1]={0x78}; /*End of file*/
            uint16_t end_of_file_length = sizeof(End_of_file_data);
            err_code = ble_cus_send_csv(&m_cus, End_of_file_data,&end_of_file_length, m_conn_handle);
            APP_ERROR_CHECK(err_code);
            End_of_file =0;//Allows it to be re-read
        }
        else
        {
            while(End_of_file != 1)//Loop this till end of file is reached
            {
            if(notify_flag == true)
                {
                    SD_CARD_Read_Line();//Gets a line of 51bytes of data
                    err_code = ble_cus_send_csv(&m_cus, ble_csv_data,&data_length, m_conn_handle);
                    if(err_code == NRF_ERROR_RESOURCES)
                    {
                        //Wait
                        while(Ble_gatts_evt_hvn_tx_complete_flag == false)//Gets set to true from interrupt
                        {
                            //Wait here
                        }
                        Ble_gatts_evt_hvn_tx_complete_flag = false;
                        err_code = ble_cus_send_csv(&m_cus, ble_csv_data,&data_length, m_conn_handle);//Error code has passed re send this data
                        //APP_ERROR_CHECK(err_code);//This still returns nrf_error_resources
                    }
                    
                   
                  notify_flag = false;
                }
            }
        }
     
         
    }

  • If the new packet is longer than the one that was ACKed (in the TX_COMPLETE event), then this still may return NRF_ERROR_RESOURCES. The queue isn't a number of packets, but number of bytes. Wait for the next TX_COMPLETE event if it still returns NRF_ERROR_RESOURCES.

     

    Thomas said:
    When I store this data to my phone I receive 533 data out of 600 in my CSV file.

     Do you have any idea of why you are missing some files? When you called ble_cus_send_csv with these lines, did it return NRF_SUCCESS, or something else?

Related