Writing Struct data in file

Could you help me on writing Struct data in Particle file system as text/csv file?

typedef struct {
  int humidity;
  time_t timestamp;
  const char * date_time;
  String device_id;
} SensorData;

Your date_time would need to be a character array, and not a mere pointer to some memory which will definitely not hold the same date once you retrieve that pointer :wink:

However, a UNIX epoch timestamp can be held in an int32_t much more compact and can be used for calculations much easier too - in order to format such a numeric timestamp you can use Time.format() anytime - hence I’m not sure why you want to store timestamp and date_time in the same struct, when both are virtually the same piece of information.

As for the device_id you’d also need a char[25] as a String for the same reasons as above.

4 Likes

I am using these 2 functions for file read and write. Passing my data as comma separated string as
fileString = “DEVICE_001,27,80,1655966444” but after writing I called the read file function but it prints empty values. Could you suggest ?

void writeFile(String fileString) {
  int fd = open("/rssi.txt", O_RDWR | O_CREAT | O_TRUNC | O_APPEND);
  if (fd != -1) { 
    write(fd, fileString.c_str(), fileString.length());
    close(fd);
  }   
}

void readFile() {
  struct stat statbuf;
  int sd = stat("/rssi.txt", &statbuf);

  if (sd != 0) {
    return;
  }

  int fd = open("/rssi.txt", O_RDONLY);
  Log.info("fd %d", fd);

  if (fd != -1) {
    void *buffer;
    int rd = read(fd, buffer, 6);
    char* content = static_cast<char*> (buffer);  
    Log.info("rd %d", rd);

    close(fd);
    Log.info("got a msg buffer");
    Log.info(content);
  }
}

Not sure how you even were able to compile this ?
don’t think that stat(); function even exist for Particle dev and SD card.
Which Lib for SD card are you using ? (I’m assuming that you want to read/write from/to SD card)
You can’t do this:

you have to initialize the File class first e.g: File myFile; or SdFile csvFile; not int myFile; as is not going to work 100% what will happen when you will try
myFile.println("TESTUS...."); compiler will give up believe me :slight_smile:
i suggest to start from here and look for: examples/LowLatencyLoggerADXL345/LowLatencyLogger.ino there’s some info how to write/read from/to struct named block_t
good luck :+1:

This is the entire code I am using. I am trying to write on Particle’s internal file system not on SD card. I just wanted to confirm my data is stored in file or not that’s why I printed content. In real time I post that file content via MQTT.


#include "Particle.h"
#include <fcntl.h>

SYSTEM_MODE(MANUAL);

SerialLogHandler logHandler(LOG_LEVEL_TRACE);

#define SCAN_INTERVAL 5000
#define ONE_DAY_MILLIS (24 * 60 * 60 * 1000)
unsigned long lastSync;

//Function Declarations
void syncCloudTime();
void readFile();
void writeFile();

typedef struct{
  String device_id;
  unsigned long timestamp;
  float sensorReading;
} SensorData;

void setup() {
    (void)logHandler; // Does nothing, just to eliminate warning for unused variable
    //DynamicJsonDocument deviceList(1024);
    syncCloudTime();
}

void loop() {
    if (millis() - lastSync >= ONE_DAY_MILLIS) {
        syncCloudTime();
    }
   
    SensorData data;
    data.device_id = "SENSOR_01";
    data.timestamp = Time.now();
    data.sensorReading = 22.0;
      
    String fileString = String(data.device_id) + "," 
                      + String(data.timestamp) + "," 
                      + String(data.sensorReading);
    writeFile(fileString);
    delay(250);
    readFile();
    delay(5000);
}

void syncCloudTime() { // Request time synchronization from the Particle Device Cloud
    WiFi.on();
    WiFi.connect();
    waitFor(WiFi.ready,60000);
    Particle.connect();
    Particle.syncTime();
    waitFor(Time.isValid, 60000);
    lastSync = millis();
    Particle.disconnect();
    WiFi.disconnect();
    WiFi.off();
}

void writeFile(String fileString) {
  int fd = open("/data.txt", O_RDWR | O_CREAT | O_TRUNC | O_APPEND);
  if (fd != -1) { 
    write(fd, fileString.c_str(), fileString.length());
    close(fd);
  }   
}

void readFile() {
  struct stat statbuf;
  int sd = stat("/data.txt", &statbuf);

  if (sd != 0) {
    return;
  }

  // this always returns 1823 for me, event if I change the file contents

  // read the file
  int fd = open("/rssi.txt", O_RDONLY);

  Log.info("fd %d", fd);

  if (fd != -1) {
    void *buffer;
    int rd = read(fd, buffer, 6);
    char* content = static_cast<char*> (buffer);  

    Log.info("rd %d", rd);
    close(fd);

    Log.info("got a msg buffer");

    // THIS IS JUST EMPTY, I would expect it to be "foobar"
    Log.info(content);
  }
}

This only creates a pointer. It does not reserve any memory to read the data into.

I’d also do away with String and rather use a character array
e.g. instead of

I’d do this

  char fileString[128];
  snprintf(fileString, sizeof(fileString)
          , "%s,%012lu,%.3f"
          , data.device_id   // where device_id should be declared as char[25] in the struct, not String
          , data.timestamp
          , data.sensorReading
          );
  writeFile(fileString, strlen(fileString)+1);
...
void writeFile(const char* fileString, size_t len) {
  ...
}

However, since you have a struct, why not write that as is and as your original question was indicating you wanted anyhow?

  write(fd, (const void*)&data, sizeof(data));
  // and
  read(fd, (void*)&data, sizeof(data));

(providing device_id is defined as char device_id[25])

4 Likes

Sure I try this definitely :+1:. Thanks a lot