websocket goes brrrrrrrrrrrrrrr

This commit is contained in:
j3d1 2021-07-24 00:40:45 +02:00
parent 09452ef7ab
commit 1b8cb3680e
8 changed files with 285 additions and 3 deletions

View file

@ -57,6 +57,7 @@ steps:
base_url: https://git.neulandlabor.de/ base_url: https://git.neulandlabor.de/
files: files:
- firmware/firmware/fiatlux.bin - firmware/firmware/fiatlux.bin
- firmware/otaflash.py
- pcb/pcb.zip - pcb/pcb.zip
checksum: checksum:
- sha512 - sha512

View file

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module classpath="External" external.linked.project.id="firmware" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="CompDB" type="CPP_MODULE" version="4" />
<module version="4"> <module version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="Python" name="Python facet"> <facet type="Python" name="Python facet">

View file

@ -11,6 +11,8 @@
#include <espressif/esp_common.h> #include <espressif/esp_common.h>
#include <esp/uart.h> #include <esp/uart.h>
#include "rboot-api.h"
void user_init(void) void user_init(void)
{ {
uart_set_baud(0, 115200); uart_set_baud(0, 115200);
@ -27,4 +29,15 @@ void user_init(void)
xTaskCreate(&httpd_task, "httpd_task", 1024, NULL, 2, NULL); xTaskCreate(&httpd_task, "httpd_task", 1024, NULL, 2, NULL);
xTaskCreate(&lux_task, "lux_task", 512, NULL, 1, 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");
} }

View file

@ -16,6 +16,8 @@
<label for="bmenub" class="burger pseudo button">&#9776;</label> <label for="bmenub" class="burger pseudo button">&#9776;</label>
<div class="menu"> <div class="menu">
<a href="/#" class="button icon-picture">Dashboard</a> <a href="/#" class="button icon-picture">Dashboard</a>
<a href="/#io" class="button icon-puzzle">I/O</a>
<a href="/#wifi" class="button icon-puzzle">Wifi Settings</a>
<a href="/#ota" class="button icon-picture">System</a> <a href="/#ota" class="button icon-picture">System</a>
</div> </div>
</nav> </nav>
@ -58,6 +60,125 @@
</article> </article>
</section> </section>
<section id="io">
<h2>I/O</h2>
<article class="card">
<header>
<h3>Protocols</h3>
</header>
<div class="table">
<div class="row">
<label>MQTT</label>
<span><input type="checkbox" class="plain"/></span>
</div>
<div class="row">
<span><input type="reset" class="button"/></span>
<span><input type="submit" value="Save"></span>
</div>
</div>
</article>
<article class="card">
<header>
<h3>Station Mode <span class="label success">current connection</span></h3>
</header>
<div class="table">
<div class="row">
<label>WS2812 via I2S</label>
<span><input type="checkbox" class="plain"/></span>
<span><input type="color"/></span>
</div>
<div class="row">
<label>APA102C via SPI</label>
<span><input type="checkbox" class="plain"/></span>
<span><input type="color"/></span>
</div>
<div class="row">
<label>6 Channel SPI Dimmer</label>
<span><input type="checkbox" class="plain"/></span>
<span><input type="color"/></span>
</div>
<div class="row">
<label>Binary Output on GPIO4</label>
<span><input type="checkbox" class="plain"/></span>
<span><button class="toggle button">Toggle</button></span>
</div>
<div class="row">
<label>Binary Output on GPIO5</label>
<span><input type="checkbox" class="plain"/></span>
<span><button class="toggle button">Toggle</button></span>
</div>
<div class="row">
<span><input type="reset" class="button"/></span>
<span><input type="submit" value="Save"></span>
</div>
</div>
</article>
</section>
<section id="wifi">
<h2>Wifi Settings</h2>
<article class="card">
<header>
<h3>AP Mode</h3>
</header>
<div class="table">
<div class="row">
<label>Enable</label>
<span><input id="ap_toggle" type="checkbox" class="plain"/></span>
</div>
<div class="row">
<label>SSID</label>
<span><input id="ap_ssid" type="text" placeholder="SSID"/></span>
</div>
<div class="row">
<label>Password</label>
<span><input id="ap_pw" type="password" placeholder="Password"/></span>
</div>
<div class="row">
<span>AP IP</span>
<span><span class="postfill_apip">N/A</span></span>
</div>
<div class="row">
<span>AP MAC</span>
<span><span class="postfill_apmac">N/A</span></span>
</div>
<div class="row">
<span><input type="reset" class="button"/></span>
<span><input onclick="ap_update();" type="submit" value="Save"></span>
</div>
</div>
</article>
<article class="card">
<header>
<h3>Station Mode <span class="label success">current connection</span></h3>
</header>
<div class="table">
<div class="row">
<label>Eanable</label>
<span><input id="sta_toggle" type="checkbox" class="plain"/></span>
</div>
<div class="row">
<label>SSID</label>
<span><input id="sta_ssid" type="text" placeholder="SSID"/></span>
</div>
<div class="row">
<label>Password</label>
<span><input id="sta_pw" type="password" placeholder="Password"/></span>
</div>
<div class="row">
<span>Sation IP</span>
<span><span class="postfill_staip">N/A</span></span>
</div>
<div class="row">
<span>Station MAC</span>
<span><span class="postfill_stamac">N/A</span></span>
</div>
<div class="row">
<span><input type="reset" class="button"/></span>
<span><input onclick="sta_update();" type="submit" value="Save"></span>
</div>
</div>
</article>
</section>
<section id="dashboard"> <section id="dashboard">
<h2>Status</h2> <h2>Status</h2>
<div class="flex"> <div class="flex">
@ -295,6 +416,46 @@
startPolling(); 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 makeCRCTable = function () {
var c; var c;
var crcTable = []; var crcTable = [];
@ -323,6 +484,8 @@
var firmware_file; var firmware_file;
function load_firmware(evt) { function load_firmware(evt) {
console.log("load_firmware", evt);
var file = evt.target.files[0]; var file = evt.target.files[0];
if (!file) { if (!file) {
return; return;
@ -360,11 +523,14 @@
reject(i); reject(i);
}, 2000); }, 2000);
wsWrite(frame.buffer); 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) { function transmit_firmware_final(buf, hash) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
console.log("final: ", buf.byteLength, hash.toString(16));
var frame = new ArrayBuffer(12); var frame = new ArrayBuffer(12);
var headerview = new DataView(frame); var headerview = new DataView(frame);
headerview.setChar(0, 'C'); headerview.setChar(0, 'C');
@ -381,8 +547,11 @@
} }
function transmit_firmware(evt) { function transmit_firmware(evt) {
console.log("transmit_firmware begin"); console.log("transmit_firmware", evt);
if (firmware_file) { if (firmware_file) {
console.log("len", firmware_file.byteLength);
//console.log(crc32(firmware_file));
(async () => { (async () => {
const ash = crc32(firmware_file); const ash = crc32(firmware_file);
for (var i = 0; i * chunk_size < firmware_file.byteLength; i++) { for (var i = 0; i * chunk_size < firmware_file.byteLength; i++) {

View file

@ -18,6 +18,7 @@ with open(args.binfile, "rb") as f:
rolling = 0 rolling = 0
total = 0 total = 0
while True: while True:
print(i)
bytes = f.read(512) bytes = f.read(512)
rolling = zlib.crc32(bytes, rolling) rolling = zlib.crc32(bytes, rolling)
total += len(bytes) total += len(bytes)
@ -28,6 +29,7 @@ with open(args.binfile, "rb") as f:
msg += bytes msg += bytes
ws.send(msg) ws.send(msg)
reply = ws.recv() reply = ws.recv()
print(reply)
time.sleep(0.05) time.sleep(0.05)
i += 1 i += 1
if len(bytes) != 512: if len(bytes) != 512:

View file

@ -23,6 +23,7 @@
void system_clear_config() { void system_clear_config() {
vPortEnterCritical(); vPortEnterCritical();
uint32_t num_sectors = 0x2000 / sdk_flashchip.sector_size; 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; uint32_t start = 0x00100000;
for (uint32_t i = 0; i < num_sectors; i++) { for (uint32_t i = 0; i < num_sectors; i++) {
spiflash_erase_sector(start + i * sdk_flashchip.sector_size); spiflash_erase_sector(start + i * sdk_flashchip.sector_size);
@ -41,6 +42,7 @@ void system_init_config() {
if(sysparam_get_info(&base_addr, &num_sectors) != SYSPARAM_OK) { if(sysparam_get_info(&base_addr, &num_sectors) != SYSPARAM_OK) {
printf("Warning: WiFi config, sysparam not initialized\n"); printf("Warning: WiFi config, sysparam not initialized\n");
num_sectors = 0x2000 / sdk_flashchip.sector_size; 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) { if(sysparam_create_area(base_addr, num_sectors, true) == SYSPARAM_OK) {
sysparam_init(base_addr, 0); sysparam_init(base_addr, 0);
} }
@ -48,7 +50,7 @@ void system_init_config() {
} }
} }
#define MAX_IMAGE_SIZE 0x100000 #define MAX_IMAGE_SIZE 0x100000 /*1MB images max at the moment */
struct { struct {
rboot_write_status status; rboot_write_status status;
@ -66,10 +68,14 @@ void system_otaflash_init() {
otaflash_context.status = rboot_write_init(otaflash_context.base); otaflash_context.status = rboot_write_init(otaflash_context.base);
otaflash_context.head = otaflash_context.base; otaflash_context.head = otaflash_context.base;
otaflash_context.seq = 0; otaflash_context.seq = 0;
//printf("slot: %u, base: %x, sector: %u\n", otaflash_context.slot, otaflash_context.base,
// otaflash_context.status.start_sector);
} }
int system_otaflash_chunk(uint8_t *data, uint16_t len, uint16_t seq, uint32_t hash) { int system_otaflash_chunk(uint8_t *data, uint16_t len, uint16_t seq, uint32_t hash) {
uint32_t local_hash = crc32(data, len); 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(hash == local_hash && otaflash_context.seq == seq) {
if(otaflash_context.head % SECTOR_SIZE == 0) { if(otaflash_context.head % SECTOR_SIZE == 0) {
sdk_spi_flash_erase_sector(otaflash_context.head / SECTOR_SIZE); sdk_spi_flash_erase_sector(otaflash_context.head / SECTOR_SIZE);
@ -85,6 +91,7 @@ int system_otaflash_chunk(uint8_t *data, uint16_t len, uint16_t seq, uint32_t ha
otaflash_context.seq++; otaflash_context.seq++;
return 0x88; return 0x88;
} else { } else {
//printf("nak: %04x = %04x, %04x = %04x\n", hash, local_hash, seq, otaflash_context.seq);
return 0xff; return 0xff;
} }
@ -108,7 +115,7 @@ int system_otaflash_verify_and_switch(uint32_t len, uint32_t hash) {
vPortEnterCritical(); vPortEnterCritical();
if(!rboot_set_current_rom(otaflash_context.slot)) { if(!rboot_set_current_rom(otaflash_context.slot)) {
printf("OTA failed to set new rboot slot\r\n"); printf("OTA TFTP failed to set new rboot slot\r\n");
} }
sdk_system_restart(); sdk_system_restart();
vPortExitCritical(); // | should not be reached vPortExitCritical(); // | should not be reached

View file

@ -184,7 +184,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); vTaskDelayMs(500);
//printf("9: %d\n",gpio_read(9));
//printf("10: %d\n",gpio_read(10));
} }
vTaskDelete(nullptr); vTaskDelete(nullptr);
@ -219,9 +233,19 @@ void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len,
uint16_t val = 0; uint16_t val = 0;
char cmd = '0'; char cmd = '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;*/
bool togl = 0; bool togl = 0;
switch (data[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 case 'R': // Restart
cmd = 'R'; cmd = 'R';
break; break;
@ -258,6 +282,41 @@ void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len,
} }
cmd = 'C'; cmd = 'C';
break; 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_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: default:
printf("[websocket_callback]:\n%.*s\n", (int) data_len, (char *) data); printf("[websocket_callback]:\n%.*s\n", (int) data_len, (char *) data);
printf("Unknown command %c\n", data[0]); printf("Unknown command %c\n", data[0]);
@ -294,11 +353,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) { extern "C" void httpd_task(void *pvParameters) {
(void) pvParameters; (void) pvParameters;
while (!uxSemaphoreGetCount(wifi_available_semaphore)) while (!uxSemaphoreGetCount(wifi_available_semaphore))
vTaskDelay(500 / portTICK_PERIOD_MS); 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); websocket_register_callbacks((tWsOpenHandler) websocket_open_cb, (tWsHandler) websocket_cb);
httpd_init(); httpd_init();

View file

@ -33,6 +33,8 @@ char *wifi_ap_password = nullptr;
SemaphoreHandle_t wifi_available_semaphore = nullptr; SemaphoreHandle_t wifi_available_semaphore = nullptr;
[[noreturn]] static void dns_task(void *pvParameters) { [[noreturn]] static void dns_task(void *pvParameters) {
printf("run dns task\n");
char *wifi_ap_ip_addr = nullptr; char *wifi_ap_ip_addr = nullptr;
sysparam_get_string("wifi_ap_ip_addr", &wifi_ap_ip_addr); sysparam_get_string("wifi_ap_ip_addr", &wifi_ap_ip_addr);
if(!wifi_ap_ip_addr) { if(!wifi_ap_ip_addr) {
@ -270,6 +272,7 @@ extern "C" void wifi_task(void *pvParameters) {
if(wifi_ap_channel < 1 || wifi_ap_channel > 14) { if(wifi_ap_channel < 1 || wifi_ap_channel > 14) {
wifi_ap_channel = 6; wifi_ap_channel = 6;
} }
wifi_ap_channel = 3;
int8_t wifi_ap_authmode = AUTH_WPA_WPA2_PSK; int8_t wifi_ap_authmode = AUTH_WPA_WPA2_PSK;
sysparam_get_int8("wifi_ap_authmode", &wifi_ap_authmode); sysparam_get_int8("wifi_ap_authmode", &wifi_ap_authmode);
@ -283,6 +286,7 @@ extern "C" void wifi_task(void *pvParameters) {
if(wifi_ap_max_conn < 1 || wifi_ap_max_conn > 8) { if(wifi_ap_max_conn < 1 || wifi_ap_max_conn > 8) {
wifi_ap_max_conn = 3; wifi_ap_max_conn = 3;
} }
wifi_ap_max_conn = 8;
int32_t wifi_ap_beacon_interval = 100; int32_t wifi_ap_beacon_interval = 100;
sysparam_get_int32("wifi_ap_beacon_interval", &wifi_ap_beacon_interval); sysparam_get_int32("wifi_ap_beacon_interval", &wifi_ap_beacon_interval);
@ -356,5 +360,6 @@ extern "C" void wifi_task(void *pvParameters) {
xSemaphoreGive(wifi_available_semaphore); xSemaphoreGive(wifi_available_semaphore);
//monitor loop connection here //monitor loop connection here
printf("wifi task done\n");
vTaskDelete(nullptr); vTaskDelete(nullptr);
} }