Sauvegarde de fichier de préférences sur carte SD

Salut à toutes et tous

J'ai retrouvé un bout de code d'un ancien programme qui permet de gérer sur carte SD un fichier de configuration et qui utilise la bibliothèque SdFat. je l'ai extrait pour en faire un petit code de démo en me disant que ça pourrait servir.

L'idée de base est de grouper tous les paramètres qui ont besoin d'être sauvegardés dans une structure, ici pour la démo j'ai 3 variables, toto, tata et tutu

struct __attribute__ ((packed)) t_sdConfig {
  uint32_t  motMagique; // NE PAS TOUCHER
  // les paramaètres de l'application
  int toto;
  int tata;
  int tutu;
};

le motMagique permet de se rassurer sur l'intégrité de ce que l'on lit sur la carte.

Il y a une fonction definirParametresParDefaut() à modifier dans laquelle vous devez fournir la valeur par défaut de vos paramètres (ici toto, tata et tutu) et si nécessaire une fonction printParametres() qui affiche les paramètres en cours.

Une fois donc la structure et definirParametresParDefaut() définies vous avez fait le job.
dans le setup() vous devez activer le lecteur SD, c'est ce que fait

  if (!SD.begin(CS_PIN)) printErreur(F("lecteur SD introuvable"), true); // erreur fatale

puis essayer de lire les paramètres. C'est ce que fait la fonction lectureParametres() qui retourne vrai si la lecture a retourné les paramètres par défaut

  if (lectureParametres()) Serial.println(F("On prend les paramètres par défaut"));
  else  Serial.println(F("Lecture des paramètres OK"));

Quand vous faites dans le code une modification d'un ou plusieurs des paramètres et que vous voulez faire une sauvegarde de ces nouvelles valeurs, il suffit juste d'appeler ecritureParametres();

Chargez le code exemple ci dessous, ouvrez la console à 115200 bauds, et à chaque reboot de la carte vous devriez voir la valeur de toto qui double.

#include <SPI.h>
#include <SdFat.h>
#define CS_PIN SS

SdFat SD;

const uint32_t clefMagique = 0xDEADBEEF;
const char*    nomFichierPreferences = "pref.bin";
const char*    nomFichierPreferencesBkup = "_pref.bin";

struct __attribute__ ((packed)) t_sdConfig {
  uint32_t  motMagique;
  // les paramaètres de l'application
  int toto;
  int tata;
  int tutu;
};
const size_t configSize = sizeof(t_sdConfig);

t_sdConfig parametres;

void printErreur(const __FlashStringHelper* message, bool erreurFatale = false)
{
  if (erreurFatale) SD.errorHalt(message);
  else SD.errorPrint(message);
}

void printParametres()
{
  Serial.print(F("motMagique = 0x")); Serial.println(parametres.motMagique, HEX);
  Serial.print(F("toto = ")); Serial.println(parametres.toto);
  Serial.print(F("tata = ")); Serial.println(parametres.tata);
  Serial.print(F("tutu = ")); Serial.println(parametres.tutu);
}

void definirParametresParDefaut()
{
  parametres.motMagique = clefMagique; // NE PAS TOUCHER
  // ICI DEFINIR VOS PROPRES PARAMETRES PAR DEFAUT
  parametres.toto = 10;
  parametres.tata = 20;
  parametres.tutu = 30;
}

bool ecritureParametres()
{
  bool sauvegardeOK = false;

  // sauvegarde du fichier précédent
  if (SD.exists(nomFichierPreferences)) SD.rename(nomFichierPreferences, nomFichierPreferencesBkup);

  // écriture du nouveau fichier
  File fichierPref = SD.open(nomFichierPreferences, O_WRITE | O_CREAT | O_TRUNC); // ouverture en écriture et détruire le fichier s'il existe
  if (fichierPref) {
    if (fichierPref.write(&parametres, configSize) == configSize) sauvegardeOK = true;
    else printErreur(F("contenu fichier Préférences"));
    fichierPref.close();
  } else {
    printErreur(F("Impossible d'écrire le Fichier Préférences"));
    if (SD.exists(nomFichierPreferencesBkup)) SD.rename(nomFichierPreferencesBkup, nomFichierPreferences);    // si on a un backup on le remet
  }

  return sauvegardeOK;
}


