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/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..0842356 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -2,11 +2,11 @@ PROGRAM=fiatlux EXTRA_CFLAGS=-O3 -Ibuild/gen -DLWIP_NETIF_HOSTNAME=1 -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/lux.cpp b/firmware/lux.cpp index 8b775c4..d5d8e3c 100644 --- a/firmware/lux.cpp +++ b/firmware/lux.cpp @@ -9,24 +9,296 @@ #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; +} + +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 = 8; + auto ret = sysparam_get_int32("lux_ws2812_number", &lux_ws2812_number); + if(ret != SYSPARAM_OK) + lux_ws2812_number = 8; + + 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/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/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/modules/rtos b/modules/rtos index 7faa16b..a821731 160000 --- a/modules/rtos +++ b/modules/rtos @@ -1 +1 @@ -Subproject commit 7faa16b07ce0d606f9525a316990da5b58e61314 +Subproject commit a8217311e0d8547127b69b7c4ead62ed3aa87b79 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