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

Reading and sending a CSV file

Hi,

I have CSV file stored on an SD card (which I create via the nordic board). I want to send this via a GATT connection.

I have gotten a service with a notifiable characteristic value that increments once per second using a notification timeout handler. 

I  am also able to read a single line of my sd cards CSV.

I now want to combine the two functionalities but need some help.

Firstly I am always reading the first line of the CSV by calling the function read_line. This is custom and reads the first line of the csv files and prints it out to the terminal.

How do I read several lines aka more data because I'll need to read the entire file and send it via my gatt connection.

Are my following assumptions of how to read and send the sd card CSV file correct?

  • I need to know how to set the last pointer of where the data is read upto.
  • Then send that data via notifications.
  • Once that data is sent read the next lines of the CSV file and send that.
  • Then repeat until the file is completely read. Which I presume I can do by identifying the size of the file and reading that many bytes.

If so I need to know

  • How large of a gatt characteristic i can have presently a byte.
  • How to set a read pointer (the point the sd card read periously got to)
  • How to read the entire CSV file
  • How to link my data to the notification

Thanks

Note Using SDK 16, NRF52840-dk PCA 10056 S140 in segger. Below is my code. I want to adapt my read line so it can read and broadcast the entire CSV file upto 2mbytes.

static void notification_timeout_handler(void * p_context)
{
    UNUSED_PARAMETER(p_context);
    ret_code_t err_code;
    
    // Increment the value of m_custom_value before nortifing it.
    m_custom_value++;
    
    err_code = ble_cus_custom_value_update(&m_cus, m_custom_value);//Need to link this to the CSV file data
    APP_ERROR_CHECK(err_code);
}

void SD_CARD_Read_Line()
{
    UINT bytesRead;//From sd card driver library
    static FATFS fs;
    static DIR dir;
    static FILINFO fno;
    static FIL file;

    uint32_t bytes_written;
    FRESULT ff_result;
    DSTATUS disk_state = STA_NOINIT;
    
    NRF_LOG_INFO("Reading SD CARD data");
    char data[100]={0}; /* Line buffer */
    unsigned int ByteRead = 0;

    ff_result = f_open(&file, FILE_NAME, FA_READ);
    if (ff_result != FR_OK)
    {
        NRF_LOG_INFO("Unable to open or create file: " FILE_NAME ".\r\n");
        return;
    }

    uint16_t size = f_size(&file) ;
    NRF_LOG_INFO("size of the file in bytes = %d\r\n",size);

    ff_result = f_read(&file,data,52, &ByteRead);

    if (ff_result != FR_OK)
    {
        NRF_LOG_INFO("Unable to read or create file: " FILE_NAME ".\r\n");
        return;
    }
    else if(ff_result == FR_OK)
    {
      NRF_LOG_INFO("%d bytes read\r\n",ByteRead);
      NRF_LOG_INFO("Data is : %s\r\n", (uint32_t) data);
    }
    else
    {
      NRF_LOG_INFO("Error operation\r\n");
    }
    (void) f_close(&file);
}

  • Hi,

    In this case I suggest to check out the ble_app_uart example in the SDK, the example show central and peripheral example of generic (UART) data transfer between two peers. In your case you simply replace UART data with the data from the file system.

    In addition you should study the FatFs documentation and examples: elm-chan.org/.../00index_e.html and FatFs User Forum: http://elm-chan.org/fsw/ff/bd/

    In short you call f_read() to read data and to send data you call sd_ble_gatts_hvx(). You can call f_read() multiple times until you have read the entire file.

    Best regards,
    Kenneth

  • Thanks I've had a look at both of them and found the webpage quite useful. I have a CSV file that can be upto 1-2mBytes.

    I have a notification based example using a timeout handler can I not use this?

    I have a function that reads my CSV file and reads a line.

    I want to be able to send this single line using my ble_cus_custom_value_update function. But presently It only works for uint8_t.

    How do I change this to be much larger at least 51bytes as an individual line of data is 51 bytes. Thanks,

    uint32_t ble_cus_custom_value_update(ble_cus_t * p_cus, uint8_t custom_value)
    {
        NRF_LOG_INFO("In ble_cus_custom_value_update. \r\n"); 
        if (p_cus == NULL)
        {
            return NRF_ERROR_NULL;
        }
    
        uint32_t err_code = NRF_SUCCESS;
        ble_gatts_value_t gatts_value;
    
        // Initialize value struct.
        memset(&gatts_value, 0, sizeof(gatts_value));
    
        gatts_value.len     = sizeof(uint8_t);
        gatts_value.offset  = 0;
        gatts_value.p_value = &custom_value;
    
        // Update database.
        err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                          p_cus->custom_value_handles.value_handle,
                                          &gatts_value);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    
        // Send value if connected and notifying.
        if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
        {
            ble_gatts_hvx_params_t hvx_params;
    
            memset(&hvx_params, 0, sizeof(hvx_params));
    
            hvx_params.handle = p_cus->custom_value_handles.value_handle;
            hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
            hvx_params.offset = gatts_value.offset;
            hvx_params.p_len  = &gatts_value.len;
            hvx_params.p_data = gatts_value.p_value;
    
            err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
            NRF_LOG_INFO("sd_ble_gatts_hvx result: %x. \r\n", err_code); 
        }
        else
        {
            err_code = NRF_ERROR_INVALID_STATE;
            NRF_LOG_INFO("sd_ble_gatts_hvx result: NRF_ERROR_INVALID_STATE. \r\n"); 
        }
    
    
        return err_code;
    }

Related