diff --git a/lib/hal/HalClock.cpp b/lib/hal/HalClock.cpp index fdd1ca4a..0264556b 100644 --- a/lib/hal/HalClock.cpp +++ b/lib/hal/HalClock.cpp @@ -377,7 +377,32 @@ void applyTimezone(uint8_t timeZoneSetting) { LOG_DBG("CLK", "Timezone applied: %s", TIMEZONES[index].tz); } -bool syncNtp() { +static const char* sntpStatusName(sntp_sync_status_t status) { + switch (status) { + case SNTP_SYNC_STATUS_RESET: + return "reset"; + case SNTP_SYNC_STATUS_IN_PROGRESS: + return "in progress"; + case SNTP_SYNC_STATUS_COMPLETED: + return "completed"; + default: + return "unknown"; + } +} + +bool syncNtp(char* errorBuf, size_t errorBufSize) { + if (errorBuf && errorBufSize > 0) { + errorBuf[0] = '\0'; + } + + if (WiFi.status() != WL_CONNECTED) { + if (errorBuf && errorBufSize > 0) { + snprintf(errorBuf, errorBufSize, "WiFi disconnected"); + } + LOG_ERR("CLK", "NTP sync failed: WiFi disconnected"); + return false; + } + time_t preSyncTime = time(nullptr); time_t prevSyncTime = nvsReadSyncTime(); float prevSyncTemp = nvsReadLastSyncTemp(); @@ -398,7 +423,11 @@ bool syncNtp() { } if (retry >= maxRetries) { - LOG_ERR("CLK", "NTP sync timeout"); + const char* statusName = sntpStatusName(sntp_get_sync_status()); + if (errorBuf && errorBufSize > 0) { + snprintf(errorBuf, errorBufSize, "NTP timeout (%s)", statusName); + } + LOG_ERR("CLK", "NTP sync timeout (%s)", statusName); return false; } @@ -453,6 +482,8 @@ bool syncNtp() { return true; } +bool syncNtp() { return syncNtp(nullptr, 0); } + void saveBeforeSleep(bool keepLpAlive) { if (!isSynced()) { return; diff --git a/lib/hal/HalClock.h b/lib/hal/HalClock.h index 976003e2..e02b68fd 100644 --- a/lib/hal/HalClock.h +++ b/lib/hal/HalClock.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -30,6 +31,10 @@ namespace HalClock { /// Returns true if the sync succeeded. bool syncNtp(); +/// Same as syncNtp(), but fills `errorBuf` with a short failure reason when +/// the sync fails. +bool syncNtp(char* errorBuf, size_t errorBufSize); + /// Apply timezone/DST rules via the POSIX TZ string for the given setting. void applyTimezone(uint8_t timeZoneSetting); diff --git a/src/activities/settings/SyncTimeActivity.cpp b/src/activities/settings/SyncTimeActivity.cpp index 6108a3c7..76d41d3b 100644 --- a/src/activities/settings/SyncTimeActivity.cpp +++ b/src/activities/settings/SyncTimeActivity.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "CrossPointSettings.h" #include "MappedInputManager.h" @@ -93,8 +94,9 @@ void SyncTimeActivity::performSync() { hadTimeBeforeSync = HalClock::isSynced(); preSyncTime = hadTimeBeforeSync ? time(nullptr) : 0; prevSyncTime = HalClock::lastSyncTime(); + syncErrorMsg[0] = '\0'; - bool ok = HalClock::syncNtp(); + bool ok = HalClock::syncNtp(syncErrorMsg, sizeof(syncErrorMsg)); if (ok && hadTimeBeforeSync) { driftSeconds = (int32_t)(time(nullptr) - preSyncTime); @@ -184,10 +186,17 @@ void SyncTimeActivity::render(RenderLock&&) { } if (state == FAILED) { - renderer.drawCenteredText(UI_10_FONT_ID, bodyRect.y + bodyRect.height / 2, tr(STR_TIME_SYNC_FAILED), true, - EpdFontFamily::BOLD); + int y = bodyRect.y + bodyRect.height / 2 - 10; + renderer.drawCenteredText(UI_10_FONT_ID, y, tr(STR_TIME_SYNC_FAILED), true, EpdFontFamily::BOLD); - const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", ""); + if (syncErrorMsg[0] != '\0') { + y += 25; + const std::string errorText = + renderer.truncatedText(UI_10_FONT_ID, syncErrorMsg, bodyRect.width, EpdFontFamily::REGULAR); + renderer.drawCenteredText(UI_10_FONT_ID, y, errorText.c_str(), true, EpdFontFamily::REGULAR); + } + + const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_RETRY), "", ""); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); renderer.displayBuffer(); return; @@ -198,6 +207,14 @@ void SyncTimeActivity::loop() { if (state == SUCCESS || state == FAILED) { if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { finish(); + return; + } + + if (state == FAILED && mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + RenderLock lock(*this); + state = SYNCING; + requestUpdateAndWait(); + performSync(); } } } diff --git a/src/activities/settings/SyncTimeActivity.h b/src/activities/settings/SyncTimeActivity.h index 08f2eecd..5198e875 100644 --- a/src/activities/settings/SyncTimeActivity.h +++ b/src/activities/settings/SyncTimeActivity.h @@ -19,6 +19,7 @@ class SyncTimeActivity final : public Activity { time_t prevSyncTime = 0; int32_t driftSeconds = 0; bool hadTimeBeforeSync = false; + char syncErrorMsg[64] = {}; void onWifiSelectionComplete(bool success); void onWifiSelectionCancelled(); void performSync();