50#include "freertos/FreeRTOS.h"
51#include "freertos/task.h"
52#include "freertos/semphr.h"
203 if (rssi > -50) bars = 4;
204 else if (rssi > -60) bars = 3;
205 else if (rssi > -70) bars = 2;
208 uint16_t fg = inverted ? EPD_WHITE : EPD_BLACK;
214 for (
int i = 0; i < 4; i++) {
215 int barHeight = 4 + i * 3;
216 int bx = x + i * (barWidth + gap);
217 int by = baseY - barHeight;
220 gfx->fillRect(bx, by, barWidth, barHeight, fg);
222 gfx->drawRect(bx, by, barWidth, barHeight, fg);
239 if (active == last)
return;
255 bool present =
s_deps.power->isBatteryPresent();
256 uint32_t nowMs =
static_cast<uint32_t
>(esp_timer_get_time() / 1000ULL);
271 if (!present)
return;
287 const bool usbConnected =
s_deps.power->isUsbConnected();
293 const bool wifiConnected = wifi && wifi->isConnected();
296 const bool bleEnabled = ble && ble->isEnabled();
298 const bool backgroundPlugin =
314 if (!
s_deps.keypad)
return;
325 time_t now = time(
nullptr);
326 struct tm* t = localtime(&now);
331 snprintf(buf,
sizeof(buf),
"%02d:%02d", t->tm_hour, t->tm_min);
333 snprintf(buf,
sizeof(buf),
"%02d.%02d.%04d", t->tm_mday, t->tm_mon + 1, t->tm_year + 1900);
361 if (
pm.hasDuressPin() &&
pm.isDuressPin(pin)) {
364 return pm.verifyBadgePin(pin);
410 if (
pm.activePluginPreventsSleep()) {
416 pm.requestStopActivePlugin();
436 while (stack.hasModal()) stack.hideModal();
437 while (stack.depth() > 1) stack.pop();
481 return static_cast<uint8_t
>(ble && ble->isEnabled() ?
'*' : 0);
553 IView* view = item.getView();
588 IView* view = item.getView();
646 auto addLanguage = [&](
const char* code) {
656 for (
const auto& lang : i18n.availableOverlayLanguages()) {
657 addLanguage(lang.code.c_str());
706 bool dropped =
false;
718 if (ble) ble->respondToNumericComparison(connHandle,
false);
727 if (ble) ble->respondToNumericComparison(connHandle,
false);
746 if (!req.
valid)
return;
750 if (ble) ble->respondToNumericComparison(req.
connHandle,
false);
781 s_deps.keypad->setLongPressEnabled(
true, 800);
783 char keyChar =
static_cast<char>(key);
786 s_deps.keypad->setPanicChordCallback([]() {
797 if (nvs_open(
"display", NVS_READONLY, &nvs) == ESP_OK) {
799 if (nvs_get_str(nvs,
"name", buf, &len) == ESP_OK && len > 1) {
806 if (nvs_get_str(nvs,
"info", buf, &len) == ESP_OK && len > 1) {
813 if (nvs_get_str(nvs,
"info2", buf, &len) == ESP_OK && len > 1) {
839 time_t now = time(
nullptr);
840 struct tm* t = localtime(&now);
843 snprintf(buf,
sizeof(buf),
"%02d:%02d", t->tm_hour, t->tm_min);
845 snprintf(buf,
sizeof(buf),
"%02d.%02d.%04d", t->tm_mday, t->tm_mon + 1, t->tm_year + 1900);
858 if (
s_deps.power->isUsbConnected()) {
902 uint16_t currentBrightness =
s_deps.display ?
s_deps.display->getBacklight() / 10 : 50;
910 uint16_t currentSleepMin = 0;
912 currentSleepMin =
static_cast<uint16_t
>(
s_deps.sleep->getLightSleepInterval() / 60);
922 int8_t currentTz = rtcTz ? rtcTz->getTimezoneOffset() : 0;
923 uint16_t tzSliderValue =
static_cast<uint16_t
>(currentTz + 12);
935 time_t now = time(
nullptr);
936 struct tm* tm = localtime(&now);
939 tm ? tm->tm_mday : 1,
940 tm ? tm->tm_mon + 1 : 1,
941 tm ? tm->tm_year + 1900 : 2026);
946 tm ? tm->tm_hour : 12,
947 tm ? tm->tm_min : 0);
999 if (strcmp(field,
"name") == 0) {
1002 }
else if (strcmp(field,
"info") == 0) {
1005 }
else if (strcmp(field,
"info2") == 0) {
1013 time_t now = time(
nullptr);
1014 struct tm* tm = localtime(&now);
1017 snprintf(buf,
sizeof(buf),
"%02d:%02d", tm->tm_hour, tm->tm_min);
1019 snprintf(buf,
sizeof(buf),
"%02d.%02d.%d", tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900);
1061 while (stack.hasModal()) {
1064 while (stack.depth() > 1) {
1074 for (
int i = 0; i < 50 &&
s_deps.display->isBusy(); ++i) {
1075 vTaskDelay(pdMS_TO_TICKS(20));
1077 s_deps.display->backlightOff();
1105 if (!
s_deps.keypad->anyKeyDown()) {
1111 char keyChar =
static_cast<char>(key);
1121 nowMs =
static_cast<uint32_t
>(esp_timer_get_time() / 1000ULL);
Main-menu entry "Plugins" - lists all installed WASM plugins.
Discovers, loads, runs and unloads WASM plugins on the badge.
Shared RAII wrappers for firmware resources.
static EventBus & instance()
Returns singleton event-bus instance.
static constexpr uint32_t eventMask(EventType type)
uint8_t subscribe(EventHandler handler, uint32_t mask=0)
Subscribes an event handler with optional type mask.
void dispatchUnlock()
Dispatches unlock lifecycle event to started modules.
static ModuleRegistry & instance()
Returns the singleton module registry instance.
void dispatchLock()
Dispatches lock lifecycle event to started modules.
RAII wrapper for a FreeRTOS semaphore / mutex.
static constexpr uint8_t BADGE_PIN_MAX
static constexpr uint8_t BADGE_PIN_MIN
static PinManager & instance()
Returns singleton PIN manager instance.
bool setDuressPin(const char *pin)
Sets the duress PIN, arming the self-destruct trigger.
bool init()
Initializes PIN state from secure storage or defaults.
static TropicSlotMap & instance()
Returns singleton Tropic slot-map instance.
const char * errorMessage() const
bool hasBackgroundPlugin() const noexcept
True if at least one plugin is currently resident in the background slot.
static PluginManager & instance() noexcept
void reloadActiveLangOverlay()
static void setTextCallback(TextChangeCallback callback)
Sets the callback used by text-setting commands.
static void setTimeCallback(TimeChangeCallback callback)
Sets the callback invoked after successful date/time updates.
static I18n & instance()
Singleton accessor.
void setOnLanguageChanged(LanguageChangedCallback cb)
bool setLanguageCode(const char *code)
Set the active language by code.
bool init()
Initialize and load persisted language code from NVS.
void checkLockScreenSleep(uint32_t nowMs)
Evaluates whether lock-screen light sleep should be entered.
static SleepManager & instance()
Returns singleton sleep manager instance.
void resetTimer(uint32_t nowMs)
Resets lock-screen sleep timer using explicit timestamp.
void init(hal::ISleepController *sleep, hal::IPowerManager *power, LockScreenView *lockScreen)
Initializes sleep-manager dependencies and state.
void setInactivityTimeout(InactivityCallback callback, uint32_t timeoutMs)
void dispatchLongPress(char key)
void replace(IView *view, void *context=nullptr)
void dispatchKey(char key)
void dispatchTick(uint32_t nowMs)
void render(bool synchronous=false)
Render current view (and modal if present) and flush to display.
static ViewStack & instance()
Returns singleton view-stack instance.
void showModal(IView *modal)
void checkInactivity(uint32_t nowMs)
void push(IView *view, void *context=nullptr)
void resetInactivityTimer()
void selfDestruct()
Triggers a full factory wipe on the next boot and restarts.
IWifiController * getWifiControllerInstance()
Returns the singleton Wi-Fi controller service instance.
IBluetoothController * getBluetoothControllerInstance()
Returns singleton Bluetooth stub when NimBLE is unavailable.
IRtc * getRtcInstance()
Returns the singleton RTC service instance.
void onPinChangeComplete(bool success)
Handles completion of PIN-change flow.
void saveDisplayField(const char *key, const char *value)
Saves one display text field to NVS.
void onBrightnessChange(uint16_t value)
Applies backlight preview without persisting.
uint16_t brightnessStepCallback(uint16_t current, bool increasing)
Returns adaptive brightness step size.
void onBrightnessSave(uint16_t value)
Persists and applies selected backlight value.
void processPendingBadgeText()
Processes the next pending badge-text wizard step.
void onDateConfirm(uint8_t day, uint8_t month, uint16_t year)
Applies confirmed date to system time.
void startBadgeTextEdit()
Starts badge-text editing wizard.
void onTimeConfirm(uint8_t hour, uint8_t minute)
Applies confirmed time to system clock.
void onTimezoneSave(uint16_t value)
Saves timezone offset and refreshes lock-screen clock.
void init(hal::IDisplay *display, hal::ISleepController *sleep, LockScreenView *lockScreen)
Initializes shared dependencies used by the settings handlers.
void onSleepIntervalSave(uint16_t value)
Saves lock-screen sleep interval in minutes.
Centralized key-code constants for cdc_views.
static bool s_lastUsbConnected
Last known status-icon inputs to avoid redundant updates.
const char * tr(const char *key)
Look up a translation by string key.
static uint16_t s_languageCount
static void performAntiBlockLock()
Anti-block instant lock: force the badge into a clean locked state.
static void updateStatusIcon(StatusIcon icon, bool active, bool &last)
Updates a single boolean-driven status icon on the lock screen.
static constexpr uint8_t TOOLS_FIXED_COUNT
static std::atomic< bool > s_antiBlockLockRequested
static const FixedMenuEntry kToolsFixed[]
static constexpr uint16_t MAX_LANGUAGES
Upper bound on languages shown in the picker (English + overlay files).
static LockScreenView * s_lockScreen
Static UI state and lazily constructed view pointers.
static uint8_t s_mainMenuPluginCount
static ListItem s_languageItems[MAX_LANGUAGES]
Language menu backing storage (filled dynamically from overlay files).
static BlePairingPromptView * s_pairingPrompt
void showDuressPinSetup()
Opens the duress / self-destruct PIN setup wizard.
static ListView * s_languageMenu
static ListView * s_toolsMenu
void prepareForBootloaderReset()
Puts the badge into a quiet pre-reset state.
static UiDeps s_deps
Runtime dependencies provided during ui_init.
static uint8_t getSettingsIndex()
Returns main-menu index of the fixed "Settings" item.
static bool s_lastBatteryPresent
static bool s_lastWifiConnected
static ListItem s_mainMenuItems[MAIN_MENU_MAX_ITEMS]
Main-menu backing storage for module and fixed menu entries.
static PinChangeView * s_pinChangeView
static bool s_lastBackgroundPlugin
static void onLanguageSelect(uint16_t index, void *userData)
Handles language-menu item selection.
static void clearKeypadBuffer()
Drains buffered keypad events.
static constexpr uint8_t TOOLS_MAX_ITEMS
static uint32_t s_lastBatterySampleMs
static void onSettingsSelect(uint16_t index, void *userData)
Handles settings-menu item selection.
static constexpr uint32_t INACTIVITY_TIMEOUT_MS
static int8_t s_lastMinute
Last rendered minute for lock-screen clock throttling.
void rebuildToolsMenu()
Rebuilds tools menu entries including dynamic module tools.
SettingsMenuIdx
Index enum for the fixed settings menu.
@ SETTINGS_IDX_AUTO_SLEEP
@ SETTINGS_IDX_BRIGHTNESS
@ SETTINGS_IDX_CHANGE_PIN
@ SETTINGS_IDX_BADGE_TEXT
static cdc::plugin_manager::PluginListView * s_pluginListView
void ui_rebuild_menus()
Rebuilds dynamic UI menus.
static char s_languageCodes[MAX_LANGUAGES][8]
static ListView * s_mainMenu
void rebuildMainMenu()
Rebuilds main menu entries including dynamically provided modules.
static bool onDuressPinSet(const char *currentPin, const char *newPin)
PinChangeView change-callback for the duress-PIN setup flow.
static SemaphoreHandle_t s_blePendingMutex
void onModuleErrorEvent(const core::Event &evt)
Displays toast notification for module error events.
static PinEntryView * s_pinEntry
void showToastAlertSticky(const char *message)
Shows a non-dismissible alert toast.
void showExpertMenu()
Shows expert menu and initial warning toast.
static void rebuildLanguageMenu()
Rebuilds the language picker from the overlay files present.
static PinChangeView * s_duressPinView
static PendingPairing s_pendingPairing
static void updateBatteryIndicator()
Updates the battery percentage indicator on the lock screen.
static void updateLockScreenClock()
Updates lock-screen clock/date once per minute while lock screen is visible.
static bool onPinVerify(const char *pin)
Verifies entered PIN via PinManager.
static void onUnlockRequested()
Starts unlock flow from lock screen.
void registerBackupSerialCommand()
Registers the AUTH-gated BACKUP serial command.
static bool s_ignoreKeyUntilRelease
Prevents stale key events directly after unlock transition.
void msgTransferUiProcess(uint32_t nowMs)
void showWifiMainMenu()
Shows top-level Wi-Fi menu and reloads stored configuration.
static uint8_t getMainMenuCount()
Returns effective main-menu item count including fixed entries.
static void onBlePairingRequestEvent(const core::Event &evt)
Main-task handler for a deferred numeric-comparison pairing request.
void ui_process(uint32_t nowMs)
Main UI tick: input processing, timeouts, status updates, and rendering.
static void onMainMenuSelect(uint16_t index, void *userData)
Handles main-menu item selection.
static void onToolsSelect(uint16_t index, void *userData)
Handles tools-menu item selection.
static ListView * s_settingsMenu
void drawSignalBars(Gdey029T94 *gfx, int x, int y, int8_t rssi, bool inverted)
Draws RSSI signal bars using the shared lock-screen visual style.
static bool s_lastBleEnabled
static void onBleNumericComparison(uint16_t connHandle, uint32_t passkey)
Numeric-comparison pairing request, invoked on the nimble_host task.
static SliderView * s_timezoneSlider
void showBluetoothMenu()
Shows top-level Bluetooth menu.
void ui_init(const UiDeps &deps)
Initializes App UI, builds all core views, and wires callbacks.
static void rebuildMenuLabels()
Rebuilds labels for translatable menus after language change.
void updatePowerStatusIcons()
Synchronizes lock-screen status icons with current hardware state.
static SliderView * s_brightnessSlider
static uint8_t toolsBluetoothIcon()
static core::ModuleMenuItem s_mainMenuModuleItems[MAIN_MENU_MAX_ITEMS]
static ListItem s_settingsItems[SETTINGS_IDX_COUNT]
Settings menu backing storage.
static TimeInputView * s_timeInput
static void onPinSuccess()
Handles successful unlock and transitions to main menu.
static constexpr uint32_t BATTERY_SAMPLE_INTERVAL_MS
static SliderView * s_sleepSlider
static uint8_t getToolsIndex()
Returns main-menu index of the fixed "Tools" item.
static core::ModuleMenuItem s_toolsModuleItems[TOOLS_MAX_ITEMS]
void ui_on_modules_ready()
Refreshes module-backed menus once module startup is complete.
static void onInactivityTimeout()
Callback invoked when inactivity timeout is reached.
static ListItem s_toolsItems[TOOLS_MAX_ITEMS]
Tools-menu backing storage for fixed and module entries.
static uint8_t s_toolsModuleCount
static DateInputView * s_dateInput
static uint8_t getPluginsIndex()
Returns main-menu index of the fixed "Plugins" item.
bool isBadgeLocked()
Returns whether the badge is currently locked (showing lock screen with no menu above).
static bool s_lastCharging
static constexpr uint8_t MAIN_MENU_MAX_ITEMS
Menu sizing and inactivity timeout constants.