147 lines
4.3 KiB
C++
147 lines
4.3 KiB
C++
|
|
#include "NtpSyncActivity.h"
|
||
|
|
|
||
|
|
#include <GfxRenderer.h>
|
||
|
|
#include <I18n.h>
|
||
|
|
#include <Logging.h>
|
||
|
|
#include <WiFi.h>
|
||
|
|
|
||
|
|
#include "ActivityResult.h"
|
||
|
|
#include "CrossPointSettings.h"
|
||
|
|
#include "MappedInputManager.h"
|
||
|
|
#include "activities/network/WifiSelectionActivity.h"
|
||
|
|
#include "components/UITheme.h"
|
||
|
|
#include "fontIds.h"
|
||
|
|
#include "util/BootNtpSync.h"
|
||
|
|
#include "util/TimeSync.h"
|
||
|
|
|
||
|
|
static constexpr unsigned long AUTO_DISMISS_MS = 5000;
|
||
|
|
|
||
|
|
void NtpSyncActivity::onWifiSelectionComplete(const bool success) {
|
||
|
|
if (!success) {
|
||
|
|
LOG_ERR("NTP", "WiFi connection failed, exiting");
|
||
|
|
finish();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
LOG_DBG("NTP", "WiFi connected, starting NTP sync");
|
||
|
|
|
||
|
|
{
|
||
|
|
RenderLock lock(*this);
|
||
|
|
state = SYNCING;
|
||
|
|
}
|
||
|
|
requestUpdateAndWait();
|
||
|
|
|
||
|
|
const bool synced = TimeSync::waitForNtpSync(8000);
|
||
|
|
|
||
|
|
{
|
||
|
|
RenderLock lock(*this);
|
||
|
|
state = synced ? SUCCESS : FAILED;
|
||
|
|
if (synced) {
|
||
|
|
successTimestamp = millis();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
requestUpdate();
|
||
|
|
|
||
|
|
if (synced) {
|
||
|
|
LOG_DBG("NTP", "Time synced successfully");
|
||
|
|
} else {
|
||
|
|
LOG_ERR("NTP", "NTP sync timed out");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void NtpSyncActivity::onEnter() {
|
||
|
|
Activity::onEnter();
|
||
|
|
|
||
|
|
BootNtpSync::cancel();
|
||
|
|
LOG_DBG("NTP", "Turning on WiFi...");
|
||
|
|
WiFi.mode(WIFI_STA);
|
||
|
|
|
||
|
|
LOG_DBG("NTP", "Launching WifiSelectionActivity...");
|
||
|
|
startActivityForResult(
|
||
|
|
std::make_unique<WifiSelectionActivity>(renderer, mappedInput),
|
||
|
|
[this](const ActivityResult& result) {
|
||
|
|
const bool success = !result.isCancelled && std::holds_alternative<WifiResult>(result.data);
|
||
|
|
onWifiSelectionComplete(success);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
void NtpSyncActivity::onExit() {
|
||
|
|
Activity::onExit();
|
||
|
|
|
||
|
|
TimeSync::stopNtpSync();
|
||
|
|
WiFi.disconnect(false);
|
||
|
|
delay(100);
|
||
|
|
WiFi.mode(WIFI_OFF);
|
||
|
|
delay(100);
|
||
|
|
}
|
||
|
|
|
||
|
|
void NtpSyncActivity::render(RenderLock&&) {
|
||
|
|
auto metrics = UITheme::getInstance().getMetrics();
|
||
|
|
const auto pageWidth = renderer.getScreenWidth();
|
||
|
|
const auto pageHeight = renderer.getScreenHeight();
|
||
|
|
|
||
|
|
renderer.clearScreen();
|
||
|
|
|
||
|
|
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, tr(STR_SYNC_CLOCK));
|
||
|
|
|
||
|
|
const auto lineHeight = renderer.getLineHeight(UI_10_FONT_ID);
|
||
|
|
const auto centerY = (pageHeight - lineHeight) / 2;
|
||
|
|
|
||
|
|
if (state == SYNCING) {
|
||
|
|
renderer.drawCenteredText(UI_10_FONT_ID, centerY, tr(STR_SYNCING_TIME));
|
||
|
|
} else if (state == SUCCESS) {
|
||
|
|
renderer.drawCenteredText(UI_10_FONT_ID, centerY, tr(STR_TIME_SYNCED), true, EpdFontFamily::BOLD);
|
||
|
|
|
||
|
|
time_t now = time(nullptr);
|
||
|
|
struct tm* t = localtime(&now);
|
||
|
|
if (t != nullptr && t->tm_year > 100) {
|
||
|
|
char timeBuf[32];
|
||
|
|
if (SETTINGS.clockFormat == CrossPointSettings::CLOCK_24H) {
|
||
|
|
snprintf(timeBuf, sizeof(timeBuf), "%02d:%02d", t->tm_hour, t->tm_min);
|
||
|
|
} else {
|
||
|
|
int hour12 = t->tm_hour % 12;
|
||
|
|
if (hour12 == 0) hour12 = 12;
|
||
|
|
snprintf(timeBuf, sizeof(timeBuf), "%d:%02d %s", hour12, t->tm_min, t->tm_hour >= 12 ? "PM" : "AM");
|
||
|
|
}
|
||
|
|
renderer.drawCenteredText(UI_10_FONT_ID, centerY + lineHeight + metrics.verticalSpacing, timeBuf);
|
||
|
|
}
|
||
|
|
|
||
|
|
const unsigned long elapsed = millis() - successTimestamp;
|
||
|
|
const int remaining = static_cast<int>((AUTO_DISMISS_MS - elapsed + 999) / 1000);
|
||
|
|
char backLabel[32];
|
||
|
|
snprintf(backLabel, sizeof(backLabel), "%s (%d)", tr(STR_BACK), remaining > 0 ? remaining : 1);
|
||
|
|
const auto labels = mappedInput.mapLabels(backLabel, "", "", "");
|
||
|
|
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||
|
|
} else if (state == FAILED) {
|
||
|
|
renderer.drawCenteredText(UI_10_FONT_ID, centerY, tr(STR_SYNC_FAILED_MSG), true, EpdFontFamily::BOLD);
|
||
|
|
|
||
|
|
const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", "");
|
||
|
|
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||
|
|
}
|
||
|
|
|
||
|
|
renderer.displayBuffer();
|
||
|
|
}
|
||
|
|
|
||
|
|
void NtpSyncActivity::loop() {
|
||
|
|
if (state == SUCCESS) {
|
||
|
|
const unsigned long elapsed = millis() - successTimestamp;
|
||
|
|
if (mappedInput.wasPressed(MappedInputManager::Button::Back) || elapsed >= AUTO_DISMISS_MS) {
|
||
|
|
finish();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const int currentSecond = static_cast<int>(elapsed / 1000);
|
||
|
|
if (currentSecond != lastCountdownSecond) {
|
||
|
|
lastCountdownSecond = currentSecond;
|
||
|
|
requestUpdate();
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (state == FAILED) {
|
||
|
|
if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
|
||
|
|
finish();
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|