wordclock/wordclock.ino
2019-02-13 19:27:22 +01:00

386 lines
8.1 KiB
C++

#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#include <AT24C32.h>
#include <DS3231.h>
#include <States.h>
#include <ViewStates.h>
#include <ControlStates.h>
#include <Button.h>
// debug
#define DEBUG 1
// Neopixel
#define MATRIX_PIN 12
#define MATRIX_SIZE 121
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(MATRIX_SIZE, MATRIX_PIN, NEO_GRB + NEO_KHZ800);
// Date view delimiter
#define DATE_DELIMITER '.'
// Buttons
#define LEFT_PIN 11
#define DECREMENT_PIN 10
#define ENTER_PIN 9
#define INCREMENT_PIN 8
#define RIGHT_PIN 7
Button leftBtn = Button(LEFT_PIN, LOW);
Button decrementBtn = Button(DECREMENT_PIN, LOW);
Button enterBtn = Button(ENTER_PIN, LOW);
Button incrementBtn = Button(INCREMENT_PIN, LOW);
Button rightBtn = Button(RIGHT_PIN, LOW);
// LED matrix
uint8_t matrix[MATRIX_SIZE];
// EPROMM AT24C32
AT24C32 at24c32;
// RTC DS3231
DS3231 ds3231;
// states
ControlStates controlState = ControlStates::VIEW;
ControlStates oldControlState = ControlStates::VIEW;
ViewStates viewState = ViewStates::TIME;
ViewStates oldViewState = ViewStates::TIME;
// control state
ControlState *currentControlState = new ControlViewState(at24c32);
// view state
ViewState *currentViewState = new ViewTimeState(ds3231, at24c32);
/**
setup
*/
void setup()
{
#ifdef DEBUG
Serial.begin(9600);
#endif
pixels.begin();
ds3231.begin();
at24c32.begin();
leftBtn.begin();
decrementBtn.begin();
enterBtn.begin();
incrementBtn.begin();
rightBtn.begin();
viewState = ViewStates(at24c32.read(VIEW_STATE_ADDRESS) % 6);
printStatus();
}
/**
loop
*/
void loop()
{
checkControlState();
controls();
checkViewState();
// render
renderInterval();
}
/**
check current control state and change eventually
*/
void checkControlState()
{
if (controlState != oldControlState)
{
delete currentControlState;
switch (controlState)
{
case ControlStates::VIEW:
currentControlState = new ControlViewState(at24c32);
break;
case ControlStates::TIME_HOURS:
currentControlState = new ControlTimeState(ds3231, at24c32);
break;
case ControlStates::TIME_MINUTES:
currentControlState = new ControlTimeState(ds3231, at24c32);
break;
case ControlStates::TIME_MODE:
currentControlState = new ControlTimeState(ds3231, at24c32);
break;
case ControlStates::TIME_SECONDS:
currentControlState = new ControlSecondsState(ds3231);
break;
case ControlStates::DATE_DATE:
currentControlState = new ControlDateState(ds3231);
break;
case ControlStates::DATE_MONTH:
currentControlState = new ControlDateState(ds3231);
break;
case ControlStates::DATE_YEAR:
currentControlState = new ControlDateState(ds3231);
break;
case ControlStates::COLOR_R:
currentControlState = new ControlColorState(at24c32);
break;
case ControlStates::COLOR_G:
currentControlState = new ControlColorState(at24c32);
break;
case ControlStates::COLOR_B:
currentControlState = new ControlColorState(at24c32);
break;
case ControlStates::TEXT:
currentControlState = new ControlTextState(at24c32);
break;
default:
currentControlState = new ControlViewState(at24c32);
}
oldControlState = controlState;
printStatus();
}
}
/**
check current view state and change eventually
*/
void checkViewState()
{
if (viewState != oldViewState)
{
delete currentViewState;
switch (viewState)
{
case ViewStates::TIME:
currentViewState = new ViewTimeState(ds3231, at24c32);
break;
case ViewStates::SECONDS:
currentViewState = new ViewSecondsState(ds3231, at24c32);
break;
case ViewStates::TEMPERATURE:
currentViewState = new ViewTemperatureState(ds3231, at24c32);
break;
case ViewStates::DATE:
currentViewState = new ViewDateState(ds3231, at24c32, DATE_DELIMITER);
break;
case ViewStates::TEXT:
currentViewState = new ViewTextState(at24c32);
break;
case ViewStates::LED_DEMO:
currentViewState = new ViewLEDState();
break;
default:
currentViewState = new ViewTimeState(ds3231, at24c32);
}
oldViewState = viewState;
at24c32.write(VIEW_STATE_ADDRESS, uint8_t(viewState));
printStatus();
}
}
/**
check inputs
*/
void controls()
{
leftBtn.loop(leftCallback);
decrementBtn.loop(decrementCallback);
enterBtn.loop(enterCallback);
incrementBtn.loop(incrementCallback);
rightBtn.loop(rightCallback);
}
/**
left callback
*/
void leftCallback()
{
// delegate to current control state
currentControlState->leftPressed(viewState, controlState);
#ifdef DEBUG
Serial.print(F("< "));
#endif
}
/**
decrement callback
*/
void decrementCallback()
{
// delegate to current control state
currentControlState->decrementPressed(viewState, controlState);
#ifdef DEBUG
Serial.print(F("- "));
#endif
}
/**
enter callback
*/
void enterCallback()
{
// delegate to current control state
currentControlState->enterPressed(viewState, controlState);
#ifdef DEBUG
Serial.print(F("# "));
#endif
}
/**
increment callback
*/
void incrementCallback()
{
// delegate to current control state
currentControlState->incrementPressed(viewState, controlState);
#ifdef DEBUG
Serial.print(F("+ "));
#endif
}
/**
right callback
*/
void rightCallback()
{
// delegate to current control state
currentControlState->rightPressed(viewState, controlState);
#ifdef DEBUG
Serial.print(F("> "));
#endif
}
/**
periodic rendering
*/
void renderInterval()
{
static const unsigned long REFRESH_INTERVAL = 100;
static unsigned long lastRefreshTime = 0;
if (millis() - lastRefreshTime >= REFRESH_INTERVAL)
{
lastRefreshTime += REFRESH_INTERVAL;
render();
}
}
/**
render
*/
void render()
{
// set default color
uint8_t const color = at24c32.read(COLOR_ADDRESS);
currentViewState->setColor(color);
// set brightness
uint8_t const brightness = at24c32.read(BRIGHTNESS_ADDRESS);
pixels.setBrightness(brightness);
// reset matrix (to black)
for (int i = 0; i < MATRIX_SIZE; i++)
{
matrix[i] = 0x00;
}
// render matrix
currentViewState->render(matrix, controlState);
// set pixel
for (int i = 0; i < MATRIX_SIZE; i++)
{
uint8_t const r = (matrix[i] >> 5) * 255 / 7;
uint8_t const g = ((matrix[i] >> 2) & 0x07) * 255 / 7;
uint8_t const b = (matrix[i] & 0x03) * 255 / 3;
pixels.setPixelColor(i, pixels.Color(r, g, b));
}
pixels.show();
}
/**
print current status VIEW STATE \t CONTROL STATE \t FREE RAM
*/
void printStatus()
{
#ifdef DEBUG
switch (viewState)
{
case ViewStates::TIME:
Serial.print(F("TIME"));
break;
case ViewStates::SECONDS:
Serial.print(F("SECS"));
break;
case ViewStates::TEMPERATURE:
Serial.print(F("TEMP"));
break;
case ViewStates::DATE:
Serial.print(F("DATE"));
break;
case ViewStates::TEXT:
Serial.print(F("TEXT"));
break;
case ViewStates::LED_DEMO:
Serial.print(F("LEDS"));
break;
default:
Serial.print(F("TIME"));
}
Serial.print(F("\t"));
switch (controlState)
{
case ControlStates::VIEW:
Serial.print(F("VIEW "));
break;
case ControlStates::TIME_HOURS:
Serial.print(F("HOURS"));
break;
case ControlStates::TIME_MINUTES:
Serial.print(F("MINS "));
break;
case ControlStates::TIME_MODE:
Serial.print(F("MODE "));
break;
case ControlStates::TIME_SECONDS:
Serial.print(F("SECS "));
break;
case ControlStates::DATE_DATE:
Serial.print(F("DATE "));
break;
case ControlStates::DATE_MONTH:
Serial.print(F("MONTH"));
break;
case ControlStates::DATE_YEAR:
Serial.print(F("YEAR "));
break;
case ControlStates::COLOR_R:
Serial.print(F("COLOR_R"));
break;
case ControlStates::COLOR_G:
Serial.print(F("COLOR_G"));
break;
case ControlStates::COLOR_B:
Serial.print(F("COLOR_B"));
break;
case ControlStates::TEXT:
Serial.print(F("TEXT "));
break;
default:
Serial.print(F("VIEW "));
}
extern int __heap_start, *__brkval;
int v;
Serial.print(F("\tRAM: "));
Serial.println((int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval));
#endif
}