Huge update of app configuration menu (params)
authorNathael Pajani <nathael.pajani@ed3l.fr>
Sat, 15 Oct 2022 00:39:04 +0000 (02:39 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Tue, 8 Nov 2022 11:07:29 +0000 (12:07 +0100)
v10/.version
v10/Makefile
v10/config.c
v10/config.h
v10/interface.c
v10/interface.h
v10/main.c
v10/param.c
v10/version.h

index e1617e8..69a893a 100644 (file)
@@ -1 +1 @@
-57
+66
index 4813728..d3cc3d6 100644 (file)
@@ -19,5 +19,8 @@ $(NAME).bin:
 clean mrproper:
        @make -C ../../.. ${PRINT_DIRECTORY} $@
 
+appclean:
+       rm ../../../objs/apps/$(MODULE)/$(NAME)/* $(NAME).bin $(NAME).elf
+
 temp:
        @$(shell ../../../update_version.sh && touch interface.c)
index 8b925c9..6495330 100644 (file)
@@ -225,6 +225,10 @@ void modules_config(void)
 /***************************************************************************** */
 /* External components */
 
+uint8_t interface_board_present = 0;
+uint8_t power_board_present = 0;
+
+
 /* Thermocouple reading */
 const struct max31855_sensor_config thermocouple = {
        .ssp_bus_num = 0,
@@ -275,9 +279,6 @@ int temp_read(uint32_t uart, int* deci_degrees_disp, int* deci_degrees_power)
 }
 
 
-uint8_t interface_board_present = 0;
-uint8_t power_board_present = 0;
-
 /* Configure external components */
 int external_components_config(uint32_t uart)
 {
@@ -430,7 +431,7 @@ uint32_t sunny_days_prod_value = 0;
 /* If temperature falls bellow ENTER_FORCE_HEATER_TEMP value, we enter forced heater mode, until
  *    TARGET_FORCED_HEATER_TEMP is reached.
  * When in forced heater mode, the heater is controlled to heat at FORCED_MODE_VALUE which
- *    is between 0 and 100.
+ *    is between 20 and 90 °C.
  */
 #define ENTER_FORCE_HEATER_TEMP  (30 * 100) /* 30 °C */
 #define TARGET_FORCED_HEATER_TEMP (50 * 100) /* 50 °C */
@@ -447,10 +448,18 @@ uint32_t sunny_days_prod_value = 0;
 #define MANUAL_ACTIVATION_DURATION  3  /* Three hours */
 /* Target temperature for manual force heating */
 #define MANUAL_TARGET_FORCED_HEATER_TEMP (60 * 100) /* 60 °C */
-/* Define type of manual force */
-#define MANUAL_TYPE_TIMER  1
-#define MANUAL_TYPE_TARGET  2
-#define DEFAULT_MANUAL_FORCE_TYPE MANUAL_TYPE_TARGET 
+
+/* Compute max_intensity from config grid_power_limit.
+ * grid_power_limit is in kVA, max_intensity in mA */
+void update_max_intensity(void)
+{
+       max_intensity = sc_conf.grid_power_limit * 1000 * 1000 / 230;
+}
+/* Update sunny_days_prod_value (Watt to mA) */
+void update_sunny_days_prod_value(void)
+{
+       sunny_days_prod_value = (((uint32_t)(sc_conf.source_has_power_ok) * 1000) / 230);
+}
 
 void scialys_check_config(void)
 {
@@ -465,27 +474,30 @@ void scialys_check_config(void)
                        uprintf(UART0, "Fallback to default config\n");
                        sc_conf.grid_power_limit = GRID_POWER_LIMIT;
                        sc_conf.source_power_max = SOURCE_POWER_MAX;
+                       sc_conf.source_has_power_ok = SOURCE_POWER_MAX / 2;
                        sc_conf.load_power_max = LOAD_POWER_MAX;
                        sc_conf.conf_max_temp = MAX_TEMP_CONFIG;
-                       sc_conf.enter_force_heater_temp = ENTER_FORCE_HEATER_TEMP;
-                       sc_conf.auto_forced_target_heater_temp = TARGET_FORCED_HEATER_TEMP;
+                       sc_conf.enter_forced_mode_temp = ENTER_FORCE_HEATER_TEMP;
                        sc_conf.auto_forced_mode_value = FORCED_MODE_VALUE;
-                       sc_conf.forced_heater_delay = FORCED_HEATER_DELAY;
-                       sc_conf.forced_heater_duration = FORCED_HEATER_DURATION;
+                       sc_conf.auto_forced_target_heater_temp = TARGET_FORCED_HEATER_TEMP;
+                       sc_conf.auto_forced_heater_delay = FORCED_HEATER_DELAY;
+                       sc_conf.auto_forced_heater_duration = FORCED_HEATER_DURATION;
                        sc_conf.manual_forced_mode_value = MANUAL_FORCED_MODE_VALUE;
                        sc_conf.manual_target_heater_temp = MANUAL_TARGET_FORCED_HEATER_TEMP;
                        sc_conf.manual_activation_duration = MANUAL_ACTIVATION_DURATION;
-                       sc_conf.manual_force_type = DEFAULT_MANUAL_FORCE_TYPE;
+                       sc_conf.manual_force_type = FORCE_TYPE_TIMER;
                        sc_conf.never_force = 0;
                /* Fallthrough : set additionnal config */
                case 0x01: /* Old config is 0x01 add parts from 0x02 and newer */
+                       sc_conf.load_type = LOAD_TYPE_AC_RES;
+                       sc_conf.auto_force_type = FORCE_TYPE_MIN;
                case 0x02: /* Old config is 0x02 add parts from 0x03 and newer */
                        sc_conf.conf_version = CONFIG_VERSION;
                        sc_conf.config_ok = CONFIG_OK;
        }
 
-       /* Update sunny_days_prod_value (Watt to mA) */
-       sunny_days_prod_value = (((uint32_t)(sc_conf.load_power_max / 3) * 1000) / 230);
+       update_sunny_days_prod_value();
+       update_max_intensity();
 }
 
 /* Read main configuration - or set to default one */
index f70c351..af8ce21 100644 (file)
  * Default values are defined within config.c
  *
  * Meaning of fields :
+ *
  * grid_power_limit :
- *   Maximum power which can be used from the external (paid) power source, specified in kWatt
- * sunny_days_prod_value :
- *   in milli Amps
- * enter_force_heater_temp :
+ *   Maximum power which can be used from the external (paid) power source, specified (in kWatt)
+ * source_power_max :
+ *   Maximum power which can be produced by installation (in Watts)
+ * source_has_power_ok :
+ *   Power production value to be considered as enough to trigger delayed force heating (in Watts)
+ * load_power_max :
+ *   Maximum power used by the load. Currently unused by code (in Watts)
+ * conf_max_temp :
+ *   Maximum temperature at which heating stops, whatever the condition (production or manual
+ *   force included) [20 .. 90]
+ *
+ * enter_forced_mode_temp :
  *   temperature bellow which the system enters auto forced heating mode
- *   degrees centigrade
- * auto_forced_target_heater_temp :
- *   
+ *   degrees centigrade [0 .. 50] (best not to set above 40)
  * auto_forced_mode_value :
- *   
- * forced_heater_delay :
- *   
- * forced_heater_duration :
- *   
+ *   command value to be used when in auto forced mode [10 .. 100]
+ * auto_forced_target_heater_temp :
+ *   temperature up to which the water is heated when in auto forced mode [20 .. 90]
+ * auto_forced_heater_delay :
+ *   time to wait before starting auto forced heating, in order to wait for production to start
+ *   (sunrise, wind, ...)
+ * auto_forced_heater_duration :
+ *   duration (hours) of auto forced heating [1 .. 10]
+ * auto_force_type :
+ *   type of termination condition for manual force mode (off (no auto force) temp, time, both (first))
  * manual_forced_mode_value :
- *   
+ *   command value to be used when in manual forced mode [10 .. 100]
  * manual_target_heater_temp :
- *   
+ *   temperature up to which the water is heated when in manual forced mode [20 .. 90]
  * manual_activation_duration :
- *   
+ *   duration (hours) of manual forced heating [1 .. 10]
  * manual_force_type :
- *   
+ *   type of termination condition for manual force mode (temp, time, both (first))
  * never_force :
  *   
  */
 #define CONFIG_OK  0x4F4B  /* "OK" in ASCII */
-#define CONFIG_VERSION  0x01
+#define CONFIG_VERSION  0x02
 struct scialys_config {
+       /* Config version and info */
        uint8_t conf_version;
        uint8_t checksum;
+       uint16_t config_ok;
        /* Config limits */
        uint16_t grid_power_limit; /* specified in kWatt */
        uint16_t source_power_max; /* specified in Watt */
+       uint16_t source_has_power_ok; /* specified in Watt */
        uint16_t load_power_max; /* specified in Watt */
        uint16_t conf_max_temp; /* degrees centigrade (0 - 90°C) */
-       uint16_t load_type; /* LOAD_TYPE_AC or LOAD_TYPE_DC */
-       uint16_t force_command_value; /* % : 0 - 100 */
-       /* Manual Force limits */
-       uint16_t enter_force_heater_temp;  /* degrees centigrade (0 - 90°C) */
+       /* Auto Force limits */
+       uint16_t enter_forced_mode_temp;  /* degrees centigrade (2 - 60°C) */
+       uint16_t auto_forced_mode_value; /* % : 25 - 100 */
        uint16_t auto_forced_target_heater_temp; /* degrees centigrade (0 - 90°C) */
-       uint16_t auto_forced_mode_value; /* % : 0 - 100 */
-       uint16_t forced_heater_delay;
-       uint16_t forced_heater_duration;
-       uint16_t manual_forced_mode_value; /* % : 0 - 100 */
+       uint16_t auto_forced_heater_delay; /* Hours : 0 - 5 */
+       uint16_t auto_forced_heater_duration; /* Hours : 1 - 5 */
+       uint16_t auto_force_type; /* Off, Min, Max, Timer, Target */
+       /* Manual Force limits */
+       uint16_t manual_forced_mode_value; /* % : 25 - 100 */
        uint16_t manual_target_heater_temp; /* degrees centigrade (0 - 90°C) */
        uint16_t manual_activation_duration;
-       uint8_t manual_force_type; /* Off, Min, Max */
-       uint8_t never_force; /* 0 or 1 */
+       uint16_t manual_force_type; /* Off, Min, Max, Timer, Target */
        /* Other */
-       uint16_t config_ok;
+       uint16_t load_type; /* LOAD_TYPE_AC_RES, LOAD_TYPE_AC_IND or LOAD_TYPE_DC */
+       uint16_t never_force; /* 0 or 1 */
 } __attribute__((packed));
 
 extern struct scialys_config sc_conf;
+
+enum force_types {
+       FORCE_TYPE_OFF,
+       FORCE_TYPE_MIN,
+       FORCE_TYPE_MAX,
+       FORCE_TYPE_TIMER,
+       FORCE_TYPE_TARGET,
+       NB_FORCE_TYPE,
+};
+
+enum load_types {
+       LOAD_TYPE_AC_RES,
+       LOAD_TYPE_AC_IND,
+       LOAD_TYPE_DC,
+       NB_LOAD_TYPES,
+};
+
+/* sunny_days_prod_value : converted to milli Amps from scialys_config.source_has_sun_power_ok */
 extern uint32_t sunny_days_prod_value;
+void update_sunny_days_prod_value(void);
+
+extern int32_t max_intensity;
+void update_max_intensity(void);
 
 /* Check that current config is valid */
 void scialys_check_config(void);
index 7cf713e..a053a61 100644 (file)
@@ -132,6 +132,21 @@ void erase_screen_content(void)
 }
 
 
