Add support to decode config from Scialys module and signal handler to close (and...
authorNathael Pajani <nathael.pajani@ed3l.fr>
Mon, 11 Mar 2024 15:30:14 +0000 (16:30 +0100)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Mon, 11 Mar 2024 15:30:14 +0000 (16:30 +0100)
host/scialys_decode/config.h [new file with mode: 0644]
host/scialys_decode/main.c

diff --git a/host/scialys_decode/config.h b/host/scialys_decode/config.h
new file mode 100644 (file)
index 0000000..cf356c8
--- /dev/null
@@ -0,0 +1,77 @@
+/***************************************************************************** */
+/* Configuration storage */
+
+/* This struct is stored to user flash when user validates new configuration
+ * and read from user flash upon statup
+ * Default values are defined within config.c
+ * Note that temperature values are stored as hundredth of degrees centigrade (1/100)
+ *
+ * Meaning of fields :
+ *
+ * grid_power_limit :
+ *   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 [0 .. 50] (best not to set above 40)
+ * auto_forced_mode_value :
+ *   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  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) */
+    /* 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_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;
+    uint16_t manual_force_type; /* Off, Min, Max, Timer, Target */
+    /* Other */
+    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));
+
index 2b98901..ab678d1 100644 (file)
 #include <errno.h>
 #include <getopt.h>
 #include <time.h>
+#include <signal.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/select.h>
+#include <byteswap.h>
 #include <sys/time.h>
 #include "serial_utils.h"
+#include "config.h"
 
 
 #define PROG_NAME  "Sensors polling and decode"
@@ -67,18 +70,31 @@ void help(char *prog_name)
 #define BUF_SIZE  100
 #define MSG_LEN  150
 char data[MSG_LEN];
-int data_idx = 0;
+uint8_t data_idx = 0;
 
