Go Down

Topic: Reading/writing struct to sd card (Read 1 time) previous topic - next topic

flocked

Hi,

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

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.

marco_c

#1
Oct 10, 2013, 10:35 pm Last Edit: Oct 11, 2013, 08:19 am by marco_c Reason: 1
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

Code: [Select]
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.
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

flocked

#2
Oct 11, 2013, 04:50 am Last Edit: Oct 11, 2013, 06:31 am by flocked Reason: 1
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?
Code: [Select]

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();
}

PaulS

Quote
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.

marco_c

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

Quote
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.
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

flocked

#5
Oct 11, 2013, 09:02 am Last Edit: Oct 11, 2013, 09:16 am by flocked Reason: 1
marco_c : Thanks!

Code: [Select]
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:
Code: [Select]
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.…

marco_c

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.
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

flocked

Okay, I took a look into sdfatlib and it has block read. But I still can't get it to work.
Code: [Select]
pattern = patternFile.read((uint8_t *)&pattern, sizeof(pattern)/sizeof(uint8_t));

gives me: 
Quote
error: no match for 'operator=' in 'pattern = patternFile.SdFile::<anonymous>.SdBaseFile::read(((void*)((uint8_t*)(& pattern))), 819u)'
note: candidates are: Pattern& Pattern::operator=(const Pattern&)

marco_c

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.
Arduino libraries http://arduinocode.codeplex.com
Parola for Arduino http://parola.codeplex.com

flocked

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

Thanks helping me, it works :)

Go Up