Stairs/module/src/main.cpp

180 lines
4.0 KiB
C++

/*
* Stairs lighting
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
#include <Arduino.h>
#include <Wire.h>
#include "global.h"
#include "display.h"
#include "protocol.h"
void setup()
{
settings.init();
// Set up I2C devices: the SSD1306 OLED display and PCA9685 LED PWM driver
Wire.begin();
display.init();
pwmDriver.setAddress(0x40);
// At 16 Mhz we pick a baud rate with a very acceptable 0.2% error rate
// Source: http://www.robotroom.com/Asynchronous-Serial-Communication-2.html
Serial.begin(76800);
comm.begin();
}
// Forward declarations
void handleCommMessage();
void handlePing(uint8_t* data, uint8_t length);
void handleDisplayModuleIndex(uint8_t* data, uint8_t length);
void handleStartLink(uint8_t* data, uint8_t length);
void handleRequestLinkResponse(uint8_t* data, uint8_t length);
void handleStopLink(uint8_t* data, uint8_t length);
void handleSetPWM(uint8_t* data, uint8_t length);
void handleGetSensors(uint8_t* data, uint8_t length);
void loop()
{
currentTime = millis();
if (comm.update())
handleCommMessage();
display.update();
}
void handleCommMessage()
{
uint8_t* data = comm.getData();
uint8_t length = comm.getLength();
if (length == 0)
return;
if (state == State::WaitingForComm)
state = State::DisplayModuleIndex;
uint8_t command = *data; data++; length--;
uint8_t moduleIndex = ModuleIndexUndefined;
if (command & MaskModuleCommand)
{
if (!settings.hasModuleIndex())
// We're not linked yet
return;
moduleIndex = *data; data++; length--;
if (settings.getModuleIndex() != moduleIndex)
// This message is meant for another module
return;
}
switch (command)
{
case CommandPing: handlePing(data, length); break;
case CommandDisplayModuleIndex: handleDisplayModuleIndex(data, length); break;
case CommandStartLink: handleStartLink(data, length); break;
case ResponseRequestLink: handleRequestLinkResponse(data, length); break;
case CommandStopLink: handleStopLink(data, length); break;
case CommandSetPWM: handleSetPWM(data, length); break;
case CommandGetSensors: handleGetSensors(data, length); break;
default:
if (command & MaskModuleCommand)
{
// Sender expects a response from us
const uint8_t msg[] = { ResponseUhmWhat, moduleIndex };
comm.sendMsg(msg, sizeof(msg));
}
}
}
void handlePing(uint8_t* data, uint8_t length)
{
const uint8_t msg[] = { ResponsePing, settings.getModuleIndex() };
comm.sendMsg(msg, sizeof(msg));
}
void handleDisplayModuleIndex(uint8_t* data, uint8_t length)
{
if (state == State::DisplayOff)
state = State::DisplayModuleIndex;
}
void handleStartLink(uint8_t* data, uint8_t length)
{
state = State::Linking;
}
void handleRequestLinkResponse(uint8_t* data, uint8_t length)
{
if (length == 0)
return;
if (state != State::Linking)
return;
settings.setModuleIndex(*data);
state = State::LinkingSet;
}
void handleStopLink(uint8_t* data, uint8_t length)
{
if (state == State::Linking || state == State::LinkingSet)
state = State::DisplayModuleIndex;
}
void handleSetPWM(uint8_t* data, uint8_t length)
{
if (length < 5)
return;
uint8_t flags = *data; data++;
uint16_t value1 = *(reinterpret_cast<uint16_t*>(data)); data += 2;
uint16_t value2 = *(reinterpret_cast<uint16_t*>(data)); data += 2;
pwmDriver.setPWM(0, value1);
pwmDriver.setPWM(1, value2);
if (flags & SetPWMFlagModuleLEDs)
{
pwmDriver.setPWM(2, value1);
pwmDriver.setPWM(3, value2);
}
else
{
pwmDriver.setPWM(2, 0);
pwmDriver.setPWM(3, 0);
}
const uint8_t msg[] = { ResponseSetPWM, settings.getModuleIndex() };
comm.sendMsg(msg, sizeof(msg));
}
void handleGetSensors(uint8_t* data, uint8_t length)
{
// TODO get sensor values
uint8_t sensor1 = 0;
uint8_t sensor2 = 0;
const uint8_t msg[] = { ResponseSetPWM, settings.getModuleIndex(), sensor1, sensor2 };
comm.sendMsg(msg, sizeof(msg));
}