Reintroduced PCA9685 and Stairs classes
Compiles, but lacks the tick implementation
This commit is contained in:
parent
0aca40c71e
commit
42647f0db7
@ -54,4 +54,8 @@ If you make any changes to the SCSS files, make sure to run ```gulp compileSass`
|
|||||||
To rebuild all the assets and compile or upload the source in one go, two tasks have been added to the gulpfile.js:
|
To rebuild all the assets and compile or upload the source in one go, two tasks have been added to the gulpfile.js:
|
||||||
|
|
||||||
1. ```gulp build``` first runs all the tasks run by a regular ```gulp```, then builds the source code using ```platformio run```
|
1. ```gulp build``` first runs all the tasks run by a regular ```gulp```, then builds the source code using ```platformio run```
|
||||||
1. ```gulp upload``` is similar, but executes ```platformio run -t upload``` to directly upload the newly compiled source to the ESP8266
|
1. ```gulp upload``` is similar, but executes ```platformio run -t upload``` to directly upload the newly compiled source to the ESP8266
|
||||||
|
|
||||||
|
### version.h
|
||||||
|
|
||||||
|
The version.h file is generated based on the current GitVersion, which means it changes if you build again right after committing, which causes a change that needs to be committed... [did you mean: recursion?](https://www.google.nl/search?q=recursion) The best way I found to deal with this is commit your changes, build, then [amend the commit](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History) with the updated version.h before pushing the changes. This ensures the version.h is in sync when cloning the repository.
|
@ -4,11 +4,11 @@
|
|||||||
const uint8_t VersionMajor = 2;
|
const uint8_t VersionMajor = 2;
|
||||||
const uint8_t VersionMinor = 0;
|
const uint8_t VersionMinor = 0;
|
||||||
const uint8_t VersionPatch = 0;
|
const uint8_t VersionPatch = 0;
|
||||||
const uint8_t VersionMetadata = 3;
|
const uint8_t VersionMetadata = 4;
|
||||||
const char VersionBranch[] = "release/2.0";
|
const char VersionBranch[] = "release/2.0";
|
||||||
const char VersionSha[] = "61d544f6f347c875e64b1e79985eeabd52ee1c9f";
|
const char VersionSha[] = "176fa2a7bae0e9604a70c69da27b68819b479b73";
|
||||||
const char VersionSemVer[] = "2.0.0-beta.1";
|
const char VersionSemVer[] = "2.0.0-beta.1";
|
||||||
const char VersionFullSemVer[] = "2.0.0-beta.1+3";
|
const char VersionFullSemVer[] = "2.0.0-beta.1+4";
|
||||||
const char VersionCommitDate[] = "2018-01-03";
|
const char VersionCommitDate[] = "2018-01-04";
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,7 +18,7 @@ void PCA9685::setAddress(uint8_t address, uint8_t pinSDA, uint8_t pinSCL)
|
|||||||
|
|
||||||
void PCA9685::setAddress(uint8_t address)
|
void PCA9685::setAddress(uint8_t address)
|
||||||
{
|
{
|
||||||
this->address = address;
|
this->mAddress = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -26,11 +26,11 @@ uint8_t PCA9685::read(uint8_t registerAddress)
|
|||||||
{
|
{
|
||||||
uint8_t result = 0;
|
uint8_t result = 0;
|
||||||
|
|
||||||
Wire.beginTransmission(this->address);
|
Wire.beginTransmission(this->mAddress);
|
||||||
Wire.write(registerAddress);
|
Wire.write(registerAddress);
|
||||||
Wire.endTransmission();
|
Wire.endTransmission();
|
||||||
|
|
||||||
Wire.requestFrom(this->address, (uint8_t)1);
|
Wire.requestFrom(this->mAddress, (uint8_t)1);
|
||||||
if (Wire.available())
|
if (Wire.available())
|
||||||
result = Wire.read();
|
result = Wire.read();
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ uint8_t PCA9685::read(uint8_t registerAddress)
|
|||||||
|
|
||||||
void PCA9685::write(uint8_t registerAddress, uint8_t value)
|
void PCA9685::write(uint8_t registerAddress, uint8_t value)
|
||||||
{
|
{
|
||||||
Wire.beginTransmission(this->address);
|
Wire.beginTransmission(this->mAddress);
|
||||||
Wire.write(registerAddress);
|
Wire.write(registerAddress);
|
||||||
Wire.write(value);
|
Wire.write(value);
|
||||||
Wire.endTransmission();
|
Wire.endTransmission();
|
||||||
@ -97,7 +97,7 @@ void PCA9685::setPWM(uint8_t pin, uint16_t value)
|
|||||||
|
|
||||||
void PCA9685::setPWM(uint8_t pin, uint16_t on, uint16_t off)
|
void PCA9685::setPWM(uint8_t pin, uint16_t on, uint16_t off)
|
||||||
{
|
{
|
||||||
Wire.beginTransmission(this->address);
|
Wire.beginTransmission(this->mAddress);
|
||||||
this->write(PCA9685::RegisterLED0OnL + (4 * pin));
|
this->write(PCA9685::RegisterLED0OnL + (4 * pin));
|
||||||
this->write(on);
|
this->write(on);
|
||||||
this->write(on >> 8);
|
this->write(on >> 8);
|
||||||
@ -124,7 +124,7 @@ void PCA9685::setAll(uint16_t value)
|
|||||||
|
|
||||||
void PCA9685::setAll(uint16_t on, uint16_t off)
|
void PCA9685::setAll(uint16_t on, uint16_t off)
|
||||||
{
|
{
|
||||||
Wire.beginTransmission(this->address);
|
Wire.beginTransmission(this->mAddress);
|
||||||
this->write(PCA9685::RegisterAllLEDOnL);
|
this->write(PCA9685::RegisterAllLEDOnL);
|
||||||
this->write(on);
|
this->write(on);
|
||||||
this->write(on >> 8);
|
this->write(on >> 8);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
class PCA9685
|
class PCA9685
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
uint8_t address;
|
uint8_t mAddress;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint8_t read(uint8_t registerAddress);
|
uint8_t read(uint8_t registerAddress);
|
||||||
|
@ -14,7 +14,9 @@ static const char* DefaultAPSSIDPrefix = "Stairs-";
|
|||||||
static const uint32_t StationModeTimeout = 30000;
|
static const uint32_t StationModeTimeout = 30000;
|
||||||
|
|
||||||
|
|
||||||
/*
|
static const char* StepSettingsFile = "/stepsettings";
|
||||||
|
|
||||||
|
|
||||||
// Pins for the I2C bus
|
// Pins for the I2C bus
|
||||||
static const uint8_t PinSDA = 13;
|
static const uint8_t PinSDA = 13;
|
||||||
static const uint8_t PinSCL = 12;
|
static const uint8_t PinSCL = 12;
|
||||||
@ -23,6 +25,6 @@ static const uint8_t PinSCL = 12;
|
|||||||
// I2C address and PWM frequency of the PCA9685 board
|
// I2C address and PWM frequency of the PCA9685 board
|
||||||
static const uint8_t PWMDriverAddress = 0x40;
|
static const uint8_t PWMDriverAddress = 0x40;
|
||||||
static const uint16_t PWMDriverPWMFrequency = 1600;
|
static const uint16_t PWMDriverPWMFrequency = 1600;
|
||||||
*/
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -9,6 +9,12 @@
|
|||||||
ConnectionSettings* connectionSettings = new ConnectionSettings();
|
ConnectionSettings* connectionSettings = new ConnectionSettings();
|
||||||
bool connectionSettingsChanged = false;
|
bool connectionSettingsChanged = false;
|
||||||
|
|
||||||
|
StepsSettings* stepsSettings = new StepsSettings();
|
||||||
|
bool stepsSettingsChanged = false;
|
||||||
|
|
||||||
|
|
||||||
|
Stairs* stairs;
|
||||||
|
|
||||||
bool shouldReboot = false;
|
bool shouldReboot = false;
|
||||||
|
|
||||||
uint32_t currentTime;
|
uint32_t currentTime;
|
||||||
|
@ -11,10 +11,17 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <IPAddress.h>
|
#include <IPAddress.h>
|
||||||
#include "settings/connection.h"
|
#include "settings/connection.h"
|
||||||
|
#include "settings/steps.h"
|
||||||
|
#include "stairs.h"
|
||||||
|
|
||||||
extern ConnectionSettings* connectionSettings;
|
extern ConnectionSettings* connectionSettings;
|
||||||
extern bool connectionSettingsChanged;
|
extern bool connectionSettingsChanged;
|
||||||
|
|
||||||
|
extern StepsSettings* stepsSettings;
|
||||||
|
extern bool stepsSettingsChanged;
|
||||||
|
|
||||||
|
extern Stairs* stairs;
|
||||||
|
|
||||||
extern bool shouldReboot;
|
extern bool shouldReboot;
|
||||||
|
|
||||||
extern uint32_t currentTime;
|
extern uint32_t currentTime;
|
||||||
|
388
src/main.cpp
388
src/main.cpp
@ -15,11 +15,13 @@ extern "C" {
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "settings/connection.h"
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
#include "components/PCA9685.h"
|
||||||
|
#include "settings/connection.h"
|
||||||
#include "server/static.h"
|
#include "server/static.h"
|
||||||
#include "server/api.h"
|
#include "server/settings.h"
|
||||||
#include "server/firmware.h"
|
#include "server/firmware.h"
|
||||||
|
#include "server/api.h"
|
||||||
|
|
||||||
|
|
||||||
ADC_MODE(ADC_VCC);
|
ADC_MODE(ADC_VCC);
|
||||||
@ -37,6 +39,8 @@ void handleNotFound(AsyncWebServerRequest* request);
|
|||||||
|
|
||||||
|
|
||||||
AsyncWebServer server(80);
|
AsyncWebServer server(80);
|
||||||
|
PCA9685* pwmDriver;
|
||||||
|
|
||||||
bool accessPoint = false;
|
bool accessPoint = false;
|
||||||
bool stationMode = false;
|
bool stationMode = false;
|
||||||
bool forceAccessPoint = false;
|
bool forceAccessPoint = false;
|
||||||
@ -58,6 +62,34 @@ void setup()
|
|||||||
_dln("Setup :: failed to mount file system");
|
_dln("Setup :: failed to mount file system");
|
||||||
|
|
||||||
connectionSettings->read();
|
connectionSettings->read();
|
||||||
|
stepsSettings->read();
|
||||||
|
|
||||||
|
|
||||||
|
_dln("Setup :: initializing PCA9685");
|
||||||
|
pwmDriver = new PCA9685();
|
||||||
|
pwmDriver->setAddress(PWMDriverAddress, PinSDA, PinSCL);
|
||||||
|
pwmDriver->setPWMFrequency(PWMDriverPWMFrequency);
|
||||||
|
|
||||||
|
_dln("Setup :: initializing Stairs");
|
||||||
|
stairs = new Stairs();
|
||||||
|
stairs->init(pwmDriver);
|
||||||
|
|
||||||
|
|
||||||
|
_dln("Setup :: starting initialization sequence");
|
||||||
|
stairs->setAll(0);
|
||||||
|
|
||||||
|
stairs->set(0, 255);
|
||||||
|
delay(300);
|
||||||
|
|
||||||
|
uint8_t stepCount = stepsSettings->count();
|
||||||
|
for (int step = 1; step < stepCount; step++)
|
||||||
|
{
|
||||||
|
stairs->set(step - 1, 0);
|
||||||
|
stairs->set(step, 255);
|
||||||
|
delay(300);
|
||||||
|
}
|
||||||
|
|
||||||
|
stairs->set(stepCount - 1, 0);
|
||||||
|
|
||||||
_dln("Setup :: initializing WiFi");
|
_dln("Setup :: initializing WiFi");
|
||||||
WiFi.persistent(false);
|
WiFi.persistent(false);
|
||||||
@ -75,8 +107,9 @@ void setup()
|
|||||||
|
|
||||||
_dln("Setup :: registering routes");
|
_dln("Setup :: registering routes");
|
||||||
registerStaticRoutes(&server);
|
registerStaticRoutes(&server);
|
||||||
registerAPIRoutes(&server);
|
registerSettingsRoutes(&server);
|
||||||
registerFirmwareRoutes(&server);
|
registerFirmwareRoutes(&server);
|
||||||
|
registerAPIRoutes(&server);
|
||||||
|
|
||||||
_dln("Setup :: starting HTTP server");
|
_dln("Setup :: starting HTTP server");
|
||||||
server.onNotFound(handleNotFound);
|
server.onNotFound(handleNotFound);
|
||||||
@ -88,7 +121,7 @@ void loop()
|
|||||||
{
|
{
|
||||||
if (shouldReboot)
|
if (shouldReboot)
|
||||||
{
|
{
|
||||||
_dln("Reboot requested, bye bye!");
|
_dln("Loop :: reboot requested, so long and thanks for all the fish!");
|
||||||
delay(100);
|
delay(100);
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
}
|
}
|
||||||
@ -144,6 +177,7 @@ void loop()
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateLED();
|
updateLED();
|
||||||
|
stairs->tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -229,80 +263,7 @@ void wifiEvent(WiFiEvent_t event)
|
|||||||
|
|
||||||
void updateLED()
|
void updateLED()
|
||||||
{
|
{
|
||||||
//while (WiFi.status() != WL_CONNECTED)
|
/*
|
||||||
//{
|
|
||||||
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void handleNotFound(AsyncWebServerRequest *request)
|
|
||||||
{
|
|
||||||
_d("HTTP :: not found: "); _dln(request->url());
|
|
||||||
request->send(404);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
#ifdef SerialDebug
|
|
||||||
Serial.begin(115200);
|
|
||||||
delay(5000);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
_dln("Initializing PCA9685");
|
|
||||||
_d("Version: ");
|
|
||||||
_dln(FirmwareVersion);
|
|
||||||
|
|
||||||
pwmDriver = new PCA9685();
|
|
||||||
pwmDriver->setAddress(PWMDriverAddress, PinSDA, PinSCL);
|
|
||||||
pwmDriver->setPWMFrequency(PWMDriverPWMFrequency);
|
|
||||||
|
|
||||||
_dln("Initializing Stairs");
|
|
||||||
|
|
||||||
stairs = new Stairs();
|
|
||||||
stairs->init(pwmDriver);
|
|
||||||
|
|
||||||
_dln("Initializing WiFi");
|
|
||||||
WiFi.mode(WIFI_STA);
|
|
||||||
WiFi.hostname(WiFiHostname);
|
|
||||||
WiFi.begin(WiFiSSID, WiFiPassword);
|
|
||||||
|
|
||||||
|
|
||||||
_dln("Starting initialization 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);
|
|
||||||
|
|
||||||
|
|
||||||
_dln("Waiting for WiFi");
|
|
||||||
|
|
||||||
// Pulsate the bottom step while WiFi is connecting
|
// Pulsate the bottom step while WiFi is connecting
|
||||||
uint16_t brightness = 0;
|
uint16_t brightness = 0;
|
||||||
uint16_t speed = 16;
|
uint16_t speed = 16;
|
||||||
@ -316,273 +277,12 @@ void setup()
|
|||||||
stairs->set(0, brightness);
|
stairs->set(0, brightness);
|
||||||
delay(16);
|
delay(16);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
setCurrentMode(new StaticMode(), Mode::Static);
|
|
||||||
|
|
||||||
|
|
||||||
_d("IP address: ");
|
|
||||||
_dln(WiFi.localIP());
|
|
||||||
|
|
||||||
_dln("Starting UDP server");
|
|
||||||
|
|
||||||
// Start the UDP server
|
|
||||||
udpServer.begin(UDPPort);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t currentTime;
|
void handleNotFound(AsyncWebServerRequest *request)
|
||||||
|
|
||||||
// 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!
|
|
||||||
const uint8_t maxPacketSize = 255;
|
|
||||||
|
|
||||||
uint8_t packet[maxPacketSize];
|
|
||||||
uint8_t* packetRef;
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
{
|
||||||
currentTime = millis();
|
_d("HTTP :: not found: "); _dln(request->url());
|
||||||
|
request->send(404);
|
||||||
checkRequest();
|
}
|
||||||
handleCurrentMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void checkRequest()
|
|
||||||
{
|
|
||||||
int packetSize = udpServer.parsePacket();
|
|
||||||
if (packetSize)
|
|
||||||
{
|
|
||||||
_dln("Handling incoming packet");
|
|
||||||
|
|
||||||
memset(packet, 0, sizeof(packet));
|
|
||||||
int length = udpServer.read(packet, maxPacketSize - 1);
|
|
||||||
if (length && packet[0])
|
|
||||||
{
|
|
||||||
packetRef = packet;
|
|
||||||
handleRequest(packetRef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void handlePing(uint8_t* packet)
|
|
||||||
{
|
|
||||||
_dln("Handling Ping");
|
|
||||||
|
|
||||||
udpServer.write(Command::Ping);
|
|
||||||
udpServer.write(StepCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void handleGetMode(uint8_t* packet)
|
|
||||||
{
|
|
||||||
_dln("Handling GetMode");
|
|
||||||
|
|
||||||
udpServer.write(Command::GetMode);
|
|
||||||
udpServer.write(currentModeIdentifier);
|
|
||||||
currentMode->write(&udpServer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void handleSetMode(uint8_t* packet)
|
|
||||||
{
|
|
||||||
_dln("Handling SetMode");
|
|
||||||
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);
|
|
||||||
|
|
||||||
_dln("Updating current mode");
|
|
||||||
setCurrentMode(newMode, newIdentifier);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
udpServer.write(Command::Error);
|
|
||||||
udpServer.write(Command::SetMode);
|
|
||||||
udpServer.write(newIdentifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void handleGetRange(uint8_t* packet)
|
|
||||||
{
|
|
||||||
udpServer.write(Command::GetRange);
|
|
||||||
stairs->getRange(&udpServer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void handleSetRange(uint8_t* packet)
|
|
||||||
{
|
|
||||||
stairs->setRange(packet);
|
|
||||||
|
|
||||||
udpServer.write(Command::SetRange);
|
|
||||||
stairs->getRange(&udpServer);
|
|
||||||
|
|
||||||
currentMode->init(stairs, currentTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t lastUpdateCheck = 0;
|
|
||||||
|
|
||||||
void handleUpdateFirmware(uint8_t* packet)
|
|
||||||
{
|
|
||||||
_dln("Handling UpdateFirmware");
|
|
||||||
|
|
||||||
HTTPUpdateResult result;
|
|
||||||
|
|
||||||
if (currentTime - lastUpdateCheck <= OTAUpdateThrottle)
|
|
||||||
{
|
|
||||||
udpServer.write(Command::Error);
|
|
||||||
udpServer.write(Command::UpdateFirmware);
|
|
||||||
udpServer.write((uint8_t)2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastUpdateCheck = currentTime;
|
|
||||||
|
|
||||||
switch (OTAUpdateEnabled)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
_dln("Checking for update (fixed)");
|
|
||||||
result = ESPhttpUpdate.update(OTAUpdateFixedHost, OTAUpdateFixedPort, OTAUpdateFixedPath, FirmwareVersion);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
_dln("Checking for update (client defined)");
|
|
||||||
|
|
||||||
uint16_t port;
|
|
||||||
memcpy(&port, packet, sizeof(port));
|
|
||||||
packet += sizeof(port);
|
|
||||||
|
|
||||||
_d("Port: ");
|
|
||||||
_dln(port);
|
|
||||||
|
|
||||||
char host[255];
|
|
||||||
char path[255];
|
|
||||||
|
|
||||||
strcpy(host, (char*)packet);
|
|
||||||
packet += strlen(host) + 1;
|
|
||||||
|
|
||||||
strcpy(path, (char*)packet);
|
|
||||||
|
|
||||||
_d("Host: ");
|
|
||||||
_dln(host);
|
|
||||||
_d("Path: ");
|
|
||||||
_dln(path);
|
|
||||||
|
|
||||||
result = ESPhttpUpdate.update(host, port, path, FirmwareVersion);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
udpServer.write(Command::Error);
|
|
||||||
udpServer.write(Command::UpdateFirmware);
|
|
||||||
udpServer.write((uint8_t)0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
case HTTP_UPDATE_NO_UPDATES:
|
|
||||||
_dln("No updates");
|
|
||||||
udpServer.write(Command::UpdateFirmware);
|
|
||||||
udpServer.write((uint8_t)0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HTTP_UPDATE_OK:
|
|
||||||
_dln("Update OK");
|
|
||||||
udpServer.write(Command::UpdateFirmware);
|
|
||||||
udpServer.write((uint8_t)1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
_d("Error while updating: ");
|
|
||||||
_dln(ESPhttpUpdate.getLastError());
|
|
||||||
_dln(ESPhttpUpdate.getLastErrorString().c_str());
|
|
||||||
|
|
||||||
udpServer.write(Command::Error);
|
|
||||||
udpServer.write(Command::UpdateFirmware);
|
|
||||||
udpServer.write((uint8_t)2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void handleRequest(uint8_t* packet)
|
|
||||||
{
|
|
||||||
_d("Handling request: ");
|
|
||||||
_dln(*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);
|
|
||||||
|
|
||||||
uint8_t command = *packet;
|
|
||||||
packet++;
|
|
||||||
|
|
||||||
switch (command)
|
|
||||||
{
|
|
||||||
case Command::Ping: handlePing(packet); break;
|
|
||||||
case Command::GetMode: handleGetMode(packet); break;
|
|
||||||
case Command::SetMode: handleSetMode(packet); break;
|
|
||||||
case Command::GetRange: handleGetRange(packet); break;
|
|
||||||
case Command::SetRange: handleSetRange(packet); break;
|
|
||||||
case Command::UpdateFirmware: handleUpdateFirmware(packet); break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
udpServer.write(Command::Error);
|
|
||||||
udpServer.write(command);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
*/
|
|
29
src/mode.h
29
src/mode.h
@ -1,29 +0,0 @@
|
|||||||
#ifndef __Mode
|
|
||||||
#define __Mode
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <Stream.h>
|
|
||||||
|
|
||||||
|
|
||||||
class IStairs
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const uint16_t Off = 0;
|
|
||||||
static const uint16_t On = 4095;
|
|
||||||
|
|
||||||
virtual uint8_t getCount() = 0;
|
|
||||||
virtual void set(uint8_t step, uint16_t value) = 0;
|
|
||||||
virtual void setAll(uint16_t value) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class IMode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual void read(uint8_t* data) = 0;
|
|
||||||
virtual void write(Stream* stream) = 0;
|
|
||||||
|
|
||||||
virtual void init(IStairs* stairs, uint32_t currentTime) = 0;
|
|
||||||
virtual void tick(IStairs* stairs, uint32_t currentTime) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,31 +0,0 @@
|
|||||||
#ifndef __Protocol
|
|
||||||
#define __Protocol
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
class Command
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const uint8_t Error = 0x00;
|
|
||||||
|
|
||||||
static const uint8_t Ping = 0x01;
|
|
||||||
static const uint8_t Reply = 0x02;
|
|
||||||
static const uint8_t GetMode = 0x03;
|
|
||||||
static const uint8_t SetMode = 0x04;
|
|
||||||
static const uint8_t GetRange = 0x05;
|
|
||||||
static const uint8_t SetRange = 0x06;
|
|
||||||
static const uint8_t UpdateFirmware = 0xFF;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Mode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const uint8_t Static = 0x01;
|
|
||||||
static const uint8_t Custom = 0x02;
|
|
||||||
static const uint8_t Alternate = 0x03;
|
|
||||||
static const uint8_t Slide = 0x04;
|
|
||||||
//static const uint8_t ADC = 0x05;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -8,21 +8,22 @@
|
|||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <IPAddress.h>
|
#include <IPAddress.h>
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
|
#include "shared.h"
|
||||||
#include "../assets/version.h"
|
#include "../assets/version.h"
|
||||||
#include "../debug.h"
|
#include "../debug.h"
|
||||||
#include "../global.h"
|
#include "../global.h"
|
||||||
#include "../settings/connection.h"
|
#include "../settings/connection.h"
|
||||||
|
|
||||||
|
|
||||||
void handleVersion(AsyncWebServerRequest *request)
|
void handleGetSteps(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
_dln("API :: version");
|
_dln("API :: get steps");
|
||||||
|
|
||||||
DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(2));
|
DynamicJsonBuffer jsonBuffer(JSON_ARRAY_SIZE(17));
|
||||||
|
|
||||||
JsonObject& root = jsonBuffer.createObject();
|
JsonArray& root = jsonBuffer.createArray();
|
||||||
root["systemID"] = String(ESP.getChipId(), HEX);
|
for (uint8_t step = 0; step < stepsSettings->count(); step++)
|
||||||
root["version"] = String(VersionFullSemVer) + " sha." + String(VersionSha);
|
root.add(stairs->get(step));
|
||||||
|
|
||||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
root.printTo(*response);
|
root.printTo(*response);
|
||||||
@ -31,71 +32,38 @@ void handleVersion(AsyncWebServerRequest *request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void handleConnectionStatus(AsyncWebServerRequest *request)
|
void handlePostSteps(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)
|
||||||
{
|
{
|
||||||
_dln("API :: connection status");
|
_dln("API :: post steps");
|
||||||
|
|
||||||
WiFiMode_t mode = WiFi.getMode();
|
DynamicJsonBuffer jsonBuffer(2*JSON_ARRAY_SIZE(17) + JSON_OBJECT_SIZE(3) + 130);
|
||||||
|
JsonObject& root = jsonBuffer.parseObject((char*)data);
|
||||||
|
if (!root.success())
|
||||||
DynamicJsonBuffer jsonBuffer((2 * JSON_OBJECT_SIZE(2)) + JSON_OBJECT_SIZE(3));
|
|
||||||
|
|
||||||
JsonObject& root = jsonBuffer.createObject();
|
|
||||||
JsonObject& ap = root.createNestedObject("ap");
|
|
||||||
ap["enabled"] = (mode == WIFI_AP || mode == WIFI_AP_STA);
|
|
||||||
ap["ip"] = WiFi.softAPIP().toString();
|
|
||||||
|
|
||||||
JsonObject& station = root.createNestedObject("station");
|
|
||||||
station["enabled"] = (mode == WIFI_STA || mode == WIFI_AP_STA);
|
|
||||||
station["status"] = (uint8_t)WiFi.status();
|
|
||||||
station["ip"] = WiFi.localIP().toString();
|
|
||||||
|
|
||||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
|
||||||
root.printTo(*response);
|
|
||||||
|
|
||||||
request->send(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void handleGetConnection(AsyncWebServerRequest *request)
|
|
||||||
{
|
|
||||||
_dln("API :: get connection");
|
|
||||||
|
|
||||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
|
||||||
connectionSettings->toJson(*response);
|
|
||||||
request->send(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void handlePostConnection(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)
|
|
||||||
{
|
|
||||||
_dln("API :: post connection");
|
|
||||||
|
|
||||||
bool changed;
|
|
||||||
if (connectionSettings->fromJson((char*)data, &changed))
|
|
||||||
{
|
{
|
||||||
connectionSettings->write();
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
connectionSettingsChanged = true;
|
|
||||||
|
|
||||||
request->send(200);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
request->send(400);
|
request->send(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t transitionTime = root["transitionTime"];
|
||||||
|
JsonArray& values = root["values"];
|
||||||
|
|
||||||
|
JsonArray& startTime = root["startTime"];
|
||||||
|
size_t startTimeCount = startTime.size();
|
||||||
|
|
||||||
|
size_t valueCount = values.size();
|
||||||
|
if (valueCount > stepsSettings->count())
|
||||||
|
valueCount = stepsSettings->count();
|
||||||
|
|
||||||
|
|
||||||
|
for (uint8_t step = 0; step < valueCount; step++)
|
||||||
|
stairs->set(step, values[step], transitionTime, step < startTimeCount ? 1 : 0);
|
||||||
|
|
||||||
|
request->send(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void devNullRequest(AsyncWebServerRequest *request) { }
|
|
||||||
void devNullFileUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) { }
|
|
||||||
|
|
||||||
|
|
||||||
void registerAPIRoutes(AsyncWebServer* server)
|
void registerAPIRoutes(AsyncWebServer* server)
|
||||||
{
|
{
|
||||||
server->on("/api/version", HTTP_GET, handleVersion);
|
server->on("/api/steps", HTTP_GET, handleGetSteps);
|
||||||
|
server->on("/api/steps", HTTP_POST, devNullRequest, devNullFileUpload, handlePostSteps);
|
||||||
server->on("/api/connection/status", HTTP_GET, handleConnectionStatus);
|
|
||||||
|
|
||||||
server->on("/api/connection", HTTP_GET, handleGetConnection);
|
|
||||||
server->on("/api/connection", HTTP_POST, devNullRequest, devNullFileUpload, handlePostConnection);
|
|
||||||
}
|
}
|
98
src/server/settings.cpp
Normal file
98
src/server/settings.cpp
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Stairs
|
||||||
|
* Copyright 2017 (c) Mark van Renswoude
|
||||||
|
*
|
||||||
|
* https://git.x2software.net/pub/Stairs
|
||||||
|
*/
|
||||||
|
#include "settings.h"
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <IPAddress.h>
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include "shared.h"
|
||||||
|
#include "../assets/version.h"
|
||||||
|
#include "../debug.h"
|
||||||
|
#include "../global.h"
|
||||||
|
#include "../settings/connection.h"
|
||||||
|
|
||||||
|
|
||||||
|
void handleVersion(AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
_dln("API :: version");
|
||||||
|
|
||||||
|
DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(2));
|
||||||
|
|
||||||
|
JsonObject& root = jsonBuffer.createObject();
|
||||||
|
root["systemID"] = String(ESP.getChipId(), HEX);
|
||||||
|
root["version"] = String(VersionFullSemVer) + " sha." + String(VersionSha);
|
||||||
|
|
||||||
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
|
root.printTo(*response);
|
||||||
|
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void handleConnectionStatus(AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
_dln("API :: connection status");
|
||||||
|
|
||||||
|
WiFiMode_t mode = WiFi.getMode();
|
||||||
|
|
||||||
|
|
||||||
|
DynamicJsonBuffer jsonBuffer((2 * JSON_OBJECT_SIZE(2)) + JSON_OBJECT_SIZE(3));
|
||||||
|
|
||||||
|
JsonObject& root = jsonBuffer.createObject();
|
||||||
|
JsonObject& ap = root.createNestedObject("ap");
|
||||||
|
ap["enabled"] = (mode == WIFI_AP || mode == WIFI_AP_STA);
|
||||||
|
ap["ip"] = WiFi.softAPIP().toString();
|
||||||
|
|
||||||
|
JsonObject& station = root.createNestedObject("station");
|
||||||
|
station["enabled"] = (mode == WIFI_STA || mode == WIFI_AP_STA);
|
||||||
|
station["status"] = (uint8_t)WiFi.status();
|
||||||
|
station["ip"] = WiFi.localIP().toString();
|
||||||
|
|
||||||
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
|
root.printTo(*response);
|
||||||
|
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void handleGetConnection(AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
_dln("API :: get connection");
|
||||||
|
|
||||||
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
|
connectionSettings->toJson(*response);
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void handlePostConnection(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)
|
||||||
|
{
|
||||||
|
_dln("API :: post connection");
|
||||||
|
|
||||||
|
bool changed;
|
||||||
|
if (connectionSettings->fromJson((char*)data, &changed))
|
||||||
|
{
|
||||||
|
connectionSettings->write();
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
connectionSettingsChanged = true;
|
||||||
|
|
||||||
|
request->send(200);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
request->send(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void registerSettingsRoutes(AsyncWebServer* server)
|
||||||
|
{
|
||||||
|
server->on("/api/version", HTTP_GET, handleVersion);
|
||||||
|
|
||||||
|
server->on("/api/connection/status", HTTP_GET, handleConnectionStatus);
|
||||||
|
|
||||||
|
server->on("/api/connection", HTTP_GET, handleGetConnection);
|
||||||
|
server->on("/api/connection", HTTP_POST, devNullRequest, devNullFileUpload, handlePostConnection);
|
||||||
|
}
|
13
src/server/settings.h
Normal file
13
src/server/settings.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* Stairs
|
||||||
|
* Copyright 2017 (c) Mark van Renswoude
|
||||||
|
*
|
||||||
|
* https://git.x2software.net/pub/Stairs
|
||||||
|
*/
|
||||||
|
#ifndef __server_settings
|
||||||
|
#define __server_settings
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
void registerSettingsRoutes(AsyncWebServer* server);
|
||||||
|
|
||||||
|
#endif
|
10
src/server/shared.cpp
Normal file
10
src/server/shared.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Stairs
|
||||||
|
* Copyright 2017 (c) Mark van Renswoude
|
||||||
|
*
|
||||||
|
* https://git.x2software.net/pub/Stairs
|
||||||
|
*/
|
||||||
|
#include "shared.h"
|
||||||
|
|
||||||
|
void devNullRequest(AsyncWebServerRequest *request) {}
|
||||||
|
void devNullFileUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {}
|
15
src/server/shared.h
Normal file
15
src/server/shared.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Stairs
|
||||||
|
* Copyright 2017 (c) Mark van Renswoude
|
||||||
|
*
|
||||||
|
* https://git.x2software.net/pub/Stairs
|
||||||
|
*/
|
||||||
|
#ifndef __server_shared
|
||||||
|
#define __server_shared
|
||||||
|
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
void devNullRequest(AsyncWebServerRequest *request);
|
||||||
|
void devNullFileUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final);
|
||||||
|
|
||||||
|
#endif
|
65
src/settings/steps.cpp
Normal file
65
src/settings/steps.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Stairs
|
||||||
|
* Copyright 2017 (c) Mark van Renswoude
|
||||||
|
*
|
||||||
|
* https://git.x2software.net/pub/Stairs
|
||||||
|
*/
|
||||||
|
#include "steps.h"
|
||||||
|
#include <FS.h>
|
||||||
|
#include "../debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct Header
|
||||||
|
{
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t stepCount;
|
||||||
|
bool useCurve;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
StepsSettings::StepsSettings()
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < MaxStepCount; i++)
|
||||||
|
mCurveShift[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StepsSettings::read()
|
||||||
|
{
|
||||||
|
_dln("StepsSettings :: Loading step settings");
|
||||||
|
File f = SPIFFS.open(StepSettingsFile, "r");
|
||||||
|
if (!f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!f.available())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Header header;
|
||||||
|
f.readBytes((char*)&header, sizeof(Header));
|
||||||
|
|
||||||
|
if (header.version != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mUseCurve = (header.useCurve == 1);
|
||||||
|
f.readBytes((char*)&mCurveShift, header.stepCount * sizeof(uint16_t));
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StepsSettings::write()
|
||||||
|
{
|
||||||
|
_dln("StepsSettings :: Saving step settings");
|
||||||
|
File f = SPIFFS.open(StepSettingsFile, "w");
|
||||||
|
if (!f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Header header;
|
||||||
|
header.version = 1;
|
||||||
|
header.useCurve = mUseCurve;
|
||||||
|
header.stepCount = mCount;
|
||||||
|
|
||||||
|
f.write((uint8_t*)&header, sizeof(Header));
|
||||||
|
f.write((uint8_t*)&mCurveShift, header.stepCount * sizeof(uint16_t));
|
||||||
|
f.close();
|
||||||
|
}
|
38
src/settings/steps.h
Normal file
38
src/settings/steps.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Stairs
|
||||||
|
* Copyright 2017 (c) Mark van Renswoude
|
||||||
|
*
|
||||||
|
* https://git.x2software.net/pub/Stairs
|
||||||
|
*/
|
||||||
|
#ifndef __settingssteps
|
||||||
|
#define __settingssteps
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define MaxStepCount 16
|
||||||
|
|
||||||
|
|
||||||
|
class StepsSettings
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint8_t mCount = 16;
|
||||||
|
bool mUseCurve = true;
|
||||||
|
uint16_t mCurveShift[MaxStepCount];
|
||||||
|
|
||||||
|
public:
|
||||||
|
StepsSettings();
|
||||||
|
|
||||||
|
void read();
|
||||||
|
void write();
|
||||||
|
|
||||||
|
uint8_t count() { return mCount; }
|
||||||
|
void count(uint8_t value) { mCount = value; }
|
||||||
|
|
||||||
|
bool useCurve() { return mUseCurve; }
|
||||||
|
void useCurve(bool value) { mUseCurve = value; }
|
||||||
|
|
||||||
|
uint16_t curveShift(uint8_t step) { return step < MaxStepCount ? mCurveShift[step] : 0; }
|
||||||
|
uint16_t curveShift(uint8_t step, uint16_t value) { if (step < MaxStepCount) mCurveShift[step] = value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
246
src/stairs.cpp
246
src/stairs.cpp
@ -2,153 +2,159 @@
|
|||||||
#include <Math.h>
|
#include <Math.h>
|
||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const static float factorBase = log10(2) / log10(PCA9685::On);
|
const uint16_t PWMCurve[] =
|
||||||
|
|
||||||
|
|
||||||
struct Header
|
|
||||||
{
|
{
|
||||||
uint8_t version;
|
0, 10, 11, 12, 12, 13, 13, 14, 15, 16, 16, 17, 18, 19, 20, 21,
|
||||||
uint8_t rangeCount;
|
22, 23, 24, 25, 26, 27, 29, 30, 32, 33, 35, 36, 38, 40, 42, 44,
|
||||||
bool useScaling;
|
46, 48, 51, 53, 56, 58, 61, 64, 67, 70, 74, 77, 81, 85, 89, 93,
|
||||||
|
97, 102, 107, 112, 117, 123, 129, 135, 141, 148, 155, 162, 169, 177, 186, 194,
|
||||||
|
203, 213, 222, 233, 243, 254, 266, 278, 291, 304, 318, 332, 347, 362, 378, 395,
|
||||||
|
412, 430, 449, 468, 488, 509, 531, 553, 576, 600, 625, 651, 677, 704, 733, 762,
|
||||||
|
792, 823, 854, 887, 920, 955, 990, 1026, 1063, 1101, 1140, 1180, 1220, 1261, 1303, 1346,
|
||||||
|
1389, 1433, 1478, 1523, 1569, 1615, 1662, 1709, 1757, 1805, 1853, 1901, 1950, 1999, 2048, 2096,
|
||||||
|
2145, 2194, 2242, 2290, 2338, 2386, 2433, 2480, 2526, 2572, 2617, 2662, 2706, 2749, 2792, 2834,
|
||||||
|
2875, 2915, 2955, 2994, 3032, 3069, 3105, 3140, 3175, 3208, 3241, 3272, 3303, 3333, 3362, 3391,
|
||||||
|
3418, 3444, 3470, 3495, 3519, 3542, 3564, 3586, 3607, 3627, 3646, 3665, 3683, 3700, 3717, 3733,
|
||||||
|
3748, 3763, 3777, 3791, 3804, 3817, 3829, 3841, 3852, 3862, 3873, 3882, 3892, 3901, 3909, 3918,
|
||||||
|
3926, 3933, 3940, 3947, 3954, 3960, 3966, 3972, 3978, 3983, 3988, 3993, 3998, 4002, 4006, 4010,
|
||||||
|
4014, 4018, 4021, 4025, 4028, 4031, 4034, 4037, 4039, 4042, 4044, 4047, 4049, 4051, 4053, 4055,
|
||||||
|
4057, 4059, 4060, 4062, 4063, 4065, 4066, 4068, 4069, 4070, 4071, 4072, 4073, 4074, 4075, 4076,
|
||||||
|
4077, 4078, 4079, 4079, 4080, 4081, 4082, 4082, 4083, 4083, 4084, 4084, 4085, 4085, 4090, 4095
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const float LinearFactor = 4095.0f / 255.0f;
|
||||||
|
|
||||||
|
|
||||||
void Stairs::init(PCA9685* pwmDriver)
|
void Stairs::init(PCA9685* pwmDriver)
|
||||||
{
|
{
|
||||||
this->useScaling = false;
|
mPWMDriver = pwmDriver;
|
||||||
|
|
||||||
|
memset(&mStep[0], 0, sizeof(mStep));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
for (uint8_t i = 0; i < StepCount; i++)
|
struct Step
|
||||||
|
{
|
||||||
|
uint16_t currentValue;
|
||||||
|
uint16_t startValue;
|
||||||
|
uint16_t targetValue;
|
||||||
|
uint16_t startTime;
|
||||||
|
uint16_t endTime;
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Stairs::tick()
|
||||||
|
{
|
||||||
|
if (!mTick) return;
|
||||||
|
mTick = false;
|
||||||
|
|
||||||
|
uint32_t elapsedTime = mTransitionStart != 0 ? currentTime - mTransitionStart : 0;
|
||||||
|
|
||||||
|
for (uint8_t step = 0; step < stepsSettings->count(); step++)
|
||||||
{
|
{
|
||||||
this->ranges[i].start = IStairs::Off;
|
if (mStep[step].currentValue != mStep[step].targetValue)
|
||||||
this->ranges[i].end = IStairs::On;
|
{
|
||||||
}
|
// TODO more maths!
|
||||||
*/
|
|
||||||
|
|
||||||
this->pwmDriver = pwmDriver;
|
/*
|
||||||
|
uint32_t diff = this->easeState == Up ? this->parameters.brightness - this->easeStartBrightness : this->easeStartBrightness - this->parameters.brightness;
|
||||||
|
uint32_t delta = (diff * elapsedTime) / this->parameters.easeTime;
|
||||||
|
|
||||||
_dln("Loading range configuration");
|
this->currentBrightness = this->easeState == Up ? this->easeStartBrightness + delta : this->easeStartBrightness - delta;
|
||||||
SPIFFS.begin();
|
|
||||||
this->readRange();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t Stairs::getCount()
|
if (elapsedTime >= this->parameters.easeTime)
|
||||||
{
|
|
||||||
return 0;//StepCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Stairs::set(uint8_t step, uint16_t brightness)
|
|
||||||
{
|
|
||||||
pwmDriver->setPWM(step, this->getPWMValue(step, brightness));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Stairs::setAll(uint16_t brightness)
|
|
||||||
{
|
|
||||||
//pwmDriver->setAll(this->getPWMValue(brightness));
|
|
||||||
|
|
||||||
/*
|
|
||||||
for (uint8_t step = 0; step < StepCount; step++)
|
|
||||||
pwmDriver->setPWM(step, this->getPWMValue(step, brightness));
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint16_t Stairs::getPWMValue(uint8_t step, uint16_t brightness)
|
|
||||||
{
|
|
||||||
_d("Getting PWM value for step "); _d(step); _d(", brightness "); _dln(brightness);
|
|
||||||
if (brightness == IStairs::Off || brightness == IStairs::On)
|
|
||||||
{
|
{
|
||||||
_dln("Full on/off, returning input");
|
this->currentBrightness = this->parameters.brightness;
|
||||||
return brightness;
|
this->easeState = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (step < 0 || step >= getCount())
|
|
||||||
{
|
|
||||||
_dln("Step out of bounds, returning input");
|
|
||||||
return brightness;
|
t /= d/2;
|
||||||
|
if (t < 1) return c/2*t*t + b;
|
||||||
|
t--;
|
||||||
|
return -c/2 * (t*(t-2) - 1) + b;
|
||||||
|
};
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Range* range = &this->ranges[step];
|
// TODO
|
||||||
_d("Start: "); _dln(range->start);
|
// mPWMDriver->setPWM(step, this->getPWMValue(step, brightness));
|
||||||
_d("End: "); _dln(range->end);
|
|
||||||
|
|
||||||
if (this->useScaling)
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t Stairs::get(uint8_t step, bool target)
|
||||||
|
{
|
||||||
|
if (step >= MaxStepCount) return 0;
|
||||||
|
return target ? mStep[step].targetValue : mStep[step].currentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Stairs::set(uint8_t step, uint8_t brightness, uint16_t transitionTime, uint16_t startTime)
|
||||||
|
{
|
||||||
|
if (step >= MaxStepCount) return;
|
||||||
|
if (mStep[step].currentValue == brightness)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO continue transition if one is already going on
|
||||||
|
|
||||||
|
mTick = true;
|
||||||
|
mStep[step].targetValue = brightness;
|
||||||
|
|
||||||
|
if (transitionTime > 0)
|
||||||
{
|
{
|
||||||
_dln("Using scaling");
|
mTransitionStart = currentTime;
|
||||||
float factor = ((range->end - range->start) + 1) * factorBase;
|
mStep[step].startValue = mStep[step].currentValue;
|
||||||
brightness = pow(2, (brightness / factor)) - 1 + range->start;
|
mStep[step].startTime = startTime;
|
||||||
|
mStep[step].endTime = transitionTime;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_dln("Not using scaling");
|
mTransitionStart = 0;
|
||||||
if (brightness < range->start) brightness = range->start;
|
}
|
||||||
if (brightness > range->end) brightness = range->end;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Stairs::setAll(uint8_t brightness, uint16_t transitionTime, uint16_t startTime)
|
||||||
|
{
|
||||||
|
for (uint8_t step = 0; step < stepsSettings->count(); step++)
|
||||||
|
set(step, brightness, transitionTime, startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t Stairs::getPWMValue(uint8_t step, uint8_t brightness)
|
||||||
|
{
|
||||||
|
//_d("Stairs :: Getting PWM value for step "); _d(step); _d(", brightness "); _dln(brightness);
|
||||||
|
if (brightness == 0 || brightness == 255)
|
||||||
|
{
|
||||||
|
//_dln("Stairs :: Full on/off, returning input");
|
||||||
|
return brightness == 0 ? 0 : 4095;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Output: "); _dln(brightness);
|
uint16_t pwmValue;
|
||||||
return brightness;
|
if (stepsSettings->useCurve())
|
||||||
}
|
{
|
||||||
|
//_dln("Stairs :: Using curve");
|
||||||
|
pwmValue = PWMCurve[brightness] + stepsSettings->curveShift(step);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//_dln("Stairs :: Not using curve");
|
||||||
|
pwmValue = brightness * LinearFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
//_d("Stairs :: Output: "); _dln(pwmValue);
|
||||||
void Stairs::getRange(Stream* stream)
|
return pwmValue;
|
||||||
{
|
|
||||||
stream->write(this->useScaling ? 1 : 0);
|
|
||||||
stream->write((uint8_t*)&this->ranges, sizeof(this->ranges));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Stairs::setRange(uint8_t* data)
|
|
||||||
{
|
|
||||||
this->useScaling = *data;
|
|
||||||
data++;
|
|
||||||
|
|
||||||
memcpy(this->ranges, data, sizeof(this->ranges));
|
|
||||||
this->writeRange();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Stairs::readRange()
|
|
||||||
{
|
|
||||||
File f = SPIFFS.open("/range", "r");
|
|
||||||
if (!f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!f.available())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Header header;
|
|
||||||
f.readBytes((char*)&header, sizeof(Header));
|
|
||||||
|
|
||||||
if (header.version != 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this->useScaling = (header.useScaling == 1);
|
|
||||||
f.readBytes((char*)&this->ranges, header.rangeCount * sizeof(Range));
|
|
||||||
f.close();
|
|
||||||
|
|
||||||
_d("- useScaling: ");
|
|
||||||
_dln(this->useScaling);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Stairs::writeRange()
|
|
||||||
{
|
|
||||||
File f = SPIFFS.open("/range", "w");
|
|
||||||
if (!f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Header header;
|
|
||||||
header.version = 1;
|
|
||||||
header.useScaling = this->useScaling;
|
|
||||||
header.rangeCount = getCount();
|
|
||||||
|
|
||||||
f.write((uint8_t*)&header, sizeof(Header));
|
|
||||||
f.write((uint8_t*)&this->ranges, sizeof(this->ranges));
|
|
||||||
f.close();
|
|
||||||
}
|
}
|
36
src/stairs.h
36
src/stairs.h
@ -3,39 +3,37 @@
|
|||||||
|
|
||||||
#include "components/PCA9685.h"
|
#include "components/PCA9685.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "mode.h"
|
#include "settings/steps.h"
|
||||||
|
|
||||||
|
struct Step
|
||||||
struct Range
|
|
||||||
{
|
{
|
||||||
uint16_t start;
|
uint16_t currentValue;
|
||||||
uint16_t end;
|
uint16_t startValue;
|
||||||
|
uint16_t targetValue;
|
||||||
|
uint16_t startTime;
|
||||||
|
uint16_t endTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Stairs : public IStairs
|
class Stairs
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
PCA9685* pwmDriver;
|
PCA9685* mPWMDriver;
|
||||||
|
Step mStep[MaxStepCount];
|
||||||
|
|
||||||
bool useScaling;
|
uint32_t mTransitionStart;
|
||||||
Range ranges[16];
|
bool mTick = false;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void readRange();
|
uint16_t getPWMValue(uint8_t step, uint8_t brightness);
|
||||||
void writeRange();
|
|
||||||
|
|
||||||
uint16_t getPWMValue(uint8_t step, uint16_t brightness);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init(PCA9685* pwmDriver);
|
void init(PCA9685* pwmDriver);
|
||||||
|
void tick();
|
||||||
|
|
||||||
uint8_t getCount();
|
uint8_t get(uint8_t step, bool target = true);
|
||||||
void set(uint8_t step, uint16_t brightness);
|
void set(uint8_t step, uint8_t brightness, uint16_t transitionTime = 0, uint16_t startTime = 0);
|
||||||
void setAll(uint16_t brightness);
|
void setAll(uint8_t brightness, uint16_t transitionTime = 0, uint16_t startTime = 0);
|
||||||
|
|
||||||
void getRange(Stream* stream);
|
|
||||||
void setRange(uint8_t* data);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Reference in New Issue
Block a user