Reading/writing struct to sd card

Hi,

Is it anyhow possible to write and read a struct to a sd card? My struct looks like this:

struct Pattern {
  byte length;
  byte shuffle;
  byte steps[12][64];
  byte accentVelocity[12][2];
  byte doubleSpeed;
};

I would like to have one file for each pattern/struct on my sd card, but simply don't know how to do that.

A struct is just an area of memory. So if the SD library allows you to write a block of bytes (or an array of bytes), then you need to have something like this

writefunctionname((uint8_t *)&Pattern_var, sizeof(Pattern_var)/sizeof(uint8_t));

In other words, a pointer to the structure is cast as a pointer to whatever the function will take (uint8_t, int, or other). The number of these elements to be written is the sizeof the structure divided by the sizeof the element to be written. In this case the divisor would be 1 as uint8_t is size 1 byte.

If block writes are not available then a similar thing can be done but you need to write each element of the memory buffer individually (usually using a loop), incrementing the memory pointer for each element.

Okay,thanks. I would like to save them in a file, so that the user can backup the patterns. How can I write and read multiple bytes into one file? file.write only writes one byte or one array of bytes into a file.

Edit. I got it.
Is this the best and fastest way to do?

void savePatternToFile() {
  File patternFile = SD.open("FF.txt", FILE_WRITE);
  patternFile.seek(0);
  patternFile.write(pattern.length);
  patternFile.write(pattern.shuffle);
  patternFile.write(pattern.doubleSpeed);
  for (int a = 0; a < 12; a++) {
    for (int i = 0; i < 64; i++) patternFile.write(pattern.steps[a][i]);
  }
  for (int a = 0; a < 12; a++) {
    for (int i = 0; i < 2; i++) { 
      patternFile.write(pattern.flamSetting[a][i]);
    }
  }
  patternFile.close();
}

void readPattern(){
  File patternFile = SD.open("FF.txt", FILE_WRITE);
  patternFile.seek(0);
  pattern.length = patternFile.read();
  pattern.shuffle = patternFile.read();
  pattern.doubleSpeed = patternFile.read();
  for (int a = 0; a < 12; a++) {
    for (int i = 0; i < 64; i++) pattern.steps[a][i] = patternFile.read();
  }
  for (int a = 0; a < 12; a++) {
    for (int i = 0; i < 2; i++) {
      pattern.accentVelocity[a][i] = patternFile.read();
    }
  }
    patternFile.close();
}

How can I write and read multiple bytes into one file? file.write only writes one byte or one array of bytes into a file.

An array is just a consecutive collection of bytes, just like the struct. marco_c showed you how to write it.

The SD library does have a block write function, pretty much like in my first reply. Extract from the library online manual:

Syntax file.write(data) file.write(buf, len)

Parameters file: an instance of the File class (returned by SD.open()) data: the byte, char, or string (char *) to write buf: an array of characters or bytes len: the number of elements in buf

Using this method would be more efficient and faster, as you do it all in one statement.

marco_c : Thanks!

 patternFile.write((uint8_t *)&pattern, sizeof(pattern)/sizeof(uint8_t));

But how can I read this again and assign it to the pattern struct?

pattern = patternFile.read() is of course not working.

Do i need to:

patternFile.seek(0);
pattern.length = patternFile.read();
pattern.shuffle = patternFile.read();
  for (int a = 0; a < 12; a++) {
    for (int i = 0; i < 64; i++) pattern.steps[a][i] = patternFile.read();
  }
//etc.…

Most good libraries have a block read as well, to match the block write. In this case you will need to use a loop to read all the data in one byte at a time. Set a uint8_t pointer to the address of the data/struct and then for each byte you read, assign it to the 'pointed' location and increment the pointer, repeat.

Okay, I took a look into sdfatlib and it has block read. But I still can’t get it to work.

pattern = patternFile.read((uint8_t *)&pattern, sizeof(pattern)/sizeof(uint8_t));

gives me:

error: no match for ‘operator=’ in ‘pattern = patternFile.SdFile::.SdBaseFile::read(((void*)((uint8_t*)(& pattern))), 819u)’
note: candidates are: Pattern& Pattern::operator=(const Pattern&)

There is no = as per the error message. Think about what the function is doing. It is filling the memory from the SD card, so why are you needing to assign anything? Also, look at the function documentation to see what the return value is. People who write libraries document stuff so you can us their libraries more easily, but you do need to make the effort to read up on it to make sure you are using it properly.

I'm sorry. I only took a quick look and yeah, I forgot to read the description :/

Thanks helping me, it works :)

Maybe its important to mention, that before writing the file to the card it has to be removed, if exists. Otherwise 'write' would append the data to the existing file. Thats what the function did in my case and it took me a long period of trials before i checked it.

This is my (working) basic code for writing and reading a struct (with the help of this thread):

void write_STRUCT() {


 if (SD.exists(filename)) {
   SD.remove(filename);
 }

 File structFile = SD.open(filename, FILE_WRITE);

 if (structFile) {
    structFile.write((uint8_t *)&struct, sizeof(struct));
 }

 structFile.close();
}


void read_STRUCT() {
 File structFile = SD.open(filename, FILE_READ);

 structFile.read((uint8_t *)&struct, sizeof(struct)/sizeof(uint8_t));

 structFile.close();
}
1 Like

Made an account just to say thanks.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.