Copy a STRUCT record to SD ?

I'm trying to write to SD a struct record.

struct previousgame {  
  byte PreviousGame; // 1 or 2
  byte PreviousGameNumberOfPlayers; // 1, 2, 3, or 4
  String PreviousPlayer1Name; // <= 12 characters
  String PreviousPlayer2Name; // <= 12 characters
  String PreviousPlayer3Name; // <= 12 characters
  String PreviousPlayer4Name; // <= 12 characters
  int PreviousHS1; // <= 9999
  int PreviousHS2; // <= 9999
  int PreviousHS3; // <= 9999
  int PreviousHS4; // <= 9999  
} 
previousgame; // Creates a record

void writepreviousgametoSD() {
myFile = SD.open("newprevi.txt", FILE_WRITE);
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to newprevi.txt...");

// Here is where I'd like to write to SD the record previousgame

    // close the file:
    myFile.close();
    Serial.println("done.");
    // if this was written successfully:
    // delete previous back up file
    // rename old file
    // rename new file    
  } 
  else {
    // if the file didn't open, print an error:
    Serial.println("error opening newprevi.txt");
  }
return;
}

I can write the record one variable at a time but wondered if there was a better way.
Here is what it looks like writing one at a time:

myFile.println(previousgame.PreviousGame);
myFile.println(previousgame.PreviousGameNumberOfPlayers);
myFile.println(previousgame.PreviousPlayer1Name);
myFile.println(previousgame.PreviousPlayer2Name);
myFile.println(previousgame.PreviousPlayer3Name);
myFile.println(previousgame.PreviousPlayer4Name);
myFile.println(previousgame.PreviousHS1);
myFile.println(previousgame.PreviousHS2);
myFile.println(previousgame.PreviousHS3);
myFile.println(previousgame.PreviousHS4);

I can write the record one variable at a time but wondered if there was a better way.

Do you want the data in the file in ASCII format, as that code shows, or binary?

If you want ASCII format, you must do it that way. If you want binary format, you can write the struct to the file with one call to write(). Of course, reading it is trickier.

OK, Thanks.

If you have time to walk through the steps in general terms, I don't understand how to write it in binary to the SD...

CW

I don't understand how to write it in binary to the SD...

myFile.write(previousgame, sizeof(previousgame));

I was going to do it almost exactly as Paul did it, but lose the String:

struct previousgame {  
  byte PreviousGame;                 // 1 or 2
  byte PreviousGameNumberOfPlayers;  // 1, 2, 3, or 4
  char PreviousPlayer1Name[13];      // <= 12 characters + null termination char
  char PreviousPlayer2Name[13];      //         "
  char PreviousPlayer3Name[13];      //         "
  char PreviousPlayer4Name[13];      //         "
  int PreviousHS1;                   // <= 9999
  int PreviousHS2;                   //    "
  int PreviousHS3;                   //    "
  int PreviousHS4;                   //    "  
} 
previousgame; // Creates a record

int recordSize = sizeof(byte) * 2 
                 + sizeof(PreviousPlayer1) + sizeof(PreviousPlayer2)
                 + sizeof(PreviousPlayer3) + sizeof(PreviousPlayer4)
                 + sizeof(int) * 4;
                                  
// some code...

myFile.write(previousgame, recordSize);

Paul's solution also does away with the recordSize calculation.

PaulS:

I don't understand how to write it in binary to the SD...

myFile.write(previousgame, sizeof(previousgame));

This didn't compile for me:
Error is:
no matching function for call to 'File:write(previousgame&, unsigned int)'

econjack:
I was going to do it almost exactly as Paul did it, but lose the String:

struct previousgame {  

byte PreviousGame;                 // 1 or 2
  byte PreviousGameNumberOfPlayers;  // 1, 2, 3, or 4
  char PreviousPlayer1Name[13];      // <= 12 characters + null termination char
  char PreviousPlayer2Name[13];      //         "
  char PreviousPlayer3Name[13];      //         "
  char PreviousPlayer4Name[13];      //         "
  int PreviousHS1;                   // <= 9999
  int PreviousHS2;                   //    "
  int PreviousHS3;                   //    "
  int PreviousHS4;                   //    " 
}
previousgame; // Creates a record

int recordSize = sizeof(byte) * 2
                 + sizeof(PreviousPlayer1) + sizeof(PreviousPlayer2)
                 + sizeof(PreviousPlayer3) + sizeof(PreviousPlayer4)
                 + sizeof(int) * 4;
                                 
// some code...

myFile.write(previousgame, recordSize);




Paul's solution also does away with the *recordSize* calculation.

This didn't compile for me:

Here is the code I used...

   int recordSize = sizeof(previousgame.PreviousGame) + sizeof(previousgame.PreviousGameNumberOfPlayers)
      + sizeof(previousgame.PreviousPlayer1Name) + sizeof(previousgame.PreviousPlayer2Name)
        + sizeof(previousgame.PreviousPlayer3Name) + sizeof(previousgame.PreviousPlayer4Name)
          + sizeof(previousgame.PreviousHS1) + sizeof(previousgame.PreviousHS2)
            + sizeof(previousgame.PreviousHS3)+ sizeof(previousgame.PreviousHS4);

    // some code...

    myFile.write(previousgame, recordSize);

Error was:
no matching function for call to 'File:write(previousgame&, int&)'

This didn't compile for me:
Error is:
no matching function for call to 'File:write(previousgame&, unsigned int)'

Sorry about that. In either case, you need to cast the first argument correctly:

myFile.write((uint8_t *)previousgame, sizeof(previousgame));

I do appreciate the help.

Compiler didn't like that either...

Error is:
invalid cast from type 'previousgame' to type 'unit8_t*'

Unrelated question? Are you person that makes the teensy?

Error is:
invalid cast from type 'previousgame' to type 'unit8_t*'

Yeah, because previousgame is not a pointer.

myFile.write((uint8_t *)&previousgame, sizeof(previousgame));

This at least compiles.

Unrelated question? Are you person that makes the teensy?

No. That's Paul Stoffregen. You can find out more about him on pjrc.com. He has WAY more hair than me.

PaulS,

My question was off topic. I just thought you are PaulS - after all. And I don't know about hair or lack of such.

That last & did help my sketch to compile and I was able to save something to SD. And as you said, reading such a binary file was not something I can easily do.

I'm not sure how to mark this thread solved?

Thanks !!!

It may help to create a union in which the struct is overlapped with a byte array.

Then you can read/write the same data either as a byte array or as a struct - great scope for a right royal [expletive]-up but it would mean you would just write and read the bytearray to the SD card (or wherever) while having it accessible as a struct elsewhere.

...R

The SD class has this:

int File::read(void *buf, uint16_t nbyte) {

It works exactly like the write method.