feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
#pragma once
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
#ifndef M_PI
|
|
|
|
|
#define M_PI 3.14159265358979323846
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
class NearbyScreen : public UIScreen {
|
|
|
|
|
UITask* _task;
|
|
|
|
|
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
int _visible = 4; // updated each render; used by handleInput for scroll clamping
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
|
2026-05-14 16:21:11 +02:00
|
|
|
static const int FILTER_COUNT = 6;
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
static const char* FILTER_LABELS[FILTER_COUNT];
|
|
|
|
|
static const uint8_t FILTER_TYPES[FILTER_COUNT];
|
|
|
|
|
|
2026-05-21 07:57:21 +02:00
|
|
|
// ── nearby list state ────────────────────────────────────────────────────────
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
struct Entry {
|
2026-05-14 16:29:04 +02:00
|
|
|
char name[32];
|
|
|
|
|
int32_t lat_e6, lon_e6;
|
|
|
|
|
float dist_km;
|
|
|
|
|
uint8_t type;
|
2026-05-21 07:57:21 +02:00
|
|
|
int contact_idx;
|
2026-05-21 00:13:36 +02:00
|
|
|
uint32_t lastmod;
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const int MAX_NEARBY = 32;
|
|
|
|
|
Entry _entries[MAX_NEARBY];
|
|
|
|
|
int _count;
|
|
|
|
|
int _sel;
|
|
|
|
|
int _scroll;
|
|
|
|
|
bool _detail;
|
|
|
|
|
int32_t _own_lat, _own_lon;
|
|
|
|
|
bool _own_gps;
|
|
|
|
|
uint8_t _filter;
|
|
|
|
|
|
2026-05-14 16:29:04 +02:00
|
|
|
unsigned long _detail_refresh_ms;
|
|
|
|
|
static const unsigned long DETAIL_REFRESH_MS = 10000UL;
|
|
|
|
|
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
PopupMenu _ctx_menu;
|
|
|
|
|
|
2026-05-21 07:57:21 +02:00
|
|
|
// ── discover sub-screen state ────────────────────────────────────────────────
|
|
|
|
|
bool _discover_mode;
|
|
|
|
|
bool _discovering;
|
|
|
|
|
unsigned long _discover_started_ms;
|
|
|
|
|
static const unsigned long DISCOVER_DURATION_MS = 8000UL;
|
|
|
|
|
|
|
|
|
|
DiscoverResult _dresults[DISCOVER_RESULTS_MAX];
|
|
|
|
|
int _dresult_count;
|
|
|
|
|
int _dscroll;
|
2026-05-21 09:05:15 +02:00
|
|
|
int _dsel;
|
|
|
|
|
bool _ddetail;
|
2026-05-21 07:57:21 +02:00
|
|
|
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
int _d_visible = 2; // updated each render; used by handleInputDiscover
|
2026-05-21 22:08:28 +02:00
|
|
|
|
2026-05-21 07:57:21 +02:00
|
|
|
// ── helpers ──────────────────────────────────────────────────────────────────
|
2026-05-21 09:14:16 +02:00
|
|
|
static void pubKeyToBase64(const uint8_t* key, char* out, int out_len) {
|
|
|
|
|
static const char T[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
|
int j = 0;
|
|
|
|
|
for (int i = 0; i < PUB_KEY_SIZE && j + 5 < out_len; i += 3) {
|
|
|
|
|
uint32_t b = ((uint32_t)key[i] << 16)
|
|
|
|
|
| (i+1 < PUB_KEY_SIZE ? (uint32_t)key[i+1] << 8 : 0)
|
|
|
|
|
| (i+2 < PUB_KEY_SIZE ? (uint32_t)key[i+2] : 0);
|
|
|
|
|
out[j++] = T[(b >> 18) & 63];
|
|
|
|
|
out[j++] = T[(b >> 12) & 63];
|
|
|
|
|
if (i+1 < PUB_KEY_SIZE) out[j++] = T[(b >> 6) & 63];
|
|
|
|
|
if (i+2 < PUB_KEY_SIZE) out[j++] = T[b & 63];
|
|
|
|
|
}
|
|
|
|
|
out[j] = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
static float haversineKm(int32_t lat1, int32_t lon1, int32_t lat2, int32_t lon2) {
|
|
|
|
|
static const float DEG2RAD = (float)M_PI / 180.0f;
|
|
|
|
|
float la1 = lat1 * (1e-6f * DEG2RAD);
|
|
|
|
|
float la2 = lat2 * (1e-6f * DEG2RAD);
|
|
|
|
|
float dla = (lat2 - lat1) * (1e-6f * DEG2RAD);
|
|
|
|
|
float dlo = (lon2 - lon1) * (1e-6f * DEG2RAD);
|
|
|
|
|
float a = sinf(dla/2)*sinf(dla/2) + cosf(la1)*cosf(la2)*sinf(dlo/2)*sinf(dlo/2);
|
|
|
|
|
return 6371.0f * 2.0f * asinf(sqrtf(a));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int bearingDeg(int32_t lat1, int32_t lon1, int32_t lat2, int32_t lon2) {
|
|
|
|
|
static const float DEG2RAD = (float)M_PI / 180.0f;
|
|
|
|
|
float la1 = lat1 * (1e-6f * DEG2RAD);
|
|
|
|
|
float la2 = lat2 * (1e-6f * DEG2RAD);
|
|
|
|
|
float dlo = (lon2 - lon1) * (1e-6f * DEG2RAD);
|
|
|
|
|
float b = atan2f(sinf(dlo)*cosf(la2),
|
|
|
|
|
cosf(la1)*sinf(la2) - sinf(la1)*cosf(la2)*cosf(dlo)) * (180.0f / (float)M_PI);
|
|
|
|
|
if (b < 0.0f) b += 360.0f;
|
|
|
|
|
return (int)(b + 0.5f) % 360;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-14 16:21:11 +02:00
|
|
|
static const char* bearingCardinal(int deg) {
|
|
|
|
|
static const char* dirs[] = { "N","NE","E","SE","S","SW","W","NW" };
|
|
|
|
|
return dirs[((deg + 22) % 360) / 45];
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-14 16:29:04 +02:00
|
|
|
static void fmtAge(char* buf, int n, uint32_t lastmod) {
|
|
|
|
|
uint32_t now = rtc_clock.getCurrentTime();
|
|
|
|
|
if (now < lastmod || lastmod == 0) { snprintf(buf, n, "unknown"); return; }
|
|
|
|
|
uint32_t age = now - lastmod;
|
|
|
|
|
if (age < 60) snprintf(buf, n, "%us ago", age);
|
|
|
|
|
else if (age < 3600) snprintf(buf, n, "%um ago", age / 60);
|
|
|
|
|
else if (age < 86400) snprintf(buf, n, "%uh ago", age / 3600);
|
|
|
|
|
else snprintf(buf, n, ">1d ago");
|
|
|
|
|
}
|
|
|
|
|
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
static void fmtDist(char* buf, int n, float km) {
|
|
|
|
|
if (km < 1.0f) snprintf(buf, n, "%dm", (int)(km * 1000 + 0.5f));
|
|
|
|
|
else if (km < 100.0f) snprintf(buf, n, "%.1fkm", km);
|
|
|
|
|
else snprintf(buf, n, "%dkm", (int)(km + 0.5f));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char* typeName(uint8_t t) {
|
|
|
|
|
switch (t) {
|
2026-05-14 15:49:23 +02:00
|
|
|
case ADV_TYPE_CHAT: return "Companion";
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
case ADV_TYPE_REPEATER: return "Repeater";
|
|
|
|
|
case ADV_TYPE_ROOM: return "Room";
|
|
|
|
|
case ADV_TYPE_SENSOR: return "Sensor";
|
|
|
|
|
default: return "Unknown";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void refresh() {
|
|
|
|
|
_count = 0;
|
|
|
|
|
_own_gps = false;
|
|
|
|
|
_own_lat = _own_lon = 0;
|
|
|
|
|
|
|
|
|
|
#if ENV_INCLUDE_GPS == 1
|
|
|
|
|
LocationProvider* loc = sensors.getLocationProvider();
|
|
|
|
|
if (loc && loc->isValid()) {
|
|
|
|
|
_own_lat = loc->getLatitude();
|
|
|
|
|
_own_lon = loc->getLongitude();
|
|
|
|
|
_own_gps = true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
int nc = the_mesh.getNumContacts();
|
|
|
|
|
for (int i = 0; i < nc && _count < MAX_NEARBY; i++) {
|
|
|
|
|
ContactInfo ci;
|
|
|
|
|
if (!the_mesh.getContactByIdx(i, ci)) continue;
|
2026-05-21 07:57:21 +02:00
|
|
|
if (_filter == 0 && !(ci.flags & 1)) continue;
|
|
|
|
|
if (_filter >= 2 && ci.type != FILTER_TYPES[_filter]) continue;
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
|
|
|
|
|
Entry& e = _entries[_count++];
|
|
|
|
|
strncpy(e.name, ci.name, sizeof(e.name) - 1);
|
|
|
|
|
e.name[sizeof(e.name) - 1] = '\0';
|
2026-05-14 15:49:23 +02:00
|
|
|
e.lat_e6 = ci.gps_lat;
|
|
|
|
|
e.lon_e6 = ci.gps_lon;
|
|
|
|
|
bool remote_gps = (ci.gps_lat != 0 || ci.gps_lon != 0);
|
|
|
|
|
e.dist_km = (_own_gps && remote_gps)
|
|
|
|
|
? haversineKm(_own_lat, _own_lon, ci.gps_lat, ci.gps_lon)
|
|
|
|
|
: -1.0f;
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
e.type = ci.type;
|
|
|
|
|
e.contact_idx = i;
|
2026-05-14 16:29:04 +02:00
|
|
|
e.lastmod = ci.lastmod;
|
2026-05-21 00:13:36 +02:00
|
|
|
}
|
|
|
|
|
|
2026-05-21 07:57:21 +02:00
|
|
|
// sort by distance ascending; nodes without GPS go to the end
|
2026-05-14 15:49:23 +02:00
|
|
|
for (int i = 0; i < _count - 1; i++) {
|
|
|
|
|
int best = i;
|
|
|
|
|
for (int j = i + 1; j < _count; j++) {
|
|
|
|
|
float dj = _entries[j].dist_km, db = _entries[best].dist_km;
|
|
|
|
|
if (dj >= 0.0f && (db < 0.0f || dj < db)) best = j;
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
}
|
2026-05-14 15:49:23 +02:00
|
|
|
if (best != i) { Entry tmp = _entries[i]; _entries[i] = _entries[best]; _entries[best] = tmp; }
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_count == 0) {
|
|
|
|
|
_sel = _scroll = 0;
|
|
|
|
|
} else if (_sel >= _count) {
|
|
|
|
|
_sel = _count - 1;
|
|
|
|
|
if (_scroll > _sel) _scroll = _sel;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-21 07:57:21 +02:00
|
|
|
// ── discover sub-screen ──────────────────────────────────────────────────────
|
|
|
|
|
void enterDiscoverMode() {
|
|
|
|
|
_discover_mode = true;
|
|
|
|
|
_discovering = true;
|
2026-05-21 09:05:15 +02:00
|
|
|
_ddetail = false;
|
2026-05-21 07:57:21 +02:00
|
|
|
_discover_started_ms = millis();
|
|
|
|
|
_dresult_count = 0;
|
|
|
|
|
_dscroll = 0;
|
2026-05-21 09:05:15 +02:00
|
|
|
_dsel = 0;
|
2026-05-21 07:57:21 +02:00
|
|
|
the_mesh.sendNodeDiscoverReq();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int renderDiscover(DisplayDriver& display) {
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
int lh = display.getLineHeight();
|
|
|
|
|
int hdr = display.headerH();
|
|
|
|
|
int d_box_h = 2 * lh + 3; // two text rows + padding
|
|
|
|
|
int d_item_h = d_box_h + 2;
|
|
|
|
|
int d_start_y = hdr;
|
|
|
|
|
_d_visible = display.listVisible(d_item_h);
|
|
|
|
|
if (_d_visible < 1) _d_visible = 1;
|
|
|
|
|
|
2026-05-21 09:05:15 +02:00
|
|
|
if (_ddetail) {
|
|
|
|
|
// ── full-screen detail for selected node ──────────────────────────────
|
|
|
|
|
const DiscoverResult& r = _dresults[_dsel];
|
|
|
|
|
const char* fullType = (r.type == ADV_TYPE_REPEATER) ? "Repeater" :
|
|
|
|
|
(r.type == ADV_TYPE_SENSOR) ? "Sensor" :
|
|
|
|
|
(r.type == ADV_TYPE_ROOM) ? "Room" : "Node";
|
|
|
|
|
|
|
|
|
|
// title bar: node name inverted
|
|
|
|
|
char label[32];
|
|
|
|
|
if (r.name[0]) { strncpy(label, r.name, 31); label[31] = '\0'; }
|
|
|
|
|
else { snprintf(label, sizeof(label), "[%s]", fullType); }
|
|
|
|
|
char filtered[32];
|
|
|
|
|
display.translateUTF8ToBlocks(filtered, label, sizeof(filtered));
|
|
|
|
|
display.setColor(DisplayDriver::LIGHT);
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.fillRect(0, 0, display.width(), hdr - 1);
|
2026-05-21 09:05:15 +02:00
|
|
|
display.setColor(DisplayDriver::DARK);
|
|
|
|
|
display.drawTextEllipsized(2, 1, display.width() - 4, filtered);
|
|
|
|
|
display.setColor(DisplayDriver::LIGHT);
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.fillRect(0, hdr - 1, display.width(), 1);
|
2026-05-21 09:05:15 +02:00
|
|
|
|
2026-05-22 19:11:25 +02:00
|
|
|
// public key as base64 — truncate to one line via charWidth
|
2026-05-21 09:14:16 +02:00
|
|
|
char b64[48];
|
|
|
|
|
pubKeyToBase64(r.pub_key, b64, sizeof(b64));
|
2026-05-22 19:11:25 +02:00
|
|
|
{
|
|
|
|
|
int max_chars = (display.width() - 4) / display.getCharWidth();
|
|
|
|
|
int b64_len = strlen(b64);
|
|
|
|
|
char b64_line[48];
|
|
|
|
|
if (b64_len > max_chars) {
|
|
|
|
|
strncpy(b64_line, b64, max_chars - 3);
|
|
|
|
|
b64_line[max_chars - 3] = '\0';
|
|
|
|
|
strcat(b64_line, "...");
|
|
|
|
|
} else {
|
|
|
|
|
strncpy(b64_line, b64, sizeof(b64_line) - 1);
|
|
|
|
|
b64_line[sizeof(b64_line) - 1] = '\0';
|
|
|
|
|
}
|
|
|
|
|
display.setCursor(2, hdr);
|
|
|
|
|
display.print(b64_line);
|
|
|
|
|
}
|
2026-05-21 09:11:32 +02:00
|
|
|
|
2026-05-22 23:13:27 +02:00
|
|
|
// distribute 4 remaining lines below b64 — compact step, shrink only if needed
|
|
|
|
|
int step = display.lineStep();
|
|
|
|
|
if (step * 5 > display.height() - hdr) step = (display.height() - hdr) / 5;
|
2026-05-21 09:05:15 +02:00
|
|
|
char buf[32];
|
|
|
|
|
snprintf(buf, sizeof(buf), "RSSI: %d dBm", (int)r.rssi);
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.setCursor(2, hdr + step); display.print(buf);
|
2026-05-21 09:05:15 +02:00
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "SNR: %d dB", (int)(r.snr_x4 / 4));
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.setCursor(2, hdr + step * 2); display.print(buf);
|
2026-05-21 09:05:15 +02:00
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "Rem: %d dB", (int)(r.remote_snr_x4 / 4));
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.setCursor(2, hdr + step * 3); display.print(buf);
|
2026-05-21 09:05:15 +02:00
|
|
|
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.setCursor(2, hdr + step * 4);
|
2026-05-21 09:05:15 +02:00
|
|
|
display.print(r.is_known ? "Status: known" : "Status: new");
|
|
|
|
|
|
|
|
|
|
return 5000;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── list view ─────────────────────────────────────────────────────────────
|
2026-05-21 07:57:21 +02:00
|
|
|
_dresult_count = the_mesh.getDiscoverResults(_dresults, DISCOVER_RESULTS_MAX);
|
|
|
|
|
|
2026-05-21 08:56:54 +02:00
|
|
|
if (_discovering && millis() - _discover_started_ms >= DISCOVER_DURATION_MS)
|
2026-05-21 07:57:21 +02:00
|
|
|
_discovering = false;
|
|
|
|
|
|
|
|
|
|
display.setColor(DisplayDriver::LIGHT);
|
|
|
|
|
char title[28];
|
2026-05-21 08:56:54 +02:00
|
|
|
if (_discovering)
|
2026-05-21 07:57:21 +02:00
|
|
|
snprintf(title, sizeof(title), "SCANNING... (%d)", _dresult_count);
|
2026-05-21 08:56:54 +02:00
|
|
|
else if (_dresult_count == 0)
|
|
|
|
|
snprintf(title, sizeof(title), "DISCOVER: none");
|
|
|
|
|
else
|
|
|
|
|
snprintf(title, sizeof(title), "DISCOVER (%d found)", _dresult_count);
|
2026-05-21 07:57:21 +02:00
|
|
|
display.drawTextCentered(display.width() / 2, 0, title);
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.fillRect(0, hdr - 1, display.width(), 1);
|
2026-05-21 07:57:21 +02:00
|
|
|
|
|
|
|
|
if (_dresult_count == 0) {
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.drawTextCentered(display.width() / 2, display.height() / 2,
|
2026-05-21 07:57:21 +02:00
|
|
|
_discovering ? "Waiting for replies..." : "No nodes found");
|
|
|
|
|
} else {
|
2026-05-21 09:05:15 +02:00
|
|
|
if (_dsel >= _dresult_count) _dsel = _dresult_count - 1;
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
if (_dscroll > _dresult_count - _d_visible)
|
|
|
|
|
_dscroll = _dresult_count > _d_visible ? _dresult_count - _d_visible : 0;
|
2026-05-21 22:08:28 +02:00
|
|
|
if (_dscroll < 0) _dscroll = 0;
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
|
|
|
|
|
for (int i = 0; i < _d_visible && (_dscroll + i) < _dresult_count; i++) {
|
2026-05-21 07:57:21 +02:00
|
|
|
int idx = _dscroll + i;
|
2026-05-21 09:05:15 +02:00
|
|
|
bool sel = (idx == _dsel);
|
2026-05-21 07:57:21 +02:00
|
|
|
const DiscoverResult& r = _dresults[idx];
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
int y = d_start_y + i * d_item_h;
|
2026-05-21 07:57:21 +02:00
|
|
|
|
2026-05-21 09:05:15 +02:00
|
|
|
const char* typeStr = (r.type == ADV_TYPE_REPEATER) ? "Rpt" :
|
|
|
|
|
(r.type == ADV_TYPE_SENSOR) ? "Snsr" :
|
|
|
|
|
(r.type == ADV_TYPE_ROOM) ? "Room" : "?";
|
2026-05-21 08:56:54 +02:00
|
|
|
|
2026-05-21 07:57:21 +02:00
|
|
|
display.setColor(DisplayDriver::LIGHT);
|
2026-05-21 09:05:15 +02:00
|
|
|
if (sel) {
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.fillRect(0, y, display.width(), d_box_h);
|
2026-05-21 09:05:15 +02:00
|
|
|
display.setColor(DisplayDriver::DARK);
|
|
|
|
|
} else {
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.drawRect(0, y, display.width(), d_box_h);
|
|
|
|
|
display.fillRect(1, y + 1, display.width() - 2, lh);
|
2026-05-21 09:05:15 +02:00
|
|
|
display.setColor(DisplayDriver::DARK);
|
|
|
|
|
}
|
2026-05-21 07:57:21 +02:00
|
|
|
|
2026-05-21 09:05:15 +02:00
|
|
|
// header: name left, type right
|
2026-05-21 07:57:21 +02:00
|
|
|
char label[32];
|
2026-05-21 09:05:15 +02:00
|
|
|
if (r.name[0]) { strncpy(label, r.name, 31); label[31] = '\0'; }
|
|
|
|
|
else {
|
|
|
|
|
const char* ft = (r.type == ADV_TYPE_REPEATER) ? "Repeater" :
|
|
|
|
|
(r.type == ADV_TYPE_SENSOR) ? "Sensor" :
|
|
|
|
|
(r.type == ADV_TYPE_ROOM) ? "Room" : "Node";
|
|
|
|
|
snprintf(label, sizeof(label), "[%s]", ft);
|
2026-05-21 07:57:21 +02:00
|
|
|
}
|
|
|
|
|
char filtered[32];
|
|
|
|
|
display.translateUTF8ToBlocks(filtered, label, sizeof(filtered));
|
2026-05-21 08:56:54 +02:00
|
|
|
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);
|
|
|
|
|
|
2026-05-21 09:05:15 +02:00
|
|
|
// body: RSSI + SNR
|
|
|
|
|
display.setColor(sel ? DisplayDriver::DARK : DisplayDriver::LIGHT);
|
|
|
|
|
char sig[24];
|
|
|
|
|
snprintf(sig, sizeof(sig), "RSSI:%d SNR:%d", (int)r.rssi, (int)(r.snr_x4 / 4));
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.drawTextEllipsized(3, y + lh + 2, display.width() - 6, sig);
|
2026-05-21 07:57:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
display.setColor(DisplayDriver::LIGHT);
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
int cw = display.getCharWidth();
|
2026-05-21 07:57:21 +02:00
|
|
|
if (_dscroll > 0)
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
{ display.setCursor(display.width() - cw, d_start_y); display.print("^"); }
|
|
|
|
|
if (_dscroll + _d_visible < _dresult_count)
|
|
|
|
|
{ display.setCursor(display.width() - cw, d_start_y + (_d_visible - 1) * d_item_h); display.print("v"); }
|
2026-05-21 07:57:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _discovering ? 200 : 2000;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool handleInputDiscover(char c) {
|
2026-05-21 09:05:15 +02:00
|
|
|
if (_ddetail) {
|
2026-05-21 22:08:28 +02:00
|
|
|
if (c == KEY_CANCEL) { _ddetail = false; return true; }
|
|
|
|
|
if (c == KEY_CONTEXT_MENU || c == KEY_ENTER) {
|
|
|
|
|
enterDiscoverMode(); // re-scan; clears _ddetail
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2026-05-21 09:05:15 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2026-05-21 07:57:21 +02:00
|
|
|
if (c == KEY_CANCEL) {
|
|
|
|
|
_discover_mode = false;
|
2026-05-21 09:05:15 +02:00
|
|
|
refresh();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (c == KEY_ENTER && _dresult_count > 0) {
|
|
|
|
|
_ddetail = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (c == KEY_CONTEXT_MENU) {
|
|
|
|
|
enterDiscoverMode(); // re-scan
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (c == KEY_UP && _dsel > 0) {
|
|
|
|
|
_dsel--;
|
|
|
|
|
if (_dsel < _dscroll) _dscroll = _dsel;
|
2026-05-21 07:57:21 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2026-05-21 09:05:15 +02:00
|
|
|
if (c == KEY_DOWN && _dsel < _dresult_count - 1) {
|
|
|
|
|
_dsel++;
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
if (_dsel >= _dscroll + _d_visible) _dscroll = _dsel - _d_visible + 1;
|
2026-05-21 07:57:21 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
public:
|
|
|
|
|
NearbyScreen(UITask* task)
|
2026-05-21 22:08:28 +02:00
|
|
|
: _task(task), _count(0), _sel(0), _scroll(0), _detail(false),
|
|
|
|
|
_own_lat(0), _own_lon(0), _own_gps(false), _filter(0),
|
|
|
|
|
_detail_refresh_ms(0),
|
|
|
|
|
_discover_mode(false), _discovering(false), _discover_started_ms(0),
|
|
|
|
|
_dresult_count(0), _dscroll(0), _dsel(0), _ddetail(false) {}
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
|
|
|
|
|
void enter() {
|
|
|
|
|
_sel = _scroll = 0;
|
|
|
|
|
_detail = false;
|
|
|
|
|
_filter = 0;
|
2026-05-21 07:57:21 +02:00
|
|
|
_discover_mode = false;
|
2026-05-21 09:05:15 +02:00
|
|
|
_ddetail = false;
|
|
|
|
|
_dsel = 0;
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
_ctx_menu.active = false;
|
|
|
|
|
refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int render(DisplayDriver& display) override {
|
|
|
|
|
display.setTextSize(1);
|
|
|
|
|
|
2026-05-21 07:57:21 +02:00
|
|
|
// ── discover sub-screen ──────────────────────────────────────────────────
|
|
|
|
|
if (_discover_mode) return renderDiscover(display);
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
|
2026-05-14 16:29:04 +02:00
|
|
|
// periodic refresh in detail view — preserve selected contact by idx
|
|
|
|
|
if (_detail && millis() - _detail_refresh_ms >= DETAIL_REFRESH_MS) {
|
|
|
|
|
int saved_contact_idx = (_sel < _count) ? _entries[_sel].contact_idx : -1;
|
|
|
|
|
refresh();
|
|
|
|
|
bool found = false;
|
|
|
|
|
if (saved_contact_idx >= 0) {
|
|
|
|
|
for (int i = 0; i < _count; i++) {
|
|
|
|
|
if (_entries[i].contact_idx == saved_contact_idx) { _sel = i; found = true; break; }
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-05-21 07:57:21 +02:00
|
|
|
if (!found) _detail = false;
|
2026-05-14 16:29:04 +02:00
|
|
|
_detail_refresh_ms = millis();
|
|
|
|
|
}
|
|
|
|
|
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
// ── detail view ──────────────────────────────────────────────────────────
|
|
|
|
|
if (_detail && _sel < _count) {
|
|
|
|
|
const Entry& e = _entries[_sel];
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
int hdr = display.headerH();
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
|
|
|
|
|
display.setColor(DisplayDriver::LIGHT);
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.fillRect(0, 0, display.width(), hdr - 1);
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
display.setColor(DisplayDriver::DARK);
|
|
|
|
|
char filtered[32];
|
|
|
|
|
display.translateUTF8ToBlocks(filtered, e.name, sizeof(filtered));
|
|
|
|
|
display.drawTextEllipsized(2, 1, display.width() - 4, filtered);
|
|
|
|
|
display.setColor(DisplayDriver::LIGHT);
|
|
|
|
|
|
2026-05-22 23:13:27 +02:00
|
|
|
// 5 lines: lat, lon, dist+bearing, type, seen — compact step, shrink only if needed
|
|
|
|
|
int step = display.lineStep();
|
|
|
|
|
if (step * 5 > display.height() - hdr) step = (display.height() - hdr) / 5;
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
char buf[32];
|
|
|
|
|
snprintf(buf, sizeof(buf), "Lat: %.5f", e.lat_e6 / 1e6);
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.setCursor(2, hdr); display.print(buf);
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "Lon: %.5f", e.lon_e6 / 1e6);
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.setCursor(2, hdr + step); display.print(buf);
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
|
|
|
|
|
if (e.dist_km >= 0.0f) {
|
|
|
|
|
char dist[12];
|
|
|
|
|
fmtDist(dist, sizeof(dist), e.dist_km);
|
2026-05-14 16:21:11 +02:00
|
|
|
int az = bearingDeg(_own_lat, _own_lon, e.lat_e6, e.lon_e6);
|
2026-05-22 19:11:25 +02:00
|
|
|
snprintf(buf, sizeof(buf), "Dist: %s %s", dist, bearingCardinal(az));
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
} else {
|
2026-05-22 19:11:25 +02:00
|
|
|
snprintf(buf, sizeof(buf), "Dist: no GPS");
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
}
|
2026-05-22 19:11:25 +02:00
|
|
|
display.setCursor(2, hdr + step * 2); display.print(buf);
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
|
2026-05-19 17:44:49 +02:00
|
|
|
snprintf(buf, sizeof(buf), "Type: %s", typeName(e.type));
|
2026-05-22 19:11:25 +02:00
|
|
|
display.setCursor(2, hdr + step * 3); display.print(buf);
|
2026-05-14 16:29:04 +02:00
|
|
|
|
|
|
|
|
char age[16];
|
|
|
|
|
fmtAge(age, sizeof(age), e.lastmod);
|
2026-05-19 17:44:49 +02:00
|
|
|
snprintf(buf, sizeof(buf), "Seen: %s", age);
|
2026-05-22 19:11:25 +02:00
|
|
|
display.setCursor(2, hdr + step * 4); display.print(buf);
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
|
2026-05-14 16:17:52 +02:00
|
|
|
return 2000;
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── list view ────────────────────────────────────────────────────────────
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
int item_h = display.lineStep();
|
|
|
|
|
int start_y = display.listStart();
|
|
|
|
|
int dist_col = display.width() - display.getCharWidth() * 7;
|
|
|
|
|
_visible = display.listVisible(item_h);
|
|
|
|
|
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
display.setColor(DisplayDriver::LIGHT);
|
2026-05-21 07:57:21 +02:00
|
|
|
char title[22];
|
|
|
|
|
snprintf(title, sizeof(title), "NEARBY[%s]", FILTER_LABELS[_filter]);
|
|
|
|
|
display.drawTextCentered(display.width() / 2, 0, title);
|
2026-05-22 23:13:27 +02:00
|
|
|
display.fillRect(0, display.headerH() - 1, display.width(), display.sepH());
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
|
|
|
|
|
if (_count == 0) {
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.drawTextCentered(display.width() / 2, display.height() / 2 - display.lineStep() / 2, "No contacts found");
|
|
|
|
|
display.drawTextCentered(display.width() / 2, display.height() / 2 + display.lineStep() / 2, "[Enter]=Discover");
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
} else {
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
for (int i = 0; i < _visible && (_scroll + i) < _count; i++) {
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
int idx = _scroll + i;
|
|
|
|
|
bool sel = (idx == _sel);
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
int y = start_y + i * item_h;
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
const Entry& e = _entries[idx];
|
|
|
|
|
|
refactor(ui): drawSelectionRow helper for the 5-line invert/restore pattern
Eight screens repeated the same if/else block to invert the row
background for selected items. Add DisplayDriver::drawSelectionRow that
sets LIGHT, optionally fills the rect, and leaves the colour as DARK
when sel (so the caller's text renders inverted). 61 lines removed
across SettingsScreen, KeyboardWidget (cells + special row), ToolsScreen,
DashboardConfigScreen, BotScreen, RingtoneEditorScreen (note slots +
menu), NearbyScreen, QuickMsgScreen (4 list views).
Card-style rows (QuickMsg hist, NearbyScreen discover, RingtoneEditor
notes display) keep their original drawRect/partial-fill outline for
unselected — they don't match the simple-invert pattern.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 20:33:02 +02:00
|
|
|
display.drawSelectionRow(0, y - 1, display.width(), item_h - 1, sel);
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
|
|
|
|
|
char filt[32];
|
|
|
|
|
display.translateUTF8ToBlocks(filt, e.name, sizeof(filt));
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.drawTextEllipsized(2, y, dist_col - 4, filt);
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
|
|
|
|
|
display.setColor(sel ? DisplayDriver::DARK : DisplayDriver::LIGHT);
|
|
|
|
|
char dist[10];
|
|
|
|
|
if (e.dist_km >= 0.0f) fmtDist(dist, sizeof(dist), e.dist_km);
|
|
|
|
|
else strncpy(dist, "?GPS", sizeof(dist));
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
display.setCursor(dist_col, y);
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
display.print(dist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
display.setColor(DisplayDriver::LIGHT);
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
int cw = display.getCharWidth();
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
if (_scroll > 0)
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
{ display.setCursor(display.width() - cw, start_y); display.print("^"); }
|
|
|
|
|
if (_scroll + _visible < _count)
|
|
|
|
|
{ display.setCursor(display.width() - cw, start_y + (_visible - 1) * item_h); display.print("v"); }
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_ctx_menu.active) {
|
|
|
|
|
_ctx_menu.render(display);
|
|
|
|
|
return 50;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-21 07:57:21 +02:00
|
|
|
return _count == 0 ? 3000 : 2000;
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool handleInput(char c) override {
|
2026-05-21 07:57:21 +02:00
|
|
|
// ── discover sub-screen ──────────────────────────────────────────────────
|
|
|
|
|
if (_discover_mode) return handleInputDiscover(c);
|
|
|
|
|
|
|
|
|
|
// ── detail view ─────────────────────────────────────────────────────────
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
if (_detail) {
|
2026-05-21 07:57:21 +02:00
|
|
|
if (c == KEY_CANCEL || c == KEY_CONTEXT_MENU) { _detail = false; return true; }
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-21 07:57:21 +02:00
|
|
|
// ── context menu ─────────────────────────────────────────────────────────
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
if (_ctx_menu.active) {
|
|
|
|
|
auto res = _ctx_menu.handleInput(c);
|
2026-05-29 00:25:02 +02:00
|
|
|
if (res == PopupMenu::SELECTED)
|
|
|
|
|
enterDiscoverMode();
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-21 07:57:21 +02:00
|
|
|
// ── list view ────────────────────────────────────────────────────────────
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
if (c == KEY_CANCEL) { _task->gotoToolsScreen(); return true; }
|
|
|
|
|
if (c == KEY_CONTEXT_MENU) {
|
2026-05-29 00:25:02 +02:00
|
|
|
_ctx_menu.begin("Options", 1);
|
2026-05-21 00:13:36 +02:00
|
|
|
_ctx_menu.addItem("Discover nearby");
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (c == KEY_UP && _sel > 0) {
|
|
|
|
|
_sel--;
|
|
|
|
|
if (_sel < _scroll) _scroll = _sel;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (c == KEY_DOWN && _sel < _count - 1) {
|
|
|
|
|
_sel++;
|
refactor: replace all hardcoded pixel positions with layout helpers
Add lineStep(), headerH(), listStart(), listVisible(), valCol() to
DisplayDriver so layout derives from getLineHeight() instead of fixed
OLED constants. Refactor all screens (SettingsScreen, NearbyScreen,
FullscreenMsgView, QuickMsgScreen, BotScreen, DashboardConfigScreen,
AutoAdvertScreen, RingtoneEditorScreen) and all HomeScreen pages plus
the lock screen and splash screen in UITask.cpp.
On OLED (lh=8) positions are unchanged; on landscape e-ink (lh=16) all
text and widgets now scale correctly to the 250×122 display.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 18:05:09 +02:00
|
|
|
if (_sel >= _scroll + _visible) _scroll = _sel - _visible + 1;
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2026-05-21 08:13:13 +02:00
|
|
|
if (c == KEY_ENTER && _count == 0) { enterDiscoverMode(); return true; }
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
if (c == KEY_ENTER && _count > 0) {
|
2026-05-14 16:17:52 +02:00
|
|
|
_detail = true;
|
2026-05-14 16:29:04 +02:00
|
|
|
_detail_refresh_ms = millis();
|
feat: NearbyScreen, configurable clock dashboard, memory optimizations
- Add NearbyScreen: GPS contact list with haversine distance sort,
type filter (ALL/Chat/Rpt/Room/Snsr), detail view with ping (RTT via
ACK poll), node scan via advert(), context menu
- Add DashboardConfigScreen: configure up to 3 data fields on the clock
page (Battery, Temp, Humidity, Pressure, GPS, Altitude, Lux, CO2,
Contacts); entered via long-press ENTER on clock page
- Rework HP_CLOCK layout: full-screen clock (size 2 at y=0), date at
y=19, separator at y=28, three data field rows at y=31/41/51;
hide node name/battery indicator on clock page
- Persist dashboard_fields[3] in NodePrefs and DataStore
- Add isAckPending() to MyMesh for NearbyScreen ping detection
- Wire NearbyScreen into ToolsScreen and UITask
- Reduce NearbyScreen entry buffer from MAX_CONTACTS(100) to 32,
saving ~3.3 KB RAM
- Switch haversine/bearing math from double to float (sinf/cosf/atan2f),
eliminating double libm and saving ~5-10 KB flash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 11:28:36 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (c == KEY_LEFT) {
|
|
|
|
|
_filter = (_filter + FILTER_COUNT - 1) % FILTER_COUNT;
|
|
|
|
|
refresh();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (c == KEY_RIGHT) {
|
|
|
|
|
_filter = (_filter + 1) % FILTER_COUNT;
|
|
|
|
|
refresh();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-05-14 16:21:11 +02:00
|
|
|
const char* NearbyScreen::FILTER_LABELS[6] = { "Fav", "ALL", "Comp", "Rpt", "Room", "Snsr" };
|
|
|
|
|
const uint8_t NearbyScreen::FILTER_TYPES[6] = { 0, 0, ADV_TYPE_CHAT, ADV_TYPE_REPEATER, ADV_TYPE_ROOM, ADV_TYPE_SENSOR };
|