diff --git a/.build.yml b/.build.yml index 7ece57b..849107e 100644 --- a/.build.yml +++ b/.build.yml @@ -9,19 +9,17 @@ steps: - name: submodules image: alpine/git commands: - - git submodule update --init --recursive --depth 1 + - git submodule update --init --recursive - name: firmware image: docker-repo.service.intern.lab.or.it:5000/fiatlux-build-env depends_on: [ submodules ] commands: - export PATH=$(pwd)/modules/sdk/xtensa-lx106-elf/bin:$PATH - - apt update - - apt install -y minify - make firmware -j$(nproc) - name: pcb - image: setsoft/kicad_auto:ki6 + image: setsoft/kicad_auto commands: - apt update - apt install -y make zip @@ -59,11 +57,10 @@ steps: base_url: https://git.neulandlabor.de/ files: - firmware/firmware/fiatlux.bin - - firmware/otaflash.py - pcb/pcb.zip checksum: - sha512 - md5 - title: fiatlux + title: buildtest when: event: tag diff --git a/.gitmodules b/.gitmodules index 5e7dc18..11a7502 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "modules/rtos"] path = modules/rtos - url = https://git.neulandlabor.de/j3d1/esp-open-rtos.git + url = https://github.com/SuperHouse/esp-open-rtos.git [submodule "modules/sdk"] path = modules/sdk url = https://github.com/pfalcon/esp-open-sdk.git diff --git a/Makefile b/Makefile index c8f31c2..8fafbe1 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ + .PHONY: firmware flash firmware_docker case pcb all: firmware case pcb @@ -18,14 +19,9 @@ clean: +@make -C firmware clean +@make -C pcb clean -flash_docker: - sh -c "docker build -t fiatlux_firmware_env docker/firmware" - sh -c "docker run --volume "$$(pwd)"/firmware:/app/firmware --device=/dev/ttyUSB0 fiatlux_firmware_env make -C firmware flash" - - 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 html all" + sh -c "docker run --volume "$$(pwd)"/firmware:/app/firmware fiatlux_firmware_env make -C firmware all" pcb_docker: sh -c "docker build -t fiatlux_pcb_env docker/pcb" diff --git a/README.md b/README.md index ecb33c2..ebf56ee 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ git submodule update --init --recursive ### Build Requirements - make - - bash gawk + - bash gawk perl - g++ gcc - libc6-dev - flex bison @@ -27,7 +27,6 @@ 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/docker/firmware/Dockerfile b/docker/firmware/Dockerfile index d278775..582fe2f 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 +RUN apt remove --purge -y python2 && apt autoremove --purge -y && apt install -y python3 python3-serial perl RUN apt install -y --reinstall python-is-python3 USER 1000 WORKDIR /app diff --git a/firmware/.gitignore b/firmware/.gitignore index 14041d9..c67e8c9 100644 --- a/firmware/.gitignore +++ b/firmware/.gitignore @@ -142,5 +142,5 @@ dkms.conf *.remove firmware/ -build/ -compile_commands.json +fsdata/fsdata.c +compile_commands.json \ No newline at end of file diff --git a/firmware/.idea/firmware.iml b/firmware/.idea/firmware.iml index 190a5aa..58ca04c 100644 --- a/firmware/.idea/firmware.iml +++ b/firmware/.idea/firmware.iml @@ -1,9 +1,2 @@ - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/firmware/.idea/modules.xml b/firmware/.idea/modules.xml new file mode 100644 index 0000000..cb860b6 --- /dev/null +++ b/firmware/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/firmware/Makefile b/firmware/Makefile index 976b533..1c91e7e 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -1,21 +1,20 @@ PROGRAM=fiatlux -EXTRA_CFLAGS=-O3 -Ibuild/gen -DLWIP_NETIF_HOSTNAME=1 +EXTRA_CFLAGS=-O3 -Ifsdata -EXTRA_COMPONENTS=extras/i2s_dma extras/ws2812_i2s extras/dhcpserver extras/rboot-ota extras/mbedtls extras/httpd extras/sntp extras/cpp_support extras/paho_mqtt_c +EXTRA_COMPONENTS=extras/i2s_dma extras/ws2812_i2s extras/dhcpserver extras/mbedtls extras/httpd extras/sntp extras/cpp_support LIBS = hal m -FLASH_MODE = qio +FLASH_MODE = dio include ../modules/rtos/common.mk -html: build/gen/fsdata.c +html: fsdata/fsdata.c -build/gen/fsdata.c: webdir/index.html webdir/404.html webdir/css/picnic.min.css webdir/css/style.css webdir/js/smoothie_min.js +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 @echo "Generating fsdata.." - @mkdir -p $(dir $@) - @./mkwebfs.py --gzip --minify -o $@ $^ + cd fsdata && ./makefsdata test: unittest systest @@ -25,4 +24,4 @@ unittest: systest: true -.NOTPARALLEL: html all +.NOTPARALLEL: html all \ No newline at end of file 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 9e3efeb..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); @@ -22,9 +324,9 @@ void user_init(void) wifi_available_semaphore = xSemaphoreCreateBinary(); - xTaskCreate(wifi_task, "wifi_task", 1024, NULL, 1, NULL); + xTaskCreate(wifi_task, "wifi_task", 512, NULL, 2, NULL); - xTaskCreate(&httpd_task, "httpd_task", 1024, NULL, 2, NULL); + xTaskCreate(&httpd_task, "httpd_task", 512, NULL, 2, NULL); xTaskCreate(&lux_task, "lux_task", 512, NULL, 1, NULL); } diff --git a/firmware/fsdata/fs/404.html b/firmware/fsdata/fs/404.html new file mode 100644 index 0000000..da81a20 --- /dev/null +++ b/firmware/fsdata/fs/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/webdir/css/picnic.min.css b/firmware/fsdata/fs/css/picnic.min.css similarity index 100% rename from firmware/webdir/css/picnic.min.css rename to firmware/fsdata/fs/css/picnic.min.css diff --git a/firmware/webdir/css/style.css b/firmware/fsdata/fs/css/style.css similarity index 63% rename from firmware/webdir/css/style.css rename to firmware/fsdata/fs/css/style.css index c84c3d9..0e0e33a 100644 --- a/firmware/webdir/css/style.css +++ b/firmware/fsdata/fs/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,34 +22,30 @@ 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 > * { - display: table-cell; - padding: .3em .6em .3em .6em; +.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/webdir/index.html b/firmware/fsdata/fs/index.html similarity index 56% rename from firmware/webdir/index.html rename to firmware/fsdata/fs/index.html index 317dc10..2244e40 100644 --- a/firmware/webdir/index.html +++ b/firmware/fsdata/fs/index.html @@ -5,7 +5,6 @@ fiatlux v0.2 -
-
-

