#include #include #include #include extern "C" { #include "ws2812_i2s.h" } #define LEDS_CNT 40 enum LEDMode { IDLE, OFF, WHITE, 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: led_t leds[LEDS_CNT]; Timer animationTimer; void animate() { /*if (i % 50 == 0) WDT.alive();*/ 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: leds[i].r = std::max(sin(i * 2*PI/LEDS_CNT - millis() / 1000.0)/2 * 255, 0.0); leds[i].g = std::max(sin(i * 2*PI/LEDS_CNT + millis() / 500.0)/2 * 255, 0.0); leds[i].b = std::max(sin(i * 2*PI/LEDS_CNT + millis() / 420.0)/2 * 255, 0.0); break; case LEDMode::TEST: leds[i].r = std::min(std::max((sin(i * 2*PI/LEDS_CNT - millis() / 1000.0)/2 + 0.2) * 255, 0.0), 255.0); leds[i].g = std::min(std::max((sin(i * 2*PI/LEDS_CNT + millis() / 500.0)/2 + 0.2) * 255, 0.0), 255.0); leds[i].b = std::min(std::max((sin(i * 2*PI/LEDS_CNT + millis() / 420.0)/2 + 0.2) * 255, 0.0), 255.0); break; case LEDMode::BRIGHT: leds[i].r = std::min(std::max((sin(i * 2*PI/LEDS_CNT - millis() / 1000.0)/4 + 0.5) * 255, 0.0), 255.0); leds[i].g = std::min(std::max((sin(i * 2*PI/LEDS_CNT + millis() / 500.0)/4 + 0.5) * 255, 0.0), 255.0); leds[i].b = std::min(std::max((sin(i * 2*PI/LEDS_CNT + millis() / 420.0)/4 + 0.5) * 255, 0.0), 255.0); break; case LEDMode::OFF: leds[i].r = leds[i].g = leds[i].b = 0; break; case LEDMode::WHITE: leds[i].r = leds[i].g = leds[i].b = 255; break; case LEDMode::STROBE: leds[i].r = leds[i].g = leds[i].b = (frameCounter % 2) ? 255 : 0; break; } } ws2812_push((uint8_t*) leds, sizeof(leds)); } FlaschenTaschenHandler ft; public: int crateWidth = 5; int crateHeight = 4; 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; // 5x4 /* if (y % 2 == 1) { k = (y+1)*crateWidth - x - 1; } else { k = y*crateWidth + x; } */ if (x % 2 == 0) { k = x*5 + y; } else { k = (x + 1)*5 - y - 1; } 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(); node.registerEndpoint("leds", new LEDEndpoint()); }