mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-26 14:58:12 +00:00
feat(repeater): politeness controls, dedicated radio profile, and diagnostics
Settings > Radio gains a repeater toggle, 16 community-suggested radio presets plus manual Freq/SF/BW/CR tuning (digit-by-digit Freq editor), 4 persisted user preset slots, and the packet pool bumped 16->32 so queued retransmits stop starving incoming-packet allocation while relaying. Four opt-in politeness knobs (skip-advert, max-hops, yield, min-SNR), all flood-only and off by default, plus overhear suppression that cancels a queued retransmit if a peer relays the same packet first. Adaptive Power Control is suppressed while relaying (pins TX power to the ceiling) and duty-cycle RX is forced off, since a repeater needs to hear and relay at consistent power. A dedicated Tools > Repeater screen consolidates the toggle, the politeness knobs, and live forwarding stats, plus an optional "Custom" radio profile — a dedicated frequency/SF/BW/CR for relaying, separate from the companion's own network, band-matched to the companion frequency by default and used everywhere a radio change can happen (boot, on-device toggle, app-driven CMD_SET_RADIO_PARAMS, Settings radio edits) so the device never silently falls back to the wrong params mid-relay. Diagnostics gains the actually-forwarded packet count, real heap-free via mallinfo(), a reset-counters popup, and hardened loop-detect bounds. Also: a frequency-floor fix and a float-equality preset-match fix in the repeater profile logic, deduped BW-table/valCol/profile- seeding helpers shared between Settings and the Repeater screen, and a build.sh fix tolerating control characters in `pio project config`'s JSON dump. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -778,9 +778,14 @@ public:
|
||||
}
|
||||
|
||||
void updateChannelUnread() {
|
||||
if (_hist_sel < 0 || _sel_channel_idx < 0 || _sel_channel_idx >= MAX_GROUP_CHANNELS) return;
|
||||
if (_hist_sel > _viewing_max_seen) _viewing_max_seen = _hist_sel;
|
||||
if (_sel_channel_idx < 0 || _sel_channel_idx >= MAX_GROUP_CHANNELS) return;
|
||||
// histEntryForChannel is newest-first: index 0 = newest (unread), higher = older.
|
||||
// Count everything actually rendered on screen as seen — not just the
|
||||
// highlighted row — so a taller screen that fits more boxes at once marks
|
||||
// more read up front, instead of requiring a press per row.
|
||||
int seen_to = _hist_scroll + _hist_visible - 1;
|
||||
if (_hist_sel > seen_to) seen_to = _hist_sel;
|
||||
if (seen_to > _viewing_max_seen) _viewing_max_seen = seen_to;
|
||||
// Each step down from 0 sees one more message; seen count = max_seen + 1.
|
||||
int remaining = _unread_at_entry - (_viewing_max_seen + 1);
|
||||
_ch_unread[_sel_channel_idx] = (uint8_t)(remaining > 0 ? remaining : 0);
|
||||
@@ -1182,6 +1187,7 @@ public:
|
||||
}
|
||||
}
|
||||
_hist_visible = n_vis;
|
||||
updateChannelUnread(); // mark everything in the just-computed visible window as seen
|
||||
|
||||
for (int i = 0; i < n_vis && (_hist_scroll + i) < ch_hist_count; i++) {
|
||||
int item = _hist_scroll + i;
|
||||
@@ -1555,7 +1561,10 @@ public:
|
||||
_hist_sel = hc > 0 ? 0 : -1;
|
||||
_viewing_max_seen = _hist_sel >= 0 ? _hist_sel : 0;
|
||||
_phase = CHANNEL_HIST;
|
||||
updateChannelUnread();
|
||||
// Not updateChannelUnread() here: _hist_visible is still whatever this
|
||||
// channel's first render() hasn't computed yet (stale, shared with
|
||||
// DM_HIST) — calling it now could ratchet _viewing_max_seen past what's
|
||||
// actually about to be shown. render() calls it once that's fresh.
|
||||
if (_share_mode) beginShareCompose(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user