System

-
-
-

Firmware Update

-
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-

Restart

-
-
-
- -
-
-
-
-
-

Reset Config

-
-
-
- -
-
-
-
-
-

Syslog

-
-
-
-

-                
-
-
- -

Status

@@ -189,23 +133,19 @@ diff --git a/firmware/webdir/js/smoothie_min.js b/firmware/fsdata/fs/js/smoothie_min.js similarity index 100% rename from firmware/webdir/js/smoothie_min.js rename to firmware/fsdata/fs/js/smoothie_min.js diff --git a/firmware/fsdata/makefsdata b/firmware/fsdata/makefsdata new file mode 100755 index 0000000..5361370 --- /dev/null +++ b/firmware/fsdata/makefsdata @@ -0,0 +1,114 @@ +#!/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/log.cpp b/firmware/log.cpp deleted file mode 100644 index 8b268d9..0000000 --- a/firmware/log.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// -// Created by jedi on 18.11.21. -// - -#include "log.h" - -#include - -constexpr unsigned syslog_buffer_size = 1024; -char syslog_buf[syslog_buffer_size]; -volatile unsigned head = 0; -volatile unsigned streams = 0; - -extern "C" void syslog(const char *msg) { - printf("syslog> %s", msg); - while (char c = *msg++) { - syslog_buf[head++ % syslog_buffer_size] = c; - } - syslog_buf[head] = 0; -} - -unsigned syslog_current_tail() { - if(head < syslog_buffer_size) - return 0; - return head + 1 - syslog_buffer_size; -} - -unsigned syslog_data_after(unsigned local_tail) { - if(local_tail > head) - return 0; - return (head % syslog_buffer_size) - (local_tail % syslog_buffer_size); -} - -extern "C" int syslog_copy_out(char *out, int len, unsigned local_tail) { - unsigned cnt = 0; - while (cnt < syslog_data_after(local_tail) && cnt < len) { - out[cnt] = syslog_buf[local_tail % syslog_buffer_size + cnt]; - cnt++; - } - return cnt; -} - -extern "C" void syslog_attach() { - streams++; -} - -extern "C" void syslog_detach() { - streams--; -} \ No newline at end of file diff --git a/firmware/log.h b/firmware/log.h deleted file mode 100644 index 0cde491..0000000 --- a/firmware/log.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// Created by jedi on 18.11.21. -// - -#ifndef FIRMWARE_LOG_H -#define FIRMWARE_LOG_H - -#ifdef __cplusplus -extern "C" { -#endif - -void syslog(const char *); - -unsigned syslog_current_tail(); - -unsigned syslog_data_after(unsigned); - -int syslog_copy_out(char *, int, unsigned); - -void syslog_attach(); - -void syslog_detach(); - -#ifdef __cplusplus -} -#endif - -#endif //FIRMWARE_LOG_H diff --git a/firmware/mkwebfs.py b/firmware/mkwebfs.py deleted file mode 100755 index e48548c..0000000 --- a/firmware/mkwebfs.py +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env python3 -import os -import gzip -import argparse -import subprocess - -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('--minify', dest='minify', action='store_true') -parser.add_argument('--no-minify', dest='minify', action='store_false') -parser.set_defaults(minify=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 mimeFromName(name): - if name.endswith(".html") or name.endswith(".htm") or name.endswith(".shtml") or name.endswith( - ".shtm") or name.endswith(".ssi"): - return "text/html" - if name.endswith(".js"): - return "application/x-javascript" - if name.endswith(".css"): - return "text/css" - if name.endswith(".ico"): - return "image/x-icon" - if name.endswith(".gif"): - return "image/gif" - if name.endswith(".png"): - return "image/png" - if name.endswith(".jpg"): - return "image/jpeg" - if name.endswith(".bmp"): - return "image/bmp" - if name.endswith(".class"): - return "application/octet-stream" - if name.endswith(".ram"): - return "audio/x-pn-realaudio" - return "text/plain" - - -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)) - - mimeType = mimeFromName(file) - - 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" - response += b'Content-type: ' + mimeType.encode() + b'\r\n' - - binFile = open(file, 'rb') - binData = binFile.read() - compEff = False - if args.minify: - p = subprocess.Popen(["minify", "--html-keep-document-tags", "--mime", mimeType], stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - minData = p.communicate(binData)[0] - if len(minData) < len(binData): - print("- Minify: {} -> {}".format(len(binData), len(minData))) - compEff = True - binData = minData - - 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/otaflash.py b/firmware/otaflash.py deleted file mode 100755 index 2c52133..0000000 --- a/firmware/otaflash.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python3 - -import time -import websocket -import argparse -import zlib -from websocket import WebSocketTimeoutException - -parser = argparse.ArgumentParser(description='Update fiatlux firmware via websocket.') -parser.add_argument("binfile") -parser.add_argument("address") - -args = parser.parse_args() - -bs = 1024 - - -def parse_reply(bytes): - cmd = bytes[0:1].decode("utf-8") - ret = int.from_bytes(bytes[1:2], "big") - val = int.from_bytes(bytes[2:4], "big") - return {'cmd': cmd, 'ret': ret, 'val': val} - - -with open(args.binfile, "rb") as f: - try: - ws = websocket.WebSocket() - print("send {}".format(args.binfile)) - ws.connect("ws://" + args.address) - i = 0 - bytes = f.read() - rolling = zlib.crc32(bytes) - total = len(bytes) - while True: - chunk = bytes[bs * i:bs * i + bs] - msg = b'F\x00\x00\x00' - msg += i.to_bytes(2, 'big') - msg += len(chunk).to_bytes(2, 'big') - msg += (zlib.crc32(chunk) & 0xffffffff).to_bytes(4, 'big') - msg += chunk - ws.send(msg) - print("\r{:6.2f}%".format(100 * i * bs / total), end='') - reply = parse_reply(ws.recv()) - if reply['cmd'] == 'F' and reply['ret'] == 0: - i += 1 - elif reply['cmd'] == 'F' and reply['ret'] == 1: - print("Error: SEQUENCE_OUT_OF_ORDER") - i = reply['val'] - elif reply['cmd'] == 'F' and reply['ret'] == 2: - print("Error: CHECKSUM_MISMATCH") - i = reply['val'] - else: - print(reply) - - time.sleep(0.05) - if len(chunk) != bs: - break - - print("\rdone ") - msg = b'C\x00\x00\x00' - msg += total.to_bytes(4, 'big') - msg += (rolling).to_bytes(4, 'big') - ws.settimeout(5) - ws.send(msg) - reply = parse_reply(ws.recv()) - print(reply) - ws.close() - except WebSocketTimeoutException: - pass - except ConnectionResetError: - pass - except KeyboardInterrupt: - pass diff --git a/firmware/system.c b/firmware/system.c index d190606..350f86e 100644 --- a/firmware/system.c +++ b/firmware/system.c @@ -3,120 +3,35 @@ // #include "system.h" -#include "crc32.h" -#include "log.h" #include +#include #include #include +#include #include -#include -#include -#include -#include -#define min(a, b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a < _b ? _a : _b; }) - -void system_clear_config() { +void system_clear_config(){ vPortEnterCritical(); - uint32_t num_sectors = 0x2000 / sdk_flashchip.sector_size; - uint32_t start = 0x00100000; + uint32_t num_sectors = 5 + DEFAULT_SYSPARAM_SECTORS; + uint32_t start = sdk_flashchip.chip_size - num_sectors * sdk_flashchip.sector_size; 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 = 0x00100000; +void system_init_config(){ + uint32_t base_addr; uint32_t num_sectors; - sysparam_init(base_addr, 0); if(sysparam_get_info(&base_addr, &num_sectors) != SYSPARAM_OK) { - syslog("Warning: WiFi config, sysparam not initialized\n"); - num_sectors = 0x2000 / sdk_flashchip.sector_size; + 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; 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; -} - -enum return_code system_otaflash_chunk(uint8_t *data, uint16_t len, uint16_t seq, uint32_t hash, uint16_t *ack) { - 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 OK; - } else if(hash != local_hash) { - return CHECKSUM_MISMATCH; - } else { - if(ack) - *ack = otaflash_context.seq; - return SEQUENCE_OUT_OF_ORDER; - } - -} - -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; -} - -enum return_code 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) { - syslog("OTA failed to verify firmware\r\n"); - return CHECKSUM_MISMATCH; - } - - vPortEnterCritical(); - if(!rboot_set_current_rom(otaflash_context.slot)) { - syslog("OTA Update failed to set new rboot slot\r\n"); - vPortExitCritical(); - return RBOOT_SWITCH_FAILED; - } - vPortExitCritical(); - return OK; } \ No newline at end of file diff --git a/firmware/system.h b/firmware/system.h index 075bd90..14f5188 100644 --- a/firmware/system.h +++ b/firmware/system.h @@ -5,23 +5,13 @@ #ifndef FIRMWARE_SYSTEM_H #define FIRMWARE_SYSTEM_H -#include -#include "types.h" - #ifdef __cplusplus extern "C" { #endif void system_clear_config(); - void system_init_config(); -void system_otaflash_init(); - -enum return_code system_otaflash_chunk(uint8_t *data, uint16_t len, uint16_t seq, uint32_t hash, uint16_t *ack); - -enum return_code system_otaflash_verify_and_switch(uint32_t len, uint32_t hash); - #ifdef __cplusplus } #endif diff --git a/firmware/types.h b/firmware/types.h deleted file mode 100644 index 726a621..0000000 --- a/firmware/types.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// Created by jedi on 09.09.21. -// - -#ifndef FIRMWARE_TYPES_H -#define FIRMWARE_TYPES_H - -#ifdef __cplusplus -extern "C" { -#endif - -enum return_code { - OK = 0, SEQUENCE_OUT_OF_ORDER, CHECKSUM_MISMATCH, RBOOT_SWITCH_FAILED, ERROR = 0xFF -}; - -#ifdef __cplusplus -} -#endif - -#endif //FIRMWARE_TYPES_H diff --git a/firmware/web.cpp b/firmware/web.cpp index ed55e2d..c900018 100644 --- a/firmware/web.cpp +++ b/firmware/web.cpp @@ -6,7 +6,6 @@ #include "system.h" #include "lux.h" #include "wifi.h" -#include "log.h" #include #include @@ -37,46 +36,28 @@ void websocket_task(void *pvParameter) { size_t connstarttime = xTaskGetTickCount(); has_changed = {true, true, true}; - syslog_attach(); - unsigned local_log_tail = syslog_current_tail(); for (;;) { - if(pcb == nullptr || pcb->state != ESTABLISHED) { - syslog("Connection closed, deleting task\n"); + if(pcb == NULL || pcb->state != ESTABLISHED) { + printf("Connection closed, deleting task\n"); break; } - //Syslog - if(syslog_data_after(local_log_tail) != 0) { - char response[128]; - response[0] = 'L'; - size_t len = syslog_copy_out(&response[4], 124, local_log_tail); - response[1] = len; - ((uint16_t &) response[2]) = local_log_tail & 0xFFFF; - if(len < sizeof(response)) { - LOCK_TCPIP_CORE(); - websocket_write(pcb, (unsigned char *) response, len + 4, WS_BIN_MODE); - local_log_tail += len; - UNLOCK_TCPIP_CORE(); - } else - syslog("buffer too small -1\n"); - vTaskDelayMs(1000); - } - //Global Info if(has_changed.global) { - timeval tv{}; - gettimeofday(&tv, nullptr); - size_t uptime = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000; + has_changed.global = false; + timeval tv; + gettimeofday(&tv, NULL); + int 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 = nullptr; + char *hostname = NULL; sysparam_get_string("hostname", &hostname); /* Generate response in JSON format */ - char response[192]; + char response[160]; size_t len = snprintf(response, sizeof(response), "{\"walltime\" : \"%d\"," "\"uptime\" : \"%d\"," @@ -90,34 +71,38 @@ void websocket_task(void *pvParameter) { if(len < sizeof(response)) { LOCK_TCPIP_CORE(); websocket_write(pcb, (unsigned char *) response, len, WS_TEXT_MODE); - has_changed.global = false; UNLOCK_TCPIP_CORE(); } else - syslog("buffer too small 0\n"); - vTaskDelayMs(1000); + printf("buffer too small 1"); + vTaskDelayMs(2000); } //Connection Info if(has_changed.connection) { - timeval tv{}; - gettimeofday(&tv, nullptr); - size_t connuptime = (xTaskGetTickCount() - connstarttime) * portTICK_PERIOD_MS / 1000; + has_changed.connection = false; + timeval tv; + gettimeofday(&tv, NULL); + int connuptime = (xTaskGetTickCount() - connstarttime) * portTICK_PERIOD_MS / 1000; - printf("conn %d: " IPSTR " <-> " IPSTR " \n", pcb->netif_idx, IP2STR(&pcb->local_ip), - IP2STR(&pcb->remote_ip)); - char response[192]; + 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(); websocket_write(pcb, (unsigned char *) response, len, WS_TEXT_MODE); - has_changed.connection = false; UNLOCK_TCPIP_CORE(); } else - syslog("buffer too small 1\n"); - vTaskDelayMs(1000); + printf("buffer too small 1"); + vTaskDelayMs(2000); } if(has_changed.wifi) { @@ -152,10 +137,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 = nullptr; + char *apssid = NULL; sysparam_get_string("wifi_ap_ssid", &apssid); /* Generate response in JSON format */ @@ -163,8 +148,12 @@ 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)) { @@ -172,15 +161,15 @@ void websocket_task(void *pvParameter) { websocket_write(pcb, (unsigned char *) response, len, WS_TEXT_MODE); UNLOCK_TCPIP_CORE(); } else - syslog("buffer too small 2\n"); + printf("buffer too small 2"); } - vTaskDelayMs(1000); + vTaskDelayMs(2000); 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); @@ -190,8 +179,12 @@ 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)) { @@ -199,121 +192,62 @@ void websocket_task(void *pvParameter) { websocket_write(pcb, (unsigned char *) response, len, WS_TEXT_MODE); UNLOCK_TCPIP_CORE(); } else - syslog("buffer too small 3\n"); + printf("buffer too small 3"); } } 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); } - syslog_detach(); - - vTaskDelete(nullptr); + vTaskDelete(NULL); } -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*/) { //mode should be WS_BIN_MODE or WS_TEXT_MODE +void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, uint8_t mode) { - uint8_t response[4]; - auto &cmd = (char &) response[0]; - auto &ret = response[1]; - auto &val = (uint16_t &) response[2]; - cmd = '0'; - ret = ERROR; - val = 0; - - bool togl = false; + uint8_t response[3]; + uint16_t val = 0; + char cmd = '0'; switch (data[0]) { - case 'R': // Restart - cmd = 'R'; - ret = OK; - break; - case 'X': // Clear Config - cmd = 'X'; - ret = OK; - break; case 'D': // Disable LED - syslog("G\n"); signal_led(false); - cmd = 'G'; - ret = OK; val = 1; + cmd = 'G'; break; case 'E': // Enable LED - syslog("E\n"); signal_led(true); - cmd = 'G'; - ret = OK; val = 0; - break; - case 'F': - togl = !togl; - signal_led(togl); - { - auto *f = (fw_frame *) data; - if(f->seq == 0) { - system_otaflash_init(); - } - uint16_t ack = 0; - ret = system_otaflash_chunk(f->data, ntohs(f->len), ntohs(f->seq), ntohl(f->hash), &ack); - val = htons(ack); - } - cmd = 'F'; - break; - case 'C': - signal_led(false); - { - auto *f = (fw_check *) data; - ret = system_otaflash_verify_and_switch(ntohl(f->len), ntohl(f->hash)); - } - cmd = 'C'; + cmd = 'G'; break; default: printf("[websocket_callback]:\n%.*s\n", (int) data_len, (char *) data); - printf("Unknown command %c\n", data[0]); - ret = ERROR; + printf("Unknown command\n"); + val = 0; break; } - LOCK_TCPIP_CORE(); - websocket_write(pcb, response, 4, WS_BIN_MODE); - UNLOCK_TCPIP_CORE(); + response[2] = (uint8_t) val; + response[1] = val >> 8; + response[0] = cmd; - if(ret == OK) { - if(cmd == 'R' || cmd == 'C') { // Restart - printf("rebooting now"); - vTaskDelay(1000 / portTICK_PERIOD_MS); - vPortEnterCritical(); - sdk_system_restart(); - } else if(cmd == 'X') { // Clear Config - vTaskDelay(1000 / portTICK_PERIOD_MS); - system_clear_config(); - } - } + websocket_write(pcb, response, 3, WS_BIN_MODE); } /** @@ -328,10 +262,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(); diff --git a/firmware/webdir/404.html b/firmware/webdir/404.html deleted file mode 100644 index ebea9c6..0000000 --- a/firmware/webdir/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/wifi.cpp b/firmware/wifi.cpp index 729e71a..65b114b 100644 --- a/firmware/wifi.cpp +++ b/firmware/wifi.cpp @@ -3,7 +3,6 @@ // #include "wifi.h" -#include "log.h" #include #include @@ -37,7 +36,7 @@ SemaphoreHandle_t wifi_available_semaphore = nullptr; char *wifi_ap_ip_addr = nullptr; sysparam_get_string("wifi_ap_ip_addr", &wifi_ap_ip_addr); if(!wifi_ap_ip_addr) { - syslog("dns: no ip address\n"); + printf("dns: no ip address\n"); vTaskDelete(nullptr); } ip4_addr_t server_addr; @@ -195,7 +194,7 @@ extern "C" void wifi_task(void *pvParameters) { /* If the ssid and password are not valid then disable the AP interface. */ if(!wifi_ap_ssid || strlen(wifi_ap_ssid) < 1 || strlen(wifi_ap_ssid) >= 32 || !wifi_ap_password || strlen(wifi_ap_password) < 8 || strlen(wifi_ap_password) >= 64) { - syslog("len err\n"); + printf("len err\n"); wifi_ap_enable = 0; } } diff --git a/modules/rtos b/modules/rtos index 7faa16b..503e66a 160000 --- a/modules/rtos +++ b/modules/rtos @@ -1 +1 @@ -Subproject commit 7faa16b07ce0d606f9525a316990da5b58e61314 +Subproject commit 503e66a500419e8863998b7ea784c5e26a7a5f7c diff --git a/pcb/.gitignore b/pcb/.gitignore index 5efb808..5d83bb6 100644 --- a/pcb/.gitignore +++ b/pcb/.gitignore @@ -31,8 +31,6 @@ fp-info-cache *.wrl *.step -*-backups/ +*-bak gen/ pcb.zip - -report.txt \ No newline at end of file diff --git a/webapp/.gitignore b/webapp/.gitignore deleted file mode 100644 index dd60b59..0000000 --- a/webapp/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules/ -src/gen/ -package-lock.json \ No newline at end of file