--- /dev/null
+/***************************************************************************** */
+/* 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));
+
#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"
#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 == '$') {
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 */
char* log_base_name = NULL;
int data_log_fd = 0;
int info_log_fd = 0;
+ FILE* conf_log_file = NULL;
/* Timestamp */
struct timeval now;
return -2;
}
+ /* Install signal handlers */
+ install_handlers();
+
/* Log files ? */
if (log_base_name != NULL) {
char name[MAX_LOGNAME_LEN];
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 */
/* 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);
/* 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];
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;
}