Exemple d'utilisation de structure avec EEPROM.put(), avec CRC et versionnage

par skywodd | | Langue : C++ | Licence : GPLv3

Description :

Exemple d'utilisation de structure avec EEPROM.put().

Variante avec versionnage et détection de première utilisation.

Utilise une somme de contrôle 16 bits pour détecter les erreurs de lecture.

Code source :

Voir le code source brut | Télécharger eeprom_struct_crc.ino | Télécharger eeprom_struct_crc.ino.zip

/**
 * Exemple d'utilisation de structure avec EEPROM.put().
 * Variante avec versionnage et détection de première utilisation.
 * Utilise une somme de contrôle 16 bits pour détecter les erreurs de lecture.
 */

#include <EEPROM.h>

/** Le nombre magique et le numéro de version actuelle */
static const unsigned long STRUCT_MAGIC = 123456789;
static const byte STRUCT_VERSION = 2;

/** La structure qui contient les données */
struct MaStructure {
  unsigned long magic;
  byte struct_version;
  uint16_t checksum;

  int valeur_1; // Depuis la struct_version = 0
  float valeur_2; // Depuis la struct_version = 1
  char valeur_3[16]; // Depuis la struct_version = 2
};

/** L'instance de la structure, globale car utilisé dans plusieurs endroits du programme */
MaStructure ms;

void setup() {
  Serial.begin(9600);

  // Charge le contenu de la mémoire
  chargeEEPROM();

  // Affiche les données dans la structure
  Serial.print("Valeur 1 = ");
  Serial.println(ms.valeur_1);

  Serial.print("Valeur 2 = ");
  Serial.println(ms.valeur_2);

  Serial.print("Valeur 3 = ");
  Serial.println(ms.valeur_3);
}

void loop() {
} 

/** Sauvegarde en mémoire EEPROM le contenu actuel de la structure */
void sauvegardeEEPROM() {
  // Met à jour le nombre magic, le numéro de version et la checksum avant l'écriture
  ms.magic = STRUCT_MAGIC;
  ms.struct_version =  STRUCT_VERSION;
  ms.checksum = 0; // Calcul la checksum sans prendre en compte la valeur actuelle
  ms.checksum = crc16_ccitt((byte*) &ms, sizeof(ms));
  EEPROM.put(0, ms);
}

/** Charge le contenu de la mémoire EEPROM dans la structure */
void chargeEEPROM() {

  // Lit la mémoire EEPROM
  EEPROM.get(0, ms);
  
  // Calcul de la checksum
  uint16_t current_checksum = ms.checksum;
  ms.checksum = 0; // Calcul la checksum sans prendre en compte la valeur actuelle
  uint16_t real_checksum = crc16_ccitt((byte*) &ms, sizeof(ms));
  
  // Détection d'une mémoire non initialisée ou corrompue
  byte erreur = ms.magic != STRUCT_MAGIC || current_checksum != real_checksum;
  
  // Valeurs par défaut struct_version == 0
  if (erreur) {

    // Valeurs par défaut pour les variables de la version 0
    ms.valeur_1 = 42;
  }
  
  // Valeurs par défaut struct_version == 1
  if (ms.struct_version < 1 || erreur) {

    // Valeurs par défaut pour les variables de la version 1
    ms.valeur_2 = 13.37;
  }

  // Valeurs par défaut pour struct_version == 2
  if (ms.struct_version < 2 || erreur) {

    // Valeurs par défaut pour les variables de la version 2
    strcpy(ms.valeur_3, "Hello World!");
  }

  // Sauvegarde les nouvelles données
  sauvegardeEEPROM();
}

/** Fonction de calcul d'une somme de contrôle CRC-16 CCITT 0xFFFF */
uint16_t crc16_ccitt(unsigned char* data, unsigned int data_len) {
  uint16_t crc = 0xFFFF;

  if (data_len == 0)
    return 0;

  for (unsigned int i = 0; i < data_len; ++i) {
    uint16_t dbyte = data[i];
    crc ^= dbyte << 8;

    for (unsigned char j = 0; j < 8; ++j) {
      uint16_t mix = crc & 0x8000;
      crc = (crc << 1);
      if (mix)
        crc = crc ^ 0x1021;
    }
  }

  return crc;
}