From a806910034f336c86880241846df807a95ebfc71 Mon Sep 17 00:00:00 2001 From: jedi Date: Sun, 8 Aug 2021 22:59:15 +0200 Subject: [PATCH 01/12] stash --- firmware/app.cpp | 261 ++++++++++++++++++++++++++++++++++ firmware/config.sample | 7 + firmware/fiatlux.c | 312 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 575 insertions(+), 5 deletions(-) create mode 100644 firmware/app.cpp create mode 100644 firmware/config.sample diff --git a/firmware/app.cpp b/firmware/app.cpp new file mode 100644 index 0000000..f7b2414 --- /dev/null +++ b/firmware/app.cpp @@ -0,0 +1,261 @@ +/* Example SPI transfert + * + * This sample code is in the public domain. + */ +#include "espressif/esp_common.h" +#include "esp/uart.h" +#include "FreeRTOS.h" +#include "task.h" +#include "esp8266.h" +#include +#include "esp/spi.h" +#include "math.h" +#include + +#define DAYTIME(h,m,s) (h*3600+m*60+s) + +struct { + time_t sunrise_start = DAYTIME(5,30,0); + time_t sunrise_end = DAYTIME(6,0,0); + time_t sunrise_shutdown = DAYTIME(7,0,0); + time_t sunset_time = DAYTIME(22,0,0); +} settings; + + + +struct { + uint8_t r = 255; + uint8_t g = 160; + uint8_t b = 80; +} white; + +time_t day_seconds() { + time_t t1, t2; + struct tm tms; + time(&t1); + localtime_r(&t1, &tms); + tms.tm_hour = 0; + tms.tm_min = 0; + tms.tm_sec = 0; + t2 = mktime(&tms); + return t1 - t2; +} + +struct led_t{ + struct { + unsigned int mod : 5, marker : 3; + } __attribute__((packed)) global = {0x1F, 0x7}; + uint8_t b = 0; + uint8_t g = 0; + uint8_t r = 0; +}; + +led_t leds[4][10]; + +float square(float x){ + return x*x; +} + +float lerp(float a, float b, float x){ + return (1.-x)*a + x *b; +} + +float clamp(float x, float a, float b){ + if(xb) + return b; + return x; +} + +float fade(float x, float offset, float factor){ + float val = (x*factor-offset); + return lerp(square(clamp(val,0,1)),square(1-clamp(1-val,0,1)),val); +} + +void write_leds(){ + spi_transfer_32(1, 0x00000000); + for(int i = 0; i < 10; i++) + spi_transfer_32(1, *(uint32_t*)&leds[0][i]); + for(int i = 0; i < 10; i++) + spi_transfer_32(1, *(uint32_t*)&leds[1][9-i]); + for(int i = 0; i < 10; i++) + spi_transfer_32(1, *(uint32_t*)&leds[2][i]); + for(int i = 0; i < 10; i++) + spi_transfer_32(1, *(uint32_t*)&leds[3][9-i]); + spi_transfer_32(1, 0xFFFFFFFF); + spi_transfer_32(1, 0xFFFFFFFF); +} + +enum state_t{ BOOT_S, SUNRISE_S, MORNING_S, DAY_S, NIGHT_S }; + +state_t s = BOOT_S; + +bool maual_mode = false; + +extern "C" void manual_switch(){ + + maual_mode = !maual_mode; + + printf("%d\n", (int)maual_mode); + + if(maual_mode){ + + if(s == NIGHT_S){ + + for(int j = 0; j < 4; j++) + for(int i = 0; i < 8; i+=2){ + leds[j][i].global.mod = 2; + leds[j][i].r = 128; + leds[j][i].g = 30; + leds[j][i].b = 15; + } + }else{ + + for(int j = 0; j < 4; j++) + for(int i = 0; i < 10; i++){ + leds[j][i].global.mod = 31; + leds[j][i].r = white.r; + leds[j][i].g = white.g; + leds[j][i].b = white.b; + } + } + + write_leds(); + + }else{ + for(int j = 0; j < 4; j++) + for(int i = 0; i < 10; i++){ + leds[j][i].global.mod = 0; + leds[j][i].r = 0; + leds[j][i].g = 0; + leds[j][i].b = 0; + } + write_leds(); + } +} + +void loop(void *pvParameters) +{ + spi_init(1, SPI_MODE0, SPI_FREQ_DIV_1M, 1, SPI_LITTLE_ENDIAN, false); + + while(1){ + + time_t rt = day_seconds(); + + if(maual_mode){ + + if(s == NIGHT_S){ + + for(int j = 0; j < 4; j++) + for(int i = 0; i < 8; i+=2){ + leds[j][i].global.mod = 2; + leds[j][i].r = 128; + leds[j][i].g = 30; + leds[j][i].b = 15; + } + }else{ + + for(int j = 0; j < 4; j++) + for(int i = 0; i < 10; i++){ + leds[j][i].global.mod = 31; + leds[j][i].r = white.r; + leds[j][i].g = white.g; + leds[j][i].b = white.b; + } + } + + write_leds(); + + }else{ + + if( s == BOOT_S ) { + if( rt >= settings.sunrise_start ) { + s = SUNRISE_S; + printf("SUNRISE_S\n"); + } + if( rt >= settings.sunrise_end ) { + s = MORNING_S; + printf("MORNING_S\n"); + } + } else if( s == SUNRISE_S ){ + if( rt >= settings.sunrise_end ) { + s = MORNING_S; + printf("MORNING_S\n"); + }else{ + int steps = (settings.sunrise_end - settings.sunrise_start)*(1000/50); + int t = (rt - settings.sunrise_start)*(1000/50); + for(; t < steps && !maual_mode; t++) { + + for(int j = 0; j < 4; j++) + for(int i = 0; i < 10; i++){ + float val = (-i*30.+t*3.*(4./5.))/(float)steps; + leds[j][i].global.mod = 8 + fade(val,0.,0.5)*23; + leds[j][i].r = fade(val,0.01,1.) * white.r; + leds[j][i].g = fade(val,0.1,0.5) * white.g; + leds[j][i].b = fade(val,0.6,0.7) * white.b; + } + + write_leds(); + + if ((t%25)==0) { + + printf("Time: %d%% %d %d/%d\n", (t*100)/steps, (int)day_seconds(), t, steps); + printf("%d %d %d %d\n", + leds[0][0].global.mod, + leds[0][0].r, + leds[0][0].g, + leds[0][0].b); + } + + vTaskDelay(50/portTICK_PERIOD_MS); + } + } + } else if( s == MORNING_S ) { + if( rt >= settings.sunrise_shutdown ) { + s = DAY_S; + printf("DAY_S\n"); + }else{ + for(int j = 0; j < 4; j++) + for(int i = 0; i < 10; i++){ + leds[j][i].global.mod = 31; + leds[j][i].r = white.r; + leds[j][i].g = white.g; + leds[j][i].b = white.b; + } + write_leds(); + } + } else if( s == DAY_S ) { + if( rt >= settings.sunset_time ) { + s = NIGHT_S; + printf("NIGHT_S\n"); + }else{ + for(int j = 0; j < 4; j++) + for(int i = 0; i < 10; i++){ + leds[j][i].global.mod = 0; + leds[j][i].r = 0; + leds[j][i].g = 0; + leds[j][i].b = 0; + } + + write_leds(); + } + } else if( s == NIGHT_S ) { + if( rt >= settings.sunrise_start && rt < settings.sunset_time) { + s = SUNRISE_S; + printf("SUNRISE_S\n"); + } + } + + } + + vTaskDelay(1000/portTICK_PERIOD_MS); + + } +} + + +extern "C" void register_app(void) +{ + xTaskCreate(loop, "loop", 1024, NULL, 2, NULL); +} diff --git a/firmware/config.sample b/firmware/config.sample new file mode 100644 index 0000000..2673cac --- /dev/null +++ b/firmware/config.sample @@ -0,0 +1,7 @@ +sunrise_start: time +sunrise_end: time +sunrise_shutdown: time +sunrise_color: color +sunrise_fade: linear, ease, ease_in, ease_out +sunset_time: time +night_color: color diff --git a/firmware/fiatlux.c b/firmware/fiatlux.c index 98d0efb..25573a6 100644 --- a/firmware/fiatlux.c +++ b/firmware/fiatlux.c @@ -1,16 +1,318 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + #include "system.h" #include "wifi.h" #include "web.h" #include "mqtt.h" #include "lux.h" -#include -#include -#include +#define LED_PIN 2 +#define SWITCH_PIN 2 -#include -#include +/* Add extras/sntp component to makefile for this include to work */ +#include +#include +#define SNTP_SERVERS "0.pool.ntp.org", "1.pool.ntp.org", \ + "2.pool.ntp.org", "3.pool.ntp.org" + +#define vTaskDelayMs(ms) vTaskDelay((ms)/portTICK_PERIOD_MS) +#define UNUSED_ARG(x) (void)x + + +const gpio_inttype_t int_type = GPIO_INTTYPE_EDGE_NEG; + +enum { + SSI_WALLTIME, + SSI_UPTIME, + SSI_FREE_HEAP, + SSI_LED_STATE +}; + + +int32_t ssi_handler(int32_t iIndex, char *pcInsert, int32_t iInsertLen) +{ + struct timeval tv; + + switch (iIndex) { + case SSI_WALLTIME: + gettimeofday(&tv, NULL); + snprintf(pcInsert, iInsertLen, "%d", + (int)tv.tv_sec); + break; + case SSI_UPTIME: + snprintf(pcInsert, iInsertLen, "%d", + xTaskGetTickCount() * portTICK_PERIOD_MS / 1000); + break; + case SSI_FREE_HEAP: + snprintf(pcInsert, iInsertLen, "%d", (int) xPortGetFreeHeapSize()); + break; + case SSI_LED_STATE: + snprintf(pcInsert, iInsertLen, (GPIO.OUT & BIT(LED_PIN)) ? "Off" : "On"); + break; + default: + snprintf(pcInsert, iInsertLen, "N/A"); + break; + } + + /* Tell the server how many characters to insert */ + return (strlen(pcInsert)); +} + +const char *gpio_cgi_handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) +{ + for (int i = 0; i < iNumParams; i++) { + if (strcmp(pcParam[i], "on") == 0) { + uint8_t gpio_num = atoi(pcValue[i]); + gpio_enable(gpio_num, GPIO_OUTPUT); + gpio_write(gpio_num, true); + } else if (strcmp(pcParam[i], "off") == 0) { + uint8_t gpio_num = atoi(pcValue[i]); + gpio_enable(gpio_num, GPIO_OUTPUT); + gpio_write(gpio_num, false); + } else if (strcmp(pcParam[i], "toggle") == 0) { + uint8_t gpio_num = atoi(pcValue[i]); + gpio_enable(gpio_num, GPIO_OUTPUT); + gpio_toggle(gpio_num); + } + } + return "/index.ssi"; +} + +const char *about_cgi_handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) +{ + return "/about.html"; +} + +const char *websocket_cgi_handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) +{ + return "/websockets.html"; +} + +void websocket_task(void *pvParameter) +{ + struct tcp_pcb *pcb = (struct tcp_pcb *) pvParameter; + + for (;;) { + if (pcb == NULL || pcb->state != ESTABLISHED) { + printf("Connection closed, deleting task\n"); + break; + } + + struct timeval tv; + gettimeofday(&tv, NULL); + + int uptime = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000; + int heap = (int) xPortGetFreeHeapSize(); + int led = !gpio_read(LED_PIN); + + /* Generate response in JSON format */ + char response[64]; + int len = snprintf(response, sizeof (response), + "{\"walltime\" : \"%d\"," + "\"uptime\" : \"%d\"," + " \"heap\" : \"%d\"," + " \"led\" : \"%d\"}", (int)tv.tv_sec, uptime, heap, led); + if (len < sizeof (response)) + websocket_write(pcb, (unsigned char *) response, len, WS_TEXT_MODE); + + vTaskDelay(2000 / portTICK_PERIOD_MS); + } + + vTaskDelete(NULL); +} + +/** + * This function is called when websocket frame is received. + * + * Note: this function is executed on TCP thread and should return as soon + * as possible. + */ +void websocket_cb(struct tcp_pcb *pcb, uint8_t *data, u16_t data_len, uint8_t mode) +{ + printf("[websocket_callback]:\n%.*s\n", (int) data_len, (char*) data); + + uint8_t response[2]; + uint16_t val; + + switch (data[0]) { + case 'A': // ADC + /* This should be done on a separate thread in 'real' applications */ + val = sdk_system_adc_read(); + break; + case 'D': // Disable LED + gpio_write(LED_PIN, true); + val = 0xDEAD; + break; + case 'E': // Enable LED + gpio_write(LED_PIN, false); + val = 0xBEEF; + break; + default: + printf("Unknown command\n"); + val = 0; + break; + } + + response[1] = (uint8_t) val; + response[0] = val >> 8; + + websocket_write(pcb, response, 2, WS_BIN_MODE); +} + +/** + * This function is called when new websocket is open and + * creates a new websocket_task if requested URI equals '/stream'. + */ +void websocket_open_cb(struct tcp_pcb *pcb, const char *uri) +{ + printf("WS URI: %s\n", uri); + if (!strcmp(uri, "/stream")) { + printf("request for streaming\n"); + xTaskCreate(&websocket_task, "websocket_task", 256, (void *) pcb, 2, NULL); + } +} + +void httpd_task(void *pvParameters) +{ + tCGI pCGIs[] = { + {"/gpio", (tCGIHandler) gpio_cgi_handler}, + {"/about", (tCGIHandler) about_cgi_handler}, + {"/websockets", (tCGIHandler) websocket_cgi_handler}, + }; + + const char *pcConfigSSITags[] = { + "walltime", // SSI_WALLTIME + "uptime", // SSI_UPTIME + "heap", // SSI_FREE_HEAP + "led" // SSI_LED_STATE + }; + + /* register handlers and start the server */ + http_set_cgi_handlers(pCGIs, sizeof (pCGIs) / sizeof (pCGIs[0])); + http_set_ssi_handler((tSSIHandler) ssi_handler, pcConfigSSITags, + sizeof (pcConfigSSITags) / sizeof (pcConfigSSITags[0])); + websocket_register_callbacks((tWsOpenHandler) websocket_open_cb, + (tWsHandler) websocket_cb); + httpd_init(); + + for (;;); +} + + +void sntp_tsk(void *pvParameters) +{ + const char *servers[] = {SNTP_SERVERS}; + UNUSED_ARG(pvParameters); + + /* Wait until we have joined AP and are assigned an IP */ + while (sdk_wifi_station_get_connect_status() != STATION_GOT_IP) { + vTaskDelayMs(100); + } + + /* Start SNTP */ + printf("Starting SNTP... "); + /* SNTP will request an update each 5 minutes */ + sntp_set_update_delay(5*60000); + /* Set GMT+1 zone, daylight savings off */ + const struct timezone tz = {1*60, 1}; + /* SNTP initialization */ + sntp_initialize(&tz); + /* Servers must be configured right after initialization */ + sntp_set_servers(servers, sizeof(servers) / sizeof(char*)); + printf("DONE!\n"); + + /* Print date and time each 5 seconds */ + while(1) { + vTaskDelayMs(5000); + //time_t ts = time(NULL); + //int t = ts; + //printf("TIME: %d %d %s", t,(int) day_seconds(), ctime(&ts)); + } +} + + +void gpio_intr_handler(uint8_t gpio_num); + +void manual_switch(void); + +void buttonIntTask(void *pvParameters) +{ + printf("Waiting for button press interrupt on gpio %d...\r\n", SWITCH_PIN); + QueueHandle_t *tsqueue = (QueueHandle_t *)pvParameters; + gpio_set_interrupt(SWITCH_PIN, int_type, gpio_intr_handler); + + uint32_t last = 0; + while(1) { + uint32_t button_ts; + xQueueReceive(*tsqueue, &button_ts, portMAX_DELAY); + button_ts *= portTICK_PERIOD_MS; + if(last < button_ts-200) { + manual_switch(); + //printf("Button interrupt fired at %dms\r\n", button_ts); + last = button_ts; + } + } +} + +static QueueHandle_t tsqueue; + +void gpio_intr_handler(uint8_t gpio_num) +{ + uint32_t now = xTaskGetTickCountFromISR(); + xQueueSendToBackFromISR(tsqueue, &now, NULL); +} + +void register_app(void); + +void user_init(void) +{ + uart_set_baud(0, 115200); + printf("SDK version:%s\n", sdk_system_get_sdk_version()); + + struct sdk_station_config config = { + .ssid = WIFI_SSID, + .password = WIFI_PASS, + }; + + /* required to call wifi_set_opmode before station_set_config */ + sdk_wifi_set_opmode(STATION_MODE); + sdk_wifi_station_set_config(&config); + //netif_set_hostname(netif_default, "nachtlicht"); + sdk_wifi_station_connect(); + + /* turn off LED */ + gpio_enable(LED_PIN, GPIO_OUTPUT); + gpio_write(LED_PIN, true); + + + gpio_enable(SWITCH_PIN, GPIO_INPUT); + + tsqueue = xQueueCreate(2, sizeof(uint32_t)); + //xTaskCreate(buttonIntTask, "buttonIntTask", 256, &tsqueue, 2, NULL); + + /* initialize tasks */ + xTaskCreate(&httpd_task, "HTTP Daemon", 2048, NULL, 2, NULL); + + xTaskCreate(&sntp_tsk, "SNTP", 512, NULL, 1, NULL); + register_app(); +} + void user_init(void) { uart_set_baud(0, 115200); From 8874fecf15691ce04eac1aed5764f91ad2f51d16 Mon Sep 17 00:00:00 2001 From: jedi Date: Sat, 28 Aug 2021 23:44:01 +0200 Subject: [PATCH 02/12] add basic OTA Update fucionality --- firmware/.idea/firmware.iml | 8 +- firmware/.idea/modules.xml | 8 -- firmware/Makefile | 2 +- firmware/fiatlux.c | 4 +- firmware/fsdata/fs/index.html | 154 ++++++++++++++++++++++++++++++++-- firmware/system.c | 97 +++++++++++++++++++-- firmware/system.h | 9 ++ firmware/web.cpp | 123 +++++++++++++++++---------- 8 files changed, 333 insertions(+), 72 deletions(-) delete mode 100644 firmware/.idea/modules.xml diff --git a/firmware/.idea/firmware.iml b/firmware/.idea/firmware.iml index 58ca04c..91a038c 100644 --- a/firmware/.idea/firmware.iml +++ b/firmware/.idea/firmware.iml @@ -1,2 +1,8 @@ - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/firmware/.idea/modules.xml b/firmware/.idea/modules.xml deleted file mode 100644 index cb860b6..0000000 --- a/firmware/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/firmware/Makefile b/firmware/Makefile index 1c91e7e..bc8dc8b 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -2,7 +2,7 @@ PROGRAM=fiatlux EXTRA_CFLAGS=-O3 -Ifsdata -EXTRA_COMPONENTS=extras/i2s_dma extras/ws2812_i2s extras/dhcpserver extras/mbedtls extras/httpd extras/sntp extras/cpp_support +EXTRA_COMPONENTS=extras/i2s_dma extras/ws2812_i2s extras/dhcpserver extras/rboot-ota extras/mbedtls extras/httpd extras/sntp extras/cpp_support LIBS = hal m diff --git a/firmware/fiatlux.c b/firmware/fiatlux.c index 98d0efb..9e3efeb 100644 --- a/firmware/fiatlux.c +++ b/firmware/fiatlux.c @@ -22,9 +22,9 @@ void user_init(void) wifi_available_semaphore = xSemaphoreCreateBinary(); - xTaskCreate(wifi_task, "wifi_task", 512, NULL, 2, NULL); + xTaskCreate(wifi_task, "wifi_task", 1024, NULL, 1, NULL); - xTaskCreate(&httpd_task, "httpd_task", 512, NULL, 2, NULL); + xTaskCreate(&httpd_task, "httpd_task", 1024, NULL, 2, NULL); xTaskCreate(&lux_task, "lux_task", 512, NULL, 1, NULL); } diff --git a/firmware/fsdata/fs/index.html b/firmware/fsdata/fs/index.html index 2244e40..8ceefa7 100644 --- a/firmware/fsdata/fs/index.html +++ b/firmware/fsdata/fs/index.html @@ -16,9 +16,48 @@
+
+

