sm1000_main: Store two copies of the settings.
authorsjlongland <sjlongland@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 27 Sep 2015 04:23:30 +0000 (04:23 +0000)
committersjlongland <sjlongland@01035d8c-6547-0410-b346-abe4f91aad63>
Sun, 27 Sep 2015 04:23:30 +0000 (04:23 +0000)
We keep a rolling serial number (64-bit, so probably flash will wear out
before rollover happens) that is incremented on each write, and we write
to the oldest image in flash.

On load, we pick the newest one that's valid.

git-svn-id: https://svn.code.sf.net/p/freetel/code@2405 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/stm32/src/sm1000_main.c

index 076a9b45453406c65cac78b7b3bd929763f6ab11..0ed856a8ffb937b925b8a36dd9884a0f3857c2f0 100644 (file)
@@ -69,6 +69,8 @@ unsigned int menuExit = 0;
  * User preferences
  */
 static struct prefs_t {
+    /*! Serial number */
+    uint64_t serial;
     /*! Menu frequency */
     uint16_t menu_freq;
     /*! Menu speed */
@@ -79,9 +81,21 @@ static struct prefs_t {
     uint8_t op_mode;
 } prefs;
 
-/* Preferences changed flag */
+/*! Preferences changed flag */
 int prefs_changed = 0;
 
+/*! Number of preference images kept */
+#define PREFS_IMG_NUM       (2)
+/*! Base ROM ID for preferences */
+#define PREFS_IMG_BASE      (0)
+/*! Minimum serial number */
+#define PREFS_SERIAL_MIN    8
+/*! Maximum serial number */
+#define PREFS_SERIAL_MAX    UINT64_MAX
+
+/*! Preference serial numbers, by slot */
+static uint64_t prefs_serial[PREFS_IMG_NUM];
+
 struct tone_gen_t tone_gen;
 struct sfx_player_t sfx_player;
 struct morse_player_t morse_player;
@@ -109,6 +123,65 @@ int16_t software_mix(int16_t a, int16_t b) {
     return s;
 }
 
+/*! Compare current serial with oldest and newest */
+void compare_prefs(int* const oldest, int* const newest, int idx)
+{
+    if (newest && prefs_serial[idx]) {
+        if ((*newest < 0)
+                || (prefs_serial[idx] > prefs_serial[*newest])
+                || ((prefs_serial[idx] == PREFS_SERIAL_MIN)
+                    && (prefs_serial[*newest] == PREFS_SERIAL_MAX)))
+            *newest = idx;
+    }
+
+    if (oldest) {
+        if ((*oldest < 0)
+                || (!prefs_serial[idx])
+                || (prefs_serial[idx] < prefs_serial[*oldest])
+                || ((prefs_serial[idx] == PREFS_SERIAL_MAX)
+                    && (prefs_serial[*oldest] == PREFS_SERIAL_MIN)))
+            *oldest = idx;
+    }
+}
+
+/*! Find oldest and newest images */
+void find_prefs(int* const oldest, int* const newest)
+{
+    int i;
+    if (newest) *newest = -1;
+    if (oldest) *oldest = -1;
+    for (i = 0; i < PREFS_IMG_NUM; i++)
+        compare_prefs(oldest, newest, i);
+}
+
+/*! Load preferences from flash */
+int load_prefs()
+{
+    struct prefs_t image[PREFS_IMG_NUM];
+    int newest = -1;
+    int i;
+
+    /* Load all copies into RAM */
+    for (i = 0; i < PREFS_IMG_NUM; i++) {
+        int res = vrom_read(PREFS_IMG_BASE + i, 0,
+                sizeof(image[i]), &image[i]);
+        if (res == sizeof(image[i])) {
+            prefs_serial[i] = image[i].serial;
+            compare_prefs(NULL, &newest, i);
+        } else {
+            prefs_serial[i] = 0;
+        }
+    }
+
+    if (newest < 0)
+        /* No newest image was found */
+        return -ENOENT;
+
+    /* Load from the latest image */
+    memcpy(&prefs, &image[newest], sizeof(prefs));
+    return 0;
+}
+
 int main(void) {
     struct freedv *f;
     int            nin, nout, i;
@@ -176,13 +249,14 @@ int main(void) {
         }
 
         /* Button released, do an EEPROM erase */
-        vrom_erase(0);
+        for (i = 0; i < PREFS_IMG_NUM; i++)
+            vrom_erase(i + PREFS_IMG_BASE);
     }
     led_rt(LED_OFF);
     tone_reset(&tone_gen, 0, 0);
 
     /* Try to load preferences from flash */
-    if (vrom_read(0, 0, sizeof(prefs), &prefs) != sizeof(prefs)) {
+    if (load_prefs() < 0) {
         /* Fail!  Load defaults. */
         memset(&prefs, 0, sizeof(prefs));
         prefs.op_mode = ANALOG;
@@ -262,10 +336,23 @@ int main(void) {
                         morse_play(&morse_player, NULL);
                         menuExit = 1;
                         if (save_settings) {
+                            int oldest = -1;
+                            int res;
                             /* Copy the settings in */
                             prefs.menu_freq = morse_player.freq;
                             prefs.menu_speed = morse_player.dit_time;
-                            vrom_write(0, 0, sizeof(prefs), &prefs);
+                            /* Increment serial number */
+                            prefs.serial++;
+                            /* Find the oldest image */
+                            find_prefs(&oldest, NULL);
+                            if (oldest < 0)
+                                oldest = 0; /* No current image */
+
+                            /* Write new settings over it */
+                            res = vrom_write(oldest + PREFS_IMG_BASE, 0,
+                                    sizeof(prefs), &prefs);
+                            if (res >= 0)
+                                prefs_serial[oldest] = prefs.serial;
                         }
                     }
                 }