+/***************************************************************************** */
+/* Display the arrows above and below a value which can be changed in
+ * param menu
+ */
+void display_arrows(uint8_t line1, uint8_t line2, uint8_t col)
+{
+       char text[DISP_LLEN];
+       snprintf(text, DISP_LLEN, "%c", 0x60);
+       display_line(line1, col, text);
+       snprintf(text, DISP_LLEN, "%c", 0x7f);
+       display_line(line2, col, text);
+}
+
+
+
 /***************************************************************************** */
 volatile uint8_t button_pressed = 0;
 void button_callback(uint32_t gpio)
@@ -198,19 +213,19 @@ extern int water_centi_degrees;
 extern uint32_t solar_prod_value;
 extern uint32_t home_conso_value;
 extern volatile uint8_t command_val;
-
+extern int manual_activation_request;
+extern int8_t force_cmd;
 
 static int interface_mode = MODE_RUN;
-volatile int manual_activation_request = 0;
 
-extern int8_t force_cmd;
+char line[DISP_LLEN];
 
 void interface_update(char heat_mode)
 {
        int abs_centi = water_centi_degrees;
-       char line[DISP_LLEN];
 
        if (interface_board_present == 0) {
+               /* DEBUG */ uprintf(UART0, "No interface board ??\n"); /* DEBUG */
                return;
        }
 
@@ -226,7 +241,7 @@ void interface_update(char heat_mode)
        if (interface_mode == MODE_RUN) {
                if (button_pressed != 0) {
                        if (button_pressed & BUTTON_OK) {
-                               manual_activation_request = -1;
+                               manual_activation_request = -1; /* Tells main loop that a request has been triggered */
                        }
                        if (button_pressed & BUTTON_UP) {
                                interface_mode = MODE_CONFIG;
@@ -247,22 +262,15 @@ void interface_update(char heat_mode)
 
                /* Update time and time display on internal memory */
                rtc_pcf85363_time_read(&rtc_conf, &now);
-               snprintf(line, DISP_LLEN, "%02xh%02x:%02x", now.hour, now.min, now.sec);
-               display_line(0, 0, line);
+               dprintf(0, 0, "%02xh%02x:%02x", now.hour, now.min, now.sec);
 
                /* Display info */
-               snprintf(line, DISP_LLEN, "Water:% 2d.%03d %cC", (water_centi_degrees / 100), (abs_centi % 100), 0x24);
-               display_line(2, 0, line);
-               snprintf(line, DISP_LLEN, "Prod :% 2d,%03dA", (solar_prod_value / 1000), ((solar_prod_value % 1000) / 10));
-               display_line(3, 0, line);
-               snprintf(line, DISP_LLEN, "Conso:% 2d,%03dA", (home_conso_value / 1000), ((home_conso_value % 1000) / 10));
-               display_line(4, 0, line);
-               snprintf(line, DISP_LLEN, "Command: %d%%", command_val);
-               display_line(5, 0, line);
-               snprintf(line, DISP_LLEN, "Mode: %c", heat_mode);
-               display_line(6, 0, line);
-               snprintf(line, DISP_LLEN, MODULE_VERSION_STR " - " SOFT_VERSION_STR "." COMPILE_VERSION);
-               display_line(7, 0, line);
+               dprintf(2, 0, "Water:% 2d.%03d %cC", (water_centi_degrees / 100), (abs_centi % 100), 0x24);
+               dprintf(3, 0, "Prod :% 2d,%03dA", (solar_prod_value / 1000), ((solar_prod_value % 1000) / 10));
+               dprintf(4, 0, "Conso:% 2d,%03dA", (home_conso_value / 1000), ((home_conso_value % 1000) / 10));
+               dprintf(5, 0, "Command: %d%%", command_val);
+               dprintf(6, 0, "Mode: %c", heat_mode);
+               dprintf(7, 0, MODULE_VERSION_STR " - " SOFT_VERSION_STR "." COMPILE_VERSION);
 
                /* Update RGB leds */
                /* FIXME : use for error signal */
index e43ab1f..1dc1575 100644 (file)
@@ -40,7 +40,6 @@ extern const struct pio button_right;
 extern const struct pio button_down;
 extern const struct pio button_ok;
 
-extern volatile int manual_activation_request;
 
 /* Exported vars */
 extern volatile uint8_t button_pressed;
@@ -62,6 +61,11 @@ enum interface_modes {
     MODE_DISPLAY,
 };
 
+extern char line[];
+#define dprintf(l, c, format, ...) \
+       snprintf(line, DISP_LLEN, format, ##__VA_ARGS__); \
+       display_line(l, c, line);
+
 /* Interface content update */
 void interface_update(char mode);
 
@@ -69,5 +73,12 @@ void erase_screen_content(void);
 
 int display_line(uint8_t line, uint8_t col, const char* text);
 
+int erase_line(uint8_t line);
+
+/* Display the arrows above and below a value which can be changed in
+ * param menu
+ */
+void display_arrows(uint8_t line1, uint8_t line2, uint8_t col);
+
 #endif /* INTERFACE_H */
 
index 8da9542..1979da2 100644 (file)
@@ -57,6 +57,8 @@ uint8_t forced_heater_mode = 0;  /* flag */
 uint32_t forced_heater_delay = 0;
 uint32_t forced_heater_time = 0;
 uint8_t manual_forced_heater = 0;  /* flag */
+int manual_activation_request = 0;
+
 
 uint8_t error_shutdown = 0;  /* flag */
 
@@ -70,10 +72,10 @@ uint8_t overvoltage = 0; /* Used to create a delay when overvoltage is detected,
 enum modes {
        heat = 'C', /* Normal heating */
        ext_disable = 'E', /* Forced heating disabled by external input */
-       forced = 'F', /* Forced heating */
-       manual = 'M',
+       forced = 'F', /* Auto Forced heating */
+       manual = 'M', /* Manual Forced heating */
        delayed_heat_prod = 'P', /* Pause */
-       overprod = 'S', /* Over production, try to start other loads */
+       overprod = 'O', /* Over production, try to start other loads */
        temp_OK = 'T', /* Max temperature reached */
 };
 
@@ -88,7 +90,7 @@ int deci_degrees_power = 0; /* Power board sensor */
 int deci_degrees_disp = 0; /* Display board sensor */
 
 /* Value in mA computed upon startup from config ext_source_power_limit */
-static int32_t max_intensity = 0;
+int32_t max_intensity = 0;
 
 /* RTC and time */
 struct rtc_time now;
@@ -107,20 +109,13 @@ void config_rx(uint8_t c)
 }
 
 
-/* Communication with slave modules */
+/* Communication with slave modules over UART1 */
 void comm_rx(uint8_t c)
 {
 }
 
 
 
-/***************************************************************************** */
-/* System communication over UART1 */
-void cmd_rx(uint8_t c)
-{
-}
-
-
 /***************************************************************************** */
 /* Decrementer for heating timers */
 void handle_dec_request(uint32_t curent_tick) {
@@ -304,8 +299,8 @@ void handle_cmd_update(uint32_t curent_tick)
                /* Entering forced heating mode from temperature getting below threshold,
                 * wait some delay before effective forced heating */
                if (forced_heater_time == 0) {
-                       forced_heater_delay = sc_conf.forced_heater_delay * T_MULT;
-                       forced_heater_time = forced_heater_delay + (sc_conf.forced_heater_duration * T_MULT);
+                       forced_heater_delay = sc_conf.auto_forced_heater_delay * T_MULT;
+                       forced_heater_time = forced_heater_delay + (sc_conf.auto_forced_heater_duration * T_MULT);
                }
        }
        if (delta < -1280) {
@@ -412,7 +407,7 @@ void mode_update(uint32_t unused)
        mode = heat;
 
        /* Need to enter Forced heating mode ? */
-       if (water_centi_degrees < sc_conf.enter_force_heater_temp) {
+       if (water_centi_degrees < sc_conf.enter_forced_mode_temp) {
                if (forced_heater_mode == 0) {
                        msg = "Water temp low, entering forced mode\n";
                        forced_heater_mode = 1;
@@ -481,12 +476,14 @@ void mode_update(uint32_t unused)
 /* Power tracking - load part */
 
 /* ADC values are between 0 and 1023, no load value is at about 520 */
+#define TRACK_MAX  1
+#define TRACK_MIN  0
 static volatile uint16_t load_power_highest = 520;
 static volatile uint16_t load_power_lowest = 520;
 void power_track(uint32_t flags)
 {
        /* Start tracking the higest value */
-       static int tracking = 1;
+       static int tracking = TRACK_MAX;
        static uint16_t last_value = 0;
        uint16_t val = 0;
 
@@ -494,22 +491,22 @@ void power_track(uint32_t flags)
        adc_get_value(&val, LPC_ADC(2));
 
        /* Four possibilities :
-        *    tracking high and value increasing : nothing to do
-        *    tracking high and value decreasing : we found the max, store it and change tracking
-        *    tracking low and value decreasing : nothing to do
-        *    tracking low and value increasing : we found the min, store it and change tracking
+        *    tracking max and value increasing : nothing to do
+        *    tracking max and value decreasing : we found the max, store it and change tracking
+        *    tracking min and value decreasing : nothing to do
+        *    tracking min and value increasing : we found the min, store it and change tracking
         */
-       if (tracking == 1) {
+       if (tracking == TRACK_MAX) {
                if (last_value > val) {
                        /* Found max */
                        load_power_highest = last_value;
-                       tracking = 0;
+                       tracking = TRACK_MIN;
                }
        } else {
                if (last_value < val) {
                        /* Found min */
                        load_power_lowest = last_value;
-                       tracking = 1;
+                       tracking = TRACK_MAX;
                }
        }
        last_value = val;
@@ -572,9 +569,6 @@ int main(void)
        external_components_config(UART0);
 
        read_scialys_main_config();
-       /* Compute max_intensity from config grid_power_limit.
-        *   grid_power_limit is in kVA, max_intensity in mA */
-       max_intensity = sc_conf.grid_power_limit * 1000 * 1000 / 230;
 
        scialys_systick_and_timers_config();
 
index ca62c55..afdba75 100644 (file)
 
 enum menu_list {
        MAIN_MENU,
-       FORCE_MODE,
-       DATE_CONFIG,
+       AUTO_FORCE,
+       MANUAL_FORCE,
        LIMITS,
-       RESET_CONFIG,
-       SAVE_CONFIG,
-       TEST_MODE,
+       DATE_CONFIG,
+       SAVE_RAZ,
        NB_MENU, /* This one must be the last */
 };
 static const char* menu_titles[] = {
-       [MAIN_MENU] = "Menu principal",
-       [FORCE_MODE] = "Marche Forcee",
-       [DATE_CONFIG] = "Regl. Heure",
+       [MAIN_MENU] = "Configuration",
+       [AUTO_FORCE] =   "MF auto.",
+       [MANUAL_FORCE] = "MF manuelle",
        [LIMITS] = "Regl. Limites",
-       [SAVE_CONFIG] = "Save config",
-       [RESET_CONFIG] = "Reset config",
-       [TEST_MODE] = "Test mode",
+       [DATE_CONFIG] = "Regl. Heure",
+       [SAVE_RAZ] = "Enreg. / RaZ",
 };
 static uint8_t current_menu = MAIN_MENU;
-static uint8_t current_entry = FORCE_MODE;
+static uint8_t current_entry = AUTO_FORCE;
+
+/* Auto Force */
+enum auto_force_list {
+       AUTO_FORCE_START_TEMP,
+       AUTO_FORCE_TARGET_TEMP,
+       AUTO_FORCE_DELAY,
+       AUTO_FORCE_DURATION,
+       AUTO_FORCE_VALUE,
+       AUTO_FORCE_TYPE,
+       AUTO_FORCE_NB_MENU, /* This one must be the last */
+};
+static const char* auto_force_titles[] = {
+       [AUTO_FORCE_START_TEMP] = "Temp. Min",
+       [AUTO_FORCE_TARGET_TEMP] = "Temp. Cible",
+       [AUTO_FORCE_DELAY] = "Delais",
+       [AUTO_FORCE_DURATION] = "Duree",
+       [AUTO_FORCE_VALUE] = "Valeur Cmd",
+       [AUTO_FORCE_TYPE] = "Type Cible",
+};
+static uint8_t auto_force_cur_menu = AUTO_FORCE_START_TEMP;
+static uint8_t auto_force_cur_entry = AUTO_FORCE_START_TEMP;
 
-enum force_mode_list {
-       MANUAL_FORCE_MODE,
-       AUTO_FORCE_MODE,
-       FORCE_NB_MENU, /* This one must be the last */
+
+/* Manual Force */
+enum manual_force_list {
+       MANUAL_FORCE_TARGET_TEMP,
+       MANUAL_FORCE_DURATION,
+       MANUAL_FORCE_VALUE,
+       MANUAL_FORCE_TYPE,
+       MANUAL_FORCE_NB_MENU, /* This one must be the last */
 };
-static const char* force_modes_titles[] = {
-       [MANUAL_FORCE_MODE] = "Manuelle",
-       [AUTO_FORCE_MODE] = "Automatique",
+static const char* manual_force_titles[] = {
+       [MANUAL_FORCE_TARGET_TEMP] = "Temp. Cible",
+       [MANUAL_FORCE_DURATION] = "Duree",
+       [MANUAL_FORCE_VALUE] = "Valeur Cmd",
+       [MANUAL_FORCE_TYPE] = "Type Cible",
 };
-static uint8_t force_cur_menu = MANUAL_FORCE_MODE;
-static uint8_t force_cur_entry = MANUAL_FORCE_MODE;
+static uint8_t manual_force_cur_menu = MANUAL_FORCE_TARGET_TEMP;
+static uint8_t manual_force_cur_entry = MANUAL_FORCE_TARGET_TEMP;
 
+/* Limits */
 enum limits_menu_list {
        TEMP_MAX,
        PMAX_GRID,
        PMAX_PROD,
+       POK_PROD,
        PMAX_CONSO,
        LOAD_TYPE,
-       FORCED_MODE_VAL,
        LIM_NB_MENU, /* This one must be the last */
 };
 static const char* limits_modes_titles[] = {
-       [TEMP_MAX] = "Temp Max",
-       [PMAX_GRID] = "Pmax Abon.",
-       [PMAX_PROD] = "Pmax Prod.",
+       [TEMP_MAX] = "Temp. Max",
+       [PMAX_GRID] = "P Max Abon.",
+       [PMAX_PROD] = "P Max Prod.",
+       [POK_PROD] = "P OK Prod.",
        [PMAX_CONSO] = "P Charge",
        [LOAD_TYPE] = "Type Charge",
-       [FORCED_MODE_VAL] = "Force Val",
 };
 static uint8_t limits_cur_menu = TEMP_MAX;
 static uint8_t limits_cur_entry = TEMP_MAX;
 
-enum test_menu_list {
+enum conf_menu_list {
+       SAVE_CONFIG,
+       RESET_CONFIG,
        TEST_FAN,
        TEST_12V,
        TEST_CMDV,
-       TEST_NB_MENU, /* This one must be the last */
+       CONF_NB_MENU, /* This one must be the last */
 };
-static const char* test_modes_titles[] = {
-       [TEST_FAN] = "Fan",
-       [TEST_12V] = "DC 12V",
-       [TEST_CMDV] = "CMD Val",
+static const char* conf_titles[] = {
+       [SAVE_CONFIG] = "Enregistrer",
+       [RESET_CONFIG] = "RaZ config",
+       [TEST_FAN] = "T. Fan",
+       [TEST_12V] = "T. DC12V",
+       [TEST_CMDV] = "T. Cmd",
 };
+static uint8_t conf_cur_menu = SAVE_CONFIG;
+static uint8_t conf_cur_entry = SAVE_CONFIG;
+
 extern uint8_t force_fan;
 extern int8_t force_cmd;
 extern uint32_t zc_cnt;
 extern void DC_switch_start();
-static uint8_t test_cur_entry = TEST_FAN;
+
+static const char* force_types_str[] = {
+       [FORCE_TYPE_OFF] = "Off",
+       [FORCE_TYPE_MIN] = "Min",
+       [FORCE_TYPE_MAX] = "Max",
+       [FORCE_TYPE_TIMER] = "Timer",
+       [FORCE_TYPE_TARGET] = "Cible",
+};
+
+static const char* load_types_str[] = {
+       [LOAD_TYPE_AC_RES] = "AC Res",
+       [LOAD_TYPE_AC_IND] = "AC Ind",
+       [LOAD_TYPE_DC] = "DC",
+};
 
 
 /* Current sub-menu level. main menu is level 0 */
 int sub_menu_level = 0;
 
+#define   BUTTONS_ACTS_DEFAULT()  \
+                       if (button & BUTTON_LEFT) { sub_menu_level = 1; } \
+                       if (button & BUTTON_OK) { sub_menu_level = 0; current_menu = MAIN_MENU; }
 
 /* Configuraton menu handler
  * Return 0 to get back to 
  */
 int config_interface_handle(void)
 {
-       char line[DISP_LLEN];
        int interface_mode = MODE_CONFIG;
        uint8_t button = 0;
 
@@ -144,14 +192,15 @@ int config_interface_handle(void)
        switch (current_menu) {
                case MAIN_MENU: {
                                int i = 0;
+                               /* Display main menu */
                                for (i = 1; i < NB_MENU; i++) {
                                        if (i != current_entry) {
                                                display_line(i + 1, 2, menu_titles[i]);
                                        } else {
-                                               snprintf(line, DISP_LLEN, " >%s", menu_titles[i]);
-                                               display_line(i + 1, 0, line);
+                                               dprintf(i + 1, 0, " >%s", menu_titles[i]);
                                        }
                                }
+                               /* Button up/down : select next/previous entry */
                                if (button & BUTTON_UP) {
                                        current_entry -= 1;
                                }
@@ -163,51 +212,71 @@ int config_interface_handle(void)
                                } else if (current_entry == 0) {
                                        current_entry = NB_MENU - 1;
                                }
+                               /* Enter sub-menu */
                                if (button & BUTTON_RIGHT) {
                                        current_menu = current_entry;
                                        sub_menu_level = 1;
                                }
+                               /* Exit menu */
                                if (button & (BUTTON_LEFT | BUTTON_OK)) {
                                        interface_mode = MODE_RUN;
                                }
                        }
                        break;
                case DATE_CONFIG: {
-                               static uint8_t date_idx = 0;
-                               snprintf(line, DISP_LLEN, "%c", 0x60);
-                               display_line(3, 6 + (date_idx * 3), line);
-                               rtc_pcf85363_time_read(&rtc_conf, &now);
-                               snprintf(line, DISP_LLEN, "%02xh%02x:%02x", now.hour, now.min, now.sec);
-                               display_line(4, 6, line);
-                               snprintf(line, DISP_LLEN, "%c", 0x7F);
-                               display_line(5, 6 + (date_idx * 3), line);
-                               if ((button & BUTTON_RIGHT) && (date_idx < 2)) {
+                               static uint8_t date_idx = 0; /* Where to put the arrows */
+                               uint8_t line_num = 0;
+                               /* Read current date and time */
+                               rtc_pcf85363_time_read_dec(&rtc_conf, &now);
+                               /* Display date and time */
+                               dprintf(3, 4, "20%02u-%02u-%02u", now.year, now.month, now.day);
+                               dprintf(5, 6, "%02uh%02u:%02u", now.hour, now.min, now.sec);
+                               /* Display arrows on top/bottom of current field */
+                               line_num = 2 + ((date_idx > 2) ? 2 : 0);
+                               display_arrows(line_num, (line_num + 2), (7 + ((date_idx % 3) * 3)));
+                               /* Update current field ? */
+                               if ((button & BUTTON_RIGHT) && (date_idx < 5)) {
                                        date_idx++;
                                }
                                if ((button & BUTTON_LEFT) && (date_idx > 0)) {
                                        date_idx--;
                                }
                                if (button & (BUTTON_UP | BUTTON_DOWN)) {
-                                       uint32_t seconds = rtc_pcf85363_daytime_to_seconds(&now);
-                                       uint32_t add[6] = {
-                                               3600, 60, 1,
-                                               (23 * 3600), (23* 3600 + 59 * 60), (23 * 3600 + 59 * 60 + 59),
-                                       };
-                                       if (button & BUTTON_UP) {
-                                               if (seconds < add[date_idx + 3]) {
-                                                       seconds += add[date_idx];
-                                               } else {
-                                                       seconds -= add[date_idx + 3];
-                                               }
-                                       } else {
-                                               if (seconds < add[date_idx]) {
-                                                       seconds += add[date_idx + 3];
-                                               } else {
-                                                       seconds -= add[date_idx];
-                                               }
+                                       int8_t add = 1;
+                                       if (button & BUTTON_DOWN) {
+                                               add = -1;
+                                       }
+                                       switch (date_idx) {
+                                               case 0:
+                                                       now.year += add;
+                                                       if (now.year > 99) { now.year = 0; }
+                                                       break;
+                                               case 1:
+                                                       now.month += add;
+                                                       if (now.month > 12) { now.month = 1; }
+                                                       if (now.month == 0) { now.month = 12; }
+                                                       break;
+                                               case 2:
+                                                       now.day += add;
+                                                       if (now.day > 31) { now.day = 1; }
+                                                       if (now.day == 0) { now.day = 31; }
+                                                       break;
+                                               case 3:
+                                                       now.hour += add;
+                                                       if (now.hour > 100) { now.hour = 23; }
+                                                       if (now.hour > 23) { now.hour = 0; }
+                                                       break;
+                                               case 4:
+                                                       now.min += add;
+                                                       if (now.min > 100) { now.min = 59; }
+                                                       if (now.min > 59) { now.min = 0; }
+                                                       break;
+                                               case 5:
+                                                       now.sec += add;
+                                                       if (now.sec > 59) { now.sec = 0; }
+                                                       break;
                                        }
-                                       rtc_pcf85363_seconds_to_daytime(&now, seconds);
-                                       rtc_pcf85363_time_write(&rtc_conf, &now);
+                                       rtc_pcf85363_time_write_dec(&rtc_conf, &now);
                                }
                                if (button & BUTTON_OK) {
                                        sub_menu_level = 0;
@@ -222,8 +291,7 @@ int config_interface_handle(void)
                                                if (i != limits_cur_entry) {
                                                        display_line(i + 2, 3, limits_modes_titles[i]);
                                                } else {
-                                                       snprintf(line, DISP_LLEN, "  >%s", limits_modes_titles[i]);
-                                                       display_line(i + 2, 0, line);
+                                                       dprintf(i + 2, 0, "  >%s", limits_modes_titles[i]);
                                                }
                                        }
                                        if (button & BUTTON_UP) {
@@ -232,10 +300,10 @@ int config_interface_handle(void)
                                        if (button & BUTTON_DOWN) {
                                                limits_cur_entry += 1;
                                        }
-                                       if (limits_cur_entry >= LIM_NB_MENU) {
-                                               limits_cur_entry = 0;
-                                       } else if (limits_cur_entry == 0xFF) {
+                                       if (limits_cur_entry == 0xFF) {
                                                limits_cur_entry = LIM_NB_MENU - 1;
+                                       } else if (limits_cur_entry >= LIM_NB_MENU) {
+                                               limits_cur_entry = 0;
                                        }
                                        if (button & (BUTTON_OK | BUTTON_RIGHT)) {
                                                limits_cur_menu = limits_cur_entry;
@@ -249,182 +317,478 @@ int config_interface_handle(void)
                                        display_line(1, 1, limits_modes_titles[limits_cur_menu]);
                                        switch (limits_cur_menu) {
                                                case TEMP_MAX:
-                                                       snprintf(line, DISP_LLEN, "          %c", 0x60);
-                                                       display_line(3, 1, line);
-                                                       snprintf(line, DISP_LLEN, "Abs. max: %d %cC", sc_conf.conf_max_temp / 100, 0x24);
-                                                       display_line(4, 1, line);
-                                                       snprintf(line, DISP_LLEN, "          %c", 0x7f);
-                                                       display_line(5, 1, line);
+                                                       display_arrows(4, 6, 12);
+                                                       dprintf(5, 1, "Abs. max: %2u %cC", (sc_conf.conf_max_temp / 100), 0x24);
                                                        if (button & BUTTON_UP) {
-                                                               if (sc_conf.conf_max_temp <= 8500) {
-                                                                       sc_conf.conf_max_temp += 500;
+                                                               if (sc_conf.conf_max_temp <= 8900) {
+                                                                       sc_conf.conf_max_temp += 100;
                                                                } else {
                                                                        sc_conf.conf_max_temp = 9000;
                                                                }
                                                        }
                                                        if (button & BUTTON_DOWN) {
-                                                               if (sc_conf.conf_max_temp > 500) {
-                                                                       sc_conf.conf_max_temp -= 500;
+                                                               if (sc_conf.conf_max_temp > 2000) {
+                                                                       sc_conf.conf_max_temp -= 100;
                                                                } else {
-                                                                       sc_conf.conf_max_temp = 0;
+                                                                       sc_conf.conf_max_temp = 2000;
                                                                }
                                                        }
-                                                       if (button & BUTTON_LEFT) {
-                                                               sub_menu_level = 1;
-                                                       }
-                                                       if (button & BUTTON_OK) {
-                                                               sub_menu_level = 0;
-                                                               current_menu = MAIN_MENU;
-                                                       }
-                                                       break;
-                                               case FORCED_MODE_VAL:
+                                                       BUTTONS_ACTS_DEFAULT();
                                                        break;
                                                case PMAX_GRID:
-                                                       /* remember to update max_intensity */
+                                                       display_arrows(4, 6, 11);
+                                                       dprintf(5, 1, "P. abo.: %2u kW", sc_conf.grid_power_limit);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.grid_power_limit++;
+                                                               if (sc_conf.grid_power_limit > 36) {
+                                                                       sc_conf.grid_power_limit = 0;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.grid_power_limit--;
+                                                               if (sc_conf.grid_power_limit > 36) {
+                                                                       sc_conf.grid_power_limit = 36;
+                                                               }
+                                                       }
+                                                       update_max_intensity();
+                                                       BUTTONS_ACTS_DEFAULT();
                                                        break;
                                                case PMAX_PROD:
-                                                       /* remember to update sunny_days_prod_value */
+                                                       display_arrows(4, 6, 8);
+                                                       dprintf(5, 1, "P. : %4u W", sc_conf.source_power_max);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.source_power_max += 50;
+                                                               if (sc_conf.source_power_max > 36000) {
+                                                                       sc_conf.source_power_max = 0;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.source_power_max -= 50;
+                                                               if (sc_conf.source_power_max > 36000) {
+                                                                       sc_conf.source_power_max = 36000;
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
+                                                       break;
+                                               case POK_PROD:
+                                                       display_arrows(4, 6, 8);
+                                                       dprintf(5, 1, "P. : %4u W", sc_conf.source_has_power_ok);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.source_has_power_ok += 50;
+                                                               if (sc_conf.source_has_power_ok > 36000) {
+                                                                       sc_conf.source_has_power_ok = 0;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.source_has_power_ok -= 50;
+                                                               if (sc_conf.source_has_power_ok > 36000) {
+                                                                       sc_conf.source_has_power_ok = 36000;
+                                                               }
+                                                       }
+                                                       update_sunny_days_prod_value();
+                                                       BUTTONS_ACTS_DEFAULT();
                                                        break;
                                                case PMAX_CONSO:
+                                                       display_arrows(4, 6, 8);
+                                                       dprintf(5, 1, "P. : %4u W", sc_conf.load_power_max);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.load_power_max += 50;
+                                                               if (sc_conf.load_power_max > 3000) {
+                                                                       sc_conf.load_power_max = 0;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.load_power_max -= 50;
+                                                               if (sc_conf.load_power_max > 3000) {
+                                                                       sc_conf.load_power_max = 3000;
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
                                                        break;
                                                case LOAD_TYPE:
+                                                       display_arrows(4, 6, 11);
+                                                       dprintf(5, 1, "Type: %s", load_types_str[sc_conf.load_type]);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.load_type++;
+                                                               if (sc_conf.load_type >= NB_LOAD_TYPES) {
+                                                                       sc_conf.load_type = 0;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.load_type--;
+                                                               if (sc_conf.load_type >= NB_LOAD_TYPES) {
+                                                                       sc_conf.load_type = (NB_LOAD_TYPES - 1);
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
                                                        break;
                                        }
                                }
                        }
                        break;
-               case FORCE_MODE: {
+               case AUTO_FORCE: {
                                if (sub_menu_level == 1) {
                                        int i = 0;
-                                       for (i = 0; i < FORCE_NB_MENU; i++) {
-                                               if (i != force_cur_entry) {
-                                                       display_line(i + 2, 3, force_modes_titles[i]);
+                                       for (i = 0; i < AUTO_FORCE_NB_MENU; i++) {
+                                               if (i != auto_force_cur_entry) {
+                                                       display_line(i + 2, 3, auto_force_titles[i]);
                                                } else {
-                                                       snprintf(line, DISP_LLEN, " ->%s", force_modes_titles[i]);
-                                                       display_line(i + 2, 0, line);
+                                                       dprintf(i + 2, 0, " ->%s", auto_force_titles[i]);
                                                }
                                        }
                                        if (button & BUTTON_UP) {
-                                               force_cur_entry -= 1;
+                                               auto_force_cur_entry -= 1;
                                        }
                                        if (button & BUTTON_DOWN) {
-                                               force_cur_entry += 1;
+                                               auto_force_cur_entry += 1;
                                        }
-                                       if (force_cur_entry >= FORCE_NB_MENU) {
-                                               force_cur_entry = 0;
-                                       } else if (force_cur_entry == 0xFF) {
-                                               force_cur_entry = FORCE_NB_MENU - 1;
+                                       if (auto_force_cur_entry >= AUTO_FORCE_NB_MENU) {
+                                               auto_force_cur_entry = 0;
+                                       } else if (auto_force_cur_entry == 0xFF) {
+                                               auto_force_cur_entry = AUTO_FORCE_NB_MENU - 1;
                                        }
                                        if (button & (BUTTON_OK | BUTTON_RIGHT)) {
-                                               force_cur_menu = force_cur_entry;
+                                               auto_force_cur_menu = auto_force_cur_entry;
                                                sub_menu_level = 2;
                                        }
                                        if (button & BUTTON_LEFT) {
                                                sub_menu_level = 0;
                                                current_menu = MAIN_MENU;
                                        }
-                               } else {
+                               } else { /* sub_menu_level == 2 */
+                                       display_line(1, 1, auto_force_titles[auto_force_cur_menu]);
+                                       switch (auto_force_cur_menu) {
+                                               case AUTO_FORCE_START_TEMP:
+                                                       display_arrows(4, 6, 11);
+                                                       dprintf(5, 1, "T. min.: %2u %cC", (sc_conf.enter_forced_mode_temp / 100), 0x24);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.enter_forced_mode_temp += 100;
+                                                               /* 60°C is already too high for this module to be of any use */
+                                                               if (sc_conf.enter_forced_mode_temp >= 6000) {
+                                                                       sc_conf.enter_forced_mode_temp = 200;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.enter_forced_mode_temp -= 100;
+                                                               /* 2°C : kind of frost protection */
+                                                               if (sc_conf.enter_forced_mode_temp < 200) {
+                                                                       sc_conf.enter_forced_mode_temp = 6000;
+                                                               }
+                                                       }
+                                                       /* Make sure the target temp is at least 5°C above enter temp. */
+                                                       if (sc_conf.enter_forced_mode_temp > (sc_conf.auto_forced_target_heater_temp - 500)) {
+                                                               sc_conf.auto_forced_target_heater_temp = sc_conf.enter_forced_mode_temp + 500;
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
+                                                       break;
+                                               case AUTO_FORCE_TARGET_TEMP:
+                                                       display_arrows(4, 6, 12);
+                                                       dprintf(5, 1, "T. cible: %2u %cC", (sc_conf.auto_forced_target_heater_temp / 100), 0x24);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.auto_forced_target_heater_temp += 100;
+                                                               if (sc_conf.auto_forced_target_heater_temp >= 9000) {
+                                                                       sc_conf.auto_forced_target_heater_temp = sc_conf.enter_forced_mode_temp + 500;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.auto_forced_target_heater_temp -= 100;
+                                                               /* Make sure the target temp is at least 5°C above enter temp. */
+                                                               if (sc_conf.auto_forced_target_heater_temp < (sc_conf.enter_forced_mode_temp + 500)) {
+                                                                       sc_conf.auto_forced_target_heater_temp = 9000;
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
+                                                       break;
+                                               case AUTO_FORCE_DELAY:
+                                                       display_arrows(4, 6, 9);
+                                                       dprintf(5, 1, "Delais: %d h", sc_conf.auto_forced_heater_delay);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.auto_forced_heater_delay++;
+                                                               if (sc_conf.auto_forced_heater_delay >= 5) {
+                                                                       sc_conf.auto_forced_heater_delay = 0;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.auto_forced_heater_delay--;
+                                                               if (sc_conf.auto_forced_heater_delay > 5) {
+                                                                       sc_conf.auto_forced_heater_delay = 5;
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
+                                                       break;
+                                               case AUTO_FORCE_DURATION:
+                                                       display_arrows(4, 6, 9);
+                                                       dprintf(5, 1, "Duree : %d h", sc_conf.auto_forced_heater_duration);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.auto_forced_heater_duration++;
+                                                               if (sc_conf.auto_forced_heater_duration > 5) {
+                                                                       sc_conf.auto_forced_heater_duration = 1;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.auto_forced_heater_duration--;
+                                                               if (sc_conf.auto_forced_heater_duration < 1 ) {
+                                                                       sc_conf.auto_forced_heater_duration = 5;
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
+                                                       break;
+                                               case AUTO_FORCE_VALUE:
+                                                       display_arrows(4, 6, 10);
+                                                       dprintf(5, 1, "Cmd. : %3u %", sc_conf.auto_forced_mode_value);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.auto_forced_mode_value += 5;
+                                                               if (sc_conf.auto_forced_mode_value > 100) {
+                                                                       sc_conf.auto_forced_mode_value = 25;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.auto_forced_mode_value -= 5;
+                                                               if (sc_conf.auto_forced_mode_value < 25 ) {
+                                                                       sc_conf.auto_forced_mode_value = 100;
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
+                                                       break;
+                                               case AUTO_FORCE_TYPE:
+                                                       display_arrows(4, 6, 10);
+                                                       dprintf(5, 1, "Type : %s", force_types_str[sc_conf.auto_force_type]);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.auto_force_type++;
+                                                               if (sc_conf.auto_force_type >= NB_FORCE_TYPE) {
+                                                                       sc_conf.auto_force_type = 0;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.auto_force_type--;
+                                                               if (sc_conf.auto_force_type >= NB_FORCE_TYPE ) {
+                                                                       sc_conf.auto_force_type = NB_FORCE_TYPE - 1;
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
+                                                       break;
+                                       }
                                }
                        }
                        break;
-               case TEST_MODE: {
-                               int i = 0;
-                               uint8_t states[3];
+               case MANUAL_FORCE: {
+                               if (sub_menu_level == 1) {
+                                       int i = 0;
+                                       for (i = 0; i < MANUAL_FORCE_NB_MENU; i++) {
+                                               if (i != manual_force_cur_entry) {
+                                                       display_line(i + 2, 3, manual_force_titles[i]);
+                                               } else {
+                                                       dprintf(i + 2, 0, " ->%s", manual_force_titles[i]);
+                                               }
+                                       }
+                                       if (button & BUTTON_UP) {
+                                               manual_force_cur_entry -= 1;
+                                       }
+                                       if (button & BUTTON_DOWN) {
+                                               manual_force_cur_entry += 1;
+                                       }
+                                       if (manual_force_cur_entry >= MANUAL_FORCE_NB_MENU) {
+                                               manual_force_cur_entry = 0;
+                                       } else if (manual_force_cur_entry == 0xFF) {
+                                               manual_force_cur_entry = MANUAL_FORCE_NB_MENU - 1;
+                                       }
+                                       if (button & (BUTTON_OK | BUTTON_RIGHT)) {
+                                               manual_force_cur_menu = manual_force_cur_entry;
+                                               sub_menu_level = 2;
+                                       }
+                                       if (button & BUTTON_LEFT) {
+                                               sub_menu_level = 0;
+                                               current_menu = MAIN_MENU;
+                                       }
+                               } else { /* sub_menu_level == 2 */
+                                       display_line(1, 1, manual_force_titles[manual_force_cur_menu]);
+                                       switch (manual_force_cur_menu) {
+                                               case MANUAL_FORCE_TARGET_TEMP:
+                                                       display_arrows(4, 6, 12);
+                                                       dprintf(5, 1, "T. cible: %2u %cC", (sc_conf.manual_target_heater_temp / 100), 0x24);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.manual_target_heater_temp += 100;
+                                                               if (sc_conf.manual_target_heater_temp >= 9000) {
+                                                                       sc_conf.manual_target_heater_temp = 1000;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.manual_target_heater_temp -= 100;
+                                                               if (sc_conf.manual_target_heater_temp < 1000) {
+                                                                       sc_conf.manual_target_heater_temp = 9000;
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
+                                                       break;
+                                               case MANUAL_FORCE_DURATION:
+                                                       display_arrows(4, 6, 9);
+                                                       dprintf(5, 1, "Duree : %d h", sc_conf.manual_activation_duration);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.manual_activation_duration++;
+                                                               if (sc_conf.manual_activation_duration > 5) {
+                                                                       sc_conf.manual_activation_duration = 1;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.manual_activation_duration--;
+                                                               if (sc_conf.manual_activation_duration < 1 ) {
+                                                                       sc_conf.manual_activation_duration = 5;
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
+                                                       break;
+                                               case MANUAL_FORCE_VALUE:
+                                                       display_arrows(4, 6, 10);
+                                                       dprintf(5, 1, "Cmd. : %3u %", sc_conf.manual_forced_mode_value);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.manual_forced_mode_value += 5;
+                                                               if (sc_conf.manual_forced_mode_value > 100) {
+                                                                       sc_conf.manual_forced_mode_value = 25;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.manual_forced_mode_value -= 5;
+                                                               if (sc_conf.manual_forced_mode_value < 25 ) {
+                                                                       sc_conf.manual_forced_mode_value = 100;
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
+                                                       break;
+                                               case MANUAL_FORCE_TYPE:
+                                                       display_arrows(4, 6, 10);
+                                                       dprintf(5, 1, "Type : %s", force_types_str[sc_conf.manual_force_type]);
+                                                       if (button & BUTTON_UP) {
+                                                               sc_conf.manual_force_type++;
+                                                               if (sc_conf.manual_force_type >= NB_FORCE_TYPE) {
+                                                                       sc_conf.manual_force_type = 0;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               sc_conf.manual_force_type--;
+                                                               if (sc_conf.manual_force_type >= NB_FORCE_TYPE ) {
+                                                                       sc_conf.manual_force_type = NB_FORCE_TYPE - 1;
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
+                                                       break;
+                                       }
+                               }
+                       }
+                       break;
+               case SAVE_RAZ: {
+                               if (sub_menu_level == 1) {
+                                       int i = 0;
+                                       uint8_t states[3];
 
-                               states[TEST_FAN] = force_fan;
-                               states[TEST_12V] = (zc_cnt != 0) ? 1 : 0;
-                               states[TEST_CMDV] = (force_cmd != -1) ? 1 : 0;
+                                       states[0] = force_fan; /* TEST_FAN */
+                                       states[1] = (zc_cnt != 0) ? 1 : 0; /* TEST_12V */
+                                       states[2] = (force_cmd != -1) ? force_cmd : 0; /* TEST_CMDV */
 
-                               for (i = 0; i < TEST_NB_MENU; i++) {
-                                       if (i != test_cur_entry) {
-                                               display_line(i + 2, 3, test_modes_titles[i]);
-                                       } else {
-                                               snprintf(line, DISP_LLEN, " ->%s : %d", test_modes_titles[i], states[i]);
-                                               display_line(i + 2, 0, line);
+                                       for (i = 0; i < CONF_NB_MENU; i++) {
+                                               if (i != conf_cur_entry) {
+                                                       display_line(i + 2, 3, conf_titles[i]);
+                                               } else if (i >= TEST_FAN) {
+                                                       dprintf(i + 2, 0, " ->%s : %d", conf_titles[i], states[i - TEST_FAN]);
+                                               } else {
+                                                       dprintf(i + 2, 0, " ->%s", conf_titles[i]);
+                                               }
                                        }
-                               }
-                               if (button & BUTTON_UP) {
-                                       test_cur_entry -= 1;
-                               }
-                               if (button & BUTTON_DOWN) {
-                                       test_cur_entry += 1;
-                               }
-                               if (test_cur_entry >= TEST_NB_MENU) {
-                                       test_cur_entry = 0;
-                               } else if (test_cur_entry == 0xFF) {
-                                       test_cur_entry = TEST_NB_MENU - 1;
-                               }
-                               if (button & (BUTTON_LEFT | BUTTON_RIGHT)) {
-                                       switch (test_cur_entry) {
+                                       if (button & BUTTON_UP) {
+                                               conf_cur_entry -= 1;
+                                       }
+                                       if (button & BUTTON_DOWN) {
+                                               conf_cur_entry += 1;
+                                       }
+                                       if (conf_cur_entry >= CONF_NB_MENU) {
+                                               conf_cur_entry = 0;
+                                       } else if (conf_cur_entry == 0xFF) {
+                                               conf_cur_entry = CONF_NB_MENU - 1;
+                                       }
+                                       if (button & (BUTTON_OK | BUTTON_RIGHT)) {
+                                               conf_cur_menu = conf_cur_entry;
+                                               sub_menu_level = 2;
+                                       }
+                                       if (button & BUTTON_LEFT) {
+                                               sub_menu_level = 0;
+                                               current_menu = MAIN_MENU;
+                                       }
+                               } else { /* sub_menu_level == 2 */
+                                       display_line(1, 1, conf_titles[conf_cur_menu]);
+                                       switch (conf_cur_menu) {
                                                case TEST_FAN:
                                                        force_fan = !force_fan;
+                                                       dprintf(4, 1, "Fan turned %s", ((force_fan == 0) ? "OFF" : "ON"));
+                                                       sub_menu_level = 1;
                                                        break;
                                                case TEST_12V:
                                                        /* Generate a fake zero-cross detect by calling the handler directly */
                                                        DC_switch_start();
+                                                       display_line(4, 1, "DC Test ON");
+                                                       display_line(5, 2, "(Reset for OFF)");
+                                                       sub_menu_level = 1;
                                                        break;
                                                case TEST_CMDV:
-                                                       if (force_cmd >= 0) {
-                                                               force_cmd = -1;
-                                                       } else {
-                                                               force_cmd = 50;
+                                                       display_arrows(4, 6, 10);
+                                                       dprintf(5, 1, "Cmd. : %3u %", ((force_cmd >= 0) ? force_cmd : 0));
+                                                       if (button & BUTTON_UP) {
+                                                               if (force_cmd < 0) {
+                                                                       force_cmd = 0;
+                                                               }
+                                                               force_cmd += 5;
+                                                               if (force_cmd > 100) {
+                                                                       force_cmd = 100;
+                                                               }
+                                                       }
+                                                       if (button & BUTTON_DOWN) {
+                                                               force_cmd -= 5;
+                                                               if (force_cmd < 0 ) {
+                                                                       force_cmd = -1;
+                                                               }
+                                                       }
+                                                       BUTTONS_ACTS_DEFAULT();
+                                                       break;
+                                               case SAVE_CONFIG: {
+                                                               display_line(2, 1, "Sauver config ?");
+                                                               display_line(5, 1, "Valider = OK");
+                                                               display_line(6, 1, "Gauche = Annul");
+                                                               if (button & BUTTON_LEFT) {
+                                                                       sub_menu_level = 0;
+                                                                       current_menu = MAIN_MENU;
+                                                               }
+                                                               if (button & BUTTON_OK) {
+                                                                       int ret = 0;
+                                                                       erase_screen_content();
+                                                                       display_line(4, 2, "Saving ...");
+                                                                       ret = scialys_user_flash_update();
+                                                                       uprintf(UART0, "\nFlash update from menu: %d\n", ret);
+                                                                       msleep(1500);
+                                                                       sub_menu_level = 0;
+                                                                       current_menu = MAIN_MENU;
+                                                               }
+                                                       }
+                                                       break;
+                                               case RESET_CONFIG: {
+                                                               display_line(2, 1, "Efface Config ?");
+                                                               display_line(5, 1, "Valider = OK");
+                                                               display_line(6, 1, "Gauche = Annul");
+                                                               if (button & BUTTON_LEFT) {
+                                                                       sub_menu_level = 0;
+                                                                       current_menu = MAIN_MENU;
+                                                               }
+                                                               if (button & BUTTON_OK) {
+                                                                       erase_screen_content();
+                                                                       display_line(4, 8, "Chargement ...");
+                                                                       sc_conf.conf_version = 0x00;
+                                                                       scialys_check_config();
+                                                                       uprintf(UART0, "\nSystem defaults reloaded from menu\n");
+                                                                       msleep(500);
+                                                                       sub_menu_level = 0;
+                                                                       current_menu = MAIN_MENU;
+                                                               }
                                                        }
-                                               default:
                                                        break;
                                        }
                                }
-                               if (button & BUTTON_OK) {
-                                       sub_menu_level = 0;
-                                       current_menu = MAIN_MENU;
-                               }
-                       }
-                       break;
-               case SAVE_CONFIG: {
-                               snprintf(line, DISP_LLEN, "Sauver config ?");
-                               display_line(2, 1, line);
-                               snprintf(line, DISP_LLEN, "Valider = OK");
-                               display_line(5, 1, line);
-                               snprintf(line, DISP_LLEN, "Gauche = Annul");
-                               display_line(6, 1, line);
-                               if (button & BUTTON_LEFT) {
-                                       sub_menu_level = 0;
-                                       current_menu = MAIN_MENU;
-                               }
-                               if (button & BUTTON_OK) {
-                                       int ret = 0;
-                                       erase_screen_content();
-                                       snprintf(line, DISP_LLEN, "Saving ...");
-                                       display_line(4, 2, line);
-                                       ret = scialys_user_flash_update();
-                                       uprintf(UART0, "\nFlash update from menu: %d\n", ret);
-                                       msleep(1500);
-                                       sub_menu_level = 0;
-                                       current_menu = MAIN_MENU;
-                               }
-                       }
-                       break;
-               case RESET_CONFIG: {
-                               snprintf(line, DISP_LLEN, "Efface Config ?");
-                               display_line(2, 1, line);
-                               snprintf(line, DISP_LLEN, "Valider = OK");
-                               display_line(5, 1, line);
-                               snprintf(line, DISP_LLEN, "Gauche = Annul");
-                               display_line(6, 1, line);
-                               if (button & BUTTON_LEFT) {
-                                       sub_menu_level = 0;
-                                       current_menu = MAIN_MENU;
-                               }
-                               if (button & BUTTON_OK) {
-                                       erase_screen_content();
-                                       snprintf(line, DISP_LLEN, "Chargement ...");
-                                       display_line(4, 8, line);
-                                       sc_conf.conf_version = 0x00;
-                                       scialys_check_config();
-                                       uprintf(UART0, "\nSystem defaults reloaded from menu\n");
-                                       msleep(500);
-                                       sub_menu_level = 0;
-                                       current_menu = MAIN_MENU;
-                               }
                        }
                        break;
                default:
index 949853a..1203912 100644 (file)
@@ -1,3 +1,3 @@
 #define MODULE_VERSION_STR  "v0.10"
 #define SOFT_VERSION_STR  "T"
-#define COMPILE_VERSION "57"
+#define COMPILE_VERSION "66"