mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-29 16:28:11 +00:00
feat: 2-line boxed discover entries with RSSI, SNR, remote SNR
Each discovered node now renders as a boxed 2-line card (same style as message history): ┌──────────────────────────────┐ │ NodeName (or [Sensor]) Type │ ← inverted header │ RSSI:-87 SNR:7 Rem:5 │ ← signal stats └──────────────────────────────┘ Add snr_x4 and remote_snr_x4 to DiscoverResult: snr_x4 = _radio->getLastSNR()*4 (how well we heard the response) remote_snr_x4 = payload[1] (how well responder heard our request) 2 items visible at a time; UP/DOWN scroll through results. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -815,6 +815,8 @@ void MyMesh::onControlDataRecv(mesh::Packet *packet) {
|
|||||||
}
|
}
|
||||||
r.type = node_type;
|
r.type = node_type;
|
||||||
r.rssi = (int8_t)_radio->getLastRSSI();
|
r.rssi = (int8_t)_radio->getLastRSSI();
|
||||||
|
r.snr_x4 = (int8_t)(_radio->getLastSNR() * 4);
|
||||||
|
r.remote_snr_x4 = (int8_t)packet->payload[1];
|
||||||
r.timestamp = getRTCClock()->getCurrentTime();
|
r.timestamp = getRTCClock()->getCurrentTime();
|
||||||
}
|
}
|
||||||
if (_ui) _ui->notify(UIEventType::newContactMessage);
|
if (_ui) _ui->notify(UIEventType::newContactMessage);
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ struct DiscoverResult {
|
|||||||
uint8_t type; // ADV_TYPE_REPEATER / ADV_TYPE_SENSOR / ADV_TYPE_ROOM
|
uint8_t type; // ADV_TYPE_REPEATER / ADV_TYPE_SENSOR / ADV_TYPE_ROOM
|
||||||
bool is_known; // true = in contacts[], false = new unknown node
|
bool is_known; // true = in contacts[], false = new unknown node
|
||||||
int8_t rssi; // RSSI of the response as received by us (dBm)
|
int8_t rssi; // RSSI of the response as received by us (dBm)
|
||||||
|
int8_t snr_x4; // SNR of the response as received by us (dB × 4)
|
||||||
|
int8_t remote_snr_x4; // SNR at which responder heard our request (dB × 4)
|
||||||
uint32_t timestamp;
|
uint32_t timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -169,23 +169,24 @@ class NearbyScreen : public UIScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int renderDiscover(DisplayDriver& display) {
|
int renderDiscover(DisplayDriver& display) {
|
||||||
// poll: fetch latest results
|
static const int D_BOX_H = 19;
|
||||||
|
static const int D_ITEM_H = 21; // box + 2px gap
|
||||||
|
static const int D_VISIBLE = 2;
|
||||||
|
static const int D_START_Y = 11;
|
||||||
|
|
||||||
_dresult_count = the_mesh.getDiscoverResults(_dresults, DISCOVER_RESULTS_MAX);
|
_dresult_count = the_mesh.getDiscoverResults(_dresults, DISCOVER_RESULTS_MAX);
|
||||||
|
|
||||||
if (_discovering && millis() - _discover_started_ms >= DISCOVER_DURATION_MS) {
|
if (_discovering && millis() - _discover_started_ms >= DISCOVER_DURATION_MS)
|
||||||
_discovering = false;
|
_discovering = false;
|
||||||
}
|
|
||||||
|
|
||||||
display.setColor(DisplayDriver::LIGHT);
|
display.setColor(DisplayDriver::LIGHT);
|
||||||
char title[28];
|
char title[28];
|
||||||
if (_discovering) {
|
if (_discovering)
|
||||||
snprintf(title, sizeof(title), "SCANNING... (%d)", _dresult_count);
|
snprintf(title, sizeof(title), "SCANNING... (%d)", _dresult_count);
|
||||||
} else {
|
else if (_dresult_count == 0)
|
||||||
if (_dresult_count == 0)
|
snprintf(title, sizeof(title), "DISCOVER: none");
|
||||||
snprintf(title, sizeof(title), "DISCOVER: none");
|
else
|
||||||
else
|
snprintf(title, sizeof(title), "DISCOVER (%d found)", _dresult_count);
|
||||||
snprintf(title, sizeof(title), "DISCOVER (%d found)", _dresult_count);
|
|
||||||
}
|
|
||||||
display.drawTextCentered(display.width() / 2, 0, title);
|
display.drawTextCentered(display.width() / 2, 0, title);
|
||||||
display.fillRect(0, 10, display.width(), 1);
|
display.fillRect(0, 10, display.width(), 1);
|
||||||
|
|
||||||
@@ -193,43 +194,50 @@ class NearbyScreen : public UIScreen {
|
|||||||
display.drawTextCentered(display.width() / 2, 32,
|
display.drawTextCentered(display.width() / 2, 32,
|
||||||
_discovering ? "Waiting for replies..." : "No nodes found");
|
_discovering ? "Waiting for replies..." : "No nodes found");
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < VISIBLE && (_dscroll + i) < _dresult_count; i++) {
|
for (int i = 0; i < D_VISIBLE && (_dscroll + i) < _dresult_count; i++) {
|
||||||
int idx = _dscroll + i;
|
int idx = _dscroll + i;
|
||||||
const DiscoverResult& r = _dresults[idx];
|
const DiscoverResult& r = _dresults[idx];
|
||||||
int y = START_Y + i * ITEM_H;
|
int y = D_START_Y + i * D_ITEM_H;
|
||||||
|
|
||||||
|
const char* typeStr = (r.type == ADV_TYPE_REPEATER) ? "Repeater" :
|
||||||
|
(r.type == ADV_TYPE_SENSOR) ? "Sensor" :
|
||||||
|
(r.type == ADV_TYPE_ROOM) ? "Room" : "Node";
|
||||||
|
|
||||||
|
// header line: inverted background
|
||||||
display.setColor(DisplayDriver::LIGHT);
|
display.setColor(DisplayDriver::LIGHT);
|
||||||
|
display.drawRect(0, y, display.width(), D_BOX_H);
|
||||||
|
display.fillRect(1, y + 1, display.width() - 2, 8);
|
||||||
|
display.setColor(DisplayDriver::DARK);
|
||||||
|
|
||||||
// left: contact name if known, otherwise "[Type]"
|
// header: name (or [Type]) left, type label right
|
||||||
char label[32];
|
char label[32];
|
||||||
if (r.name[0]) {
|
if (r.name[0]) {
|
||||||
strncpy(label, r.name, sizeof(label) - 1);
|
strncpy(label, r.name, sizeof(label) - 1);
|
||||||
label[sizeof(label) - 1] = '\0';
|
label[sizeof(label) - 1] = '\0';
|
||||||
} else {
|
} else {
|
||||||
snprintf(label, sizeof(label), "[%s]", typeName(r.type));
|
snprintf(label, sizeof(label), "[%s]", typeStr);
|
||||||
}
|
}
|
||||||
char filtered[32];
|
char filtered[32];
|
||||||
display.translateUTF8ToBlocks(filtered, label, sizeof(filtered));
|
display.translateUTF8ToBlocks(filtered, label, sizeof(filtered));
|
||||||
display.drawTextEllipsized(2, y, DIST_COL - 4, filtered);
|
int tw = display.getTextWidth(typeStr);
|
||||||
|
display.drawTextEllipsized(3, y + 1, display.width() - 6 - tw, filtered);
|
||||||
|
display.setCursor(display.width() - 3 - tw, y + 1);
|
||||||
|
display.print(typeStr);
|
||||||
|
|
||||||
// right: type+RSSI for known ("Rpt-87"), just RSSI with '*' for new ("*-87")
|
// body line: RSSI / SNR / remote SNR
|
||||||
const char* st = (r.type == ADV_TYPE_REPEATER) ? "Rpt" :
|
display.setColor(DisplayDriver::LIGHT);
|
||||||
(r.type == ADV_TYPE_SENSOR) ? "Snsr" :
|
char sig[32];
|
||||||
(r.type == ADV_TYPE_ROOM) ? "Room" : "?";
|
int snr = r.snr_x4 / 4;
|
||||||
char rtype[12];
|
int rsnr = r.remote_snr_x4 / 4;
|
||||||
if (r.is_known)
|
snprintf(sig, sizeof(sig), "RSSI:%d SNR:%d Rem:%d", (int)r.rssi, snr, rsnr);
|
||||||
snprintf(rtype, sizeof(rtype), "%s%d", st, (int)r.rssi);
|
display.drawTextEllipsized(3, y + 10, display.width() - 6, sig);
|
||||||
else
|
|
||||||
snprintf(rtype, sizeof(rtype), "*%d", (int)r.rssi);
|
|
||||||
display.setCursor(DIST_COL, y);
|
|
||||||
display.print(rtype);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
display.setColor(DisplayDriver::LIGHT);
|
display.setColor(DisplayDriver::LIGHT);
|
||||||
if (_dscroll > 0)
|
if (_dscroll > 0)
|
||||||
{ display.setCursor(display.width() - 6, START_Y); display.print("^"); }
|
{ display.setCursor(display.width() - 6, D_START_Y + 1); display.print("^"); }
|
||||||
if (_dscroll + VISIBLE < _dresult_count)
|
if (_dscroll + D_VISIBLE < _dresult_count)
|
||||||
{ display.setCursor(display.width() - 6, START_Y + (VISIBLE - 1) * ITEM_H); display.print("v"); }
|
{ display.setCursor(display.width() - 6, D_START_Y + D_VISIBLE * D_ITEM_H - 10); display.print("v"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
return _discovering ? 200 : 2000;
|
return _discovering ? 200 : 2000;
|
||||||
@@ -247,7 +255,7 @@ class NearbyScreen : public UIScreen {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (c == KEY_UP && _dscroll > 0) { _dscroll--; return true; }
|
if (c == KEY_UP && _dscroll > 0) { _dscroll--; return true; }
|
||||||
if (c == KEY_DOWN && _dscroll + VISIBLE < _dresult_count) { _dscroll++; return true; }
|
if (c == KEY_DOWN && _dscroll + 2 < _dresult_count) { _dscroll++; return true; }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user