diff --git a/examples/companion_radio/ui-lvgl/HomeScreen.h b/examples/companion_radio/ui-lvgl/HomeScreen.h index ee7244f2..203301ce 100644 --- a/examples/companion_radio/ui-lvgl/HomeScreen.h +++ b/examples/companion_radio/ui-lvgl/HomeScreen.h @@ -331,7 +331,7 @@ static void onEditTile(lv_event_t* e) { if (!side) previewSlot(t, slotAt(p)); int page = s_page + side; if (!side || page < APPS || page >= pageCount()) { s_edge_since = 0; return; } - if (!s_edge_since) { s_edge_since = millis() | 1; return; } + if (!s_edge_since) { s_edge_since = (millis() - 1) | 1; return; } // never 0, never ahead of millis() if (millis() - s_edge_since < EDGE_MS) return; // Onto that page's nearest slot; the finger lifts to drag it on from there. int to = side > 0 ? (page - APPS) * PER_PAGE : (page - APPS) * PER_PAGE + PER_PAGE - 1; @@ -621,7 +621,7 @@ void UITask::homeFieldText(uint8_t f, char* v, int n) { in.gps_on = _core->gpsEnabled(); if (telemetry::isSensor(f)) { // the sensors on the bus: read every few seconds, not per field if (_sensors && (s_lpp_ms == 0 || millis() - s_lpp_ms > 5000)) { - s_lpp_ms = millis() | 1; + s_lpp_ms = (millis() - 1) | 1; // never 0, never ahead of millis() s_lpp.reset(); queryLocalSensors(*_sensors, board.getMCUTemperature(), s_lpp); } diff --git a/examples/companion_radio/ui-lvgl/LvglPort.h b/examples/companion_radio/ui-lvgl/LvglPort.h index 3138a4a9..ac59344e 100644 --- a/examples/companion_radio/ui-lvgl/LvglPort.h +++ b/examples/companion_radio/ui-lvgl/LvglPort.h @@ -310,7 +310,7 @@ static bool mountStorage() { if (s_sd_lent) return false; if (s_sd_mounted) return true; if (s_sd_last_try && millis() - s_sd_last_try < 5000) return false; - s_sd_last_try = millis() | 1; + s_sd_last_try = (millis() - 1) | 1; // never 0, never ahead of millis() SD_MMC.setPins(2, 3, 1); s_sd_mounted = SD_MMC.begin("/sdcard", true /* 1-bit */); return s_sd_mounted; diff --git a/examples/companion_radio/ui-lvgl/MapScreen.h b/examples/companion_radio/ui-lvgl/MapScreen.h index ce559c65..94f74937 100644 --- a/examples/companion_radio/ui-lvgl/MapScreen.h +++ b/examples/companion_radio/ui-lvgl/MapScreen.h @@ -1807,7 +1807,7 @@ void UITask::mapDownloadTick() { // The WiFi goes 30 s after the map was left or the screen went off (a // quick look elsewhere keeps it). if (_screen != SCR_MAP || _asleep) { - if (!_map_left_ms) _map_left_ms = millis() | 1; + if (!_map_left_ms) _map_left_ms = (millis() - 1) | 1; // never 0, never ahead of millis() else if (millis() - _map_left_ms > 30000) dl.liveEnd(); } } diff --git a/examples/companion_radio/ui-lvgl/Widgets.h b/examples/companion_radio/ui-lvgl/Widgets.h index f425594f..b9304ef4 100644 --- a/examples/companion_radio/ui-lvgl/Widgets.h +++ b/examples/companion_radio/ui-lvgl/Widgets.h @@ -1257,7 +1257,7 @@ static void fmtDate(char* b, size_t n, const struct tm& ti) { // itself changes at once; shutdown() saves whatever is pending. static uint32_t s_prefs_dirty_ms = 0; // when the first unsaved change came (0: none) static uint32_t s_prefs_save_at = 0; // the screen was left: save from then (0: not yet) -static void prefsSave() { if (!s_prefs_dirty_ms) s_prefs_dirty_ms = millis() | 1; } +static void prefsSave() { if (!s_prefs_dirty_ms) s_prefs_dirty_ms = (millis() - 1) | 1; } // never 0, never ahead of millis() static void prefsSaveSoon(uint32_t delay_ms) { if (s_prefs_dirty_ms && !s_prefs_save_at) s_prefs_save_at = (millis() + delay_ms) | 1; } diff --git a/examples/companion_radio/ui-lvgl/WifiScreen.h b/examples/companion_radio/ui-lvgl/WifiScreen.h index 965d7fb4..8c971738 100644 --- a/examples/companion_radio/ui-lvgl/WifiScreen.h +++ b/examples/companion_radio/ui-lvgl/WifiScreen.h @@ -307,7 +307,7 @@ void UITask::wifiSave() { } lvport::netEnd(); // a scan might have left the radio on lvport::netJoin(s_wifi_test_ssid, s_wifi_test_pass); - s_wifi_test_ms = millis() | 1; + s_wifi_test_ms = (millis() - 1) | 1; // never 0, never ahead of millis() snprintf(msg, sizeof(msg), LV_SYMBOL_REFRESH " Connecting to %s...", s_wifi_test_ssid); wifiTestShow(msg, nullptr, nullptr); } diff --git a/examples/companion_radio/ui-new/MessagesScreen.h b/examples/companion_radio/ui-new/MessagesScreen.h index 678f9c11..ae617dec 100644 --- a/examples/companion_radio/ui-new/MessagesScreen.h +++ b/examples/companion_radio/ui-new/MessagesScreen.h @@ -1433,10 +1433,7 @@ public: void commitPickSos(const ContactInfo& ci) { NodePrefs* p = _task->getNodePrefs(); - if (p) { - memcpy(p->sos_dm[_pick_sos_slot], ci.id.pub_key, NodePrefs::FAVOURITE_PREFIX_LEN); - the_mesh.savePrefs(); - } + if (p) memcpy(p->sos_dm[_pick_sos_slot], ci.id.pub_key, NodePrefs::FAVOURITE_PREFIX_LEN); // saved on leaving SOS _pick_sos_slot = -1; _task->gotoSosScreen(); } diff --git a/examples/companion_radio/ui-new/SosScreen.h b/examples/companion_radio/ui-new/SosScreen.h index 4d22c51e..50b14244 100644 --- a/examples/companion_radio/ui-new/SosScreen.h +++ b/examples/companion_radio/ui-new/SosScreen.h @@ -13,6 +13,7 @@ class SosScreen : public UIScreen { NodePrefs* _prefs; KeyboardWidget* _kb; bool _dirty = false; + bool _picking = false; // off to the contact picker: the changes stay unsaved until we leave int _sel = 0; int _scroll = 0; int _kb_row = -1; // >=0: the keyboard is open on that row @@ -135,7 +136,9 @@ class SosScreen : public UIScreen { if (enter) openChannels(); break; case K_DM1: case K_DM2: case K_DM3: - if (enter) { _task->savePrefsIfDirty(_dirty); _task->pickSosContact(k - K_DM1); } + // No save on the way: a prefs write stalls the L1 for a moment, and + // leaving this screen saves the pick with the rest. + if (enter) { _picking = true; _task->pickSosContact(k - K_DM1); } else { memset(_prefs->sos_dm[k - K_DM1], 0, NodePrefs::FAVOURITE_PREFIX_LEN); _dirty = true; } break; case K_ACK: case K_NOTE: @@ -156,7 +159,12 @@ class SosScreen : public UIScreen { public: SosScreen(UITask* task, NodePrefs* prefs, KeyboardWidget* kb) : _task(task), _prefs(prefs), _kb(kb) {} - void onShow() override { _dirty = false; _kb_row = -1; _ch_list = false; } // the row stays: the contact list comes back here + void onShow() override { // the row stays: the contact list comes back here + _dirty = _picking; // back from the picker: what was changed, and the pick, still to save + _picking = false; + _kb_row = -1; + _ch_list = false; + } int render(DisplayDriver& display) override { if (_kb_row >= 0) return _kb->render(display); diff --git a/examples/companion_radio/ui-new/StatusScreen.h b/examples/companion_radio/ui-new/StatusScreen.h index 2cc853cb..69155dca 100644 --- a/examples/companion_radio/ui-new/StatusScreen.h +++ b/examples/companion_radio/ui-new/StatusScreen.h @@ -242,7 +242,7 @@ private: if (!_lpp_at || millis() - _lpp_at > 5000) { // both passes (measure, draw) read one query _lpp.reset(); { CardKBBusLock bus_lock; queryLocalSensors(sensors, board.getMCUTemperature(), _lpp); } // shares the CardKB's bus - _lpp_at = millis() | 1; + _lpp_at = (millis() - 1) | 1; // never 0, never ahead of millis() } static const struct { uint8_t type; const char* name; } NAMES[] = { { LPP_TEMPERATURE, "Temperature" }, { LPP_RELATIVE_HUMIDITY, "Humidity" }, @@ -428,7 +428,7 @@ public: static unsigned long at = 0; static int n = 0; if (at && millis() - at < 10000) return n; - at = millis() | 1; + at = (millis() - 1) | 1; // never 0, never ahead of millis() n = 0; const uint32_t now = rtc_clock.getCurrentTime(); const int nc = the_mesh.getNumContacts(); diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index fd5bbdba..5406df37 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -1456,12 +1456,21 @@ void UITask::loop() { if (_lock_seq_used && millis() - _lock_seq_ms > 5000) { _lock_seq_used = false; // safety reset if Back release event was missed } + // The lock sequence lives while Back is held. A long hold gives no click on + // release, so a sequence left half done stayed and kept the SOS hold off: + // cleared once Back has been up past the click window. + if (back_btn.isPressed()) _back_up_at = 0; + else if (!_back_up_at) _back_up_at = (millis() - 1) | 1; + else if ((_lock_seq_count > 0 || _lock_seq_used) && millis() - _back_up_at > 500) { + _lock_seq_count = 0; + _lock_seq_used = false; + } // Back held on its own: past the button's long press, so no click comes of it. // Enter during the hold is the lock sequence, not this. if (!back_btn.isPressed() || user_btn.isPressed() || _lock_seq_count > 0 || _lock_seq_used) { _back_held_at = back_btn.isPressed() ? 1 : 0; // 1: spoken for until released } else if (_back_held_at == 0) { - _back_held_at = millis() | 2; + _back_held_at = (millis() - 2) | 2; // never 0 or 1, never ahead of millis(): ahead, the next pass read 3 s held } else if (_back_held_at != 1 && millis() - _back_held_at >= SOS_HOLD_MS) { _back_held_at = 1; onBackHeld(); diff --git a/examples/companion_radio/ui-new/UITask.h b/examples/companion_radio/ui-new/UITask.h index 22098d27..89590ffe 100644 --- a/examples/companion_radio/ui-new/UITask.h +++ b/examples/companion_radio/ui-new/UITask.h @@ -158,6 +158,7 @@ class UITask : public UITaskBase, public UiCoreHost { unsigned long _sos_view_until = 0; // 0 = closed int _sos_left = 0; // countdown second last beeped unsigned long _back_held_at = 0; // 0 = not held, or already acted on + unsigned long _back_up_at = 0; // when Back was let go (0: held)