/* * Stairs lighting * Copyright 2017 (c) Mark van Renswoude */ #include #include #include #include #include "config.h" #include "protocol.h" #include "components\PCA9685.h" //#include "modes\adc.h" #include "modes\alternate.h" #include "modes\custom.h" #include "modes\slide.h" #include "modes\static.h" #include "stairs.h" PCA9685* pwmDriver; Stairs* stairs; WiFiUDP udpServer; uint8_t currentModeIdentifier; IMode* currentMode; // Forward declarations void checkRequest(); void handleRequest(uint8_t* packet); IMode* createMode(uint8_t identifier); void setCurrentMode(IMode *mode, uint8_t identifier); void handleCurrentMode(); void setup() { pwmDriver = new PCA9685(); pwmDriver->setAddress(PWMDriverAddress, PinSDA, PinSCL); pwmDriver->setPWMFrequency(PWMDriverPWMFrequency); stairs = new Stairs(); stairs->init(pwmDriver); WiFi.hostname(WiFiHostname); WiFi.begin(WiFiSSID, WiFiPassword); // Run a little startup test sequence stairs->setAll(IStairs::Off); stairs->set(0, IStairs::On); delay(300); for (int step = 1; step < StepCount; step++) { stairs->set(step - 1, IStairs::Off); stairs->set(step, IStairs::On); delay(300); } stairs->set(StepCount - 1, IStairs::Off); // Pulsate the bottom step while WiFi is connecting uint16_t brightness = 0; uint16_t speed = 16; while (WiFi.status() != WL_CONNECTED) { brightness += speed; if (brightness <= 0 || brightness >= 1024) speed = -speed; stairs->set(0, brightness); delay(16); } setCurrentMode(new StaticMode(), Mode::Static); // Start the UDP server udpServer.begin(UDPPort); } uint32_t currentTime; // Note: the packet size must at least be able to accomodate the // command with the largest parameter list, there is no overflow // checking in the mode classes! // // At the time of writing, CustomMode is the largest: // Set Mode (1) + Custom (1) + StepCount * Word (2) // = 30 for 14 steps uint8_t packet[50]; uint8_t* packetRef; void loop() { currentTime = millis(); checkRequest(); handleCurrentMode(); } void checkRequest() { int packetSize = udpServer.parsePacket(); if (packetSize) { memset(packet, 0, sizeof(packet)); int length = udpServer.read(packet, 50); if (length && packet[0]) { packetRef = packet; handleRequest(packetRef); } } } void handleRequest(uint8_t* packet) { // Every request will result in a reply, either containing the // requested data or a copy of the input parameters for verification. // // Apparantly this also makes the ESP8266 more stable, as reports // have been made that UDP communication can stall if no replies are sent. udpServer.beginPacket(udpServer.remoteIP(), udpServer.remotePort()); udpServer.write(Command::Reply); switch (*packet) { case Command::Ping: udpServer.write(Command::Ping); break; case Command::GetMode: udpServer.write(Command::GetMode); udpServer.write(currentModeIdentifier); break; case Command::SetMode: { packet++; uint8_t newIdentifier = *packet; packet++; IMode* newMode = createMode(newIdentifier); if (newMode != NULL) { newMode->read(packet); udpServer.write(Command::SetMode); udpServer.write(newIdentifier); newMode->write(&udpServer); setCurrentMode(newMode, newIdentifier); } else { udpServer.write(Command::Error); udpServer.write(Command::SetMode); } break; } default: udpServer.write(Command::Error); udpServer.write(*packet); break; } udpServer.endPacket(); } IMode* createMode(uint8_t identifier) { if (identifier == currentModeIdentifier) return currentMode; switch (identifier) { case Mode::Static: return new StaticMode(); //case Mode::Custom: return new CustomMode(); case Mode::Alternate: return new AlternateMode(); //case Mode::Slide: return new SlideMode(); //case Mode::ADC: return new ADCInputMode(); } return NULL; } void setCurrentMode(IMode* mode, uint8_t identifier) { currentModeIdentifier = identifier; currentMode = mode; currentMode->init(stairs, currentTime); } void handleCurrentMode() { currentMode->tick(stairs, currentTime); }