System

+
+
+

Firmware Update

+
+
+
+ +
+
+ +
+
+
+
+
+

Restart

+
+
+
+ +
+
+
+
+
+

Reset Config

+
+
+
+ +
+
+
+ +

Status

@@ -133,19 +172,18 @@ diff --git a/firmware/system.c b/firmware/system.c index 350f86e..f9dcadd 100644 --- a/firmware/system.c +++ b/firmware/system.c @@ -3,35 +3,114 @@ // #include "system.h" +#include "crc32.h" #include -#include #include #include -#include #include +#include +#include +#include +#include -void system_clear_config(){ +#define min(a, b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + +void system_clear_config() { vPortEnterCritical(); - uint32_t num_sectors = 5 + DEFAULT_SYSPARAM_SECTORS; - uint32_t start = sdk_flashchip.chip_size - num_sectors * sdk_flashchip.sector_size; + uint32_t num_sectors = 0x2000 / sdk_flashchip.sector_size; + uint32_t start = 0x00100000; for (uint32_t i = 0; i < num_sectors; i++) { spiflash_erase_sector(start + i * sdk_flashchip.sector_size); } + if(sysparam_create_area(start, num_sectors, true) == SYSPARAM_OK) { + sysparam_init(start, 0); + } + sysparam_init(start, start + 0x2000); sdk_system_restart(); } -void system_init_config(){ - uint32_t base_addr; +void system_init_config() { + uint32_t base_addr = 0x00100000; uint32_t num_sectors; + sysparam_init(base_addr, 0); if(sysparam_get_info(&base_addr, &num_sectors) != SYSPARAM_OK) { printf("Warning: WiFi config, sysparam not initialized\n"); - num_sectors = DEFAULT_SYSPARAM_SECTORS; - base_addr = sdk_flashchip.chip_size - (5 + num_sectors) * sdk_flashchip.sector_size; + num_sectors = 0x2000 / sdk_flashchip.sector_size; if(sysparam_create_area(base_addr, num_sectors, true) == SYSPARAM_OK) { sysparam_init(base_addr, 0); } sdk_system_restart(); } +} + +#define MAX_IMAGE_SIZE 0x100000 + +struct { + rboot_write_status status; + uint32_t head; + uint32_t base; + uint16_t seq; + uint8_t slot; +} otaflash_context; + +void system_otaflash_init() { + rboot_config conf; + conf = rboot_get_config(); + otaflash_context.slot = (conf.current_rom + 1) % conf.count; + otaflash_context.base = rboot_get_slot_offset(otaflash_context.slot); + otaflash_context.status = rboot_write_init(otaflash_context.base); + otaflash_context.head = otaflash_context.base; + otaflash_context.seq = 0; +} + +int system_otaflash_chunk(uint8_t *data, uint16_t len, uint16_t seq, uint32_t hash) { + uint32_t local_hash = crc32(data, len); + if(hash == local_hash && otaflash_context.seq == seq) { + if(otaflash_context.head % SECTOR_SIZE == 0) { + sdk_spi_flash_erase_sector(otaflash_context.head / SECTOR_SIZE); + } + if(((uint32_t) data) % 4) { + uint32 buf[len / 4]; + memcpy(buf, data, len); + sdk_spi_flash_write(otaflash_context.head, buf, len); + } else { + sdk_spi_flash_write(otaflash_context.head, (uint32_t *) data, len); + } + otaflash_context.head += len; + otaflash_context.seq++; + return 0x88; + } else { + return 0xff; + } + +} + +void system_otaflash_verify_chunk(void *ctx, void *data, size_t len) { + uint32_t digest = *(uint32_t *) ctx; + digest = crc32_partial(digest, data, len); + *(uint32_t *) ctx = digest; +} + +int system_otaflash_verify_and_switch(uint32_t len, uint32_t hash) { + + uint32_t digest = 0; + rboot_digest_image(otaflash_context.base, min(len, MAX_IMAGE_SIZE), system_otaflash_verify_chunk, &digest); + + if(hash != digest) { + printf("OTA failed to verify firmware\r\n"); + return 0x99; + } + + vPortEnterCritical(); + if(!rboot_set_current_rom(otaflash_context.slot)) { + printf("OTA failed to set new rboot slot\r\n"); + } + sdk_system_restart(); + vPortExitCritical(); // | should not be reached + return 0x77; // | } \ No newline at end of file diff --git a/firmware/system.h b/firmware/system.h index 14f5188..ac97a9b 100644 --- a/firmware/system.h +++ b/firmware/system.h @@ -5,13 +5,22 @@ #ifndef FIRMWARE_SYSTEM_H #define FIRMWARE_SYSTEM_H +#include + #ifdef __cplusplus extern "C" { #endif void system_clear_config(); + void system_init_config(); +void system_otaflash_init(); + +int system_otaflash_chunk(uint8_t *data, uint16_t len, uint16_t seq, uint32_t hash); + +int system_otaflash_verify_and_switch(uint32_t len, uint32_t hash); + #ifdef __cplusplus } #endif diff --git a/firmware/web.cpp b/firmware/web.cpp index c900018..6176a43 100644 --- a/firmware/web.cpp +++ b/firmware/web.cpp @@ -38,7 +38,7 @@ void websocket_task(void *pvParameter) { has_changed = {true, true, true}; for (;;) { - if(pcb == NULL || pcb->state != ESTABLISHED) { + if(pcb == nullptr || pcb->state != ESTABLISHED) { printf("Connection closed, deleting task\n"); break; } @@ -46,14 +46,14 @@ void websocket_task(void *pvParameter) { //Global Info if(has_changed.global) { has_changed.global = false; - timeval tv; - gettimeofday(&tv, NULL); - int uptime = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000; + timeval tv{}; + gettimeofday(&tv, nullptr); + size_t uptime = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000; int heap = (int) xPortGetFreeHeapSize(); uint32_t chip_id = sdk_system_get_chip_id(); uint32_t flash_id = sdk_spi_flash_get_id(); uint32_t flash_size = sdk_flashchip.chip_size >> 10; - char *hostname = NULL; + char *hostname = nullptr; sysparam_get_string("hostname", &hostname); /* Generate response in JSON format */ @@ -80,21 +80,16 @@ void websocket_task(void *pvParameter) { //Connection Info if(has_changed.connection) { has_changed.connection = false; - timeval tv; - gettimeofday(&tv, NULL); - int connuptime = (xTaskGetTickCount() - connstarttime) * portTICK_PERIOD_MS / 1000; + timeval tv{}; + gettimeofday(&tv, nullptr); + size_t connuptime = (xTaskGetTickCount() - connstarttime) * portTICK_PERIOD_MS / 1000; - printf("conn %d: " - IPSTR - " <-> " - IPSTR - " \n", pcb->netif_idx, IP2STR(&pcb->local_ip), IP2STR(&pcb->remote_ip)); + printf("conn %d: " IPSTR " <-> " IPSTR " \n", pcb->netif_idx, IP2STR(&pcb->local_ip), + IP2STR(&pcb->remote_ip)); char response[160]; size_t len = snprintf(response, sizeof(response), "{\"connage\" : \"%d\"," - "\"clientip\" : \"" - IPSTR - "\"" + "\"clientip\" : \"" IPSTR "\"" "}", connuptime, IP2STR(&pcb->remote_ip)); if(len < sizeof(response)) { LOCK_TCPIP_CORE(); @@ -137,10 +132,10 @@ void websocket_task(void *pvParameter) { if(opmode == SOFTAP_MODE || opmode == STATIONAP_MODE) { uint8_t hwaddr[6]; sdk_wifi_get_macaddr(SOFTAP_IF, hwaddr); - ip_info info; + ip_info info{}; sdk_wifi_get_ip_info(SOFTAP_IF, &info); - char *apssid = NULL; + char *apssid = nullptr; sysparam_get_string("wifi_ap_ssid", &apssid); /* Generate response in JSON format */ @@ -148,12 +143,8 @@ void websocket_task(void *pvParameter) { size_t len = snprintf(response, sizeof(response), "{\"opmode\" : \"%s\"," " \"apssid\" : \"%s\"," - " \"apip\" : \"" - IPSTR - "\"," - " \"apmac\" : \"" - MACSTR - "\"" + " \"apip\" : \"" IPSTR "\"," + " \"apmac\" : \"" MACSTR "\"" "}", opmode_str, apssid, IP2STR(&info.ip), MAC2STR(hwaddr)); free(apssid); if(len < sizeof(response)) { @@ -169,7 +160,7 @@ void websocket_task(void *pvParameter) { if(opmode == STATION_MODE || opmode == STATIONAP_MODE) { uint8_t hwaddr[6]; sdk_wifi_get_macaddr(STATION_IF, hwaddr); - ip_info info; + ip_info info{}; sdk_wifi_get_ip_info(STATION_IF, &info); char *stassid = nullptr; sysparam_get_string("wifi_sta_ssid", &stassid); @@ -179,12 +170,8 @@ void websocket_task(void *pvParameter) { size_t len = snprintf(response, sizeof(response), "{\"opmode\" : \"%s\"," " \"stassid\" : \"%s\"," - " \"staip\" : \"" - IPSTR - "\"," - " \"stamac\" : \"" - MACSTR - "\"" + " \"staip\" : \"" IPSTR "\"," + " \"stamac\" : \"" MACSTR "\"" "}", opmode_str, stassid, IP2STR(&info.ip), MAC2STR(hwaddr)); free(stassid); if(len < sizeof(response)) { @@ -198,34 +185,49 @@ void websocket_task(void *pvParameter) { } vTaskDelayMs(500); - { - uint8_t response[3]; - uint16_t val = 0; - val = sdk_system_adc_read(); - response[2] = (uint8_t) val; - response[1] = val >> 8; - response[0] = 'V'; - websocket_write(pcb, response, 3, WS_BIN_MODE); - } - vTaskDelayMs(500); } - vTaskDelete(NULL); + vTaskDelete(nullptr); } +struct fw_frame { + char t; + uint8_t reserved[3]; + uint16_t seq; + uint16_t len; + uint32_t hash; + uint8_t data[]; +} __attribute__((packed)); + +struct fw_check { + char t; + uint8_t reserved[3]; + uint32_t len; + uint32_t hash; +} __attribute__((packed)); + /** * This function is called when websocket frame is received. * * Note: this function is executed on TCP thread and should return as soon * as possible. */ -void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, uint8_t mode) { +void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, + uint8_t /*mode*/) { //mode should be WS_BIN_MODE or WS_TEXT_MODE uint8_t response[3]; uint16_t val = 0; char cmd = '0'; + bool togl = 0; + switch (data[0]) { + case 'R': // Restart + cmd = 'R'; + break; + case 'X': // Clear Config + cmd = 'X'; + break; case 'D': // Disable LED signal_led(false); val = 1; @@ -236,9 +238,29 @@ void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, uint8_t mode) val = 0; cmd = 'G'; break; + case 'F': + togl = ~togl; + signal_led(togl); + { + auto *f = (fw_frame *) data; + if(f->seq == 0) { + system_otaflash_init(); + } + val = system_otaflash_chunk(f->data, ntohs(f->len), ntohs(f->seq), ntohl(f->hash)); + } + cmd = 'F'; + break; + case 'C': + signal_led(false); + { + auto *f = (fw_check *) data; + val = system_otaflash_verify_and_switch(ntohl(f->len), ntohl(f->hash)); + } + cmd = 'C'; + break; default: printf("[websocket_callback]:\n%.*s\n", (int) data_len, (char *) data); - printf("Unknown command\n"); + printf("Unknown command %c\n", data[0]); val = 0; break; } @@ -247,7 +269,18 @@ void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, uint8_t mode) response[1] = val >> 8; response[0] = cmd; + LOCK_TCPIP_CORE(); websocket_write(pcb, response, 3, WS_BIN_MODE); + UNLOCK_TCPIP_CORE(); + + if(data[0] == 'R') { // Restart + vTaskDelay(500 / portTICK_PERIOD_MS); + vPortEnterCritical(); + sdk_system_restart(); + } else if(data[0] == 'X') { // Clear Config + vTaskDelay(500 / portTICK_PERIOD_MS); + system_clear_config(); + } } /** @@ -262,10 +295,10 @@ void websocket_open_cb(struct tcp_pcb *pcb, const char *uri) { } extern "C" void httpd_task(void *pvParameters) { + (void) pvParameters; while (!uxSemaphoreGetCount(wifi_available_semaphore)) vTaskDelay(500 / portTICK_PERIOD_MS); - websocket_register_callbacks((tWsOpenHandler) websocket_open_cb, (tWsHandler) websocket_cb); httpd_init(); From 09452ef7ab346cf92587313a995b93be28680de9 Mon Sep 17 00:00:00 2001 From: jedi Date: Sat, 28 Aug 2021 23:48:01 +0200 Subject: [PATCH 03/12] add minimal OTA Update CLI --- README.md | 1 + firmware/otaflash.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100755 firmware/otaflash.py diff --git a/README.md b/README.md index ebf56ee..6ff897e 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ git submodule update --init --recursive - ncurses-dev libexpat-dev - python3 python3-serial python-dev + - pip install websocket-client (for otaflash.py, optional) ### Build Steps diff --git a/firmware/otaflash.py b/firmware/otaflash.py new file mode 100755 index 0000000..aeefe3f --- /dev/null +++ b/firmware/otaflash.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 + +import time +import websocket +import argparse +import zlib + +parser = argparse.ArgumentParser(description='Update fiatlux firmware via websocket.') +parser.add_argument("binfile") + +args = parser.parse_args() + +with open(args.binfile, "rb") as f: + try: + ws = websocket.WebSocket() + ws.connect("ws://172.16.0.1") + i = 0 + rolling = 0 + total = 0 + while True: + bytes = f.read(512) + rolling = zlib.crc32(bytes, rolling) + total += len(bytes) + msg = b'F\x00\x00\x00' + msg += i.to_bytes(2, 'big') + msg += len(bytes).to_bytes(2, 'big') + msg += (zlib.crc32(bytes) & 0xffffffff).to_bytes(4, 'big') + msg += bytes + ws.send(msg) + reply = ws.recv() + time.sleep(0.05) + i += 1 + if len(bytes) != 512: + break + msg = b'C\x00\x00\x00' + msg += total.to_bytes(4, 'big') + msg += rolling.to_bytes(4, 'big') + ws.send(msg) + print(ws.recv()) + ws.close() + except ConnectionResetError: + pass + except KeyboardInterrupt: + pass From 5fa1ec14e26d15b2ebfc509a7ab6f07a4b8e8fbc Mon Sep 17 00:00:00 2001 From: jedi Date: Mon, 6 Sep 2021 23:21:43 +0200 Subject: [PATCH 04/12] add otaflash.py script to release files --- .build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.build.yml b/.build.yml index 849107e..af5617d 100644 --- a/.build.yml +++ b/.build.yml @@ -57,6 +57,7 @@ steps: base_url: https://git.neulandlabor.de/ files: - firmware/firmware/fiatlux.bin + - firmware/otaflash.py - pcb/pcb.zip checksum: - sha512 From c0228cdf4954704106ceb61bab55593c4b8d6eeb Mon Sep 17 00:00:00 2001 From: 7m9 Date: Thu, 9 Sep 2021 02:35:15 +0200 Subject: [PATCH 05/12] Added gzip compression --- Makefile | 2 +- README.md | 2 +- docker/firmware/Dockerfile | 2 +- firmware/.gitignore | 4 +- firmware/Makefile | 11 +- firmware/fsdata/fs/404.html | 22 ---- firmware/fsdata/makefsdata | 114 ------------------ firmware/mkwebfs.py | 112 +++++++++++++++++ firmware/webdir/404.html | 22 ++++ .../{fsdata/fs => webdir}/css/picnic.min.css | 0 firmware/{fsdata/fs => webdir}/css/style.css | 24 ++-- firmware/{fsdata/fs => webdir}/index.html | 0 .../{fsdata/fs => webdir}/js/smoothie_min.js | 0 13 files changed, 159 insertions(+), 156 deletions(-) delete mode 100644 firmware/fsdata/fs/404.html delete mode 100755 firmware/fsdata/makefsdata create mode 100755 firmware/mkwebfs.py create mode 100644 firmware/webdir/404.html rename firmware/{fsdata/fs => webdir}/css/picnic.min.css (100%) rename firmware/{fsdata/fs => webdir}/css/style.css (71%) rename firmware/{fsdata/fs => webdir}/index.html (100%) rename firmware/{fsdata/fs => webdir}/js/smoothie_min.js (100%) diff --git a/Makefile b/Makefile index 8fafbe1..0518768 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ clean: firmware_docker: sh -c "docker build -t fiatlux_firmware_env docker/firmware" - sh -c "docker run --volume "$$(pwd)"/firmware:/app/firmware fiatlux_firmware_env make -C firmware all" + sh -c "docker run --volume "$$(pwd)"/firmware:/app/firmware fiatlux_firmware_env make -C firmware html all" pcb_docker: sh -c "docker build -t fiatlux_pcb_env docker/pcb" diff --git a/README.md b/README.md index 6ff897e..ecb33c2 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ git submodule update --init --recursive ### Build Requirements - make - - bash gawk perl + - bash gawk - g++ gcc - libc6-dev - flex bison diff --git a/docker/firmware/Dockerfile b/docker/firmware/Dockerfile index 582fe2f..d278775 100644 --- a/docker/firmware/Dockerfile +++ b/docker/firmware/Dockerfile @@ -6,7 +6,7 @@ RUN cd app; git clone --recursive https://github.com/SuperHouse/esp-open-rtos.gi RUN cd app; sed -i 's/GNU bash, version (3\\\.\[1-9\]|4)/GNU bash, version (3.[1-9]|4|5)/g' modules/sdk/crosstool-NG/configure.ac; mkdir -p modules/sdk/crosstool-NG/.build/tarballs; wget https://github.com/libexpat/libexpat/releases/download/R_2_1_0/expat-2.1.0.tar.gz -O modules/sdk/crosstool-NG/.build/tarballs/expat-2.1.0.tar.gz RUN cd app/modules/sdk; export CT_EXPERIMENTAL=y; export CT_ALLOW_BUILD_AS_ROOT=y; export CT_ALLOW_BUILD_AS_ROOT_SURE=y; make standalone=y -j$(nproc); wget -N https://raw.githubusercontent.com/espressif/esptool/master/esptool.py -O xtensa-lx106-elf/bin/esptool.py USER 0 -RUN apt remove --purge -y python2 && apt autoremove --purge -y && apt install -y python3 python3-serial perl +RUN apt remove --purge -y python2 && apt autoremove --purge -y && apt install -y python3 python3-serial RUN apt install -y --reinstall python-is-python3 USER 1000 WORKDIR /app diff --git a/firmware/.gitignore b/firmware/.gitignore index c67e8c9..14041d9 100644 --- a/firmware/.gitignore +++ b/firmware/.gitignore @@ -142,5 +142,5 @@ dkms.conf *.remove firmware/ -fsdata/fsdata.c -compile_commands.json \ No newline at end of file +build/ +compile_commands.json diff --git a/firmware/Makefile b/firmware/Makefile index bc8dc8b..e0a7ccb 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -1,6 +1,6 @@ PROGRAM=fiatlux -EXTRA_CFLAGS=-O3 -Ifsdata +EXTRA_CFLAGS=-O3 -Ibuild/gen EXTRA_COMPONENTS=extras/i2s_dma extras/ws2812_i2s extras/dhcpserver extras/rboot-ota extras/mbedtls extras/httpd extras/sntp extras/cpp_support @@ -10,11 +10,12 @@ FLASH_MODE = dio include ../modules/rtos/common.mk -html: fsdata/fsdata.c +html: build/gen/fsdata.c -fsdata/fsdata.c: fsdata/fs/index.html fsdata/fs/404.html fsdata/fs/css/picnic.min.css fsdata/fs/css/style.css fsdata/fs/js/smoothie_min.js +build/gen/fsdata.c: webdir/index.html webdir/404.html webdir/css/picnic.min.css webdir/css/style.css webdir/js/smoothie_min.js @echo "Generating fsdata.." - cd fsdata && ./makefsdata + @mkdir -p $(dir $@) + @./mkwebfs.py --gzip -o $@ $^ test: unittest systest @@ -24,4 +25,4 @@ unittest: systest: true -.NOTPARALLEL: html all \ No newline at end of file +.NOTPARALLEL: html all diff --git a/firmware/fsdata/fs/404.html b/firmware/fsdata/fs/404.html deleted file mode 100644 index da81a20..0000000 --- a/firmware/fsdata/fs/404.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - HTTP Server - - - - -
-

