Hi all,
the idea of counting the boots popped up in this forum recently. I found it interesting, so as an exercise I wrote a quick sketch that does just that. This apparently simple task made me think about some interesting problems, and their solutions, which can have broader applicability (e.g. how to check if the data read from eeprom is not garbage).
So for anyone interested, here's the code.
Just set the serial monitor to 9600, upload and enjoy
// This sketch counts the number of times the board has booted.
#include <EEPROM.h>
#define SKETCH_NAME "Boot count test"
#define SIGNATURE 0xAEÂ Â Â Â // arbitrary "magic" number to ensure we detect uninitialized eeprom cells
#define DATA_ADDRESS 0Â Â Â Â // this is where we store our data; could be anything between 0 and 1023-sizeof(data)
// uncomment to make the sketch tell you what's going on...
#define _VERBOSE
// data we'll put into eeprom
struct boot_count_t {
  unsigned long value;
  uint8_t signature;
  uint8_t checksum;
};
// sum num_bytes bytes modulo 255 starting from address ptr
uint8_t naive_checksum(const void* ptr, unsigned int num_bytes) {
  uint8_t* p;
  uint8_t result;
  unsigned int i;
 Â
  result = 0;
  p = (uint8_t*)ptr;
  for (i = 0; i < num_bytes; i++) {
    result += *p;
    p++;
  }
 Â
  return result;
}
uint8_t struct_checksum(const struct boot_count_t* s) {
  return naive_checksum(s, sizeof(*s) - sizeof(s->checksum));
}
boolean is_struct_good(const struct boot_count_t* s) {
  return (s->signature == SIGNATURE) && (s->checksum == struct_checksum(s));
}
void set_value(struct boot_count_t* s, unsigned long value) {
  s->signature = SIGNATURE;
  s->value = value;
  s->checksum = struct_checksum(s);
}
unsigned long get_value(const struct boot_count_t* s) {
  return s->value;
}
void read_struct(struct boot_count_t* s) {
  unsigned int i;
  uint8_t b;
  uint8_t* p;
 Â
  p = (uint8_t*)s;
  for (i = 0; i < sizeof(*s); i++) {
    b = EEPROM.read(DATA_ADDRESS + i);
    *p = b;
    p++;
  }
}
void write_struct(const struct boot_count_t* s) {
  unsigned int i;
  uint8_t* p;
  p = (uint8_t*)s;
  for (i = 0; i < sizeof(*s); i++) {
    EEPROM.write(DATA_ADDRESS + i, *p);
    p++;
  }
}
// stores the struct into eeprom, and returns true if the verification succeded
// false means the data was not correctly written or read back from eeprom
boolean write_struct_and_verify(const struct boot_count_t* s) {
  struct boot_count_t aux;
 Â
  write_struct(s);
  read_struct(&aux);
  return (memcmp(s, &aux, sizeof(aux)) == 0);
}
void eeprom_dump(unsigned int start_addr = 0, unsigned int end_addr = 1023) {
  unsigned int i;
 Â
  if (start_addr > end_addr) {
    return;
  }
 Â
  if (end_addr >= 1024) {
    end_addr = 1023;
  }
 Â
  for (i = start_addr; i <= end_addr; i++) {
    Serial.print(EEPROM.read(i), HEX);
    if (((i+1) % 8 == 0)) {
      Serial.println();
    }
    else {
      Serial.print(" ");
    }
  }
}
void print_struct(const struct boot_count_t* s) {
  Serial.print("value = ");
  Serial.println(s->value);
  Serial.print("signature = ");
  Serial.println(s->signature, HEX);
  Serial.print("checksum = ");
  Serial.println(s->checksum, HEX);
}
struct boot_count_t boot_count;
void setup() {
  boolean b;
Â
  Serial.begin(9600);
  Serial.println(SKETCH_NAME);
Â
  delay(1000);
Â
#ifdef _VERBOSE
  /* verbose mode ;-) */
  Serial.print("Reading struct... ");
  read_struct(&boot_count);
  Serial.println("done.");
Â
  Serial.print("Checking data consistency... ");
  if (!is_struct_good(&boot_count)) {
    Serial.println("NOT ok: initializing");
    set_value(&boot_count, 0);
  }
  else {
    Serial.println("ok");
  }
Â
  Serial.println("Data printout:");
  print_struct(&boot_count);
Â
  Serial.print("Incrementing boot count... ");
  set_value(&boot_count, get_value(&boot_count) + 1);
  Serial.println("done.");
  Serial.println("Data printout:");
  print_struct(&boot_count);
  Serial.print("Writing+verifying... ");
  b = write_struct_and_verify(&boot_count);
  if (b) {
    Serial.println("OK");
  }
  else {
    Serial.println("ERROR: eeprom is probabl corrupt!");
  }
Â
  Serial.println("Final memory dump:");
  eeprom_dump(0, 255);
 Â
#else
 Â
  // normal operation: just print the number of boots so far, including this one
  read_struct(&boot_count);
  if (!is_struct_good(&boot_count)) {
    set_value(&boot_count, 0);      // initialize if needed
  }
  set_value(&boot_count, get_value(&boot_count) + 1);    // incr. number of boots
 Â
  Serial.print("Boot count: ");            // print it
  Serial.println(get_value(&boot_count));
 Â
  if (!write_struct_and_verify(&boot_count)) {    // save new value and notify in case of errors
    Serial.println("Error writing/verifying: EEPROM is probably corrupt!");
  }
#endif
}
void loop() {
}