CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
SleepManager.cpp
Go to the documentation of this file.
3#include "cdc_ui/ViewStack.h"
6#include "cdc_hal/IDisplay.h"
7#include "cdc_core/EventBus.h"
8#include "cdc_log.h"
9#include "esp_timer.h"
10#include <ctime>
11#include <cstdio>
12#include <cstring>
13
14static const char* TAG = "SleepMgr";
15
16namespace cdc::ui {
17
22
27SleepManager& SleepManager::instance() {
28 static SleepManager s_instance;
29 return s_instance;
30}
31
40 sleep_ = sleep;
41 power_ = power;
42 lockScreen_ = lockScreen;
43 lockScreenEnteredMs_ = 0;
44 inLightSleep_ = false;
45}
46
52void SleepManager::resetTimer(uint32_t nowMs) {
53 lockScreenEnteredMs_ = nowMs;
54}
55
61 lockScreenEnteredMs_ = esp_timer_get_time() / 1000;
62}
63
70 // Only on lock screen (depth == 1)
71 if (ViewStack::instance().depth() != 1) return;
72 if (!lockScreen_) return;
73
74 // Initialize timer if needed
75 if (lockScreenEnteredMs_ == 0) {
76 lockScreenEnteredMs_ = nowMs;
77 return;
78 }
79
80 // Skip if USB connected (keep device responsive)
81 if (power_ && power_->isUsbConnected()) {
82 lockScreenEnteredMs_ = nowMs; // Reset timer
83 // Remove light sleep icon if shown
84 if ((lockScreen_->getStatusIcons() & StatusIcon::LIGHT_SLEEP) != StatusIcon::NONE) {
85 lockScreen_->removeStatusIcon(StatusIcon::LIGHT_SLEEP);
86 }
87 return;
88 }
89
90 // Skip if sleep is inhibited (caffeinated mode)
91 if (isSleepInhibited()) {
92 lockScreenEnteredMs_ = nowMs; // Reset timer
93 return;
94 }
95
96 // Check timeout
97 uint32_t elapsed = nowMs - lockScreenEnteredMs_;
98 if (elapsed >= LIGHT_SLEEP_TIMEOUT_MS) {
99 enterLockScreenSleep();
100 }
101}
102
107void SleepManager::enterLockScreenSleep() {
108 if (!lockScreen_ || !sleep_) return;
109
110 auto& bus = cdc::core::EventBus::instance();
112 bus.process();
113
115 inLightSleep_ = true;
116
117 // Render the icon synchronously so the full SPI command/data stream reaches
118 // the panel before light sleep halts the chip; otherwise an in-flight
119 // refresh is frozen mid-transfer and the panel is left half-rendered.
121
122 // Light-sleep loop: timer wakeups refresh the clock and re-enter sleep at
123 // constant stack depth; a key/USB/unknown wakeup exits the loop.
124 do {
125 sleep_->enterLightSleep();
126 } while (handleWakeup());
127}
128
134bool SleepManager::handleWakeup() {
135 if (!sleep_ || !lockScreen_) return false;
136
137 // Immediately ensure backlight is off after wakeup to prevent glitches
138 // (LEDC may briefly show wrong state after light sleep)
140 if (display && !display->isBacklightOn()) {
141 display->backlightOff();
142 }
143
144 hal::WakeupSource source = sleep_->getWakeupSource();
145
146 if (source == hal::WakeupSource::GPIO) {
147 // Key press wakeup - user interaction
148 lockScreen_->removeStatusIcon(StatusIcon::LIGHT_SLEEP);
149 lockScreenEnteredMs_ = esp_timer_get_time() / 1000; // Reset timer
150 inLightSleep_ = false;
151
152 // Update status icons (battery, USB, etc.)
154
155 // Force display refresh
156 lockScreen_->markDirty();
157 return false;
158
159 } else if (source == hal::WakeupSource::TIMER) {
160 // Timer wakeup - just update clock, keep icon, go back to sleep
161 time_t now = time(nullptr);
162 struct tm* tm = localtime(&now);
163 if (tm) {
164 char buf[40];
165 snprintf(buf, sizeof(buf), "%02d:%02d", tm->tm_hour, tm->tm_min);
166 lockScreen_->setClock(buf);
167 snprintf(buf, sizeof(buf), "%02d.%02d.%04d", tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900);
168 lockScreen_->setDate(buf);
169 }
170
171 // Update power icons
173
174 // Render clock update synchronously so the panel update completes
175 // before the caller re-enters light sleep. The lock screen declares
176 // prefersLightRefresh(), so this stays a pure partial (never promoted
177 // to a flickering full refresh).
179
180 // Check if USB was connected during sleep
181 if (power_ && power_->isUsbConnected()) {
182 // USB connected - exit light sleep mode
183 lockScreen_->removeStatusIcon(StatusIcon::LIGHT_SLEEP);
184 lockScreenEnteredMs_ = esp_timer_get_time() / 1000;
185 inLightSleep_ = false;
186 return false;
187 }
188 // Timer wakeup without USB: re-enter sleep via the caller's loop.
189 return true;
190 } else {
191 // Unknown wakeup - treat like GPIO
192 lockScreen_->removeStatusIcon(StatusIcon::LIGHT_SLEEP);
193 lockScreenEnteredMs_ = esp_timer_get_time() / 1000;
194 inLightSleep_ = false;
195 return false;
196 }
197}
198
202
208bool SleepManager::addSleepInhibitor(const char* reason) {
209 if (!reason) return false;
210
211 // Check if already exists
212 for (uint8_t i = 0; i < inhibitorCount_; i++) {
213 if (inhibitors_[i] && strcmp(inhibitors_[i], reason) == 0) {
214 return false; // Already exists
215 }
216 }
217
218 // Check if full
219 if (inhibitorCount_ >= MAX_SLEEP_INHIBITORS) {
220 LOG_W(TAG, "Sleep inhibitor list full, cannot add: %s", reason);
221 return false;
222 }
223
224 // Add inhibitor
225 inhibitors_[inhibitorCount_++] = reason;
226 LOG_I(TAG, "Sleep inhibitor added: %s (count=%d)", reason, inhibitorCount_);
227
228 // Update icon
229 updateCaffeinatedIcon();
230 return true;
231}
232
238bool SleepManager::removeSleepInhibitor(const char* reason) {
239 if (!reason) return false;
240
241 // Find and remove
242 for (uint8_t i = 0; i < inhibitorCount_; i++) {
243 if (inhibitors_[i] && strcmp(inhibitors_[i], reason) == 0) {
244 // Shift remaining entries
245 for (uint8_t j = i; j < inhibitorCount_ - 1; j++) {
246 inhibitors_[j] = inhibitors_[j + 1];
247 }
248 inhibitors_[--inhibitorCount_] = nullptr;
249
250 LOG_I(TAG, "Sleep inhibitor removed: %s (count=%d)", reason, inhibitorCount_);
251
252 // Update icon
253 updateCaffeinatedIcon();
254 return true;
255 }
256 }
257
258 return false; // Not found
259}
260
265void SleepManager::updateCaffeinatedIcon() {
266 if (!lockScreen_) return;
267
268 if (inhibitorCount_ > 0) {
270 } else {
272 }
273}
274
275} // namespace cdc::ui
static const char * TAG
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_W(tag, fmt,...)
Definition cdc_log.h:146
#define LOG_I(tag, fmt,...)
Definition cdc_log.h:147
static EventBus & instance()
Returns singleton event-bus instance.
Definition EventBus.cpp:19
virtual void enterLightSleep()=0
void removeStatusIcon(StatusIcon icon)
Removes one status icon flag.
void addStatusIcon(StatusIcon icon)
Adds one status icon flag.
bool isSleepInhibited() const
void resetTimer()
Resets lock-screen sleep timer using current system tick.
void checkLockScreenSleep(uint32_t nowMs)
Evaluates whether lock-screen light sleep should be entered.
bool addSleepInhibitor(const char *reason)
Sleep inhibitor API implementation.
static SleepManager & instance()
Returns singleton sleep manager instance.
bool removeSleepInhibitor(const char *reason)
Removes a sleep inhibitor reason.
void init(hal::ISleepController *sleep, hal::IPowerManager *power, LockScreenView *lockScreen)
Initializes sleep-manager dependencies and state.
void render(bool synchronous=false)
Render current view (and modal if present) and flush to display.
static ViewStack & instance()
Returns singleton view-stack instance.
Definition ViewStack.cpp:34
IDisplay * getDisplayInstance()
Returns lazily created singleton display instance.
Centralized key-code constants for cdc_views.
Definition IModule.h:8
static constexpr uint8_t MAX_SLEEP_INHIBITORS
static constexpr uint32_t LIGHT_SLEEP_TIMEOUT_MS
Gdey029T94 * display
void updatePowerStatusIcons()
Synchronizes lock-screen status icons with current hardware state.
Definition AppUi.cpp:284
static const char * TAG