/* * Hot Beverage Companion – desktop application utilities * * Copyright (C) 2018 Gediminas Jakutis * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; version 2.1 * of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * 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. * Multiply by 0.1f (divide by 10) to get the correct scale. */ static float digest_temp(const short int rawtemp) { return (rawtemp - 2730) * 0.1f; } /* * raw data is in 1/1024 parts of the max A0 input voltage * on the D1 mini board, which is 3.2V */ static float digest_volt(const short int rawvolt) { return 3.2f / 1024.0f * rawvolt; } int refresh_data(int nd, struct tempmodule_state *state) { int ret; char buf[dgsize]; ret = net_getlastdata(nd, buf); if (ret == A_OK) { memcpy(&state->sequence, buf + 2, sizeof(state->size)); state->temperature = digest_temp(state->temperature_raw); state->voltage = digest_volt(state->voltage_raw); } 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); }