1616#include "application/input.h"
1717#include "application/keyer.h"
1818#include "application/led.h"
19+ #include "application/storage.h"
20+ #include "core/sys.h"
1921#include "utility/debug.h"
22+ #include "utility/types.h"
2023#include "utility/utility.h"
2124
25+ /* --------------------------------------------------- CONSTANTS ---------------------------------------------------- */
26+
27+ /**
28+ * @def CONFIG_VERSION_CURRENT
29+ * @brief The currently active configuration version.
30+ */
31+ #define CONFIG_VERSION_CURRENT ( 1 )
32+
33+ /**
34+ * @def MINIMUM_SAVE_PERIOD
35+ * @brief Minimum elapsed time between saving config to storage.
36+ */
37+ #define MINIMUM_SAVE_PERIOD ( 5 * TICKS_PER_SEC )
38+
2239/* ----------------------------------------------------- MACROS ----------------------------------------------------- */
2340
2441_Static_assert ( _CONFIG_DFLT_WPM >= WPM_MINIMUM &&
@@ -31,9 +48,17 @@ _Static_assert( _CONFIG_DFLT_BUZZER_FREQUENCY >= BUZZER_MINIMUM_FREQUENCY &&
3148/* --------------------------------------------------- VARIABLES ---------------------------------------------------- */
3249
3350static config_t s_config ; /**< Currently active app configuration. */
51+ static bool s_modified = false; /**< Has the configuration been modified? */
52+ static tick_t s_save_tick = 0 ; /**< Tick config was last saved. */
3453
3554/* ---------------------------------------------- PROCEDURE PROTOTYPES ---------------------------------------------- */
3655
56+ /**
57+ * @fn flush( tick_t )
58+ * @brief Writes the configuration to non-volatile storage and updates state.
59+ */
60+ static void flush ( tick_t tick );
61+
3762/**
3863 * @fn validate_config( config_t const * )
3964 * @brief Returns `true` if all fields in the specified configuration struct are valid.
@@ -83,17 +108,31 @@ void config_default( config_t * config )
83108} /* config_default() */
84109
85110
111+ void config_flush ( void )
112+ {
113+ flush ( sys_get_tick () );
114+
115+ } /* config_flush() */
116+
117+
86118void config_get ( config_t * config )
87119{
88- memcpy ( config , & s_config , sizeof ( config_t ) ) ;
120+ * config = s_config ;
89121
90122} /* config_get() */
91123
92124
93125void config_init ( void )
94126{
95- // Set configuration to defaults, for now
96- config_default ( & s_config );
127+ // Try to get configuration from storage, and restore defaults if that fails.
128+ // In this case, any existing configuration will be lost the next time config is saved.
129+ config_t config ;
130+ if ( ! storage_get_config ( CONFIG_VERSION_CURRENT , sizeof ( config_t ), & config ) ||
131+ ! validate_config ( & config ) )
132+ config_default ( & config );
133+
134+ // Set local copy
135+ s_config = config ;
97136
98137} /* config_init() */
99138
@@ -110,12 +149,31 @@ bool config_set( config_t const * config )
110149 if ( ! validate_config ( config ) )
111150 return ( false );
112151
113- memcpy ( & s_config , config , sizeof ( config_t ) );
152+ s_config = * config ;
153+ s_modified = true;
114154 return ( true );
115155
116156} /* config_set() */
117157
118158
159+ void config_tick ( tick_t tick )
160+ {
161+ if ( ! s_modified || sys_elapsed ( tick , s_save_tick ) < MINIMUM_SAVE_PERIOD )
162+ return ;
163+ flush ( tick );
164+
165+ } /* config_tick() */
166+
167+
168+ static void flush ( tick_t tick )
169+ {
170+ storage_set_config ( CONFIG_VERSION_CURRENT , sizeof ( config_t ), & s_config );
171+ s_modified = false;
172+ s_save_tick = tick ;
173+
174+ } /* flush() */
175+
176+
119177static bool validate_config ( config_t const * config )
120178{
121179 if ( config -> wpm < WPM_MINIMUM ||
0 commit comments