From e6afaf6451a02c96850649bc179983b9193b08ac Mon Sep 17 00:00:00 2001 From: jedi Date: Tue, 6 Jul 2021 22:49:45 +0200 Subject: [PATCH 01/12] stash --- firmware/mqtt.cpp | 155 ++++++++++++++++++++++++++++++++++++++++++++++ firmware/mqtt.h | 3 + 2 files changed, 158 insertions(+) diff --git a/firmware/mqtt.cpp b/firmware/mqtt.cpp index 9622645..5cbeaac 100644 --- a/firmware/mqtt.cpp +++ b/firmware/mqtt.cpp @@ -3,3 +3,158 @@ // #include "mqtt.h" + +#include +#include + +#include +#include + +extern "C" { + +#include +#include + +} + +#include + + +/* You can use http://test.mosquitto.org/ to test mqtt_client instead + * of setting up your own MQTT server */ +#define MQTT_HOST ("172.16.1.53") +#define MQTT_PORT 1883 + +#define MQTT_USER NULL +#define MQTT_PASS NULL + +QueueHandle_t publish_queue; +#define PUB_MSG_LEN 16 + +extern "C" void beat_task(void *pvParameters) { + TickType_t xLastWakeTime = xTaskGetTickCount(); + char msg[PUB_MSG_LEN]; + int count = 0; + + while (1) { + vTaskDelayUntil(&xLastWakeTime, 10000 / portTICK_PERIOD_MS); + printf("beat\r\n"); + snprintf(msg, PUB_MSG_LEN, "Beat %d\r\n", count++); + if(xQueueSend(publish_queue, (void *) msg, 0) == pdFALSE) { + printf("Publish queue overflow.\r\n"); + } + } +} + +static void topic_received(mqtt_message_data_t *md) { + int i; + mqtt_message_t *message = md->message; + printf("Received: "); + for (i = 0; i < md->topic->lenstring.len; ++i) + printf("%c", md->topic->lenstring.data[i]); + + printf(" = "); + for (i = 0; i < (int) message->payloadlen; ++i) + printf("%c", ((char *) (message->payload))[i]); + + printf("\r\n"); +} + +static const char *get_my_id(void) { + // Use MAC address for Station as unique ID + static char my_id[13]; + static bool my_id_done = false; + int8_t i; + uint8_t x; + if(my_id_done) + return my_id; + if(!sdk_wifi_get_macaddr(STATION_IF, (uint8_t *) my_id)) + return NULL; + for (i = 5; i >= 0; --i) { + x = my_id[i] & 0x0F; + if(x > 9) x += 7; + my_id[i * 2 + 1] = x + '0'; + x = my_id[i] >> 4; + if(x > 9) x += 7; + my_id[i * 2] = x + '0'; + } + my_id[12] = '\0'; + my_id_done = true; + return my_id; +} + +extern "C" void mqtt_task(void *pvParameters) { + int ret = 0; + struct mqtt_network network; + mqtt_client_t client = mqtt_client_default; + char mqtt_client_id[20]; + uint8_t mqtt_buf[100]; + uint8_t mqtt_readbuf[100]; + mqtt_packet_connect_data_t data = mqtt_packet_connect_data_initializer; + + mqtt_network_new(&network); + memset(mqtt_client_id, 0, sizeof(mqtt_client_id)); + strcpy(mqtt_client_id, "ESP-"); + strcat(mqtt_client_id, get_my_id()); + + while (1) { + printf("%s: started\n\r", __func__); + printf("%s: (Re)connecting to MQTT server %s ... ", __func__, + MQTT_HOST); + ret = mqtt_network_connect(&network, MQTT_HOST, MQTT_PORT); + if(ret) { + printf("error: %d\n\r", ret); + taskYIELD(); + continue; + } + printf("done\n\r"); + mqtt_client_new(&client, &network, 5000, mqtt_buf, 100, + mqtt_readbuf, 100); + + data.willFlag = 0; + data.MQTTVersion = 3; + data.clientID.cstring = mqtt_client_id; + data.username.cstring = MQTT_USER; + data.password.cstring = MQTT_PASS; + data.keepAliveInterval = 10; + data.cleansession = 0; + printf("Send MQTT connect ... "); + ret = mqtt_connect(&client, &data); + if(ret) { + printf("error: %d\n\r", ret); + mqtt_network_disconnect(&network); + taskYIELD(); + continue; + } + printf("done\r\n"); + mqtt_subscribe(&client, "/esptopic", MQTT_QOS1, topic_received); + xQueueReset(publish_queue); + + while (1) { + + char msg[PUB_MSG_LEN - 1] = "\0"; + while (xQueueReceive(publish_queue, (void *) msg, 0) == + pdTRUE) { + printf("got message to publish\r\n"); + mqtt_message_t message; + message.payload = msg; + message.payloadlen = PUB_MSG_LEN; + message.dup = 0; + message.qos = MQTT_QOS1; + message.retained = 0; + ret = mqtt_publish(&client, "/beat", &message); + if(ret != MQTT_SUCCESS) { + printf("error while publishing message: %d\n", ret); + break; + } + } + + ret = mqtt_yield(&client, 1000); + if(ret == MQTT_DISCONNECTED) + break; + } + printf("Connection dropped, request restart\n\r"); + mqtt_network_disconnect(&network); + taskYIELD(); + } +} \ No newline at end of file diff --git a/firmware/mqtt.h b/firmware/mqtt.h index a5e03b6..b8d8a8e 100644 --- a/firmware/mqtt.h +++ b/firmware/mqtt.h @@ -9,6 +9,9 @@ extern "C" { #endif +void mqtt_task(void *pvParameters); +void beat_task(void *pvParameters); + #ifdef __cplusplus } #endif From c0228cdf4954704106ceb61bab55593c4b8d6eeb Mon Sep 17 00:00:00 2001 From: 7m9 Date: Thu, 9 Sep 2021 02:35:15 +0200 Subject: [PATCH 02/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 03/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 + @@ -58,6 +59,87 @@ +
+

