2017-03-23 18:45:29 +00:00
|
|
|
/*
|
|
|
|
* Stairs lighting
|
|
|
|
* Copyright 2017 (c) Mark van Renswoude
|
|
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <Stream.h>
|
|
|
|
#include <ESP8266WiFi.h>
|
|
|
|
#include <WiFiUdp.h>
|
|
|
|
|
|
|
|
#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();
|
2017-03-24 20:40:56 +00:00
|
|
|
pwmDriver->setAddress(PWMDriverAddress, PinSDA, PinSCL);
|
2017-03-23 18:45:29 +00:00
|
|
|
pwmDriver->setPWMFrequency(PWMDriverPWMFrequency);
|
|
|
|
|
|
|
|
stairs = new Stairs();
|
|
|
|
stairs->init(pwmDriver);
|
|
|
|
|
2017-03-24 20:40:56 +00:00
|
|
|
WiFi.hostname(WiFiHostname);
|
2017-03-23 18:45:29 +00:00
|
|
|
WiFi.begin(WiFiSSID, WiFiPassword);
|
|
|
|
|
|
|
|
|
|
|
|
// Run a little startup test sequence
|
2017-03-24 22:04:58 +00:00
|
|
|
stairs->setAll(IStairs::Off);
|
|
|
|
stairs->set(0, IStairs::On);
|
2017-03-23 18:45:29 +00:00
|
|
|
delay(300);
|
|
|
|
|
|
|
|
for (int step = 1; step < StepCount; step++)
|
|
|
|
{
|
2017-03-24 22:04:58 +00:00
|
|
|
stairs->set(step - 1, IStairs::Off);
|
|
|
|
stairs->set(step, IStairs::On);
|
2017-03-23 18:45:29 +00:00
|
|
|
delay(300);
|
|
|
|
}
|
|
|
|
|
2017-03-24 22:04:58 +00:00
|
|
|
stairs->set(StepCount - 1, IStairs::Off);
|
2017-03-23 18:45:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
2017-03-24 22:04:58 +00:00
|
|
|
stairs->set(0, brightness);
|
2017-03-23 18:45:29 +00:00
|
|
|
delay(16);
|
|
|
|
}
|
|
|
|
|
|
|
|
setCurrentMode(new StaticMode(), Mode::Static);
|
|
|
|
|
|
|
|
|
|
|
|
// Start the UDP server
|
|
|
|
udpServer.begin(UDPPort);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t currentTime;
|
2017-03-24 22:04:58 +00:00
|
|
|
|
|
|
|
// 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];
|
2017-03-23 18:45:29 +00:00
|
|
|
uint8_t* packetRef;
|
|
|
|
|
|
|
|
void loop()
|
|
|
|
{
|
|
|
|
currentTime = millis();
|
|
|
|
|
|
|
|
checkRequest();
|
|
|
|
handleCurrentMode();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void checkRequest()
|
|
|
|
{
|
|
|
|
int packetSize = udpServer.parsePacket();
|
|
|
|
if (packetSize)
|
|
|
|
{
|
2017-03-24 22:04:58 +00:00
|
|
|
memset(packet, 0, sizeof(packet));
|
2017-03-23 18:45:29 +00:00
|
|
|
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)
|
|
|
|
{
|
2017-03-24 20:40:56 +00:00
|
|
|
case Command::Ping:
|
|
|
|
udpServer.write(Command::Ping);
|
2017-03-25 15:36:04 +00:00
|
|
|
udpServer.write(StepCount);
|
2017-03-24 20:40:56 +00:00
|
|
|
break;
|
|
|
|
|
2017-03-23 18:45:29 +00:00
|
|
|
case Command::GetMode:
|
2017-03-24 20:40:56 +00:00
|
|
|
udpServer.write(Command::GetMode);
|
2017-03-23 18:45:29 +00:00
|
|
|
udpServer.write(currentModeIdentifier);
|
2017-03-25 15:36:04 +00:00
|
|
|
currentMode->write(&udpServer);
|
2017-03-23 18:45:29 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::SetMode:
|
|
|
|
{
|
|
|
|
packet++;
|
|
|
|
uint8_t newIdentifier = *packet;
|
|
|
|
packet++;
|
|
|
|
|
|
|
|
IMode* newMode = createMode(newIdentifier);
|
|
|
|
|
|
|
|
if (newMode != NULL)
|
|
|
|
{
|
|
|
|
newMode->read(packet);
|
2017-03-24 20:40:56 +00:00
|
|
|
|
|
|
|
udpServer.write(Command::SetMode);
|
2017-03-24 22:04:58 +00:00
|
|
|
udpServer.write(newIdentifier);
|
2017-03-23 18:45:29 +00:00
|
|
|
newMode->write(&udpServer);
|
2017-03-24 20:40:56 +00:00
|
|
|
|
2017-03-23 18:45:29 +00:00
|
|
|
setCurrentMode(newMode, newIdentifier);
|
|
|
|
}
|
|
|
|
else
|
2017-03-24 20:40:56 +00:00
|
|
|
{
|
|
|
|
udpServer.write(Command::Error);
|
|
|
|
udpServer.write(Command::SetMode);
|
2017-03-25 15:36:04 +00:00
|
|
|
udpServer.write(newIdentifier);
|
2017-03-24 20:40:56 +00:00
|
|
|
}
|
2017-03-23 18:45:29 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2017-03-24 20:40:56 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
udpServer.write(Command::Error);
|
|
|
|
udpServer.write(*packet);
|
|
|
|
break;
|
2017-03-23 18:45:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
udpServer.endPacket();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
IMode* createMode(uint8_t identifier)
|
|
|
|
{
|
|
|
|
if (identifier == currentModeIdentifier)
|
|
|
|
return currentMode;
|
|
|
|
|
|
|
|
switch (identifier)
|
|
|
|
{
|
|
|
|
case Mode::Static: return new StaticMode();
|
2017-03-25 15:36:04 +00:00
|
|
|
case Mode::Custom: return new CustomMode();
|
2017-03-23 18:45:29 +00:00
|
|
|
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);
|
|
|
|
}
|