diff --git a/firmware/fiatlux.c b/firmware/fiatlux.c index 9e3efeb..7e89970 100644 --- a/firmware/fiatlux.c +++ b/firmware/fiatlux.c @@ -11,6 +11,8 @@ #include #include +#include "rboot-api.h" + void user_init(void) { uart_set_baud(0, 115200); @@ -27,4 +29,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 #include +#include -const int signal_led_pin = 2; +extern "C" { +#include +} -const int cs0 = 15; -const int gpio4 = 4; -const int gpio5 = 5; +struct apa10xx_pixel_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; +}; + +static ws2812_pixel_t next_colour(int i) { + ws2812_pixel_t colour = {{0, 0, 0, 0}}; + colour.red = 0; + colour.green = 0; + colour.blue = 0; + colour.white = 8; + + return colour; +} + +static apa10xx_pixel_t next_color(int i) { + apa10xx_pixel_t colour; + colour.global.mod = 8; + colour.r = 16; + colour.g = 16; + colour.b = 16; + + return colour; +} + +namespace fiatlux { + + struct hal_error_t { + constexpr hal_error_t() = default; + + hal_error_t(const char *) {} + + hal_error_t(const char *, hal_error_t *cause) {} + }; + + constexpr hal_error_t empty_error; + + enum class hal_module_t { + NONE, SIGNAL, RELAIS, SPI_DIMMER, WS28X, APA10X + }; + + namespace ports { + hal_module_t spi = hal_module_t::NONE; + hal_module_t uart = hal_module_t::NONE; + hal_module_t gpio2 = hal_module_t::NONE; + hal_module_t gpio4 = hal_module_t::NONE; + hal_module_t gpio5 = hal_module_t::NONE; + hal_module_t gpio15 = hal_module_t::NONE; + } + + namespace signal { + void write_data(bool data) { + gpio_write(2, !data); + } + + void setup() { + gpio_enable(2, GPIO_OUTPUT); + } + } + + namespace relais { + void write_data(bool a, bool b) { + gpio_write(4, a); + gpio_write(5, b); + } + + void write_data(uint8_t data[2]) { + write_data((bool) data[0], (bool) data[1]); + } + + void setup() { + gpio_enable(4, GPIO_OUTPUT); + gpio_enable(5, GPIO_OUTPUT); + } + } + + namespace spi_dimmer { + constexpr int cs0 = 15; + + void write_data(uint16_t data[6]) { + for (int i = 0; i < 6; ++i) { + int dac_val = (data[i] << 2) & 0x3FFC; + + spi_transfer_8(1, ~(0x00)); + gpio_write(cs0, true); + gpio_write(cs0, false); + spi_transfer_8(1, ~(0x01 << i)); + gpio_write(cs0, true); + gpio_write(cs0, false); + + spi_transfer_16(1, dac_val); + + spi_transfer_8(1, ~(0x00)); + gpio_write(cs0, true); + gpio_write(cs0, false); + spi_transfer_8(1, ~(0x01 << i)); + gpio_write(cs0, true); + gpio_write(cs0, false); + } + } + + void setup() { + gpio_enable(cs0, GPIO_OUTPUT); + spi_init(1, SPI_MODE0, SPI_FREQ_DIV_1M, 1, SPI_BIG_ENDIAN, 1); + } + } + + namespace ws28x { + void write_data(ws2812_pixel_t *data) { + ws2812_i2s_update(data, PIXEL_RGBW); + } + + void setup(size_t len) { + ws2812_i2s_init(len, PIXEL_RGBW); + } + } + + namespace apa10x { + void write_data(apa10xx_pixel_t *data, size_t len) { + spi_transfer_32(1, 0x00000000); + for (size_t i = 0; i < len; i++) + spi_transfer_32(1, *(uint32_t *) &data[i]); + //spi_transfer_32(1, *(uint32_t *) &data[len - 1]); // dunno maybe this helps + //spi_transfer_32(1, *(uint32_t *) &data[len - 1]); // dunno maybe this helps + spi_transfer_32(1, 0xFFFFFFFF); + spi_transfer_32(1, 0xFFFFFFFF); + } + + void setup() { + spi_init(1, SPI_MODE0, SPI_FREQ_DIV_1M, 1, SPI_LITTLE_ENDIAN, false); + } + } + + hal_error_t write_channel(uint8_t *data, size_t count, size_t stride, hal_module_t mod) { + if(mod == hal_module_t::SIGNAL) { + if(count != 1) + return "unsupported value for count"; + if(stride != 1) + return "unsupported value for stride"; + signal::write_data(data[0]); + } else if(mod == hal_module_t::RELAIS) { + if(count != 2) + return "unsupported value for count"; + if(stride != 1) + return "unsupported value for stride"; + relais::write_data(data); + } else if(mod == hal_module_t::SPI_DIMMER) { + if(count != 6) + return "unsupported value for count"; + if(stride != 2) + return "unsupported value for stride"; + spi_dimmer::write_data((uint16_t *) data); + } else if(mod == hal_module_t::WS28X) { + if(stride != 4) + return "unsupported value for stride"; + ws28x::write_data((ws2812_pixel_t *) data); + } else if(mod == hal_module_t::APA10X) { + if(stride != 4) + return "unsupported value for stride"; + apa10x::write_data((apa10xx_pixel_t *) data, count); + } else { + return "unsupported module"; + } + return empty_error; + } + + hal_error_t setup_channel(size_t count, size_t stride, hal_module_t mod) { + /*if(mod == hal_module_t::SIGNAL) { + if(count != 1) + return "unsupported value for count"; + if(stride != 1) + return "unsupported value for stride"; + signal::write_data(data[0]); + } else if(mod == hal_module_t::RELAIS) { + if(count != 2) + return "unsupported value for count"; + if(stride != 1) + return "unsupported value for stride"; + relais::write_data(data); + } else if(mod == hal_module_t::SPI_DIMMER) { + if(count != 6) + return "unsupported value for count"; + if(stride != 2) + return "unsupported value for stride"; + spi_dimmer::write_data((uint16_t *) data); + } else if(mod == hal_module_t::WS28X) { + if(stride != 4) + return "unsupported value for stride"; + ws28x::write_data((ws2812_pixel_t *) data, count); + } else if(mod == hal_module_t::APA10X) { + if(stride != 4) + return "unsupported value for stride"; + apa10x::write_data((apa10xx_pixel_t *) data, count); + } else { + return "unsupported module"; + }*/ + return empty_error; + } + +} + +//ws2812_pixel_t **pixels_ptr; extern "C" void signal_led(bool state) { + fiatlux::signal::write_data(state); +} + +extern "C" void white_led(bool state) { gpio_write(signal_led_pin, !state); } -extern "C" void lux_task(void *pvParameters) { - gpio_enable(signal_led_pin, GPIO_OUTPUT); - gpio_enable(cs0, GPIO_OUTPUT); - gpio_enable(gpio4, GPIO_OUTPUT); - gpio_enable(gpio5, GPIO_OUTPUT); - spi_init(1, SPI_MODE0, SPI_FREQ_DIV_1M, 1, SPI_BIG_ENDIAN, 1); +/* This task uses the high level GPIO API (esp_gpio.h) to blink an LED. + * + */ +extern "C" [[noreturn]] void lux_task(void *pvParameters) { - vTaskDelete(nullptr); + int32_t lux_ws2812_number = 40; + auto ret = sysparam_get_int32("lux_ws2812_number", &lux_ws2812_number); + if(ret != SYSPARAM_OK) + lux_ws2812_number = 40; + + int32_t lux_apa10xx_number = 40; + ret = sysparam_get_int32("lux_apa10xx_number", &lux_apa10xx_number); + if(ret != SYSPARAM_OK) + lux_apa10xx_number = 40; + + ws2812_pixel_t pixels[lux_ws2812_number]; + ws2812_i2s_init(lux_ws2812_number, PIXEL_RGBW); + memset(pixels, 0, sizeof(ws2812_pixel_t) * lux_ws2812_number); + + apa10xx_pixel_t leds[lux_apa10xx_number]; + + //lux_apa102c_number + + //gpio_enable(9, GPIO_INPUT); + //gpio_enable(10, GPIO_INPUT); + + //fiatlux::spi_dimmer::setup(); + + fiatlux::signal::setup(); + fiatlux::relais::setup(); + + fiatlux::apa10x::setup(); + + while (true) { + /*for (int j = 0; j < 64; j++) { + for (int i = 0; i < 8; i++) + spi_dac(i, 64 * j); + //printf("> %d\n", 64*j); + vTaskDelay(100 / portTICK_PERIOD_MS); + }*/ + /*gpio_write(gpio4, 1); + vTaskDelay(200 / portTICK_PERIOD_MS); + gpio_write(gpio4, 0); + for (int i = 0; i < 8; i++) + spi_dac(i, 0); + + gpio_write(gpio5, 1); + vTaskDelay(200 / portTICK_PERIOD_MS); + gpio_write(gpio5, 0);*/ + fiatlux::signal::write_data(false); + for (int c = 8; c >= 0; c--) { + + for (auto &pixel: pixels) { + pixel = next_colour(c); + } + for (auto &led: leds) { + led = next_color(c); + } + ws2812_i2s_update(pixels, PIXEL_RGBW); + fiatlux::write_channel((uint8_t *) &leds[0], lux_apa10xx_number, 4, fiatlux::hal_module_t::APA10X); + vTaskDelay(200 / portTICK_PERIOD_MS); + } + fiatlux::relais::write_data(true, false); + vTaskDelay(200 / portTICK_PERIOD_MS); + fiatlux::relais::write_data(false, true); + vTaskDelay(200 / portTICK_PERIOD_MS); + fiatlux::relais::write_data(false, false); + fiatlux::signal::write_data(true); + vTaskDelay(200 / portTICK_PERIOD_MS); + + } } \ No newline at end of file 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..0e3c7fd 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(); @@ -245,9 +259,16 @@ void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, ret = ERROR; val = 0; + int8_t en = 0; 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; @@ -270,6 +291,18 @@ void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, ret = OK; val = 0; break; + case 'd': // Disable LED + signal_led(false); + cmd = 'G'; + ret = OK; + val = 1; + break; + case 'e': // Enable LED + signal_led(true); + cmd = 'G'; + ret = OK; + val = 0; + break; case 'F': togl = !togl; signal_led(togl); @@ -292,6 +325,46 @@ 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); + + /*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 +400,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..41d3897 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

