123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- #include "common.h"
- #include "config.h"
- #include <esp_spiffs.h>
- #include <ctype.h>
- #define CONFIG_FILE "/spiffs/config.txt"
- static int save_config(void);
- static bool is_end_of_string(int c)
- {
- return c <= 0 || c == '\n' || c == '\r';
- }
- /*
- * Note: the string must be mutable; use strdup() if necessary.
- * The "separator" allows the string to be separated into multiple
- * arguments; no other decoding is done.
- */
- static int set_config_string(char *str, unsigned int separator)
- {
- char *p, *q;
- unsigned char c;
- p = str;
- do {
- const char *var = p;
- do {
- c = *p++;
- } while (isalnum(c) || c == '.' || c == '-');
- if (c != '=')
- return -EINVAL; /* Invalid config line (blank, comment...) */
- p[-1] = '\0';
- q = p;
- do {
- c = *q++;
- } while (!is_end_of_string(c) && c != separator);
- /* Overlong line */
- if (q >= str + MAX_CONFIG_LINE)
- return -EOVERFLOW;
- q[-1] = '\0';
- size_t nvar = sysvar_find(sysvar_ns_config, var);
- if (nvar) {
- setvar_fromstr(nvar, p);
- }
- p = q;
- } while (c == separator);
- return 0;
- }
- static void finish_config_update(bool save)
- {
- if (sysvar_changed < sysvar_ns[sysvar_ns_status].first) {
- if (save)
- save_config();
- /* Can do other things here... */
- }
- sysvar_changed = sysvar_count;
- }
- /*
- * At the moment "url" just allows values to be separated by semicolons;
- * no other decoding is done, and '&' is not supported.
- */
- int set_config_url_string(const char *str)
- {
- char *wstr = strdup(str);
- if (!wstr)
- return -ENOMEM;
- int err = set_config_string(wstr, ';');
- free(wstr);
- finish_config_update(true);
- return err;
- }
- static void skip_rest_of_line(FILE *f)
- {
- int c;
- do {
- c = getc(f);
- } while (!is_end_of_string(c));
- }
- /* Calling with with f == NULL just finalizes the update */
- int read_config(FILE *f, bool save)
- {
- char *linebuf = NULL;
- int err = -1;
- if (f) {
- linebuf = malloc(MAX_CONFIG_LINE);
- if (!linebuf) {
- err = -ENOMEM;
- goto exit;
- }
- while (fgets(linebuf, MAX_CONFIG_LINE, f)) {
- if (set_config_string(linebuf, -1) == -EOVERFLOW)
- skip_rest_of_line(f);
- }
- }
- err = 0;
- if (linebuf)
- free(linebuf);
- exit:
- finish_config_update(save);
- return err;
- };
- int write_sysvars(FILE *f, bool status)
- {
- size_t ns = status ? sysvar_ns_status : sysvar_ns_config;
- const sysvar_ns_t * const nsi = &sysvar_ns[ns];
- for (enum sysvar_enum var = nsi->first; var < nsi[1].first; var++) {
- fputs(sysvar_name[var], f);
- putc('=', f);
- fputs(notempty(getvar_tostr(var)), f);
- putc('\n', f);
- }
- return ferror(f) ? -1 : 0;
- }
- static int save_config(void)
- {
- int err = -ENOENT;
- FILE *f = fopen(CONFIG_FILE, "w");
- if (f) {
- err = write_sysvars(f, false);
- fclose(f);
- }
- if (err)
- printf("[CONF] Failed to save configuration (error %d)\n", err);
- return err;
- }
- static const esp_vfs_spiffs_conf_t spiffs_conf = {
- .base_path = "/spiffs",
- .partition_label = NULL,
- .max_files = 4,
- .format_if_mount_failed = true
- };
- void init_config(void)
- {
- if (!esp_spiffs_mounted(spiffs_conf.partition_label)) {
- esp_err_t err;
- err = esp_vfs_spiffs_register(&spiffs_conf);
- if (err)
- printf("[CONF] Failed to mount %s (error 0x%x)\n",
- spiffs_conf.base_path, err);
- }
- sysvar_reset(sysvar_ns_config);
- FILE *f = fopen(CONFIG_FILE, "r");
- if (!f)
- printf("[CONF] No configuration file found, using defaults\n");
- read_config(f, false);
- if (f)
- fclose(f);
- }
- void log_config_status(void)
- {
- const sysvar_ns_t *nsi = &sysvar_ns[0];
- for (enum sysvar_enum var = 1; var < sysvar_count; var++) {
- if (var >= nsi[1].first)
- nsi++;
- logmsg(nsi->name, "%s = %s\n", sysvar_name[var],
- notempty(getvar_tostr(var)));
- }
- }
|