#include "apps.h" #include "os_gfx.h" #include "os_status.h" #include "sys_time.h" #include #include #include "esp_timer.h" static uint8_t s_view_mode = 0; static const char *const s_days[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"}; static const char *const s_months[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; static void clock_init(void) { s_view_mode = 0; } static void clock_enter(void) { } static void clock_update(uint32_t delta_ms) { sys_status_t status; sys_status_get(&status); sys_gfx_draw_status_bar(&status); struct tm tm_info; bool is_synced = sys_time_get_local(&tm_info); uint32_t sec, min, hrs; if (is_synced) { sec = tm_info.tm_sec; min = tm_info.tm_min; hrs = tm_info.tm_hour; } else { sec = status.uptime_sec % 60; min = (status.uptime_sec / 60) % 60; hrs = (status.uptime_sec / 3600); } char time_str[32]; char sub_str[48]; if (s_view_mode == 0) { // Mode 0: Digital Clock (HH:MM:SS) + Date / Status snprintf(time_str, sizeof(time_str), "%02lu:%02lu:%02lu", (unsigned long)hrs, (unsigned long)min, (unsigned long)sec); sys_gfx_draw_str_5x7(12, 11, time_str, COLOR_WHITE); if (is_synced) { int wday = tm_info.tm_wday % 7; int mon = tm_info.tm_mon % 12; int mday = tm_info.tm_mday % 100; int year = (tm_info.tm_year + 1900) % 100; snprintf(sub_str, sizeof(sub_str), "%s %02d-%s-%02d", s_days[wday], mday, s_months[mon], year); sys_gfx_draw_str_3x5(9, 21, sub_str, COLOR_WHITE); } else { snprintf(sub_str, sizeof(sub_str), "NTP: WAITING..."); sys_gfx_draw_str_3x5(8, 21, sub_str, COLOR_WHITE); } sys_gfx_draw_progress_bar(4, 27, 64, 4, (uint8_t)((sec * 100) / 59)); sys_gfx_draw_action_bar("C:MODE", "H:HOME"); } else if (s_view_mode == 1) { // Mode 1: Large Minimalist Time (HH:MM) + Seconds + Date snprintf(time_str, sizeof(time_str), "%02lu:%02lu", (unsigned long)hrs, (unsigned long)min); sys_gfx_draw_str_5x7(16, 13, time_str, COLOR_WHITE); sys_gfx_draw_str_5x7(17, 13, time_str, COLOR_WHITE); // Bold effect char sec_str[16]; snprintf(sec_str, sizeof(sec_str), ":%02lu", (unsigned long)sec); sys_gfx_draw_str_3x5(49, 14, sec_str, COLOR_WHITE); if (is_synced) { int wday = tm_info.tm_wday % 7; int mon = tm_info.tm_mon % 12; int mday = tm_info.tm_mday % 100; snprintf(sub_str, sizeof(sub_str), "%s %02d %s", s_days[wday], mday, s_months[mon]); sys_gfx_draw_str_3x5(14, 23, sub_str, COLOR_WHITE); } else { snprintf(sub_str, sizeof(sub_str), "UP:%luh %lum (SYNC..)", (unsigned long)hrs, (unsigned long)min); sys_gfx_draw_str_3x5(4, 23, sub_str, COLOR_WHITE); } sys_gfx_draw_action_bar("C:MODE", "H:HOME"); } else { // Mode 2: Detailed System Clock & Telemetry Diagnostics if (is_synced) { snprintf(sub_str, sizeof(sub_str), "TIME:%02lu:%02lu:%02lu", (unsigned long)hrs, (unsigned long)min, (unsigned long)sec); sys_gfx_draw_str_3x5(3, 10, sub_str, COLOR_WHITE); int year = (tm_info.tm_year + 1900) % 10000; int mon = (tm_info.tm_mon + 1) % 100; int mday = tm_info.tm_mday % 100; snprintf(sub_str, sizeof(sub_str), "DATE:%04d-%02d-%02d", year, mon, mday); sys_gfx_draw_str_3x5(3, 17, sub_str, COLOR_WHITE); } else { snprintf(sub_str, sizeof(sub_str), "NTP: NOT SYNCED"); sys_gfx_draw_str_3x5(3, 10, sub_str, COLOR_WHITE); snprintf(sub_str, sizeof(sub_str), "HEAP:%lu KB", (unsigned long)(status.free_heap / 1024)); sys_gfx_draw_str_3x5(3, 17, sub_str, COLOR_WHITE); } uint32_t up_sec = status.uptime_sec % 60; uint32_t up_min = (status.uptime_sec / 60) % 60; uint32_t up_hrs = (status.uptime_sec / 3600); snprintf(sub_str, sizeof(sub_str), "UP: %02lu:%02lu:%02lu", (unsigned long)up_hrs, (unsigned long)up_min, (unsigned long)up_sec); sys_gfx_draw_str_3x5(3, 24, sub_str, COLOR_WHITE); sys_gfx_draw_action_bar("C:MODE", "H:HOME"); } } static void clock_handle_input(input_action_t action) { if (action == INPUT_ACTION_CLICK) { s_view_mode = (s_view_mode + 1) % 3; } else if (action == INPUT_ACTION_LONG_PRESS) { sys_gfx_show_toast("Mode Saved", 600); } } static void clock_exit(void) { } const sys_app_t g_app_clock = { .id = "clock", .name = "Clock", .init = clock_init, .enter = clock_enter, .update = clock_update, .handle_input = clock_handle_input, .exit = clock_exit, };