mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-11-02 19:02:00 +00:00
fix(sos): one click on a locked L1 no longer starts and cancels an SOS; the hold always works; the contact picker doesn't stall
The Back hold started at millis() | 2, up to 2 ms ahead of the clock. With the screen off the loop comes round in under that, the unsigned difference wrapped and read as 3 s held: the countdown started and the release cancelled it. The same "| 1" sentinel ahead of millis() is fixed in the other places it was used (L1 status screen, L2 prefs flush, WiFi test, live tiles, home edge flip, SD retry). A lock sequence left half done by a long Back hold (no click on release) kept the SOS hold off until the next click: cleared 500 ms after Back is let go. Picking an SOS contact no longer saves prefs on the way there and back (a flash write stalls the L1); leaving the SOS screen saves it with the rest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user