From e91ad4bac49552311f56ee9bdb5b86c831b93ea4 Mon Sep 17 00:00:00 2001 From: pelgraine <140762863+pelgraine@users.noreply.github.com> Date: Thu, 5 Mar 2026 18:04:28 +1100 Subject: [PATCH] repeater admin login regression bugfix and timing response improvements --- examples/companion_radio/MyMesh.cpp | 19 +++++++--- examples/companion_radio/MyMesh.h | 2 +- .../ui-new/Repeateradminscreen.h | 37 ++++++++++++------- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index a52e8af..cb4a863 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -694,17 +694,25 @@ bool MyMesh::uiSendDirectMessage(uint32_t contact_idx, const char* text) { return true; } -bool MyMesh::uiLoginToRepeater(uint32_t contact_idx, const char* password) { +bool MyMesh::uiLoginToRepeater(uint32_t contact_idx, const char* password, uint32_t& est_timeout_ms) { ContactInfo contact; if (!getContactByIdx(contact_idx, contact)) return false; ContactInfo* recipient = lookupContactByPubKey(contact.id.pub_key, PUB_KEY_SIZE); if (!recipient) return false; - uint32_t est_timeout; - int result = sendLogin(*recipient, password, est_timeout); + // Force flood routing for login — a mobile repeater's direct path may be stale. + // The companion protocol does the same for telemetry requests. + int8_t save_path_len = recipient->out_path_len; + recipient->out_path_len = -1; + + int result = sendLogin(*recipient, password, est_timeout_ms); + + recipient->out_path_len = save_path_len; // restore + if (result == MSG_SEND_FAILED) { MESH_DEBUG_PRINTLN("UI: Admin login send failed to %s", recipient->name); + est_timeout_ms = 0; return false; } @@ -712,9 +720,8 @@ bool MyMesh::uiLoginToRepeater(uint32_t contact_idx, const char* password) { memcpy(&pending_login, recipient->id.pub_key, 4); _admin_contact_idx = contact_idx; - MESH_DEBUG_PRINTLN("UI: Admin login sent to %s (%s), timeout=%dms", - recipient->name, result == MSG_SEND_SENT_FLOOD ? "flood" : "direct", - est_timeout); + MESH_DEBUG_PRINTLN("UI: Admin login sent to %s (flood, was path_len=%d), timeout=%dms", + recipient->name, (int)save_path_len, est_timeout_ms); return true; } diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index c202244..b068e7b 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -127,7 +127,7 @@ public: bool uiSendDirectMessage(uint32_t contact_idx, const char* text); // Repeater admin - UI-initiated operations - bool uiLoginToRepeater(uint32_t contact_idx, const char* password); + bool uiLoginToRepeater(uint32_t contact_idx, const char* password, uint32_t& est_timeout_ms); bool uiSendCliCommand(uint32_t contact_idx, const char* command); bool uiSendTelemetryRequest(uint32_t contact_idx); int getAdminContactIdx() const { return _admin_contact_idx; } diff --git a/examples/companion_radio/ui-new/Repeateradminscreen.h b/examples/companion_radio/ui-new/Repeateradminscreen.h index b50fb34..f8b39e9 100644 --- a/examples/companion_radio/ui-new/Repeateradminscreen.h +++ b/examples/companion_radio/ui-new/Repeateradminscreen.h @@ -197,6 +197,7 @@ private: // Timing unsigned long _cmdSentAt; + unsigned long _loginTimeoutMs; // computed timeout for login (ms), falls back to ADMIN_TIMEOUT_MS bool _waitingForLogin; // Password cache @@ -428,7 +429,7 @@ public: _catSel(0), _cmdSel(0), _scrollOffset(0), _paramLen(0), _pendingCmd(nullptr), _responseLen(0), _responseScroll(0), _responseTotalLines(0), - _cmdSentAt(0), _waitingForLogin(false), _pwdCacheCount(0), + _cmdSentAt(0), _loginTimeoutMs(ADMIN_TIMEOUT_MS), _waitingForLogin(false), _pwdCacheCount(0), _telemVoltage(0), _telemTempC(0), _telemHasVoltage(false), _telemHasTemp(false), _telemRequested(false) { _password[0] = '\0'; @@ -529,19 +530,23 @@ public: } void poll() override { - if ((_state == STATE_LOGGING_IN || _state == STATE_COMMAND_PENDING) && - _cmdSentAt > 0 && (millis() - _cmdSentAt) > ADMIN_TIMEOUT_MS) { - if (_pendingCmd && (_pendingCmd->flags & CMDF_EXPECT_TIMEOUT)) { - snprintf(_response, sizeof(_response), "Command sent.\nTimeout is expected\n(device is rebooting/updating)."); - _responseLen = strlen(_response); - _responseTotalLines = countLines(_response); - _state = STATE_RESPONSE_VIEW; - } else { - snprintf(_response, sizeof(_response), "Timeout - no response."); - _responseLen = strlen(_response); - _state = STATE_ERROR; + if (_cmdSentAt > 0) { + unsigned long elapsed = millis() - _cmdSentAt; + unsigned long timeout = (_state == STATE_LOGGING_IN) ? _loginTimeoutMs : ADMIN_TIMEOUT_MS; + + if ((_state == STATE_LOGGING_IN || _state == STATE_COMMAND_PENDING) && elapsed > timeout) { + if (_pendingCmd && (_pendingCmd->flags & CMDF_EXPECT_TIMEOUT)) { + snprintf(_response, sizeof(_response), "Command sent.\nTimeout is expected\n(device is rebooting/updating)."); + _responseLen = strlen(_response); + _responseTotalLines = countLines(_response); + _state = STATE_RESPONSE_VIEW; + } else { + snprintf(_response, sizeof(_response), "Timeout - no response."); + _responseLen = strlen(_response); + _state = STATE_ERROR; + } + _task->forceRefresh(); // Immediate redraw on state change } - _task->forceRefresh(); // Immediate redraw on state change } } @@ -1160,9 +1165,13 @@ private: inline bool RepeaterAdminScreen::doLogin() { if (_contactIdx < 0 || _pwdLen == 0) return false; - if (the_mesh.uiLoginToRepeater(_contactIdx, _password)) { + uint32_t timeout_ms = 0; + if (the_mesh.uiLoginToRepeater(_contactIdx, _password, timeout_ms)) { _state = STATE_LOGGING_IN; _cmdSentAt = millis(); + // Add a 1.5s buffer over the mesh estimate; fall back to ADMIN_TIMEOUT_MS + // if the estimate came back zero for any reason. + _loginTimeoutMs = (timeout_ms > 0) ? timeout_ms + 1500 : ADMIN_TIMEOUT_MS; _waitingForLogin = true; return true; } else {