Can't read bytes on SD card inside a function

Hi everyone,

I would like to create a queue on a file on SD card. I want to store struct data in the queue. To make it easy I write data in the form of bytes.

I managed to write the data on the file using the following function:

 void enqueue(const struct_data theData, bool debug) {
  String queueFileName = "/QUEUE.TXT";

  if (!SD.exists(queueFileName)) {
    File queueFile = SD.open(queueFileName, FILE_WRITE);
    queueFile.close();
  }
  File queueFile = SD.open(queueFileName, FILE_APPEND);

  if (queueFile) {
    queueFile.write((const uint8_t *)&theData, sizeof(struct_data));
  }
  else {
    if (debug) Serial.println("Can't open queue");
  }

  queueFile.close();
}

And I can read the data in the loop function as follow:

String queueFileName = "/QUEUE.TXT";
File queueFile = SD.open(queueFileName, FILE_READ);

while (queueFile.available() > 0) {
  struct_data buffer;
  queueFile.read((uint8_t *)&buffer, sizeof(struct_data));
  printData(buffer);
  Serial.write((const uint8_t *)&buffer, sizeof(struct_data));
  Serial.println();
}

queueFile.close();

However, when I write almost the same lines inside a specific dequeue function, it doesn't work anymore. It feels like some bytes are "corrupted". I don't have any error but the format of the struct isn't respected and I can't get back the values of the several fiels.

bool dequeue(struct_data theData, bool debug) {
  String queueFileName = "/QUEUE.TXT";

  // check if the queue file exists
  if (!SD.exists(queueFileName)) {
    if (debug) Serial.println("No queue available!");
    return false;
  }

  File queueFile = SD.open(queueFileName, FILE_READ);
  if (!queueFile) {
    if (debug) Serial.println("Failed to open the queue file!");
    return false;
  }

  // check if the queue is empty
  if (queueFile.available()<=0) {
    if (debug) Serial.println("Queue is empty!");
    return false;
  }
  
  // read the first element of the queue
  queueFile.read((uint8_t *)&theData, sizeof(struct_data));

  String tempFileName = "/TEMP.TXT";
  // ensure the temp file does not already exist, and if it does, remove it
  if (SD.exists(tempFileName)) {
    SD.remove(tempFileName);
  }
  
  File tempFile = SD.open(tempFileName, FILE_WRITE);
  if (!tempFile) {
    if (debug) Serial.println("Failed to create the temporary file!");
    queueFile.close();
    return false;
  }

  // transfer remaining elements to the temp file
  while (queueFile.available() > 0) {
    struct_data buffer;
    queueFile.read((uint8_t *)&buffer, sizeof(struct_data));
    tempFile.write((const uint8_t *)&buffer, sizeof(struct_data));
  }

  queueFile.close();
  tempFile.close();

  // remove the old queue file
  SD.remove(queueFileName);

  char c_tempFileName[tempFileName.length() + 1];
  char c_queueFileName[queueFileName.length() + 1];
  memcpy(c_tempFileName, tempFileName.c_str(), tempFileName.length() + 1);
  memcpy(c_queueFileName, queueFileName.c_str(), queueFileName.length() + 1);
  if (!SD.rename(c_tempFileName, c_queueFileName) && debug) {
    Serial.println("Failed to rename the temporary file!");
    return false;
  }

  return true;
}


void enqueue(const struct_data theData, bool debug) {
  String queueFileName = "/QUEUE.TXT";

  if (!SD.exists(queueFileName)) {
    File queueFile = SD.open(queueFileName, FILE_WRITE);
    queueFile.close();
  }
  File queueFile = SD.open(queueFileName, FILE_APPEND);

  if (queueFile) {
    queueFile.write((const uint8_t *)&theData, sizeof(struct_data));
  }
  else {
    if (debug) Serial.println("Can't open queue");
  }

  queueFile.close();
}

Does someone understand why it doesn't work?

Thanks in advance

Please explain what "doesn't work" means. What did you expect to happen, and what happened instead.

By the way, always post all the code, as the error can often be found in the part you did not post.

close the file before return false in the case it is empty

Thank you for your answer !

