#include #include #include #include #include #include #include #include // 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 }