// on retourne true si on a pris les valeurs par défaut
bool lectureParametres(bool forceDefaut = false)
{
  File fichierPref;

  if (!forceDefaut) {
    forceDefaut = true;
    if (SD.exists(nomFichierPreferences)) {
      fichierPref = SD.open(nomFichierPreferences, O_RDONLY); // ouverture en lecture seule
      if (!fichierPref) {
        printErreur(F("Accès au fichier Préférences"));
      } else {
        if (fichierPref.fileSize() != configSize) printErreur(F("Taille fichier Préférences"));
        else if ((fichierPref.read(&parametres, configSize) == configSize) && (parametres.motMagique == clefMagique)) forceDefaut = false;
        else printErreur(F("contenu fichier Préférences"));
        fichierPref.close();
      }
    } else printErreur(F("Fichier Préférences inexistant"));
  }

  if (forceDefaut) {
    definirParametresParDefaut(); // on se rabat sur les préférences par défaut
    ecritureParametres();         // que l'on sauvegarde
  }
  return forceDefaut;
}

void setup()
{
  Serial.begin(115200);
  while (!Serial); // wait for Serial to be ready, needed on certain boards

  // on configure le lecteur de carte SD
  if (!SD.begin(CS_PIN)) printErreur(F("lecteur SD introuvable"), true); // erreur fatale

  Serial.println(F("--- DEFINITION DES PARAMETRES ----"));
  if (lectureParametres()) Serial.println(F("On prend les paramètres par défaut"));
  else  Serial.println(F("Lecture des paramètres OK"));
  printParametres();

  // en cas de modifications, on sauvegarde
  parametres.toto *= 2;
  ecritureParametres();

  // on relit pour voir
  Serial.println(F("\nRelecture après modification"));
  if (lectureParametres()) Serial.println(F("On prend les paramètres par défaut"));
  else  Serial.println(F("Lecture des paramètres OK"));
  printParametres();
}

void loop() {}

Merci J-M-L,
De bonnes idees en perspective.

Bonsoir J-M-L
Votre sujet m'intéresse, mais j'aimerais vous exposer mes besoins pour savoir si cela peut être réalisable
J'utilise le programmateur horaire de Sweethome pour faire fonctionner plusieurs systèmes d'arrosages, mais je rencontre un certain doute sur l'exécution réelle des opérations. Donc j'aimerais enregistrer sur plusieurs jours les dates, heures et minutes de fonctionnement .
Est-ce votre projet peut être la solution des enregistrements ?

PS: je suis débutant en Arduino

Bonjour - ça n’a rien à voir avec la sauvegarde de préférences. Je vous suggère de poster votre demande dans le forum principal français en exposant bien votre montage, donnant des liens vers le code source utilisé et en expliquant vos constatations de mauvais déclenchement. (Avez vous contacté l’auteur du code/Sweethome je n’ai aucune idée de quoi vous parlez?)

Soit il faudra debugger le code ou votre montage hardware soit instrumenter les commandes pour créer un log dans le temps et voir si les ordres ont bien été donnés

Merci de votre réponse
Je vais faire le nécessaire pour avancer au mieux
Cordialement

J'ai un petit problème avec ce tutoriel:
les cartes Sd font plusieurs Gigas, et ça ressemble à un crime économique de s'en servir pour stocker un fichier de configuration; de plus, les cartes SD peuvent être lues/écrites depuis un PC/RPi via un adaptateur; un stockage en ASCII (json; csv, ..) permettrait, me semble-t-il, d'éditer assez facilement ce fichier de configuration (tel quel, il faut recompiler un programme) , avec un gaspillage de place négligeable.

OTOH, sur UNO, la structure de programme et de données qui est décrite dans ce tutorial est quasiment idéale -à une adaptation près- pour un stockage de données de configuration ... dans l'EEPROM (est livrée avec l'Arduino, dans lequel elle est cachée)