@@ -180,6 +301,10 @@ toggle signal led +
@@ -220,7 +345,7 @@ sbox = document.getElementById('status_box'); sbox.className = "label " + cls; sbox.innerHTML = text; - console.info(text); + //console.info(text); } function startPolling() { @@ -325,11 +450,58 @@ wsWrite('D'); } + function leds() { + if (document.getElementById('white-switch').checked) + wsWrite('e'); + else + wsWrite('d'); + } + window.onload = function () { wsOpen(); 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 +530,8 @@ var firmware_file; function load_firmware(evt) { + //console.log("load_firmware", evt); + var file = evt.target.files[0]; if (!file) { return; @@ -395,11 +569,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 +593,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/webdir/index.htmll b/firmware/webdir/index.htmll new file mode 100644 index 0000000..6599b06 --- /dev/null +++ b/firmware/webdir/index.htmll @@ -0,0 +1 @@ + fiatlux v0.2

System

Firmware Update

Restart

Reset Config

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

System

Chip ID N/A
Hostname N/A
Firmware Version N/A
Flash ID N/A
Flash size N/A KiB
Free heap N/A bytes
Uptime N/A s

Network current connection

Mode N/A
Station SSID N/A
Station IP N/A
Station MAC N/A
AP SSID N/A
AP IP N/A
AP MAC N/A

Power

Input 5V12V
Output 11.2V

I/O

\ No newline at end of file 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