+char conf[MSG_LEN];
+uint8_t conf_idx = 0;
 
 int protocol_decode(char c)
 {
-       if (data_idx == 0) {
+       if ((data_idx == 0) && (conf_idx == 0)) {
                if (c == '#') {
                        data[0] = c;
                        data_idx = 1;
+               } else if (c == 'C') {
+                       conf[0] = c;
+                       conf_idx = 1;
                }
                return 0;
        }
+       if (conf_idx > 0) {
+               conf[conf_idx] = c;
+               conf_idx++;
+               if (conf_idx > (sizeof(struct scialys_config) + 1)) {
+                       conf_idx = 0;
+                       return 2;
+               }
+       }
        if (data_idx > 0) {
                data[data_idx] = c;
                if (c == '$') {
@@ -94,6 +110,30 @@ int protocol_decode(char c)
        return 0;
 }
 
+volatile int exit_loop = 0;
+void catcher(int signum)
+{
+       printf("Caught signal %d, terminating\n", signum);
+       exit_loop = 1;
+}
+void install_handlers(void)
+{
+       struct sigaction setup_action;
+       sigset_t block_mask;
+
+       sigemptyset(&block_mask);
+       /* Block other terminal-generated signals while handler runs. */
+       sigaddset(&block_mask, SIGINT);
+       sigaddset(&block_mask, SIGQUIT);
+       sigaddset(&block_mask, SIGTERM);
+       setup_action.sa_handler = catcher;
+       setup_action.sa_mask = block_mask;
+       setup_action.sa_flags = 0;
+       sigaction(SIGQUIT, &setup_action, NULL);
+       sigaction(SIGTERM, &setup_action, NULL);
+       sigaction(SIGINT, &setup_action, NULL);
+}
+
 int main(int argc, char* argv[])
 {
        /* Serial */
@@ -104,6 +144,7 @@ int main(int argc, char* argv[])
        char* log_base_name = NULL;
        int data_log_fd = 0;
        int info_log_fd = 0;
+       FILE* conf_log_file = NULL;
 
        /* Timestamp */
        struct timeval now;
@@ -166,6 +207,9 @@ int main(int argc, char* argv[])
                return -2;
        }
 
+       /* Install signal handlers */
+       install_handlers();
+
        /* Log files ? */
        if (log_base_name != NULL) {
                char name[MAX_LOGNAME_LEN];
@@ -183,6 +227,11 @@ int main(int argc, char* argv[])
                if (info_log_fd <= 0) {
                        printf("Unable to open Info log file '%s' : %s", name, strerror(errno));
                }
+               snprintf(name, MAX_LOGNAME_LEN, "%s.config", log_base_name);
+               conf_log_file = fopen(name, "a");
+               if (conf_log_file == NULL) {
+                       printf("Unable to open Config log file '%s' : %s", name, strerror(errno));
+               }
        }
 
        /* Save start second */
@@ -208,6 +257,9 @@ int main(int argc, char* argv[])
                                /* Read returnd 0 ... EOF */
                                printf("Serial disapeared ... closing and re-opening\n");
                        }
+                       if (exit_loop == 1) {
+                               break;
+                       }
                        close(slave_fd);
                        do {
                                slave_fd = serial_setup(device);
@@ -230,8 +282,8 @@ int main(int argc, char* argv[])
                        /* Extract frames from data stream */
                        ret = protocol_decode(buf[idx]);
                        /* Log ? */
-                       if ((info_log_fd > 0) && (ret == 0) && (data_idx == 0)) {
-                               static char last_logged_char = '\0';
+                       if ((info_log_fd > 0) && (ret == 0) && (data_idx == 0) && (conf_idx == 0)) {
+                               static char last_logged_char = '\n';
                                /* Add timestamps */
                                if ((last_logged_char == '\n') && (buf[idx] != '\n')) {
                                        char ts[20];
@@ -290,13 +342,62 @@ int main(int argc, char* argv[])
                                        write(data_log_fd, data, strnlen(data, MSG_LEN));
                                        write(data_log_fd, "\n", 1);
                                }
+                       } else if (ret == 2) {
+                               struct scialys_config sc_conf;
+                               uint8_t cksum = 0, i = 0;
+                               memcpy(&sc_conf, (conf + 1), sizeof(struct scialys_config));
+                               /* Check config checksum */
+                               for (i = 0; i < sizeof(struct scialys_config); i++) {
+                                       cksum += conf[i + 1];
+                               }
+                               if (cksum != 0) {
+                                       printf("Received possible config with bad checksum\n");
+                               } else if (conf_log_file != NULL) {
+                                       char confok[3] = {0};
+                                       sc_conf.config_ok = bswap_16(sc_conf.config_ok); /* "OK" stored in little endian */
+                                       memcpy(confok, &sc_conf.config_ok, 2);
+                                       fprintf(conf_log_file, "% 5d.%03d : Dumped internal configuration :\n", sec, msec);
+                                       fprintf(conf_log_file, "  conf_version : %d\n", sc_conf.conf_version);
+                                       fprintf(conf_log_file, "  config_ok : %s\n", confok);
+                                       fprintf(conf_log_file, "  grid_power_limit : %d\n", sc_conf.grid_power_limit);
+                                       fprintf(conf_log_file, "  source_power_max : %d\n", sc_conf.source_power_max);
+                                       fprintf(conf_log_file, "  source_has_power_ok : %d\n", sc_conf.source_has_power_ok);
+                                       fprintf(conf_log_file, "  load_power_max : %d\n", sc_conf.load_power_max);
+                                       fprintf(conf_log_file, "  conf_max_temp : %d\n", sc_conf.conf_max_temp);
+                                       fprintf(conf_log_file, "  enter_forced_mode_temp : %d\n", sc_conf.enter_forced_mode_temp);
+                                       fprintf(conf_log_file, "  auto_forced_mode_value : %d\n", sc_conf.auto_forced_mode_value);
+                                       fprintf(conf_log_file, "  auto_forced_target_heater_temp : %d\n", sc_conf.auto_forced_target_heater_temp);
+                                       fprintf(conf_log_file, "  auto_forced_heater_delay : %d\n", sc_conf.auto_forced_heater_delay);
+                                       fprintf(conf_log_file, "  auto_forced_heater_duration : %d\n", sc_conf.auto_forced_heater_duration);
+                                       fprintf(conf_log_file, "  auto_force_type : %d\n", sc_conf.auto_force_type);
+                                       fprintf(conf_log_file, "  manual_forced_mode_value : %d\n", sc_conf.manual_forced_mode_value);
+                                       fprintf(conf_log_file, "  manual_target_heater_temp : %d\n", sc_conf.manual_target_heater_temp);
+                                       fprintf(conf_log_file, "  manual_activation_duration : %d\n", sc_conf.manual_activation_duration);
+                                       fprintf(conf_log_file, "  manual_force_type : %d\n", sc_conf.manual_force_type);
+                                       fprintf(conf_log_file, "  load_type : %d\n", sc_conf.load_type);
+                                       fprintf(conf_log_file, "  never_force : %d\n", sc_conf.never_force);
+                                       fsync(fileno(conf_log_file));
+                               }
                        }
 
                        idx++;
                }
 
+               if (exit_loop == 1) {
+                       break;
+               }
        } /* End of infinite loop */
 
+       printf("Terminating cleanly !\n");
+       if (conf_log_file != NULL) {
+               fclose(conf_log_file);
+       }
+       if (data_log_fd != 0) {
+               close(data_log_fd);
+       }
+       if (info_log_fd != 0) {
+               close(info_log_fd);
+       }
        close(slave_fd);
        return 0;
 }