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

  • Ok thanks I'll have a look into implementing that. I have gotten a log to print in my on_cus_evt (handler in main). Given I write a specific gatt code. I just need to add that bool as you stated as a flag and process it in the main code. Quicky though why do you use sd_app_evt_wait(); and not idle_state_handle();?

  • Also I found out an issue of myflag1 never runs in the main however, this is due to my code in my main loop. I have a function called process data that works like this in the main loop.

    for(;;)
        {
            Process_data();
            if(myflag1 == true)//Does this run?
            {
                NRF_LOG_INFO("Go to reading CSV file in main code");
                myflag1 = false;
                //SEND_CSV();//Run the function to send the CSV file
            }
            sd_app_evt_wait();//Processing for SD CARD
        }

    If I un-comment my process_data function the myflag1 works. So why would my function(below stop the main execution?)

    void Process_data(void)
    {
        if(GATT_CONNECTED == false)
        {
            // Get next gyte from FIFO
            while (app_uart_get(&c) != NRF_SUCCESS);
            string[pos] = c;
    
            // Assume that all strings end with \n. If end, print and start over.
            if (string[pos] == '\n')
            {
                string[pos+1] = '\0';
                sscanf(string,  "%*d , %d , %*d , %d , %*d , %d , %*d , %d , %*d , %f",&T1_data,&T2_data,&T3_data,&T4_data,&Pdif_data);
    
                if(Print_log_enabled == 1)
                {
                    NRF_LOG_RAW_INFO("Received string: \"%s\"", string);//Print the received string
                    NRF_LOG_RAW_INFO("T1 is:\"%d\"", T1_data);//T1 data string
                    NRF_LOG_RAW_INFO("T2 is:\"%d\"", T2_data);//T2 data string
                    NRF_LOG_RAW_INFO("T3 is:\"%d\"", T3_data);//T3 data string
                    NRF_LOG_RAW_INFO("T4 is:\"%d\"", T4_data);//T4 data string
                    NRF_LOG_RAW_INFO("Pdiff" NRF_LOG_FLOAT_MARKER "\r\n", NRF_LOG_FLOAT(Pdif_data));//Pdif data string
                }
                pos = 0;
                //Storage
                if((Unix_Time != Last_Unix_Time))//Time instance has changed and logging is enabled.
                {
                    Last_Unix_Time = Unix_Time;
                    counter++;
                    advertising_mod(counter,T1_data,T2_data,T3_data,T4_data,Pdif_data);
                    if(Log_to_sd_card == 1)
                    {
                        SD_CARD_T1[SD_Card_Data_Pointer] = T1_data;//From data string t1
                        SD_CARD_T2[SD_Card_Data_Pointer] = T2_data;//From data string t2
                        SD_CARD_T3[SD_Card_Data_Pointer] = T3_data;//From data string t3
                        SD_CARD_T4[SD_Card_Data_Pointer] = T4_data;//From data string t4
                        SD_CARD_Pdiff[SD_Card_Data_Pointer] = Pdif_data;   //From pressure sensor
                        SD_CARD_UNIX_TIME  [SD_Card_Data_Pointer] = Unix_Time;//Unix time stamp
                        SD_Card_Data_Pointer = SD_Card_Data_Pointer + 1;//Increment the SD_Card_Data_Pointer by 1
                        if(SD_Card_Data_Pointer == MAXIMUM_BUFFER_STORAGE)//Buffer is full
                        {
                            Write_block_to_sd_card();//Write a block of data to the SD card
                            SD_Card_Data_Pointer = 0;//Reset the SD_Card_Data_Pointer to 0
                        }
                    }
                }
            }
            else
            {
                pos++;
            }
            
        }
        else//Gatt connected
        {
            
        }
        NRF_LOG_INFO("Processing main loop");//Runs if gatt is not connected
        
    }

    Edit: GATT_CONNECTED is a volatile bool set inside ble_evt_handler given if the gatt is connected or not.

    Edit: I've debugged it. And when process data is un-commented the board crashes to my advertising mod function. Which should not be running as the gatt is connected. I do not know why my loop is running when the gatt is connected.

  • Thomas said:
    Quicky though why do you use sd_app_evt_wait(); and not idle_state_handle();?

    It was just from the top of my head. Use idle_state_handle. (the different examples use different idle handlers, depending on whether it has logging or power management enabled). Use whatever you were using. Idle_state_handle is a good one, because it processes the log (if enabled) and also does the power management handling.

    I think you should consider using an event handler for your UART input. In this case, whenever you connect, your CPU will stand on while (app_uart_get(&c) != NRF_SUCCESS), so it will never reach ide_state_handle(). Again, check how this is done in the ble_app_uart example.

    I didn't quite get your question as for why the it is advertising when you are connected. Where are the places that you call advertising start from in your project?

  • I presume I therefore, move my process_data()  inside of my uart handler. If the event is APP_UART_DATA_READY?

  • Oh, I guess you have an event handler for the UART. I thought that the app_uart_get was another function. However, I suggest you look at the uart_event_handle in ble_app_uart. You should call app_uart_get whenever you get the RX event on the UART, because you want to empty the buffer. 

    I don't know, if it works in your case, that is probably fine. It is hard to say only from the snippets.

Related