diff --git a/zephcore/CMakeLists.txt b/zephcore/CMakeLists.txt index 6d5f9d5..13234b0 100644 --- a/zephcore/CMakeLists.txt +++ b/zephcore/CMakeLists.txt @@ -430,6 +430,7 @@ target_sources(app PRIVATE adapters/sensors/ZephyrEnvSensors.cpp helpers/AdvertDataHelpers.cpp helpers/oled_power.c + helpers/time_sync.c ) # ========== Radio Driver Selection ========== diff --git a/zephcore/app/CompanionMesh.cpp b/zephcore/app/CompanionMesh.cpp index ccf8fc8..d40f3ee 100644 --- a/zephcore/app/CompanionMesh.cpp +++ b/zephcore/app/CompanionMesh.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #if IS_ENABLED(CONFIG_ZEPHCORE_UI_DESIGN_BUTTON) || IS_ENABLED(CONFIG_ZEPHCORE_UI_DESIGN_JOYSTICK) #include #define ZEPHCORE_HAS_UI_TASK 1 @@ -2239,6 +2241,7 @@ bool CompanionMesh::handleProtocolFrame(const uint8_t *data, size_t len) // Arduino: only allow setting time forward (prevents time attacks) if (secs >= curr) { getRTCClock()->setCurrentTime(secs); + time_sync_report(TIME_SYNC_APP); sendPacketOk(); } else { sendPacketError(ERR_ILLEGAL_ARG); diff --git a/zephcore/app/RepeaterMesh.cpp b/zephcore/app/RepeaterMesh.cpp index 3fd3ed2..f0b8c25 100644 --- a/zephcore/app/RepeaterMesh.cpp +++ b/zephcore/app/RepeaterMesh.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ static void uplink_time_sync_cb(uint32_t unix_ts) { if (s_uplink_mesh) { s_uplink_mesh->getRTCClock()->setCurrentTime(unix_ts); + time_sync_report(TIME_SYNC_WIFI); } } #endif diff --git a/zephcore/app/main_observer.cpp b/zephcore/app/main_observer.cpp index 2f78646..e4b6a5f 100644 --- a/zephcore/app/main_observer.cpp +++ b/zephcore/app/main_observer.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #define CLI_REPLY_SIZE 256 @@ -222,6 +222,7 @@ static mesh::ZephyrRTCClock s_rtc_clock; static void time_sync_cb(uint32_t unix_ts) { s_rtc_clock.setCurrentTime(unix_ts); + time_sync_report(TIME_SYNC_WIFI); LOG_INF("RTC synced from SNTP: %u", unix_ts); } diff --git a/zephcore/helpers/CommonCLI.cpp b/zephcore/helpers/CommonCLI.cpp index 9fcccc4..03fef0d 100644 --- a/zephcore/helpers/CommonCLI.cpp +++ b/zephcore/helpers/CommonCLI.cpp @@ -4,6 +4,7 @@ */ #include "CommonCLI.h" +#include #include #include #include @@ -327,6 +328,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch uint32_t curr = getRTCClock()->getCurrentTime(); if (sender_timestamp > curr) { getRTCClock()->setCurrentTime(sender_timestamp + 1); + time_sync_report(TIME_SYNC_CLI); uint32_t now = getRTCClock()->getCurrentTime(); time_t t = (time_t)now; struct tm *tm = gmtime(&t); @@ -346,6 +348,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch uint32_t curr = getRTCClock()->getCurrentTime(); if (secs > curr) { getRTCClock()->setCurrentTime(secs); + time_sync_report(TIME_SYNC_CLI); time_t t = (time_t)secs; struct tm *tm = gmtime(&t); snprintf(reply, CLI_REPLY_SIZE, "OK - clock set: %02d:%02d - %d/%d/%d UTC", diff --git a/zephcore/helpers/time_sync.c b/zephcore/helpers/time_sync.c new file mode 100644 index 0000000..a503e89 --- /dev/null +++ b/zephcore/helpers/time_sync.c @@ -0,0 +1,45 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "time_sync.h" +#include +#include + +static enum time_sync_source s_last = TIME_SYNC_NONE; + +static const char *source_short_name(enum time_sync_source src) +{ + switch (src) { + case TIME_SYNC_GPS: return "GPS"; + case TIME_SYNC_APP: return "App"; + case TIME_SYNC_WIFI: return "WiFi"; + case TIME_SYNC_CLI: return "CLI"; + default: return NULL; + } +} + +void time_sync_report(enum time_sync_source src) +{ + s_last = src; +} + +const char *time_sync_display_label(void) +{ + if (gps_has_time_sync()) { + return "GPS"; + } + + const char *src = source_short_name(s_last); + if (!src) { + return "None"; + } + + if (s_last != TIME_SYNC_GPS) { + return src; + } + + static char label[20]; + snprintf(label, sizeof(label), "Local (%s)", src); + return label; +} diff --git a/zephcore/helpers/time_sync.h b/zephcore/helpers/time_sync.h new file mode 100644 index 0000000..86c1719 --- /dev/null +++ b/zephcore/helpers/time_sync.h @@ -0,0 +1,28 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Track which source last set the RTC for UI display. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +enum time_sync_source { + TIME_SYNC_NONE = 0, + TIME_SYNC_GPS, + TIME_SYNC_APP, + TIME_SYNC_WIFI, + TIME_SYNC_CLI, +}; + +/** Record a successful RTC set from @p src. */ +void time_sync_report(enum time_sync_source src); + +/** Label for System > Info > Time. GPS authority wins while gps_has_time_sync(). */ +const char *time_sync_display_label(void); + +#ifdef __cplusplus +} +#endif diff --git a/zephcore/helpers/ui-joystick/screens/system.cpp b/zephcore/helpers/ui-joystick/screens/system.cpp index 457b34b..4ccd44a 100644 --- a/zephcore/helpers/ui-joystick/screens/system.cpp +++ b/zephcore/helpers/ui-joystick/screens/system.cpp @@ -8,6 +8,7 @@ #include "../joystick_ui_task.h" #include "screen_helpers.h" #include +#include #include #include #include @@ -303,7 +304,7 @@ int SystemTimeScreen::render(JoystickDisplay &display) const char *labels[4] = { "Time:", "Date:", "TZ:", "Source:" }; const char *values[4] = { timeText, dateText, "UTC", - _task->getGPSState() ? "GPS" : "App" }; + time_sync_display_label() }; int y = kContentY + 2; for (int i = 0; i < 4; i++) { display.setColor(JoystickDisplay::GREEN); diff --git a/zephcore/src/main_companion.cpp b/zephcore/src/main_companion.cpp index d056a6e..dcb16e7 100644 --- a/zephcore/src/main_companion.cpp +++ b/zephcore/src/main_companion.cpp @@ -23,6 +23,7 @@ LOG_MODULE_REGISTER(zephcore_main, CONFIG_ZEPHCORE_MAIN_LOG_LEVEL); #include #include #include +#include #include "ui_task.h" #include "ui_mesh_actions.h" #include "oled_power.h" @@ -461,6 +462,7 @@ static void gps_fix_callback(double lat, double lon, int64_t utc_time) if (utc_time > 0) { LOG_INF("GPS fix: RTC sync time=%lld", utc_time); rtc_clock.setCurrentTime((uint32_t)utc_time); + time_sync_report(TIME_SYNC_GPS); } #ifdef ZEPHCORE_LORA diff --git a/zephcore/src/main_repeater.cpp b/zephcore/src/main_repeater.cpp index a1a55b0..64f1500 100644 --- a/zephcore/src/main_repeater.cpp +++ b/zephcore/src/main_repeater.cpp @@ -41,6 +41,7 @@ extern "C" void bt_ctlr_assert_handle(char *file, uint32_t line) #include #include #include +#include #include /* UI subsystem (display, buttons, buzzer) */ @@ -261,6 +262,7 @@ static void gps_fix_callback(double lat, double lon, int64_t utc_time) if (utc_time > 0) { LOG_INF("GPS fix: RTC sync time=%lld", utc_time); rtc_clock.setCurrentTime((uint32_t)utc_time); + time_sync_report(TIME_SYNC_GPS); } int lat_deg = (int)lat;