From e3279646f9b6abc9373345d1fe10b2b6f3ddeb54 Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Tue, 8 Sep 2026 16:03:37 +0200 Subject: [PATCH] refactor(companion): unify every reboot/power-off through UITask::shutdown() Settings > Reboot, the phone app's CMD_REBOOT, and the serial CLI's "reboot" command each hand-rolled their own flush-then-board.reboot() sequence, so each could drift independently (Settings > Reboot and the CLI command were both missing the contacts flush added in the previous commit). Add a pure-virtual AbstractUITask::shutdown(bool restart) -- every UI variant (ui-new/ui-tiny/ui-orig) already implements a method with this exact signature -- and route all three call sites through it instead. CMD_FACTORY_RESET intentionally keeps calling board.reboot() directly: flushing stale in-RAM prefs back out would defeat the format it just did. Co-Authored-By: Claude Sonnet 5 --- examples/companion_radio/AbstractUITask.h | 7 +++++++ examples/companion_radio/MyMesh.cpp | 19 +++++++++++++------ .../companion_radio/ui-new/SettingsScreen.h | 3 +-- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/examples/companion_radio/AbstractUITask.h b/examples/companion_radio/AbstractUITask.h index 7a019e07..070ebf9b 100644 --- a/examples/companion_radio/AbstractUITask.h +++ b/examples/companion_radio/AbstractUITask.h @@ -148,5 +148,12 @@ public: // added later at the same slot would silently inherit the old one's bot/ // share target or notification melody. Default no-op. virtual void onChannelRemoved(uint8_t channel_idx) {} + // Single choke point for every controlled power-down (low-battery auto-off, + // long-press power-off, and now every board.reboot() caller too): flush + // prefs/RTC/contacts/trail before the board actually goes down or restarts, + // so no exit path can silently skip a pending write. restart=true reboots, + // false powers off. Every UI variant (ui-new/ui-tiny/ui-orig) implements + // this the same way -- see each's UITask::shutdown(). + virtual void shutdown(bool restart = false) = 0; virtual void loop() = 0; }; diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 3509821c..dc59f454 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -2380,11 +2380,13 @@ void MyMesh::handleCmdFrame(size_t len) { writeOKFrame(); } } else if (cmd_frame[0] == CMD_REBOOT && memcmp(&cmd_frame[1], "reboot", 6) == 0) { - if (dirty_contacts_expiry) { // is there are pending dirty contacts write needed? - saveContacts(); + if (_ui) { + _ui->shutdown(true); + } else { + flushDirtyContacts(); + savePrefs(); + board.reboot(); } - savePrefs(); // flush any on-device setting change not yet persisted -- see UITask::shutdown()'s comment - board.reboot(); } else if (cmd_frame[0] == CMD_GET_BATT_AND_STORAGE) { uint8_t reply[11]; int i = 0; @@ -3192,8 +3194,13 @@ void MyMesh::checkCLIRescueCmd() { } } else if (strcmp(cli_command, "reboot") == 0) { - savePrefs(); // flush any on-device setting change not yet persisted -- see UITask::shutdown()'s comment - board.reboot(); // doesn't return + if (_ui) { + _ui->shutdown(true); + } else { + flushDirtyContacts(); + savePrefs(); // flush any on-device setting change not yet persisted -- see UITask::shutdown()'s comment + board.reboot(); // doesn't return + } } else { Serial.println(" Error: unknown command"); } diff --git a/examples/companion_radio/ui-new/SettingsScreen.h b/examples/companion_radio/ui-new/SettingsScreen.h index 66c0ee86..39287440 100644 --- a/examples/companion_radio/ui-new/SettingsScreen.h +++ b/examples/companion_radio/ui-new/SettingsScreen.h @@ -1018,9 +1018,8 @@ public: return true; } if (_selected == REBOOT && enter) { - _task->savePrefsIfDirty(_dirty); // don't lose pending edits across the restart _task->showAlert("Rebooting...", 800); - board.reboot(); + _task->shutdown(true); // flushes prefs/RTC/contacts/trail, then reboots -- single choke point return true; } if (_selected == KEYBOARD_TYPE && p && (left || right || enter)) {