mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-10-09 03:06:39 +00:00
refactor(ui-core): move ping state into PingEngine
Single in-flight ping + last result move from UITask to ui-core/PingEngine.h; MyMesh's ping callback routes to the engine instead of casting the Listener back to UITask. UITask keeps thin wrappers (and the "not supported" alert), NearbyScreen is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
// Ping engine: one on-device ping in flight at a time (MyMesh::sendPing), its
|
||||
// result (RTT + SNR both ways) kept after the in-flight slot is released so the
|
||||
// view can keep showing it. The reply arrives through MyMesh's ping callback,
|
||||
// which is a plain function pointer -- routed here via a single static instance.
|
||||
//
|
||||
// The ping timeout is still decided by the view (NearbyScreen's
|
||||
// PING_TIMEOUT_MS), which calls clear() when it gives up.
|
||||
|
||||
class PingEngine {
|
||||
public:
|
||||
enum StartResult : uint8_t { STARTED = 0, BUSY, UNSUPPORTED, SEND_FAILED };
|
||||
|
||||
void begin(NodePrefs* prefs) { _prefs = prefs; s_instance = this; }
|
||||
|
||||
StartResult start(const uint8_t* pub_key) {
|
||||
if (_active || !pub_key) return BUSY;
|
||||
if (_prefs && _prefs->path_hash_mode > 1) return UNSUPPORTED; // no 3-byte path hash support
|
||||
|
||||
_active = true;
|
||||
_tag = 0;
|
||||
_snr_out_x4 = 0;
|
||||
_snr_back_x4 = 0;
|
||||
_rtt_ms = 0;
|
||||
|
||||
// Always install the callback before sending so the response cannot race it.
|
||||
the_mesh.setPingCallback(onPingResult, NULL);
|
||||
_tag = the_mesh.sendPing(pub_key, _prefs ? _prefs->path_hash_mode + 1 : 1);
|
||||
if (_tag == 0) {
|
||||
clear();
|
||||
return SEND_FAILED;
|
||||
}
|
||||
return STARTED;
|
||||
}
|
||||
|
||||
// Release the in-flight slot (result values are kept).
|
||||
void clear() {
|
||||
if (_tag != 0) the_mesh.clearPingResult(_tag);
|
||||
_active = false;
|
||||
_tag = 0;
|
||||
}
|
||||
|
||||
bool isActive() const { return _active; }
|
||||
void getResult(int16_t& snr_out_x4, int16_t& snr_back_x4, uint32_t& rtt_ms) const {
|
||||
snr_out_x4 = _snr_out_x4;
|
||||
snr_back_x4 = _snr_back_x4;
|
||||
rtt_ms = _rtt_ms;
|
||||
}
|
||||
|
||||
private:
|
||||
void handleResult(uint32_t tag, int16_t snr_out_x4, int16_t snr_back_x4, uint32_t rtt_ms) {
|
||||
if (_active && _tag == tag) {
|
||||
_snr_out_x4 = snr_out_x4;
|
||||
_snr_back_x4 = snr_back_x4;
|
||||
_rtt_ms = rtt_ms;
|
||||
// Release the in-flight slot immediately; the view keeps the result values.
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
static void onPingResult(uint32_t tag, int16_t snr_out_x4, int16_t snr_back_x4, uint32_t rtt_ms) {
|
||||
if (s_instance) s_instance->handleResult(tag, snr_out_x4, snr_back_x4, rtt_ms);
|
||||
}
|
||||
|
||||
static PingEngine* s_instance;
|
||||
|
||||
NodePrefs* _prefs = nullptr;
|
||||
bool _active = false;
|
||||
uint32_t _tag = 0;
|
||||
int16_t _snr_out_x4 = 0;
|
||||
int16_t _snr_back_x4 = 0;
|
||||
uint32_t _rtt_ms = 0;
|
||||
};
|
||||
|
||||
// Header-only Core, single TU (see UiCore.h) -- the one definition lives here.
|
||||
PingEngine* PingEngine::s_instance = nullptr;
|
||||
@@ -11,11 +11,13 @@
|
||||
#include "DmUnreadTable.h"
|
||||
#include "UiEvents.h"
|
||||
#include "ClockEngine.h"
|
||||
#include "PingEngine.h"
|
||||
|
||||
class UiCore {
|
||||
public:
|
||||
void begin(NodePrefs* prefs) {
|
||||
clock.begin(prefs, &events);
|
||||
ping.begin(prefs);
|
||||
}
|
||||
|
||||
// Driven from the frontend's loop(), before it drains `events`.
|
||||
@@ -27,6 +29,7 @@ public:
|
||||
|
||||
// ── Engines ───────────────────────────────────────────────────────────────
|
||||
ClockEngine clock; // alarm / countdown / ring
|
||||
PingEngine ping; // single in-flight ping + last result
|
||||
|
||||
// ── Models ────────────────────────────────────────────────────────────────
|
||||
MessageHistory history; // channel + DM rings, delivery state, channel unread
|
||||
|
||||
@@ -1646,14 +1646,6 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize ping state
|
||||
_ping_active = false;
|
||||
_ping_tag = 0;
|
||||
_ping_sent_ms = 0;
|
||||
_ping_snr_out_x4 = 0;
|
||||
_ping_snr_back_x4 = 0;
|
||||
_ping_rtt_ms = 0;
|
||||
|
||||
_core = new UiCore(); // before any screen -- MessagesScreen binds to its history
|
||||
_core->begin(node_prefs);
|
||||
splash = new SplashScreen(this);
|
||||
@@ -1775,57 +1767,16 @@ void UITask::gotoMapScreen() {
|
||||
void UITask::gotoLocatorScreen() { setCurrScreen(locator_screen); }
|
||||
void UITask::gotoAutoAdvertScreen() { setCurrScreen(auto_advert_screen); }
|
||||
|
||||
// Public method to handle ping result callback
|
||||
void UITask::handlePingResult(uint32_t tag, int16_t snr_out_x4, int16_t snr_back_x4, uint32_t rtt_ms) {
|
||||
if (_ping_active && _ping_tag == tag) {
|
||||
_ping_snr_out_x4 = snr_out_x4;
|
||||
_ping_snr_back_x4 = snr_back_x4;
|
||||
_ping_rtt_ms = rtt_ms;
|
||||
// Release the in-flight slot immediately; the UI keeps the result values.
|
||||
clearPing();
|
||||
}
|
||||
}
|
||||
|
||||
// Static ping callback (for MyMesh)
|
||||
static void onPingResult(uint32_t tag, int16_t snr_out_x4, int16_t snr_back_x4, uint32_t rtt_ms) {
|
||||
MyMesh::Listener* ui = the_mesh.getListener();
|
||||
if (ui) {
|
||||
UITask* task = static_cast<UITask*>(ui);
|
||||
task->handlePingResult(tag, snr_out_x4, snr_back_x4, rtt_ms);
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::clearPing() {
|
||||
if (_ping_tag != 0) {
|
||||
the_mesh.clearPingResult(_ping_tag);
|
||||
}
|
||||
_ping_active = false;
|
||||
_ping_tag = 0;
|
||||
}
|
||||
|
||||
bool UITask::startPing(const uint8_t* pub_key) {
|
||||
if (_ping_active || !pub_key) return false;
|
||||
if (_node_prefs && _node_prefs->path_hash_mode > 1) {
|
||||
showAlert("Ping not supported with 3-byte path hashes", 3000);
|
||||
return false;
|
||||
}
|
||||
|
||||
_ping_active = true;
|
||||
_ping_tag = 0;
|
||||
_ping_sent_ms = millis();
|
||||
_ping_snr_out_x4 = 0;
|
||||
_ping_snr_back_x4 = 0;
|
||||
_ping_rtt_ms = 0;
|
||||
|
||||
// Always install the callback before sending so the response cannot race it.
|
||||
the_mesh.setPingCallback(onPingResult, NULL);
|
||||
_ping_tag = the_mesh.sendPing(pub_key, _node_prefs ? _node_prefs->path_hash_mode + 1 : 1);
|
||||
if (_ping_tag == 0) {
|
||||
clearPing();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
PingEngine::StartResult r = _core->ping.start(pub_key);
|
||||
if (r == PingEngine::UNSUPPORTED) showAlert("Ping not supported with 3-byte path hashes", 3000);
|
||||
return r == PingEngine::STARTED;
|
||||
}
|
||||
bool UITask::isPingActive() const { return _core->ping.isActive(); }
|
||||
void UITask::getPingResult(int16_t& snr_out_x4, int16_t& snr_back_x4, uint32_t& rtt_ms) const {
|
||||
_core->ping.getResult(snr_out_x4, snr_back_x4, rtt_ms);
|
||||
}
|
||||
void UITask::clearPing() { _core->ping.clear(); }
|
||||
|
||||
void UITask::playMelody(const char* melody) {
|
||||
#ifdef PIN_BUZZER
|
||||
|
||||
@@ -168,13 +168,6 @@ class UITask : public AbstractUITask {
|
||||
uint32_t _next_cog_sample_ms = 0;
|
||||
void pushCogFix(int32_t lat, int32_t lon);
|
||||
|
||||
// Ping state
|
||||
bool _ping_active = false;
|
||||
uint32_t _ping_tag = 0;
|
||||
unsigned long _ping_sent_ms = 0;
|
||||
int16_t _ping_snr_out_x4 = 0;
|
||||
int16_t _ping_snr_back_x4 = 0;
|
||||
uint32_t _ping_rtt_ms = 0;
|
||||
|
||||
void userLedHandler();
|
||||
|
||||
@@ -447,16 +440,11 @@ public:
|
||||
bool hasDisplay() const { return _display != NULL; }
|
||||
DisplayDriver* getDisplay() const { return _display; }
|
||||
|
||||
// Ping helpers
|
||||
// Ping helpers (engine in ui-core/PingEngine.h)
|
||||
bool startPing(const uint8_t* pub_key);
|
||||
bool isPingActive() const { return _ping_active; }
|
||||
void getPingResult(int16_t& snr_out_x4, int16_t& snr_back_x4, uint32_t& rtt_ms) const {
|
||||
snr_out_x4 = _ping_snr_out_x4;
|
||||
snr_back_x4 = _ping_snr_back_x4;
|
||||
rtt_ms = _ping_rtt_ms;
|
||||
}
|
||||
bool isPingActive() const;
|
||||
void getPingResult(int16_t& snr_out_x4, int16_t& snr_back_x4, uint32_t& rtt_ms) const;
|
||||
void clearPing();
|
||||
void handlePingResult(uint32_t tag, int16_t snr_out_x4, int16_t snr_back_x4, uint32_t rtt_ms);
|
||||
|
||||
// Favourites dial helpers. Slot index 0..FAVOURITES_COUNT-1. A slot holds
|
||||
// either a contact/room (pubkey prefix) or a channel (index), per
|
||||
|
||||
Reference in New Issue
Block a user