From 03b7473d4faddcb87a5e82205a42028768e7c177 Mon Sep 17 00:00:00 2001 From: Gediminas Jakutis Date: Sat, 19 May 2018 12:02:08 +0300 Subject: add support for "live"-flashing new settings. --- src/server/gtk.c | 216 +++++++++++++++++++++--- src/server/gtk.h | 1 + src/server/gtk.o | Bin 15864 -> 0 bytes src/server/gtklayout.ui | 333 +++++++++++++++++++++++++++---------- src/server/gtklayout_flash.ui | 371 ++++++++++++++++++++++++++++++++++++++++++ src/server/meson.build | 1 + src/server/util.c | 142 ++++++++++++++++ src/server/util.h | 11 +- 8 files changed, 962 insertions(+), 113 deletions(-) delete mode 100644 src/server/gtk.o create mode 100644 src/server/gtklayout_flash.ui (limited to 'src/server') diff --git a/src/server/gtk.c b/src/server/gtk.c index 36b36bb..f48d1d9 100644 --- a/src/server/gtk.c +++ b/src/server/gtk.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "util.h" #include "gtk.h" @@ -37,20 +38,45 @@ struct gtkui { GObject *voltage; GObject *reslabel; GObject *voltlabel; - GObject *showmorebutton; - GObject *button_on; - GObject *button_off; + GObject *show_more; + GObject *show_less; GObject *ticker; GError *error; int showmore; }; +struct gtkui_flash { + GtkBuilder *builder; + GObject *window; + GObject *ssid; + GObject *password; + GObject *htemp; + GObject *mhtemp; + GObject *mltemp; + GObject *ltemp; + GObject *flashdialog; + GObject *dialog_ok; + GObject *dialog_text; + const char *confdata[6]; + int close_with_dialog; +}; + static struct settings settings; static struct gtkui gtkui; +static struct gtkui_flash gtkui_flash; static int gtkui_update(void *data); static void gtkui_die(void *data); -static void gtkui_togglemore(void); +static int strtokel(const char * const s); +void gtkui_togglemore(void); +void gtkui_flashwindow_create(void); +void gtkui_flashwindow_destroy(void); +void gtkui_flashwindow_clean(void); +void gtkui_issue_flash_request(void); +void gtkui_readhtemp(void); +void gtkui_readmhtemp(void); +void gtkui_readmltemp(void); +void gtkui_readltemp(void); int gtkui_init(int *argc, char ***argv, int nd, struct timespec period) { @@ -66,10 +92,7 @@ int gtkui_init(int *argc, char ***argv, int nd, struct timespec period) gtkui.builder = gtk_builder_new(); - if (!gtk_builder_add_from_file(gtkui.builder, DATA_DIR "/gtklayout.ui", >kui.error)) { - ret = ERROR; - goto fail; - } + gtkui.builder = gtk_builder_new_from_file(DATA_DIR "/gtklayout.ui"); gtkui.window = gtk_builder_get_object(gtkui.builder, "window"); gtkui.tempvalue = gtk_builder_get_object(gtkui.builder, "tempvalue"); @@ -77,12 +100,13 @@ int gtkui_init(int *argc, char ***argv, int nd, struct timespec period) gtkui.voltage = gtk_builder_get_object(gtkui.builder, "voltage"); gtkui.reslabel = gtk_builder_get_object(gtkui.builder, "reslabel"); gtkui.voltlabel = gtk_builder_get_object(gtkui.builder, "voltlabel"); - gtkui.showmorebutton = gtk_builder_get_object(gtkui.builder, "showmore"); - gtkui.button_on = gtk_builder_get_object(gtkui.builder, "button_on"); - gtkui.button_off = gtk_builder_get_object(gtkui.builder, "button_off"); + gtkui.show_more = gtk_builder_get_object(gtkui.builder, "show_more"); + gtkui.show_less = gtk_builder_get_object(gtkui.builder, "show_less"); gtkui.ticker = gtk_builder_get_object(gtkui.builder, "ticker"); - g_signal_connect(gtkui.window, "destroy", G_CALLBACK(gtk_main_quit), NULL); - g_signal_connect(gtkui.showmorebutton, "toggled", G_CALLBACK(gtkui_togglemore), NULL); + gtk_builder_connect_signals(gtkui.builder, NULL); + g_object_unref(G_OBJECT(gtkui.builder)); + gtkui.builder = NULL; + gtkui.showmore = 1; /* we are setting this so we can toggle this off on the following call */ gtkui_togglemore(); @@ -137,13 +161,165 @@ static void gtkui_die(void *data) return; } -static void gtkui_togglemore(void) +static int strtokel(const char * const s) +{ + int ret; + + ret = atoi(s); + ret += 273; + ret *= 10; + + return ret; +} + +void gtkui_togglemore(void) { gtkui.showmore = !gtkui.showmore; - gtkui.showmore ? gtk_button_set_image(GTK_BUTTON(gtkui.showmorebutton), GTK_WIDGET(gtkui.button_on)) : - gtk_button_set_image(GTK_BUTTON(gtkui.showmorebutton), GTK_WIDGET(gtkui.button_off)); - gtk_widget_set_visible (GTK_WIDGET(gtkui.resistance), gtkui.showmore); - gtk_widget_set_visible (GTK_WIDGET(gtkui.voltage), gtkui.showmore); - gtk_widget_set_visible (GTK_WIDGET(gtkui.reslabel), gtkui.showmore); - gtk_widget_set_visible (GTK_WIDGET(gtkui.voltlabel), gtkui.showmore); + + /* this actually switches them around their state */ + gtk_widget_set_visible(GTK_WIDGET(gtkui.show_more), !gtkui.showmore); + gtk_widget_set_visible(GTK_WIDGET(gtkui.show_less), gtkui.showmore); + + gtk_widget_set_visible(GTK_WIDGET(gtkui.resistance), gtkui.showmore); + gtk_widget_set_visible(GTK_WIDGET(gtkui.voltage), gtkui.showmore); + gtk_widget_set_visible(GTK_WIDGET(gtkui.reslabel), gtkui.showmore); + gtk_widget_set_visible(GTK_WIDGET(gtkui.voltlabel), gtkui.showmore); +} + +void gtkui_flashwindow_create(void) +{ + if (gtkui_flash.window) { + goto fail; + } + + gtkui_flash.builder = gtk_builder_new_from_file(DATA_DIR "/gtklayout_flash.ui"); + gtkui_flash.window = gtk_builder_get_object(gtkui_flash.builder, "flashwindow"); + gtkui_flash.ssid = gtk_builder_get_object(gtkui_flash.builder, "ssid_entry"); + gtkui_flash.password = gtk_builder_get_object(gtkui_flash.builder, "pass_entry"); + gtkui_flash.htemp = gtk_builder_get_object(gtkui_flash.builder, "htemp_entry"); + gtkui_flash.mhtemp = gtk_builder_get_object(gtkui_flash.builder, "mhtemp_entry"); + gtkui_flash.mltemp = gtk_builder_get_object(gtkui_flash.builder, "mltemp_entry"); + gtkui_flash.ltemp = gtk_builder_get_object(gtkui_flash.builder, "ltemp_entry"); + gtkui_flash.flashdialog = gtk_builder_get_object(gtkui_flash.builder, "flashdialog"); + gtkui_flash.dialog_ok = gtk_builder_get_object(gtkui_flash.builder, "dialog_ok"); + gtkui_flash.dialog_text = gtk_builder_get_object(gtkui_flash.builder, "dialog_text"); + gtk_builder_connect_signals(gtkui_flash.builder, NULL); + g_object_unref(G_OBJECT(gtkui_flash.builder)); + gtkui_flash.builder = NULL; + +fail: + return; +} + +void gtkui_window_destroy(void *window) +{ + gtk_window_close(GTK_WINDOW(window)); +} + +void gtkui_flashwindow_clean(void) +{ + gtkui_flash.window = NULL; +} + +void gtkui_issue_flash_request(void) +{ + static const struct configuration def = {{{ + PADDING_START, + "ssid", /* ssid */ + "password", /* password */ + {3330, 3230, 3130, 3030}, /* calibration */ + PADDING_END + }}}; + + struct configuration conf; + size_t i; + size_t len; + const char *tmp; + + gtk_widget_set_visible(GTK_WIDGET(gtkui_flash.flashdialog), 1); + + for (i = 0; i < sizeof (gtkui_flash.confdata); ++i) { + switch (i) { + case 0: + tmp = gtkui_flash.confdata[i] ? gtkui_flash.confdata[i] : def.ssid; + len = strlen(tmp) > (sizeof(conf.ssid) - 1) ? sizeof(conf.ssid) - 1 : strlen(tmp); + memcpy(conf.ssid, tmp, len); + conf.ssid[len] = '\0'; + break; + case 1: + tmp = gtkui_flash.confdata[i] ? gtkui_flash.confdata[i] : def.password; + len = strlen(tmp) > (sizeof(conf.password) - 1) ? sizeof(conf.password) - 1 : strlen(tmp); + memcpy(conf.password, tmp, len); + conf.password[len] = '\0'; + break; + case 2: + case 3: + case 4: + case 5: + tmp = gtkui_flash.confdata[i] ? (char *) strlen(gtkui_flash.confdata[i]) : NULL; + conf.calibration[i - 2] = tmp ? strtokel(gtkui_flash.confdata[i]) : def.calibration[i -2]; + break; + default: + break; + } + + } + + write_settings(DATA_DIR "/fw.bin", &conf); +} + +void gtkui_readssid(void) +{ + gtkui_flash.confdata[0] = gtk_entry_get_text(GTK_ENTRY(gtkui_flash.ssid)); +} + +void gtkui_readpass(void) +{ + gtkui_flash.confdata[1] = gtk_entry_get_text(GTK_ENTRY(gtkui_flash.password)); +} + +void gtkui_readhtemp(void) +{ + gtkui_flash.confdata[2] = gtk_entry_get_text(GTK_ENTRY(gtkui_flash.htemp)); +} + +void gtkui_readmhtemp(void) +{ + gtkui_flash.confdata[3] = gtk_entry_get_text(GTK_ENTRY(gtkui_flash.mhtemp)); +} + +void gtkui_readmltemp(void) +{ + gtkui_flash.confdata[4] = gtk_entry_get_text(GTK_ENTRY(gtkui_flash.mltemp)); +} + +void gtkui_readltemp(void) +{ + gtkui_flash.confdata[5] = gtk_entry_get_text(GTK_ENTRY(gtkui_flash.ltemp)); +} + +void gtkui_manhandle_flashdialog(void *dialog) +{ + gtk_label_set_markup(GTK_LABEL(gtkui_flash.dialog_text), "Writing to flash... "); + if (gtkui_flash.close_with_dialog) { + gtk_widget_destroy(GTK_WIDGET(dialog)); + /* we also want to close tha parent */ + gtk_window_close(GTK_WINDOW(gtkui_flash.window)); + } else { + gtk_widget_set_visible(GTK_WIDGET(dialog), 0); + } +} + +void gtkui_dialog_done(int status) +{ + static const char * const text[2] = {"done", "FAIL"}; + static const char * const color[2] = {"#4E9A06", "#EF2929"}; + char msg[128]; + + status = status ? 1 : status; + gtkui_flash.close_with_dialog = !status; + sprintf(msg, "Writing to flash... %s!", color[status], text[status]); + + gtk_widget_set_sensitive(GTK_WIDGET(gtkui_flash.dialog_ok), 1); + gtk_label_set_markup(GTK_LABEL(gtkui_flash.dialog_text), msg); } diff --git a/src/server/gtk.h b/src/server/gtk.h index 0c47b0b..ad739e5 100644 --- a/src/server/gtk.h +++ b/src/server/gtk.h @@ -27,5 +27,6 @@ int gtkui_init(int *argc, char ***argv, int nd, struct timespec period); int gtkui_loop(void); +void gtkui_dialog_done(int status); #endif /* GTK_H_INCLUDED */ diff --git a/src/server/gtk.o b/src/server/gtk.o deleted file mode 100644 index 0c2098d..0000000 Binary files a/src/server/gtk.o and /dev/null differ diff --git a/src/server/gtklayout.ui b/src/server/gtklayout.ui index 69fd947..e6d3f5a 100644 --- a/src/server/gtklayout.ui +++ b/src/server/gtklayout.ui @@ -2,12 +2,17 @@ - + + True + False + gtk-properties + + True False gtk-no - + True False gtk-yes @@ -15,112 +20,260 @@ True False - Coffeetemp False + - + True False + vertical - - True - False - - - 0 - 0 - - - - - True - False - Temperature: - - - 1 - 0 - - - - - True - False - - - 2 - 0 - - - - - show all - True - True - True - button_on - True - True - - - 3 - 0 - - - - - True - False - Resistence: - - - 1 - 1 - - - - - True - False - - - 2 - 1 - - - - + True False + + + True + False + _File + True + + + True + False + + + gtk-quit + True + False + True + True + True + + + + + + + + + + True + False + _Edit + True + + + True + False + + + _Reflash + True + False + True + gtk-flash + False + True + + + + + + + + + + True + False + _View + True + + + True + False + + + Show _more + True + False + True + gtk-yes-stock + False + True + + + + + + Show _less + False + True + gtk-no-stock + False + True + + + + + + + + + + True + False + _Help + True + + + True + False + + + gtk-about + True + False + True + True + True + + + + + + - 2 - 2 + False + True + 0 - + True False - Voltage: + + + True + False + 4 + 2 + 2 + 2 + + + 0 + 0 + + + + + True + False + end + 2 + 2 + 2 + 2 + Temperature: + + + 1 + 0 + + + + + True + False + start + 2 + 2 + 2 + 2 + + + 2 + 0 + + + + + True + False + end + 2 + 2 + 2 + 2 + Resistence: + + + 1 + 1 + + + + + True + False + start + 2 + 2 + 2 + 2 + + + 2 + 1 + + + + + True + False + start + 2 + 2 + 2 + 2 + + + 2 + 2 + + + + + True + False + end + 2 + 2 + 2 + 2 + Voltage: + + + 1 + 2 + + + + + + + + - 1 - 2 + False + True + 1 - - - - - - - - - - - - diff --git a/src/server/gtklayout_flash.ui b/src/server/gtklayout_flash.ui new file mode 100644 index 0000000..9972a4e --- /dev/null +++ b/src/server/gtklayout_flash.ui @@ -0,0 +1,371 @@ + + + + + + True + False + gtk-cancel + + + True + False + gtk-apply + + + True + False + coffeetemp – write flash + False + True + + + True + False + + + + True + True + 32 + + + + 1 + 0 + + + + + True + True + 32 + False + password + + + + 1 + 1 + + + + + True + True + 6 + digits + + + + 1 + 2 + + + + + True + False + end + 2 + 2 + 2 + 2 + SSID: + + + 0 + 0 + + + + + True + False + end + 2 + 2 + 2 + 2 + Password: + + + 0 + 1 + + + + + True + False + end + 2 + 2 + 2 + 2 + High Temp: + + + 0 + 2 + + + + + True + False + end + 2 + 2 + 2 + 2 + Mid-high Temp: + + + 0 + 3 + + + + + True + True + 6 + digits + + + + 1 + 3 + + + + + True + False + start + 2 + 2 + 2 + 2 + °C + + + 2 + 2 + + + + + True + False + start + 2 + 2 + 2 + 2 + °C + + + 2 + 3 + + + + + Cancel + True + True + True + cancel + + + + 0 + 6 + + + + + Write Flash + True + True + True + ok + + + + 1 + 6 + + + + + True + False + end + 2 + 2 + 2 + 2 + Low Temp: + + + 0 + 5 + + + + + True + True + 6 + digits + + + + 1 + 5 + + + + + True + False + start + 2 + 2 + 2 + 2 + °C + + + 2 + 4 + + + + + True + False + start + 2 + 2 + 1 + 1 + °C + + + 2 + 5 + + + + + True + False + end + 2 + 2 + 1 + 1 + Mid-low Temp: + + + 0 + 4 + + + + + True + True + 6 + digits + + + + 1 + 4 + + + + + + + + + + + + + + + + False + Flashing... + False + True + True + dialog + True + flashwindow + flashwindow + + + + + True + False + vertical + 2 + + + False + end + + + gtk-ok + True + False + True + True + True + + + + True + True + 0 + + + + + False + False + 2 + + + + + True + False + start + 3 + 3 + 3 + 3 + True + Writing to flash... + 25 + + + False + True + 0 + + + + + + diff --git a/src/server/meson.build b/src/server/meson.build index c95f9a9..2b7af61 100644 --- a/src/server/meson.build +++ b/src/server/meson.build @@ -14,6 +14,7 @@ dp_filenames = [ dp_extra_filenames = [ 'gtklayout.ui', + 'gtklayout_flash.ui', ] dp_sources = files(dp_filenames) diff --git a/src/server/util.c b/src/server/util.c index bb494c8..4aee886 100644 --- a/src/server/util.c +++ b/src/server/util.c @@ -18,12 +18,32 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include #include "util.h" #include "net.h" +#include "gtk.h" + +struct child_data { + char **argv; + int fd; + char *buf; +}; static float digest_temp(const short int rawtemp); static float digest_volt(const short int rawvolt); +static int find_settings_region(char *start, char *end, char *buf, size_t n); +static int flash(char *buf, size_t address, size_t size, char* port); +void reap_dead_children(int pid, int status, void *data); /* * raw data is in 0.1°K per 1. Subtract 2730 to get Celsius. @@ -57,3 +77,125 @@ int refresh_data(int nd, struct tempmodule_state *state) return ret; } + + +int write_settings(char *imagename, const struct configuration * const conf) +{ + /* the largest flash size supported by ESP-8266 is 16MiB, so let's just use that. */ + static const size_t flash_size = 16 * 1024 * 1024; + char pattern_a[4] = PADDING_START; + char pattern_b[4] = PADDING_END; + ssize_t buf_used; + ssize_t offset; + char *buf = NULL; + int fd; + int ret = ERROR; + + fd = open(imagename, O_RDONLY); + if (fd < 0) { + goto fail; + } + buf = malloc(flash_size); + buf_used = read(fd, buf, flash_size); + close(fd); + if (buf_used < sizeof(struct configuration)) { + goto fail; + } + + offset = find_settings_region(pattern_a, pattern_b, buf, buf_used); + if (offset == ERROR) { + goto fail; + }; + + memcpy(buf + offset, conf, sizeof(struct configuration)); + /* make sure the block written is aligned on 4k boundry + * and is 4k of size. + * + * see: + * https://github.com/espressif/esptool/issues/306 + */ + offset &= ~(0xfff); + ret = flash(buf + offset, offset, 4 * 1024, NULL); + +fail: + free(buf); + return ret; +} + +static int find_settings_region(char *start, char *end, char *buf, size_t n) +{ + int ret = ERROR; + char *a; + + if (!(a = memmem(buf, n, start, 4))) { + goto fail; + } + + if ((a - buf + sizeof(struct configuration)) > n) { + goto fail; + } + + if (memcmp(a + sizeof(struct configuration) - 4, end, 4)) { + goto fail; + } + + ret = a - buf; +fail: + return ret; +} + +static int flash(char *buf, size_t address, size_t size, char* port) +{ + static const char esptool[] = "esptool.py"; + static const char command[] = "write_flash"; + struct child_data *cdata; + char tmpfn[] = "espXXXXXX"; /* temporary file name template */ + char *fifn; /* flash image file name */ + char textbuf[32]; + char *argv[7] = {0}; + int ret = ERROR; + pid_t pid; + int fd; + size_t i = 1; + + fd = mkstemp(tmpfn); + write(fd, buf, size); + fifn = malloc(0x100); + memset(fifn, '\0', 0x100); + sprintf(textbuf, "/proc/self/fd/%d", fd); + if (readlink(textbuf, fifn, 0x100) == -1) { + exit(TMPFILE); + } + + argv[0] = strdup(esptool); + if (port) { + argv[i++] = strdup("--port"); + argv[i++] = strdup(port); + } + argv[i++] = strdup(command); + sprintf(textbuf, "%#.4lx", address); + argv[i++] = strdup(textbuf); + argv[i++] = strdup(fifn); + argv[i] = NULL; + + cdata = malloc(sizeof(*cdata)); + cdata->argv = argv; + cdata->fd = fd; + cdata->buf = fifn; + + g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL, NULL, NULL, NULL); + g_child_watch_add(pid, reap_dead_children, cdata); + return ret; +} + +void reap_dead_children(int pid, int status, void *data) +{ + struct child_data *a; + + a = data; + free(a->buf); + close(a->fd); + free(data); + g_spawn_close_pid(pid); + gtkui_dialog_done(status); +} diff --git a/src/server/util.h b/src/server/util.h index 9c0f907..ef5cde2 100644 --- a/src/server/util.h +++ b/src/server/util.h @@ -21,13 +21,17 @@ #ifndef UTIL_H_INCLUDED #define UTIL_H_INCLUDED +#include "datatypes.h" + #define arrsize(a) (sizeof(a)/sizeof(*a)) enum response { ERROR = -1, - A_OK = 0, - NONEWDATA = 1, - DEAD = 2 + A_OK = 0, /* would be "OK", but clashes with some lib definitions */ + NONEWDATA, + DEAD, + NO_ESPTOOL, + TMPFILE, }; struct tempmodule_state { @@ -51,5 +55,6 @@ struct tempmodule_state { }; int refresh_data(int nd, struct tempmodule_state *state); +int write_settings(char *imagename, const struct configuration * const conf); #endif /* UTIL_H_INCLUDED */ -- cgit v1.2.3