From f19441985e0a6234e6ff0fda3b32944eb7805739 Mon Sep 17 00:00:00 2001 From: Piotr Dobrowolski Date: Sun, 7 Apr 2019 14:39:04 +0200 Subject: [PATCH] WIP: accept flaschentaschen protocol --- ledcontroller/app/application.cpp | 167 ++++++++++++++++++++++++------ 1 file changed, 138 insertions(+), 29 deletions(-) diff --git a/ledcontroller/app/application.cpp b/ledcontroller/app/application.cpp index a906d1a..29c676f 100644 --- a/ledcontroller/app/application.cpp +++ b/ledcontroller/app/application.cpp @@ -8,7 +8,7 @@ extern "C" { #include "ws2812_i2s.h" } -#define LEDS_CNT 150 +#define LEDS_CNT 20 enum LEDMode { IDLE, @@ -17,17 +17,35 @@ enum LEDMode { STROBE, BRIGHT, TEST, + REMOTE, +}; + +typedef struct __attribute__((packed)) { + uint8_t r; + uint8_t g; + uint8_t b; +} led_t; + +class LEDEndpoint; + +class FlaschenTaschenHandler { +public: + void init(LEDEndpoint* _ep) { + ep = _ep; + socket = new UdpConnection(UdpConnectionDataDelegate(&FlaschenTaschenHandler::onReceive, this)); + socket->listen(1337); + } + +protected: + LEDEndpoint* ep; + UdpConnection* socket; + + void onReceive(UdpConnection& connection, char* data, int size, IPAddress remoteIP, uint16_t remotePort); }; class LEDEndpoint : public Endpoint { private: - struct __attribute__((packed)) { - uint8_t g; - uint8_t r; - uint8_t b; - } leds[LEDS_CNT]; - - enum LEDMode currentMode = LEDMode::IDLE; + led_t leds[LEDS_CNT]; Timer animationTimer; void animate() { @@ -36,6 +54,11 @@ private: static int frameCounter = 0; frameCounter++; + if (overrideTime && millis() - overrideTime > 5000) { + overrideTime = 0; + currentMode = LEDMode::IDLE; + } + for(int i = 0; i < LEDS_CNT; i++) { switch(currentMode) { case LEDMode::IDLE: @@ -68,37 +91,123 @@ private: ws2812_push((uint8_t*) leds, sizeof(leds)); } + FlaschenTaschenHandler ft; + public: - LEDEndpoint() : Endpoint("leds", { - {"mode", "enum", true, "idle,off,white,strobe,bright,test", "Current LED mode"}, - }) { - animationTimer.initializeMs(50, TimerDelegate(&LEDEndpoint::animate, this)).start(); - ws2812_init(); - } + int crateWidth = 5; + int crateHeight = 4; - EndpointResult onValue(String property, String value) { - if (property != "mode") { - return 400; + enum LEDMode currentMode = LEDMode::IDLE; + long overrideTime = 0; + + LEDEndpoint(); + + EndpointResult onValue(String property, String value); + + void set(uint8_t x, uint8_t y, uint8_t r, uint8_t g, uint8_t b) { + int k; + + if (y % 2 == 1) { + k = (y+1)*crateWidth - x - 1; + } else { + k = y*crateWidth + x; } - if (value == "idle") currentMode = LEDMode::IDLE; - else if (value == "off") currentMode = LEDMode::OFF; - else if (value == "white") currentMode = LEDMode::WHITE; - else if (value == "strobe") currentMode = LEDMode::STROBE; - else if (value == "bright") currentMode = LEDMode::BRIGHT; - else if (value == "test") currentMode = LEDMode::TEST; - else { - return 400; - } - - notify("mode", value); - return 200; + leds[k].r = r; + leds[k].g = g; + leds[k].b = b; } }; +LEDEndpoint::LEDEndpoint() : Endpoint("leds", { + {"mode", "enum", true, "idle,off,white,strobe,bright,test", "Current LED mode"}, + }) { + animationTimer.initializeMs(50, TimerDelegate(&LEDEndpoint::animate, this)).start(); + ft.init(this); + ws2812_init(); +} + +EndpointResult LEDEndpoint::onValue(String property, String value) { + if (property != "mode") { + return 400; + } + + if (value == "idle") currentMode = LEDMode::IDLE; + else if (value == "off") currentMode = LEDMode::OFF; + else if (value == "white") currentMode = LEDMode::WHITE; + else if (value == "strobe") currentMode = LEDMode::STROBE; + else if (value == "bright") currentMode = LEDMode::BRIGHT; + else if (value == "test") currentMode = LEDMode::TEST; + else { + return 400; + } + + notify("mode", value); + return 200; +} SpejsNode node("ledcontroller"); +#define debug(s) node.notify("$debug", s) + +void FlaschenTaschenHandler::onReceive(UdpConnection& connection, char* data, int size, IPAddress remoteIP, uint16_t remotePort) { + ep->currentMode = LEDMode::REMOTE; + ep->overrideTime = millis(); + + int bufW, bufH; + + int bufleft = size; + int linecnt = 0; + char* linestart = data; + char* lineend; + while (linecnt < 3 && bufleft > 0) { + lineend = (char*) memchr(linestart, '\n', bufleft); + String line = String(linestart, lineend-linestart); + if (linecnt == 0 && !line.equals("P6")) { + // invalid frame + ep->currentMode = LEDMode::WHITE; + return; + } else if (line.startsWith("#")) { + // comment + } else { + if (linecnt == 1) { + // buffer size + bufW = line.substring(0, line.indexOf(" ")).toInt(); + bufH = line.substring(line.indexOf(" ")).toInt(); + } else if (linecnt == 2) { + if (!line.equals("255")) { + // this should be 255 ;_; + ep->currentMode = LEDMode::STROBE; + return; + } + } + linecnt++; + } + + bufleft -= lineend-linestart+1; + linestart = lineend+1; + } + + + if (bufW*bufH*3 > bufleft) { + ep->currentMode = LEDMode::STROBE; + return; + } + + for (int x = 0; x < bufW; x++) { + for (int y = 0; y < bufH; y++) { + int b = (y*bufW + x) * 3; + ep->set(x, y, linestart[b], linestart[b+1], linestart[b+2]); + } + } + + //debug(String(bufW)); + //debug(String(bufH)); + //debug(String()); + //debug(String(bufleft)); + //node.notify("$debug", String(linestart, lineend-linestart)); +} + void init() { node.init();