When I try to print the fields of the struct after calling enqueue, all the fields are set to default value: (I guess it's due to a "wrong data format")

Tank ID: 0; Board ID: 0; Date: 2000/01/01 00:00:00; Temperature: 0.00; Humidity: 0.00; Distance: -1.00

And the struct is the following:

typedef struct struct_data {
  const char prefix[3] = {'D', 'A', 'T'};
  uint8_t tankID;
  uint8_t boardID;
  DateTime date;
  float temperature;
  float humidity;
  float distance = -1;
} struct_data;

For the moment the code is pretty empty. I didn't go further since this part of the code doesn't work.


#include "message.hpp"
#include "SD.h"

#define DEBUG true

#define CS_PIN 5

struct_data theData;
 
void setup() {
  // initialize Serial monitor
  Serial.begin(115200);


  //------------------------------SD card module------------------------------
  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  while (!SD.begin(CS_PIN)) {
    Serial.println("Card failed, or not present.");
    delay(500);
  }
  Serial.println("Card initialized!");
  

}


void loop() {

  /*String queueFileName = "/QUEUE.TXT";
  File queueFile = SD.open(queueFileName, FILE_READ);

  while (queueFile.available() > 0) {
    struct_data buffer;
    queueFile.read((uint8_t *)&buffer, sizeof(struct_data));
    printData(buffer);
    Serial.write((const uint8_t *)&buffer, sizeof(struct_data));
    Serial.println();
  }

  queueFile.close();*/
  
  if (dequeue(theData, true)) printData(theData);
  delay(4000);
}


bool dequeue(struct_data theData, bool debug) {
  String queueFileName = "/QUEUE.TXT";

  // check if the queue file exists
  if (!SD.exists(queueFileName)) {
    if (debug) Serial.println("No queue available!");
    return false;
  }

  File queueFile = SD.open(queueFileName, FILE_READ);
  if (!queueFile) {
    if (debug) Serial.println("Failed to open the queue file!");
    return false;
  }

  // check if the queue is empty
  if (queueFile.available()<=0) {
    if (debug) Serial.println("Queue is empty!");
    queueFile.close();
    return false;
  }
  
  // read the first element of the queue
  queueFile.read((uint8_t *)&theData, sizeof(struct_data));

  String tempFileName = "/TEMP.TXT";
  // ensure the temp file does not already exist, and if it does, remove it
  if (SD.exists(tempFileName)) {
    SD.remove(tempFileName);
  }
  
  File tempFile = SD.open(tempFileName, FILE_WRITE);
  if (!tempFile) {
    if (debug) Serial.println("Failed to create the temporary file!");
    queueFile.close();
    return false;
  }

  // transfer remaining elements to the temp file
  while (queueFile.available() > 0) {
    struct_data buffer;
    queueFile.read((uint8_t *)&buffer, sizeof(struct_data));
    tempFile.write((const uint8_t *)&buffer, sizeof(struct_data));
  }

  queueFile.close();
  tempFile.close();

  // remove the old queue file
  SD.remove(queueFileName);

  char c_tempFileName[tempFileName.length() + 1];
  char c_queueFileName[queueFileName.length() + 1];
  memcpy(c_tempFileName, tempFileName.c_str(), tempFileName.length() + 1);
  memcpy(c_queueFileName, queueFileName.c_str(), queueFileName.length() + 1);
  if (!SD.rename(c_tempFileName, c_queueFileName) && debug) {
    Serial.println("Failed to rename the temporary file!");
    return false;
  }

  return true;
}


void enqueue(const struct_data theData, bool debug) {
  String queueFileName = "/QUEUE.TXT";

  if (!SD.exists(queueFileName)) {
    File queueFile = SD.open(queueFileName, FILE_WRITE);
    queueFile.close();
  }
  File queueFile = SD.open(queueFileName, FILE_APPEND);

  if (queueFile) {
    queueFile.write((const uint8_t *)&theData, sizeof(struct_data));
  }
  else {
    if (debug) Serial.println("Can't open queue");
  }

  queueFile.close();
}


You're right, I added it. Thank you !

I think you should pass a pointer to your struct, not the struct itself, ' cause in this case your passing a value to the function, value that belog to a local variable, not at your struct. Try like this:

bool dequeue(struct_data *theData, bool debug) {
  String queueFileName = "/QUEUE.TXT";

  // check if the queue file exists
  if (!SD.exists(queueFileName)) {
    if (debug) Serial.println("No queue available!");
    return false;
  }

  File queueFile = SD.open(queueFileName, FILE_READ);
  if (!queueFile) {
    if (debug) Serial.println("Failed to open the queue file!");
    return false;
  }

  // check if the queue is empty
  if (queueFile.available()<=0) {
    if (debug) Serial.println("Queue is empty!");
    return false;
  }
  
  // read the first element of the queue
  queueFile.read((uint8_t *)theData, sizeof(struct_data));

and call it dequeue(&theData,true);

Ciao, Ale.

It works! Thank you so much!

in C++ you can use

bool dequeue(struct_data& theData, bool debug) {

with

dequeue(theData,true);

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