diff --git a/.build.yml b/.build.yml index 7ece57b..af5617d 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 @@ -64,6 +62,6 @@ steps: 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..0518768 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ + .PHONY: firmware flash firmware_docker case pcb all: firmware case pcb @@ -18,11 +19,6 @@ 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" diff --git a/firmware/Makefile b/firmware/Makefile index 976b533..e0a7ccb 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -1,12 +1,12 @@ PROGRAM=fiatlux -EXTRA_CFLAGS=-O3 -Ibuild/gen -DLWIP_NETIF_HOSTNAME=1 +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 extras/paho_mqtt_c +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 -FLASH_MODE = qio +FLASH_MODE = dio include ../modules/rtos/common.mk @@ -15,7 +15,7 @@ html: build/gen/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 @echo "Generating fsdata.." @mkdir -p $(dir $@) - @./mkwebfs.py --gzip --minify -o $@ $^ + @./mkwebfs.py --gzip -o $@ $^ test: unittest systest diff --git a/firmware/fiatlux.c b/firmware/fiatlux.c index 9e3efeb..f89dbba 100644 --- a/firmware/fiatlux.c +++ b/firmware/fiatlux.c @@ -11,8 +11,9 @@ #include #include -void user_init(void) -{ +#include "rboot-api.h" + +void user_init(void) { uart_set_baud(0, 115200); printf("SDK version: %s\n", sdk_system_get_sdk_version()); @@ -27,4 +28,15 @@ void user_init(void) xTaskCreate(&httpd_task, "httpd_task", 1024, NULL, 2, NULL); xTaskCreate(&lux_task, "lux_task", 512, NULL, 1, NULL); + + rboot_config conf = rboot_get_config(); + printf("\r\n\r\nOTA Basic demo.\r\nCurrently running on flash slot %d / %d.\r\n\r\n", + conf.current_rom, conf.count); + + printf("Image addresses in flash:\r\n"); + for (int i = 0; i < conf.count; i++) { + printf("%c%d: offset 0x%08x\r\n", i == conf.current_rom ? '*' : ' ', i, conf.roms[i]); + } + + printf("profit!\n"); } diff --git a/firmware/mkwebfs.py b/firmware/mkwebfs.py index e48548c..667af23 100755 --- a/firmware/mkwebfs.py +++ b/firmware/mkwebfs.py @@ -2,7 +2,6 @@ import os import gzip import argparse -import subprocess parser = argparse.ArgumentParser() parser.add_argument('-o', '--output', help='Output file name', default='stdout') @@ -10,9 +9,6 @@ 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) @@ -20,31 +16,6 @@ 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 @@ -70,28 +41,40 @@ for file in httpFiles: 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' + 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.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): @@ -120,8 +103,7 @@ for file in httpFiles: 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))) + .format(escFileFile, lastFileStruct, escFileData, escFileData, len(fnameBin), escFileData, len(fnameBin))) # TODO: The last value is 1 if args.header == True lastFileStruct = escFileFile diff --git a/firmware/system.c b/firmware/system.c index d190606..f12b19b 100644 --- a/firmware/system.c +++ b/firmware/system.c @@ -24,6 +24,7 @@ void system_clear_config() { vPortEnterCritical(); uint32_t num_sectors = 0x2000 / sdk_flashchip.sector_size; + //uint32_t start = sdk_flashchip.chip_size - num_sectors * 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); @@ -42,6 +43,7 @@ void system_init_config() { 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; + //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); } @@ -49,7 +51,7 @@ void system_init_config() { } } -#define MAX_IMAGE_SIZE 0x100000 +#define MAX_IMAGE_SIZE 0x100000 /*1MB images max at the moment */ struct { rboot_write_status status; @@ -67,10 +69,14 @@ void system_otaflash_init() { otaflash_context.status = rboot_write_init(otaflash_context.base); otaflash_context.head = otaflash_context.base; otaflash_context.seq = 0; + + //printf("slot: %u, base: %x, sector: %u\n", otaflash_context.slot, otaflash_context.base, + // otaflash_context.status.start_sector); } 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); + //printf("@%x seq: %u, len: %u, hash: %x =? %x\n", otaflash_context.head, seq, len, hash, local_hash); 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); diff --git a/firmware/web.cpp b/firmware/web.cpp index ed55e2d..474dec3 100644 --- a/firmware/web.cpp +++ b/firmware/web.cpp @@ -204,7 +204,21 @@ 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); + //printf("9: %d\n",gpio_read(9)); + //printf("10: %d\n",gpio_read(10)); } syslog_detach(); @@ -248,6 +262,12 @@ void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, bool togl = false; switch (data[0]) { + case 'V': // ADC + /* This should be done on a separate thread in 'real' applications */ + cmd = 'V'; + ret = OK; + val = sdk_system_adc_read(); + break; case 'R': // Restart cmd = 'R'; ret = OK; @@ -292,6 +312,48 @@ void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, } cmd = 'C'; break; + case 'S': { + int8_t en = 1; + 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': { + int8_t en = 1; + 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); + + /*uint8_t ap_disable_if_sta = 0; + uint8_t ssid_hidden = 0; + uint8_t dns_enable = 0; + uint8_t mdns_enable = 0;*/ + + //sysparam_set_int8("wifi_ap_disable_if_sta", ap_disable_if_sta); + //sysparam_set_int8("wifi_ap_ssid_hidden", ssid_hidden); + //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]); @@ -327,11 +389,36 @@ void websocket_open_cb(struct tcp_pcb *pcb, const char *uri) { } } +/*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.html"; +}*/ + extern "C" void httpd_task(void *pvParameters) { (void) pvParameters; while (!uxSemaphoreGetCount(wifi_available_semaphore)) vTaskDelay(500 / portTICK_PERIOD_MS); + /*tCGI pCGIs[] = { + {"/gpio", (tCGIHandler) gpio_cgi_handler}, + }; + + // register handlers and start the server + http_set_cgi_handlers(pCGIs, sizeof(pCGIs) / sizeof(pCGIs[0]));*/ websocket_register_callbacks((tWsOpenHandler) websocket_open_cb, (tWsHandler) websocket_cb); httpd_init(); diff --git a/firmware/webdir/index.html b/firmware/webdir/index.html index 317dc10..0b4bac1 100644 --- a/firmware/webdir/index.html +++ b/firmware/webdir/index.html @@ -17,6 +17,8 @@ @@ -75,6 +77,125 @@ +
+

I/O

+
+
+

Protocols

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

Station Mode current connection

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

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

@@ -220,7 +341,7 @@ sbox = document.getElementById('status_box'); sbox.className = "label " + cls; sbox.innerHTML = text; - console.info(text); + //console.info(text); } function startPolling() { @@ -330,6 +451,46 @@ startPolling(); } + 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); + 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); + wsWrite(buffer); + } + var makeCRCTable = function () { var c; var crcTable = []; @@ -358,6 +519,8 @@ var firmware_file; function load_firmware(evt) { + //console.log("load_firmware", evt); + var file = evt.target.files[0]; if (!file) { return; @@ -395,11 +558,14 @@ reject({frame_error: i}); }, 2000); wsWrite(frame.buffer); + //build packet: type, seq, len, hash, data + console.log(i, (end - begin), crc32(slice), (100 * end / buf.byteLength) + "%"); }); } function transmit_firmware_final(buf, hash) { return new Promise((resolve, reject) => { + console.log("final: ", buf.byteLength, hash.toString(16)); var frame = new ArrayBuffer(12); var headerview = new DataView(frame); headerview.setChar(0, 'C'); @@ -416,8 +582,11 @@ } function transmit_firmware(evt) { - console.log("transmit_firmware begin"); + console.log("transmit_firmware", evt); if (firmware_file) { + console.log("len", firmware_file.byteLength); + //console.log(crc32(firmware_file)); + (async () => { const ash = crc32(firmware_file); for (var i = 0; i * chunk_size < firmware_file.byteLength; i++) { diff --git a/firmware/wifi.cpp b/firmware/wifi.cpp index 729e71a..4501813 100644 --- a/firmware/wifi.cpp +++ b/firmware/wifi.cpp @@ -34,6 +34,8 @@ char *wifi_ap_password = nullptr; SemaphoreHandle_t wifi_available_semaphore = nullptr; [[noreturn]] static void dns_task(void *pvParameters) { + printf("run dns task\n"); + char *wifi_ap_ip_addr = nullptr; sysparam_get_string("wifi_ap_ip_addr", &wifi_ap_ip_addr); if(!wifi_ap_ip_addr) { @@ -271,6 +273,7 @@ extern "C" void wifi_task(void *pvParameters) { if(wifi_ap_channel < 1 || wifi_ap_channel > 14) { wifi_ap_channel = 6; } + wifi_ap_channel = 3; int8_t wifi_ap_authmode = AUTH_WPA_WPA2_PSK; sysparam_get_int8("wifi_ap_authmode", &wifi_ap_authmode); @@ -284,6 +287,7 @@ extern "C" void wifi_task(void *pvParameters) { if(wifi_ap_max_conn < 1 || wifi_ap_max_conn > 8) { wifi_ap_max_conn = 3; } + wifi_ap_max_conn = 8; int32_t wifi_ap_beacon_interval = 100; sysparam_get_int32("wifi_ap_beacon_interval", &wifi_ap_beacon_interval); @@ -357,5 +361,6 @@ extern "C" void wifi_task(void *pvParameters) { xSemaphoreGive(wifi_available_semaphore); //monitor loop connection here + printf("wifi task done\n"); vTaskDelete(nullptr); } \ No newline at end of file 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