#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_I2CDevice.h>
#include "images.h"
#define LONGPRESSTHRESHOLD 5000
#define TIME_BASEPOSITION 32
#define DATE_BASEPOSITION 48
#define X_BASEPOSITION 64
#define SERIALRATE 115200
#define USEEXPO 0
Adafruit_SSD1306 display(128, 64, &Wire, -1, 888888); // Define Display
int textSizeTime = 2;
int textSizeDate = 1;
int animState = 1, animCounter = 0;
float animProgress = 25;
bool USBSyncMode = false;
#ifdef USEEXPO
float easeInOut(float x) { return x == 0 ? 0 : powf(2, 10 * x - 10); }
#else
float easeInOut(float x) { return powf(x, 4); }
#endif
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Begin I2C Communication With Display
display.clearDisplay(); // Clear Display Buffer
display.setTextColor(SSD1306_BLACK);
display.println("READY.");
display.display(); // Display On Screen
pinMode(13, OUTPUT);
pinMode(10, INPUT);
pinMode(9, INPUT);
pinMode(8, INPUT);
updateStates();
}
tmElements_t tm;
String currTime;
float a;
int l, pl; int s, ps; int r, pr; int lr, plr;
uint32_t framec = 0;
uint32_t longPressStart = 0;
bool longPressCanStart = true;
void loop() {
updateStates();
if (!(animState == 0 && animProgress >= 26) && USBSyncMode == false) {
display.clearDisplay();
if (animState == 0) {
a = easeInOut(animProgress / 25) *32;
if (animProgress <= 25) animProgress++;
} else if (animState == 1) {
a = easeInOut(animProgress / 25) *32;
if (animProgress > 0) animProgress--;
animCounter++;
if (animCounter > 200) { animState = 0; }
}
if (RTC.read(tm)) {
display.setTextColor(SSD1306_BLACK);
display.fillRoundRect(0, a, 128, 64-(a*2), 10, SSD1306_WHITE);
currTime = DuoDigit(String(tm.Hour)) + ":" + DuoDigit(String(tm.Minute)) + ":" + DuoDigit(String(tm.Second));
display.setTextSize(textSizeTime);
display.setCursor(
X_BASEPOSITION - ((5 * textSizeTime)*(currTime.length() +1.5) / 2),
TIME_BASEPOSITION - (7*textSizeTime / 2) - (7*textSizeDate / 2)
);
display.print(currTime);
currTime = DuoDigit(String(tm.Day)) + "/" + DuoDigit(String(tm.Month)) + "/" + DuoDigit(String(tm.Year));
display.setTextSize(textSizeDate);
display.setCursor(
X_BASEPOSITION - ((5 * textSizeDate)*(currTime.length() +1) / 2),
DATE_BASEPOSITION - (7*textSizeDate / 2) - (7*textSizeTime / 2)
);
display.print(currTime);
} else {
display.drawBitmap(0, 0, warning, 72, 64, SSD1306_WHITE);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(55, 0);
if (RTC.chipPresent()) {
display.println("RTC Module");
display.setCursor(61, 10);
display.print("Has Stopped");
} else {
display.print("RTC Not");
display.setCursor(61, 10);
display.print("Detected");
}
}
display.display();
} else if (USBSyncMode) { // USB Sync Mode
display.clearDisplay();
Serial.begin(SERIALRATE);
Serial.println("\nHH:MM:SS DD/MM/YYYY");
bool Error = !RTC.read(tm);
drawUSBSyncInterface();
if (Error) display.println("RTC Error");
else display.println("Waiting for Serial...");
display.display();
if (Error) { while(!(s < ps)) updateStates(); USBSyncMode = false; }
int h = tm.Hour;
int m = tm.Minute;
int s = tm.Second;
int d = tm.Day;
int mo = tm.Month;
int y = tm.Year;
while(USBSyncMode) {
updateStates();
if (Serial.available() > 0) {
String rectime = Serial.readStringUntil('\n');
Serial.println(rectime);
display.clearDisplay();
drawUSBSyncInterface();
display.println("Select to confirm");
h = rectime.substring(0, 2).toInt();
m = rectime.substring(3, 5).toInt();
s = rectime.substring(6, 8).toInt();
d = rectime.substring(9, 11).toInt();
mo = rectime.substring(12, 14).toInt();
y = rectime.substring(15, 19).toInt();
tmElements_t tm2;
tm2.Hour = h; tm2.Minute = m; tm2.Second = s; tm2.Day = d; tm2.Month = mo; tm2.Year = y;
int unix = makeTime(tm2);
//Serial.println(unixTime);
//display.println("unix: " + String(unix));
display.println("hour: " + String(h));
display.println("minute: " + String(m));
display.println("second: " + String(s));
display.display();
}
}
} else {
if (bitRead(framec, 16) == 1) { display.display(); framec = 0; /*digitalWrite(13, !digitalRead(13)); <-- debug feature*/ }
framec++;
}
}
String DuoDigit(String v) {
return v.length() < 2 ? "0" + v : v;
}
void updateStates() {
pl = l;
ps = s;
pr = r;
plr = lr;
l = digitalRead(8);
s = digitalRead(9);
r = digitalRead(10);
lr = !l && !r;
if (s < ps && animState != 1) { animState = 1; animProgress = 25; animCounter = 0; framec = 0; }
if (plr < lr) longPressStart = millis();
else if (lr < plr) longPressCanStart = true;
if (lr && (millis() - longPressStart) > LONGPRESSTHRESHOLD && longPressCanStart) {
longPressStart = millis();
if (USBSyncMode) Serial.end();
USBSyncMode = !USBSyncMode;
longPressCanStart = false;
}
}
void drawUSBSyncInterface() {
display.drawBitmap(0, 0, usb, 48, 23, SSD1306_WHITE);
display.setTextColor(SSD1306_WHITE);
display.setCursor(52, 2); display.print("USB Sync");
display.setCursor(52, 12); display.print(SERIALRATE);
display.setCursor(0, 25);
}