fix: prevent infinite render loop in Calibre Wireless after file transfer (#1070)
## Summary * **What is the goal of this PR?** Fix an infinite render loop bug in CalibreConnectActivity that caused the e-ink display to refresh continuously every ~421ms after a file transfer completed. * **What changes are included?** - Added lastProcessedCompleteAt member variable to track which server completion timestamp has already been processed - Modified the completion status update logic to only accept new values from the server, preventing re-processing of old timestamps - Added clarifying comments explaining the fix ## Problem Description After receiving a file via Calibre Wireless, the activity displays "Received: [filename]" for 6 seconds, then clears the message. However, the web server's wsLastCompleteAt timestamp persists indefinitely and is never cleared. This created a race condition: After 6 seconds, lastCompleteAt is set to 0 (timeout) In the next loop iteration, status.lastCompleteAt (still has the old timestamp) ≠ lastCompleteAt (0) The code restores lastCompleteAt from the server value Immediately, the 6-second timeout condition is met again This creates an infinite cycle causing unnecessary e-ink refreshes ## Solution The fix introduces lastProcessedCompleteAt to track which server timestamp value has already been processed: Only accept a new status.lastCompleteAt if it differs from lastProcessedCompleteAt Update lastProcessedCompleteAt when processing a new value Do NOT reset lastProcessedCompleteAt when the 6-second timeout clears lastCompleteAt This prevents re-processing the same old server value after the timeout. ## Testing Tested on device with multiple file transfer scenarios: ✅ File received message appears correctly after transfer ✅ Message clears after 6 seconds as expected ✅ No infinite render loop after timeout ✅ Multiple consecutive transfers work correctly ✅ Exiting and re-entering Calibre Wireless works as expected ## Performance Impact Before: Infinite refreshes every ~421ms after timeout (high battery drain, display wear) After: 2-3 refreshes after timeout, then stops (normal behavior) ## Additional Context This is a targeted fix that only affects the Calibre Wireless file transfer screen. The root cause is the architectural difference between the persistent web server state (wsLastCompleteAt) and the per-activity display state (lastCompleteAt). An alternative fix would be to clear wsLastCompleteAt in the web server after some timeout, but that would affect all consumers of the web server status. The chosen solution keeps the fix localized to CalibreConnectActivity. --- ### AI Usage Did you use AI tools to help write this code? _**< YES >**_
This commit is contained in:
@@ -28,6 +28,7 @@ void CalibreConnectActivity::onEnter() {
|
||||
currentUploadName.clear();
|
||||
lastCompleteName.clear();
|
||||
lastCompleteAt = 0;
|
||||
lastProcessedCompleteAt = 0;
|
||||
exitRequested = false;
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
@@ -147,14 +148,18 @@ void CalibreConnectActivity::loop() {
|
||||
currentUploadName.clear();
|
||||
changed = true;
|
||||
}
|
||||
if (status.lastCompleteAt != 0 && status.lastCompleteAt != lastCompleteAt) {
|
||||
// Only update lastCompleteAt if the server has a NEW value (not one we already processed)
|
||||
// This prevents restoring an old value after the 6s timeout clears it
|
||||
if (status.lastCompleteAt != 0 && status.lastCompleteAt != lastProcessedCompleteAt) {
|
||||
lastCompleteAt = status.lastCompleteAt;
|
||||
lastCompleteName = status.lastCompleteName;
|
||||
lastProcessedCompleteAt = status.lastCompleteAt; // Mark this value as processed
|
||||
changed = true;
|
||||
}
|
||||
if (lastCompleteAt > 0 && (millis() - lastCompleteAt) >= 6000) {
|
||||
lastCompleteAt = 0;
|
||||
lastCompleteName.clear();
|
||||
// Note: we DON'T reset lastProcessedCompleteAt here, so we won't re-process the old server value
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
|
||||
@@ -26,6 +26,7 @@ class CalibreConnectActivity final : public ActivityWithSubactivity {
|
||||
std::string currentUploadName;
|
||||
std::string lastCompleteName;
|
||||
unsigned long lastCompleteAt = 0;
|
||||
unsigned long lastProcessedCompleteAt = 0; // Track which server value we've already processed
|
||||
bool exitRequested = false;
|
||||
|
||||
void renderServerRunning() const;
|
||||
|
||||
Reference in New Issue
Block a user