diff --git a/.build.yml b/.build.yml index 18ed3f0..ef0452a 100644 --- a/.build.yml +++ b/.build.yml @@ -25,14 +25,8 @@ steps: commands: - apt update - apt install -y make zip - - cd pcb - - kibot -d gen -c fiatlux.kiplot.yaml -s update_xml,run_drc -i - - kibot -d gen -c fiatlux.kiplot.yaml -s update_xml,run_erc -i - - kibot -d gen -c fiatlux.kiplot.yaml -s run_drc,run_erc print_sch - - kibot -d gen -c fiatlux.kiplot.yaml -s all print_front gerbers - - ls -lA - - cd - - - make pcb -j$(nproc) + - make pcb -j$(nproc) BOARD=fiatlux + - make pcb -j$(nproc) BOARD=fiatlux_cc48 - name: case image: debian:sid @@ -67,7 +61,8 @@ steps: files: - firmware/firmware/fiatlux.bin - firmware/otaflash.py - - pcb/pcb.zip + - pcb/fiatlux_pcb.zip + - pcb/fiatlux_cc48_pcb.zip checksum: - sha512 - md5 diff --git a/firmware/log.cpp b/firmware/log.cpp index 70bf940..7cecc8a 100644 --- a/firmware/log.cpp +++ b/firmware/log.cpp @@ -7,12 +7,12 @@ #include constexpr unsigned syslog_buffer_size = 1024; -char syslog_buf[syslog_buffer_size]; +char syslog_buf[syslog_buffer_size + 1]; volatile unsigned head = 0; volatile unsigned streams = 0; extern "C" void syslog(const char *msg) { - printf("syslog> %s", msg); + //printf("syslog> %s", msg); while (char c = *msg++) { syslog_buf[head++ % syslog_buffer_size] = c; } diff --git a/firmware/lux.cpp b/firmware/lux.cpp index 8b775c4..0c757f1 100644 --- a/firmware/lux.cpp +++ b/firmware/lux.cpp @@ -9,24 +9,308 @@ #include #include +#include -const int signal_led_pin = 2; - -const int cs0 = 15; -const int gpio4 = 4; -const int gpio5 = 5; - -extern "C" void signal_led(bool state) { - gpio_write(signal_led_pin, !state); +extern "C" { +#include } -extern "C" void lux_task(void *pvParameters) { +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; +}; - 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); +static ws2812_pixel_t next_colour(int i) { + ws2812_pixel_t colour = {{0, 0, 0, 0}}; + if(i == 8) { + colour.white = 32; + } else { + colour.red = i & 1 ? 32 : 0; + colour.green = i & 2 ? 32 : 0; + colour.blue = i & 4 ? 32 : 0; + } - vTaskDelete(nullptr); + return colour; +} + +static apa10xx_pixel_t next_color(int i) { + apa10xx_pixel_t colour; + colour.global.mod = 8; + colour.r = i & 1 ? 32 : 0; + colour.g = i & 2 ? 32 : 0; + colour.b = i & 4 ? 32 : 0; + + return colour; +} + +rgba_t top_color; +rgba_t bottom_color; + +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); +} + + +/* This task uses the high level GPIO API (esp_gpio.h) to blink an LED. + * + */ +extern "C" [[noreturn]] void lux_task(void *pvParameters) { + + int32_t lux_ws2812_number = 240; + auto ret = sysparam_get_int32("lux_ws2812_number", &lux_ws2812_number); + if(ret != SYSPARAM_OK) + lux_ws2812_number = 240; + + 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); + } + + for (int i = 0; i < 120; i++) + pixels[i] = {{top_color.r, top_color.g, top_color.b, top_color.a}}; + + for (int i = 120; i < 240; i++) + pixels[i] = {{bottom_color.r, bottom_color.g, bottom_color.b, bottom_color.a}}; + + + 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/lux.h b/firmware/lux.h index caf4a88..db5acb2 100644 --- a/firmware/lux.h +++ b/firmware/lux.h @@ -13,6 +13,16 @@ void lux_task(void *pvParameters); void signal_led(bool state); +typedef struct { + char r; + char g; + char b; + char a; +} rgba_t; + +extern rgba_t top_color; +extern rgba_t bottom_color; + #ifdef __cplusplus } #endif diff --git a/firmware/web.cpp b/firmware/web.cpp index 94790a4..9ce4d79 100644 --- a/firmware/web.cpp +++ b/firmware/web.cpp @@ -30,6 +30,8 @@ using namespace fiatlux; #define vTaskDelayMs(ms) vTaskDelay((ms) / portTICK_PERIOD_MS) +const char hex_lookup[] = "0123456789ABCDEF\0\0"; + uint16_t voltage_val; struct { @@ -230,6 +232,8 @@ void websocket_task(void *pvParameter) { vTaskDelete(nullptr); } +char str[] = "L00000000\n"; + /** * This function is called when websocket frame is received. * @@ -254,6 +258,47 @@ void websocket_cb(struct tcp_pcb *pcb, char *data, u16_t data_len, // Clear Config res.cmd = (messages::id) 'X'; res.ret = OK; + } else if(data[0] == 'B') { + // Disable LED + uint32_t val = data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24); + bottom_color.r = data[7]; + bottom_color.g = data[6]; + bottom_color.b = data[5]; + str[0] = 'B'; + str[2] = hex_lookup[val & 0xF]; + str[1] = hex_lookup[(val >> 4) & 0xF]; + str[4] = hex_lookup[(val >> 8) & 0xF]; + str[3] = hex_lookup[(val >> 12) & 0xF]; + str[6] = hex_lookup[(val >> 16) & 0xF]; + str[5] = hex_lookup[(val >> 20) & 0xF]; + str[8] = hex_lookup[(val >> 24) & 0xF]; + str[7] = hex_lookup[(val >> 28) & 0xF]; + // + syslog(str); + //signal_led(false); + res.cmd = (messages::id) 'B'; + res.ret = OK; + res.val = 1; + } else if(data[0] == 'T') { + // Disable LED + uint32_t val = data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24); + top_color.r = data[7]; + top_color.g = data[6]; + top_color.b = data[5]; + str[0] = 'T'; + str[2] = hex_lookup[val & 0xF]; + str[1] = hex_lookup[(val >> 4) & 0xF]; + str[4] = hex_lookup[(val >> 8) & 0xF]; + str[3] = hex_lookup[(val >> 12) & 0xF]; + str[6] = hex_lookup[(val >> 16) & 0xF]; + str[5] = hex_lookup[(val >> 20) & 0xF]; + str[8] = hex_lookup[(val >> 24) & 0xF]; + str[7] = hex_lookup[(val >> 28) & 0xF]; + syslog(str); + //signal_led(false); + res.cmd = (messages::id) 'T'; + res.ret = OK; + res.val = 1; } else if(data[0] == 'D') { // Disable LED syslog("G\n"); diff --git a/firmware/webdir/index.html b/firmware/webdir/index.html index 914923a..3f4bc10 100644 --- a/firmware/webdir/index.html +++ b/firmware/webdir/index.html @@ -259,9 +259,17 @@ @@ -348,7 +356,7 @@ document.getElementById("unused_values").innerHTML = JSON.stringify(unused_values); } else { var dv = new DataView(evt.data); - console.log("[0]",dv.getUint8(0)); + console.log("[0]", dv.getUint8(0)); var cmd = String.fromCharCode(dv.getUint8(0)); var val = dv.getUint16(1); @@ -413,13 +421,31 @@ ws.send(data); } - function gpio() { - if (document.getElementById('led-switch').checked) + function gpio(val) { + if (val) wsWrite('E'); else wsWrite('D'); } + function colorTop(val) { + var header = new ArrayBuffer(8); + var headerview = new DataView(header); + headerview.setChar(0, 'T'); + headerview.setInt32(4, parseInt(val.substring(1), 16)); + console.log(buf2hex(header)); + wsWrite(header); + } + + function colorBottom(val) { + var header = new ArrayBuffer(8); + var headerview = new DataView(header); + headerview.setChar(0, 'B'); + headerview.setInt32(4, parseInt(val.substring(1), 16)); + console.log(buf2hex(header)); + wsWrite(header); + } + window.onload = function () { wsOpen(); startPolling();