feat(repeater): default network profile, band-matched to companion freq

Enabling the repeater now defaults to a dedicated radio profile rather
than relaying on the companion's current frequency: same-network
repeating isn't the MeshCore community norm. The default profile is
seeded with a frequency in the same legal band as the companion's own
network (433/868/915 MHz, via defaultRepeaterFreqForBand()) rather than
a flat firmware constant, so it can't land outside what's allowed for
the operator's region.

Also fixes a gap where a true first boot (no prefs file yet) never hit
the DataStore.cpp migration fallback and stayed on repeater_use_profile=0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-06-20 01:04:35 +02:00
parent aba924bac9
commit afe7b8a0ca
7 changed files with 81 additions and 26 deletions

View File

@@ -356,16 +356,23 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
rd(&_prefs.repeater_bw, sizeof(_prefs.repeater_bw));
rd(&_prefs.repeater_sf, sizeof(_prefs.repeater_sf));
rd(&_prefs.repeater_cr, sizeof(_prefs.repeater_cr));
// Pre-0x10 files leave stray sentinel bytes here. If the profile fields aren't a
// valid radio config, force the profile off so the repeater can't switch to junk.
// Pre-0x10 files leave stray sentinel bytes here, same as a never-configured
// device. Either way there's no valid saved profile, so default to a profile
// in the same band as the companion's own network (_prefs.freq, already read
// above) rather than "Current" — a repeater silently following the companion
// onto whatever private network it later joins isn't the MeshCore community
// norm; that stays opt-in. Band-matched rather than a flat frequency so the
// default can't land outside what's legal where the companion is set up.
if (_prefs.repeater_use_profile > 1) _prefs.repeater_use_profile = 0;
if (!(_prefs.repeater_freq >= 100.0f && _prefs.repeater_freq <= 960.0f
&& _prefs.repeater_sf >= 5 && _prefs.repeater_sf <= 12
&& _prefs.repeater_cr >= 5 && _prefs.repeater_cr <= 8
&& _prefs.repeater_bw >= 7.0f && _prefs.repeater_bw <= 510.0f)) {
_prefs.repeater_use_profile = 0;
_prefs.repeater_freq = _prefs.repeater_bw = 0.0f;
_prefs.repeater_sf = _prefs.repeater_cr = 0;
_prefs.repeater_use_profile = 1;
_prefs.repeater_freq = defaultRepeaterFreqForBand(_prefs.freq);
_prefs.repeater_bw = LORA_BW;
_prefs.repeater_sf = LORA_SF;
_prefs.repeater_cr = LORA_CR;
}
// → 0xC0DE000B: append bot_commands_enabled + quiet-hours. Older files leave
// stray bytes here; clamp so upgraders fall back to off / no quiet hours.

View File

@@ -1307,6 +1307,14 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
_prefs.bw = LORA_BW;
_prefs.cr = LORA_CR;
_prefs.tx_power_dbm = LORA_TX_POWER;
// Repeater profile default for a true first boot (no prefs file yet, so
// loadPrefs() below is a no-op) — same band-matched seed as the upgrade
// path in DataStore.cpp, kept in sync rather than left at memset's 0/Current.
_prefs.repeater_use_profile = 1;
_prefs.repeater_freq = defaultRepeaterFreqForBand(_prefs.freq);
_prefs.repeater_bw = LORA_BW;
_prefs.repeater_sf = LORA_SF;
_prefs.repeater_cr = LORA_CR;
_prefs.gps_enabled = 0; // GPS disabled by default
_prefs.gps_interval = 0; // No automatic GPS updates by default
_prefs.display_brightness = 2; // medium brightness by default

View File

@@ -41,18 +41,7 @@ class UITask;
/* ---------------------------------- CONFIGURATION ------------------------------------- */
#ifndef LORA_FREQ
#define LORA_FREQ 915.0
#endif
#ifndef LORA_BW
#define LORA_BW 250
#endif
#ifndef LORA_SF
#define LORA_SF 10
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
// LORA_FREQ/BW/SF/CR fallbacks now live in NodePrefs.h (DataStore.cpp needs them too).
#ifndef LORA_TX_POWER
#define LORA_TX_POWER 20
#endif

View File

@@ -2,6 +2,37 @@
#include <cstdint>
#include <stdio.h>
// Firmware's own boot-default radio params — used both as the companion's
// initial freq/sf/bw/cr (MyMesh.cpp) and, here, as the seed for a never-
// configured repeater profile (DataStore.cpp). Kept above any per-board
// target.h include so a board can still override via -D before this file
// is reached.
#ifndef LORA_FREQ
#define LORA_FREQ 915.0
#endif
#ifndef LORA_BW
#define LORA_BW 250
#endif
#ifndef LORA_SF
#define LORA_SF 10
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
// Bucket a companion frequency into whichever of the three license-exempt
// bands MeshCore's app-driven repeat toggle historically restricted to (see
// repeat_freq_ranges in MyMesh.cpp: 433.000 / 869.495 / 918.000 MHz). Used to
// seed a never-configured repeater profile in the same legal band as the
// companion's own network (MyMesh.cpp begin(), DataStore.cpp) — a flat
// single frequency could land outside the bands allowed where the operator
// actually lives.
static inline float defaultRepeaterFreqForBand(float companion_freq) {
if (companion_freq < 500.0f) return 433.000f;
if (companion_freq < 890.0f) return 869.495f;
return 918.000f;
}
#define TELEM_MODE_DENY 0
#define TELEM_MODE_ALLOW_FLAGS 1 // use contact.flags
#define TELEM_MODE_ALLOW_ALL 2
@@ -176,7 +207,11 @@ struct NodePrefs { // persisted to file
// Optional dedicated radio profile for repeater mode. When repeater_use_profile
// is 1, enabling the repeater switches the radio to repeater_freq/bw/sf/cr and
// disabling restores the companion's freq/bw/sf/cr (the fields above). 0 = the
// repeater stays on the current companion frequency (default — no switch).
// repeater stays on the current companion frequency. Default (a never-configured
// device) is 1, seeded via defaultRepeaterFreqForBand(freq) + LORA_SF/BW/CR —
// repeating on whatever private network the companion later joins isn't the
// community norm, and the seed stays in the same legal band as the companion's
// own network rather than a flat frequency.
uint8_t repeater_use_profile;
float repeater_freq;
float repeater_bw;

View File

@@ -6,10 +6,14 @@
// and keeps the relaying controls next to the numbers that show them working.
//
// Network modes:
// - Current — repeat on the companion's current frequency (default).
// - Current — repeat on the companion's current frequency. Opt-in only:
// relaying on whatever network the operator is chatting on
// isn't the MeshCore community norm.
// - Custom — enabling the repeater switches the radio to a dedicated profile
// (preset or manual), and disabling restores the companion params.
// Set the profile equal to the companion's for "same network".
// Default for a never-configured device, seeded with a frequency
// in the same band as the companion's own network (so the default
// can't land outside what's legal for the operator's region).
// Included by UITask.cpp.
#include <helpers/ui/DisplayDriver.h>