Wifi Settings

+
+
+

AP Mode

+
+
+
+ + +
+
+ + +
+
+ + +
+
+ AP IP + N/A +
+
+ AP MAC + N/A +
+
+ + +
+
+
+
+
+

Station Mode current connection

+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ Sation IP + N/A +
+
+ Station MAC + N/A +
+
+ + +
+
+
+

Status

@@ -190,6 +272,18 @@ return pos; }; + DataView.prototype.setInt8Vec = function (pos, vec) { + for (var i = 0; i < vec.length; i++) { + this.setInt8(pos++, vec[i]); + } + return pos; + }; + + function colorStringToVec(hex) { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : null; + } + var ws; var retries; var series = new TimeSeries(); @@ -394,6 +488,55 @@ }) } } + + var sta_toggle = document.getElementById("sta_toggle"); + var sta_ssid = document.getElementById("sta_ssid"); + var sta_pw = document.getElementById("sta_pw"); + + function sta_update() { + var en = sta_toggle.checked; + + const ssid = sta_ssid.value; + const password = sta_pw.value; + + const buffer = new ArrayBuffer(ssid.length + password.length + 4); + const view1 = new DataView(buffer); + var tx_len = 0; + view1.setChar(tx_len++, 'S'); + view1.setChar(tx_len++, (en ? "E" : "D")); + tx_len = view1.setString(tx_len, ssid); + tx_len = view1.setString(tx_len, password); + wsWrite(buffer); + } + + var ap_toggle = document.getElementById("ap_toggle"); + var ap_ssid = document.getElementById("ap_ssid"); + var ap_pw = document.getElementById("ap_pw"); + + function ap_update() { + var en = ap_toggle.checked; + + const ssid = ap_ssid.value; + const password = ap_pw.value; + + const buffer = new ArrayBuffer(ssid.length + password.length + 4 + 8); + const view1 = new DataView(buffer); + var tx_len = 0; + view1.setChar(tx_len++, 'A'); + view1.setChar(tx_len++, (en ? "E" : "D")); + tx_len = view1.setString(tx_len, ssid); + tx_len = view1.setString(tx_len, password); + tx_len = view1.setInt8Vec(tx_len, [192, 168, 111, 1]); + tx_len = view1.setInt8Vec(tx_len, [255, 255, 255, 0]); + wsWrite(buffer); + } + + function update_progress(progressBar, progress) { + var iP = Math.floor(progress); + var dBar = document.getElementById("progress_bar_" + progressBar); + dBar.innerText = iP + "%"; + dBar.style.width = progress + "%"; + } diff --git a/firmware/web.cpp b/firmware/web.cpp index 6176a43..dc43e08 100644 --- a/firmware/web.cpp +++ b/firmware/web.cpp @@ -184,6 +184,18 @@ void websocket_task(void *pvParameter) { } + vTaskDelayMs(250); + { + uint8_t response[3]; + uint16_t val; + val = sdk_system_adc_read(); + response[2] = (uint8_t) val; + response[1] = val >> 8; + response[0] = 'V'; + LOCK_TCPIP_CORE(); + websocket_write(pcb, response, 3, WS_BIN_MODE); + UNLOCK_TCPIP_CORE(); + } vTaskDelayMs(500); } @@ -221,7 +233,18 @@ void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, bool togl = 0; + int8_t en = 0; + /*uint8_t ap_disable_if_sta = 0; + uint8_t ssid_hidden = 0; + uint8_t dns_enable = 0; + uint8_t mdns_enable = 0;*/ + switch (data[0]) { + case 'V': // ADC + /* This should be done on a separate thread in 'real' applications */ + val = sdk_system_adc_read(); + cmd = 'V'; + break; case 'R': // Restart cmd = 'R'; break; @@ -258,6 +281,39 @@ void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, } cmd = 'C'; break; + case 'S': { + if(data[1] == 'E') + en = 1; + char *ssid = &data[2]; + size_t ssid_len = strlen(ssid); + char *password = &data[3 + ssid_len]; + size_t password_len = strlen(password); + (void) password_len; + + sysparam_set_int8("wifi_sta_enable", en); + sysparam_set_string("wifi_sta_ssid", ssid); + sysparam_set_string("wifi_sta_password", password); + } + cmd = 'S'; + break; + case 'A': { + if(data[1] == 'E') + en = 1; + char *ssid = &data[2]; + size_t ssid_len = strlen(ssid); + char *password = &data[3 + ssid_len]; + size_t password_len = strlen(password); + (void) password_len; + + sysparam_set_int8("wifi_ap_enable", en); + sysparam_set_string("wifi_ap_ssid", ssid); + sysparam_set_string("wifi_ap_password", password); + + //sysparam_set_int8("wifi_ap_dns", dns_enable); + //sysparam_set_int8("wifi_ap_mdns", mdns_enable); + } + cmd = 'A'; + break; default: printf("[websocket_callback]:\n%.*s\n", (int) data_len, (char *) data); printf("Unknown command %c\n", data[0]); diff --git a/firmware/wifi.cpp b/firmware/wifi.cpp index 65b114b..a958a95 100644 --- a/firmware/wifi.cpp +++ b/firmware/wifi.cpp @@ -210,7 +210,7 @@ extern "C" void wifi_task(void *pvParameters) { if(wifi_sta_enable) { printf("try STA Mode: %s %s\n", wifi_sta_ssid, wifi_sta_password); - sdk_station_config config; + sdk_station_config config{}; strcpy((char *) config.ssid, wifi_sta_ssid); strcpy((char *) config.password, wifi_sta_password); config.bssid_set = 0; @@ -230,7 +230,7 @@ extern "C" void wifi_task(void *pvParameters) { wifi_sta_netmask && strlen(wifi_sta_netmask) > 4 && wifi_sta_gateway && strlen(wifi_sta_gateway) > 4) { sdk_wifi_station_dhcpc_stop(); - ip_info info; + ip_info info{}; memset(&info, 0x0, sizeof(info)); info.ip.addr = ipaddr_addr(wifi_sta_ip_addr); info.netmask.addr = ipaddr_addr(wifi_sta_netmask); @@ -305,13 +305,13 @@ extern "C" void wifi_task(void *pvParameters) { } if(strlen(wifi_ap_ip_addr) >= 7 && strlen(wifi_ap_netmask) >= 7) { - ip_info ap_ip; + ip_info ap_ip{}; ap_ip.ip.addr = ipaddr_addr(wifi_ap_ip_addr); ap_ip.netmask.addr = ipaddr_addr(wifi_ap_netmask); IP4_ADDR(&ap_ip.gw, 0, 0, 0, 0); sdk_wifi_set_ip_info(1, &ap_ip); - sdk_softap_config ap_config; + sdk_softap_config ap_config{}; strcpy((char *) ap_config.ssid, wifi_ap_ssid); ap_config.ssid_len = strlen(wifi_ap_ssid); strcpy((char *) ap_config.password, wifi_ap_password); From 224fc57582268e91b488ec69ebd5219af648421e Mon Sep 17 00:00:00 2001 From: Eleon Date: Sun, 3 Oct 2021 02:02:26 +0200 Subject: [PATCH 07/12] Adding flash_docker function --- Makefile | 5 +++++ docker/firmware/Dockerfile | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8fafbe1..e298e7a 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,11 @@ 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 all" diff --git a/docker/firmware/Dockerfile b/docker/firmware/Dockerfile index 582fe2f..825fa4f 100644 --- a/docker/firmware/Dockerfile +++ b/docker/firmware/Dockerfile @@ -8,6 +8,6 @@ RUN cd app/modules/sdk; export CT_EXPERIMENTAL=y; export CT_ALLOW_BUILD_AS_ROOT= USER 0 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 +USER 0 WORKDIR /app -ENV PATH=/app/modules/sdk/xtensa-lx106-elf/bin:$PATH \ No newline at end of file +ENV PATH=/app/modules/sdk/xtensa-lx106-elf/bin:$PATH From 7a627ee1f13930adf12207de47eb59d126ed0579 Mon Sep 17 00:00:00 2001 From: jedi Date: Thu, 18 Nov 2021 04:03:53 +0100 Subject: [PATCH 08/12] add cli argument for address to otaflash.py --- firmware/otaflash.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/otaflash.py b/firmware/otaflash.py index c7f51a7..2c52133 100755 --- a/firmware/otaflash.py +++ b/firmware/otaflash.py @@ -8,6 +8,7 @@ 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() @@ -25,7 +26,7 @@ with open(args.binfile, "rb") as f: try: ws = websocket.WebSocket() print("send {}".format(args.binfile)) - ws.connect("ws://172.16.0.1") + ws.connect("ws://" + args.address) i = 0 bytes = f.read() rolling = zlib.crc32(bytes) From 5466bceb0ed309868eaa894a2c20e0a9ea1ed26c Mon Sep 17 00:00:00 2001 From: jedi Date: Thu, 18 Nov 2021 07:37:20 +0100 Subject: [PATCH 09/12] implement syslog via websocket with 1k buffer --- firmware/log.cpp | 49 ++++++++++++++++++++++++++++++++++++++ firmware/log.h | 28 ++++++++++++++++++++++ firmware/system.c | 7 +++--- firmware/web.cpp | 48 +++++++++++++++++++++++++++---------- firmware/webdir/index.html | 20 +++++++++++++++- firmware/wifi.cpp | 5 ++-- 6 files changed, 139 insertions(+), 18 deletions(-) create mode 100644 firmware/log.cpp create mode 100644 firmware/log.h diff --git a/firmware/log.cpp b/firmware/log.cpp new file mode 100644 index 0000000..8b268d9 --- /dev/null +++ b/firmware/log.cpp @@ -0,0 +1,49 @@ +// +// 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 new file mode 100644 index 0000000..0cde491 --- /dev/null +++ b/firmware/log.h @@ -0,0 +1,28 @@ +// +// 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/system.c b/firmware/system.c index b853792..d190606 100644 --- a/firmware/system.c +++ b/firmware/system.c @@ -4,6 +4,7 @@ #include "system.h" #include "crc32.h" +#include "log.h" #include #include @@ -39,7 +40,7 @@ void system_init_config() { 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"); + syslog("Warning: WiFi config, sysparam not initialized\n"); num_sectors = 0x2000 / sdk_flashchip.sector_size; if(sysparam_create_area(base_addr, num_sectors, true) == SYSPARAM_OK) { sysparam_init(base_addr, 0); @@ -106,13 +107,13 @@ enum return_code system_otaflash_verify_and_switch(uint32_t len, uint32_t hash) 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"); + syslog("OTA failed to verify firmware\r\n"); return CHECKSUM_MISMATCH; } vPortEnterCritical(); if(!rboot_set_current_rom(otaflash_context.slot)) { - printf("OTA Update failed to set new rboot slot\r\n"); + syslog("OTA Update failed to set new rboot slot\r\n"); vPortExitCritical(); return RBOOT_SWITCH_FAILED; } diff --git a/firmware/web.cpp b/firmware/web.cpp index 255149f..ed55e2d 100644 --- a/firmware/web.cpp +++ b/firmware/web.cpp @@ -6,6 +6,7 @@ #include "system.h" #include "lux.h" #include "wifi.h" +#include "log.h" #include #include @@ -36,16 +37,34 @@ 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) { - printf("Connection closed, deleting task\n"); + syslog("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) { - has_changed.global = false; timeval tv{}; gettimeofday(&tv, nullptr); size_t uptime = xTaskGetTickCount() * portTICK_PERIOD_MS / 1000; @@ -57,7 +76,7 @@ void websocket_task(void *pvParameter) { sysparam_get_string("hostname", &hostname); /* Generate response in JSON format */ - char response[160]; + char response[192]; size_t len = snprintf(response, sizeof(response), "{\"walltime\" : \"%d\"," "\"uptime\" : \"%d\"," @@ -71,22 +90,22 @@ 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 - printf("buffer too small 1"); - vTaskDelayMs(2000); + syslog("buffer too small 0\n"); + vTaskDelayMs(1000); } //Connection Info if(has_changed.connection) { - has_changed.connection = false; 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)); - char response[160]; + char response[192]; size_t len = snprintf(response, sizeof(response), "{\"connage\" : \"%d\"," "\"clientip\" : \"" IPSTR "\"" @@ -94,10 +113,11 @@ void websocket_task(void *pvParameter) { 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 - printf("buffer too small 1"); - vTaskDelayMs(2000); + syslog("buffer too small 1\n"); + vTaskDelayMs(1000); } if(has_changed.wifi) { @@ -152,10 +172,10 @@ void websocket_task(void *pvParameter) { websocket_write(pcb, (unsigned char *) response, len, WS_TEXT_MODE); UNLOCK_TCPIP_CORE(); } else - printf("buffer too small 2"); + syslog("buffer too small 2\n"); } - vTaskDelayMs(2000); + vTaskDelayMs(1000); if(opmode == STATION_MODE || opmode == STATIONAP_MODE) { uint8_t hwaddr[6]; @@ -179,7 +199,7 @@ void websocket_task(void *pvParameter) { websocket_write(pcb, (unsigned char *) response, len, WS_TEXT_MODE); UNLOCK_TCPIP_CORE(); } else - printf("buffer too small 3"); + syslog("buffer too small 3\n"); } } @@ -187,6 +207,8 @@ void websocket_task(void *pvParameter) { vTaskDelayMs(500); } + syslog_detach(); + vTaskDelete(nullptr); } @@ -235,12 +257,14 @@ void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, ret = OK; break; case 'D': // Disable LED + syslog("G\n"); signal_led(false); cmd = 'G'; ret = OK; val = 1; break; case 'E': // Enable LED + syslog("E\n"); signal_led(true); cmd = 'G'; ret = OK; diff --git a/firmware/webdir/index.html b/firmware/webdir/index.html index 0a7bf04..317dc10 100644 --- a/firmware/webdir/index.html +++ b/firmware/webdir/index.html @@ -63,6 +63,16 @@
+
+
+

Syslog

+
+
+
+

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