404 - Page not found

-
Sorry, the page you are requesting was not found on this server.
-
- - - diff --git a/firmware/fsdata/makefsdata b/firmware/fsdata/makefsdata deleted file mode 100755 index 5361370..0000000 --- a/firmware/fsdata/makefsdata +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/perl - -$incHttpHeader = 1; - -open(OUTPUT, "> fsdata.c"); -print(OUTPUT "#include \"httpd/fsdata.h\"\n\n"); - -chdir("fs"); -open(FILES, "find . -type f |"); - -while($file = ) { - - # Do not include files in CVS directories nor backup files. - if($file =~ /(CVS|~)/) { - next; - } - - chop($file); - - if($incHttpHeader == 1) { - open(HEADER, "> /tmp/header") || die $!; - if($file =~ /404/) { - print(HEADER "HTTP/1.0 404 File not found\r\n"); - } else { - print(HEADER "HTTP/1.0 200 OK\r\n"); - } - print(HEADER "lwIP/1.4.1 (http://savannah.nongnu.org/projects/lwip)\r\n"); - if($file =~ /\.html$/ || $file =~ /\.htm$/ || $file =~ /\.shtml$/ || $file =~ /\.shtm$/ || $file =~ /\.ssi$/) { - print(HEADER "Content-type: text/html\r\n"); - } elsif($file =~ /\.js$/) { - print(HEADER "Content-type: application/x-javascript\r\n\r\n"); - } elsif($file =~ /\.css$/) { - print(HEADER "Content-type: text/css\r\n\r\n"); - } elsif($file =~ /\.ico$/) { - print(HEADER "Content-type: image/x-icon\r\n\r\n"); - } elsif($file =~ /\.gif$/) { - print(HEADER "Content-type: image/gif\r\n"); - } elsif($file =~ /\.png$/) { - print(HEADER "Content-type: image/png\r\n"); - } elsif($file =~ /\.jpg$/) { - print(HEADER "Content-type: image/jpeg\r\n"); - } elsif($file =~ /\.bmp$/) { - print(HEADER "Content-type: image/bmp\r\n\r\n"); - } elsif($file =~ /\.class$/) { - print(HEADER "Content-type: application/octet-stream\r\n"); - } elsif($file =~ /\.ram$/) { - print(HEADER "Content-type: audio/x-pn-realaudio\r\n"); - } else { - print(HEADER "Content-type: text/plain\r\n"); - } - print(HEADER "\r\n"); - close(HEADER); - - unless($file =~ /\.plain$/ || $file =~ /cgi/) { - system("cat /tmp/header $file > /tmp/file"); - } else { - system("cp $file /tmp/file"); - } - } else { - system("cp $file /tmp/file"); - } - - open(FILE, "/tmp/file"); - unlink("/tmp/file"); - unlink("/tmp/header"); - - $file =~ s/\.//; - $fvar = $file; - $fvar =~ s-/-_-g; - $fvar =~ s-\.-_-g; - - print(OUTPUT "static const unsigned char data".$fvar."[] = {\n"); - print(OUTPUT "\t/* $file */\n\t"); - for($j = 0; $j < length($file); $j++) { - printf(OUTPUT "0x%02X, ", unpack("C", substr($file, $j, 1))); - } - printf(OUTPUT "0,\n"); - - - $i = 0; - while(read(FILE, $data, 1)) { - if($i == 0) { - print(OUTPUT "\t"); - } - printf(OUTPUT "0x%02X, ", unpack("C", $data)); - $i++; - if($i == 10) { - print(OUTPUT "\n"); - $i = 0; - } - } - print(OUTPUT "};\n\n"); - close(FILE); - push(@fvars, $fvar); - push(@files, $file); -} - -for($i = 0; $i < @fvars; $i++) { - $file = $files[$i]; - $fvar = $fvars[$i]; - - if($i == 0) { - $prevfile = "NULL"; - } else { - $prevfile = "file" . $fvars[$i - 1]; - } - print(OUTPUT "const struct fsdata_file file".$fvar."[] = {{\n$prevfile,\ndata$fvar, "); - print(OUTPUT "data$fvar + ". (length($file) + 1) .",\n"); - print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) .",\n"); - print(OUTPUT $incHttpHeader."\n}};\n\n"); -} - -print(OUTPUT "#define FS_ROOT file$fvars[$i - 1]\n\n"); -print(OUTPUT "#define FS_NUMFILES $i\n"); diff --git a/firmware/mkwebfs.py b/firmware/mkwebfs.py new file mode 100755 index 0000000..667af23 --- /dev/null +++ b/firmware/mkwebfs.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +import os +import gzip +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument('-o', '--output', help='Output file name', default='stdout') +parser.add_argument('-W', '--webroot', help='Output file name', default='webdir/') +parser.add_argument('--gzip', dest='gzip', action='store_true') +parser.add_argument('--no-gzip', dest='gzip', action='store_false') +parser.set_defaults(gzip=False) +parser.add_argument('--header', dest='header', action='store_true') +parser.add_argument('--no-header', dest='header', action='store_false') +parser.set_defaults(header=True) +parser.add_argument('input', nargs='+', default=os.getcwd()) +args = parser.parse_args() + + +def dumpBin2CHex(f, b): + oStr = "\t" + n = 0 + for val in b: + oStr += hex(val) + ", " + n += 1 + if n % 8 == 0: + oStr += "\n\t" + oStr += "\n" + f.write(oStr) + + +f_fsdata_c = open(args.output, 'w') +f_fsdata_c.write('#include "httpd/fsdata.h"\n\n') + +httpFiles = [file for file in args.input if (args.webroot in file)] + +lastFileStruct = "NULL" + +for file in httpFiles: + response = b'' + + webPath = ("/" + file.removeprefix(args.webroot)).replace("//", "/") + print("{} > {}".format(file, webPath)) + + if args.header: + if ("404" in file): + response = b'HTTP/1.0 404 File not found\r\n' + else: + response = b'HTTP/1.0 200 OK\r\n' + response += b"lwIP/1.4.1 (http://savannah.nongnu.org/projects/lwip)\r\n" + fext = file.split('.')[-1] + ctype = b'Content-type: text/plain\r\n' + if (fext.endswith("html") or fext.endswith("htm") or fext.endswith("shtml") or fext.endswith( + "shtm") or fext.endswith("ssi")): + ctype = b'Content-type: text/html\r\n' + if (fext.endswith("js")): + ctype = b'Content-type: application/x-javascript\r\n' + if (fext.endswith("css")): + ctype = b'Content-type: text/css\r\n' + if (fext.endswith("ico")): + ctype = b'Content-type: image/x-icon\r\n' + if (fext.endswith("gif")): + ctype = b'Content-type: image/gif\r\n' + if (fext.endswith("png")): + ctype = b'Content-type: image/png\r\n' + if(fext.endswith("jpg")): + ctype = b'Content-type: image/jpeg\r\n' + if(fext.endswith("bmp")): + ctype = b'Content-type: image/bmp\r\n' + if(fext.endswith("class")): + ctype = b'Content-type: application/octet-stream\r\n' + if(fext.endswith("ram")): + ctype = b'Content-type: audio/x-pn-realaudio\r\n' + response += ctype + + binFile = open(file, 'rb') + binData = binFile.read() + compEff = False + if args.gzip: + compData = gzip.compress(binData, 9) + if len(compData) < len(binData): + compEff = True + print("- Compressed from {} to {}".format(len(binData), len(compData))) + binData = compData + else: + print("- Compression skipped Orig: {} Comp: {}".format(len(binData), len(compData))) + binFile.close() + + if compEff: + response += b'Content-Encoding: gzip\r\n' + response += b"\r\n" + response += binData + binFile.close() + escFile = file.replace("/", "_").replace(".", "_") + escFileData = "data_" + escFile + escFileFile = "file_" + escFile + + f_fsdata_c.write('static const unsigned char {}[] = {{\n'.format(escFileData)) + f_fsdata_c.write('\t/* LOCAL:{} */\n'.format(file)) + f_fsdata_c.write('\t/* WEB: {} */\n'.format(webPath)) + fnameBin = webPath.encode("ascii") + b'\0' + dumpBin2CHex(f_fsdata_c, fnameBin) + dumpBin2CHex(f_fsdata_c, response) + f_fsdata_c.write("};\n\n") + + f_fsdata_c.write("const struct fsdata_file {}[] = {{{{\n {},\n {}, {} + {}, sizeof({}) - {}, 1 }}}};\n\n" + .format(escFileFile, lastFileStruct, escFileData, escFileData, len(fnameBin), escFileData, len(fnameBin))) + # TODO: The last value is 1 if args.header == True + lastFileStruct = escFileFile + +f_fsdata_c.write("\n") +f_fsdata_c.write("#define FS_ROOT {}\n\n".format(lastFileStruct)) +f_fsdata_c.write("#define FS_NUMFILES {}\n\n".format(len(httpFiles))) diff --git a/firmware/webdir/404.html b/firmware/webdir/404.html new file mode 100644 index 0000000..ebea9c6 --- /dev/null +++ b/firmware/webdir/404.html @@ -0,0 +1,22 @@ + + + + + + + HTTP Server + + + + +
+

404 - Page not found

+
Sorry, the page you are requesting was not found on this server.
+
+ + + diff --git a/firmware/fsdata/fs/css/picnic.min.css b/firmware/webdir/css/picnic.min.css similarity index 100% rename from firmware/fsdata/fs/css/picnic.min.css rename to firmware/webdir/css/picnic.min.css diff --git a/firmware/fsdata/fs/css/style.css b/firmware/webdir/css/style.css similarity index 71% rename from firmware/fsdata/fs/css/style.css rename to firmware/webdir/css/style.css index 0e0e33a..136393e 100644 --- a/firmware/fsdata/fs/css/style.css +++ b/firmware/webdir/css/style.css @@ -6,15 +6,15 @@ main { margin-right: auto; } -canvas{ +canvas { width: 100%; } -main section:target ~ section, main section#io, main section#wifi, main section#ota { +main section:target ~ section, main section#io, main section#wifi, main section#ota { display: none; } -main section:target{ +main section:target { display: block !important; } @@ -22,30 +22,34 @@ main section:target{ width: 100%; display: table; } -.table>.row{ + +.table > .row { display: table-row; } -.table>.row:nth-child(2n) { - background: rgba(17,17,17,0.05); + +.table > .row:nth-child(2n) { + background: rgba(17, 17, 17, 0.05); } -.table>.row>*{ + +.table > .row > * { display: table-cell; padding: .3em 2.4em .3em .6em; } -.table>header.row>*{ + +.table > header.row > * { text-align: left; font-weight: 900; color: #fff; background-color: #0074d9; } -.table>.row>input{ +.table > .row > input { border: none; background: none; font-weight: 900; } -.plain{ +.plain { opacity: initial; width: initial; } \ No newline at end of file diff --git a/firmware/fsdata/fs/index.html b/firmware/webdir/index.html similarity index 100% rename from firmware/fsdata/fs/index.html rename to firmware/webdir/index.html diff --git a/firmware/fsdata/fs/js/smoothie_min.js b/firmware/webdir/js/smoothie_min.js similarity index 100% rename from firmware/fsdata/fs/js/smoothie_min.js rename to firmware/webdir/js/smoothie_min.js From 8f052ecb374e13a213200b456965e5e222c96637 Mon Sep 17 00:00:00 2001 From: Marcus Date: Wed, 8 Sep 2021 01:23:03 +0200 Subject: [PATCH 06/12] Added Progress bar and Fixed OTA update --- firmware/.idea/firmware.iml | 1 + firmware/webdir/css/style.css | 4 ++-- firmware/webdir/index.html | 30 ++++++++++++++++++++++++++---- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/firmware/.idea/firmware.iml b/firmware/.idea/firmware.iml index 91a038c..190a5aa 100644 --- a/firmware/.idea/firmware.iml +++ b/firmware/.idea/firmware.iml @@ -1,4 +1,5 @@ + diff --git a/firmware/webdir/css/style.css b/firmware/webdir/css/style.css index 136393e..c84c3d9 100644 --- a/firmware/webdir/css/style.css +++ b/firmware/webdir/css/style.css @@ -32,8 +32,8 @@ main section:target { } .table > .row > * { - display: table-cell; - padding: .3em 2.4em .3em .6em; + display: table-cell; + padding: .3em .6em .3em .6em; } .table > header.row > * { diff --git a/firmware/webdir/index.html b/firmware/webdir/index.html index 8ceefa7..f769a5a 100644 --- a/firmware/webdir/index.html +++ b/firmware/webdir/index.html @@ -5,6 +5,7 @@ fiatlux v0.2 +
+
+
+

Syslog

+
+
+
+

+                
+
+
@@ -181,6 +191,7 @@