In my application I am datalogging (2 ints and 2 floats) into a CSV file. After logging, I would like to be able to retrieve the entries in a "last-in first-out" fashion. Are their any libraries, compatible with Arduino or not, that I may look at the code and learn from?
To avoid this, a solution maybe to datalog into the SD card in a reverse manner and read normally, or datalog normally and read in a reverse manner. I feel like these 2 solutions will require wasted clock cycles, especially if the stack is large.
I think the SD library supports random access, so you could design your encoding to use a fixed number of bytes per line, and then calculate the offset into the file that you need to seek to to address specific records. This would let you process the records in reverse order if you wanted.
PeterH:
I think the SD library supports random access,
I am a little confused about this? Do you mind expanding on it.
Here is my idea, but I am having trouble implementing it. Lets say I have a file.csv with entries looking like A,B,C,D (A,B are ints and C,D are floats).
I want to read the value of 'D' starting from the buttom going up towards the top of the file. I was thinking of using pointers to address the memory address of these values. I want to stay away from using a while() to get to the bottom of the file. The file can is thousands of entries long and I want to be reading these values at least 50 Hz back into the micro.
I am not the greatest in C++ and I have never implemented pointers in the Arduino, but I think it should be the same.
Sounds like a reason to use constant-sized records in the file (a power of two would be good - you could
even just use a whole 512 byte block per record), then keep track of the number of records written.
If the SD driver supports position seeking then you can go straight to the record you are interested in.
Are there SD drivers supporting seek() ? Not sure about that.
You will be using the SD library to read and write the file contents. Look at the documentation for the SD library.
After you have opened the file you can seek() to a specified position within the file. If you have designed your encoding scheme to use a fixed number of characters for each record in the file then you can calculate the position that any row starts at and read just that row. Your processing code would then be something like:
// incomplete, untested
const int RECORD_LENGTH = 16; // for example
int recordsInFile(File *fp)
{
return fp->size() / RECORD_LENGTH;
}
void readRecord(File *fp, int recordNumber, char *dest)
{
file.seek(RECORD_LENGTH * recordNumber); // seek to the start of the record
for(int i = 0; j < RECORD_LENGTH; i++)
{
dest[j++] = file.read();
}
}
void loop()
{
File file = SD.open("foo.csv");
int recordCount = recordsInFile(&file);
for(int i = recordCount-1; i >= 0; i--)
{
char buffer[RECORD_LENGTH+1]; // allow space for the terminating null
readRecord(&file, i, buffer);
buffer[RECORD_LENGTH] = 0; // null-terminate the buffer so the contents can be accessed as a c-string
processCsvRecord(i, buffer);
}
}
void processCsvRecord(int recordNumber, char *record)
{
// your code here
}
This looks like a great solution and is pretty much what I am looking for, but I am getting a compiling error when trying to use <SD.h> with <SdFat.h>. Are there any other functions similar to seek() and position() in SdFat? or possibly another solution?
I guess if there isn't I can try and redesign my sketch to write the .csv files using SD.h rather than SdFat.h, but there might be a problem down the road.