#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "main.h" size_t qr_w = 0; uint16_t qr_img[128*128]; int qr_version = 4; int qr_scale = 3; OneButton bt_a, bt_b; void long_press_a(void); void click_a(void); void click_b(void); void update_display(void); void setup() { Serial.begin(115200); /* the thing just kept spuriously triggering. */ esp_task_wdt_deinit(); rtc_wdt_protect_off(); rtc_wdt_disable(); disableCore0WDT(); disableCore1WDT(); ledcSetup(backlightChannel, 12000, 8); ledcAttachPin(TFT_BL, backlightChannel); ledcWrite(backlightChannel, 255); tft.init(); tft.fillScreen(TFT_BLACK); bt_a.setup(0); bt_b.setup(35); struct timeval now = {1746823581}; settimeofday(&now, nullptr); SPIFFS.begin(true); tft.fillScreen(TFT_RED); QRCode qrcode; uint8_t *qr_buf = new uint8_t[qrcode_getBufferSize(qr_version)]; qrcode_initText(&qrcode, qr_buf, qr_version, ECC_LOW, "otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example"); qr_w = qrcode.size * qr_scale; for (int y=0; y 500) { display_valid = false; last_refresh = now; } if (!display_valid) { update_display(); } } void update_display() { if (ui_state == ST_INIT) { Serial.println("ST_INIT"); } else if (ui_state == ST_STANDBY) { Serial.println("ST_STANDBY"); tft.fillScreen(TFT_BLACK); } else if (ui_state == ST_SET_TIME) { Serial.println("ST_SET_TIME"); tft.fillScreen(TFT_BLACK); tft.setCursor(10, 10); time_t tt = time(nullptr); struct tm *t = localtime(&tt); char buf[128]; snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); String msg(buf); int adjusted_cursor = cursor_pos + 2; adjusted_cursor += cursor_pos / 2; if (cursor_pos < 10) { tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.print(msg.substring(0, adjusted_cursor)); tft.setTextColor(TFT_BLACK, TFT_WHITE); tft.print(msg[adjusted_cursor]); tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.print(msg.substring(adjusted_cursor+1, msg.length())); } else { tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.print(msg.substring(0, adjusted_cursor)); tft.setTextColor(TFT_BLACK, TFT_WHITE); tft.print(msg.substring(adjusted_cursor, msg.length())); } } else { tft.fillScreen(TFT_RED); } display_valid = true; } void long_press_a() { Serial.println("Long A"); if (ui_state == ST_SET_TIME) { ui_state = ST_STANDBY; display_valid = false; } else if (ui_state == ST_STANDBY) { ui_state = ST_SET_TIME; display_valid = false; } } void click_a() { Serial.println("Click A"); if (ui_state == ST_INIT) { ui_state = ST_SET_TIME; display_valid = false; } else if (ui_state == ST_SET_TIME) { cursor_pos ++; if (cursor_pos == 11) { ui_state = ST_STANDBY; cursor_pos = 0; } display_valid = false; } } bool is_leap_year(int year) { if (year % 4 == 0) { if (year % 100 == 0) { if (year % 400 == 0) { return true; } return false; } return true; } return false; } int month_length(int year, int month) { switch (month) { /* note: month is 0-indexed */ case 1: return is_leap_year(year) ? 29 : 28; case 3: return 30; case 5: return 30; case 8: return 30; case 10: return 30; default: return 31; } } void click_b() { Serial.println("Click B"); if (ui_state == ST_SET_TIME) { time_t tt = time(nullptr); struct tm *t = localtime(&tt); struct tm mod = *t; int adj = (cursor_pos%2 == 0) ? 10 : 1; switch (cursor_pos/2) { case 0: mod.tm_year += adj; if (mod.tm_year >= 2100 - 1900) mod.tm_year = 2000 - 1900; break; case 1: mod.tm_mon += adj; if (mod.tm_mon >= 12) mod.tm_mon = 0; break; case 2: mod.tm_mday += adj; if (mod.tm_mday > month_length(mod.tm_year, mod.tm_mon)) mod.tm_mday = 1; break; case 3: mod.tm_hour += adj; if (mod.tm_hour >= 24) mod.tm_hour = 0; break; case 4: mod.tm_min += adj; if (mod.tm_min >= 60) mod.tm_min = 0; break; case 5: mod.tm_sec = 0; break; } struct timeval new_tv = { .tv_sec = mktime(&mod), }; Serial.print("Old time "); Serial.print(tt); Serial.print(" new time "); Serial.print(new_tv.tv_sec); Serial.print(" cursor "); Serial.print(cursor_pos); Serial.print(" adj "); Serial.println(adj); settimeofday(&new_tv, nullptr); display_valid = false; } }