fix(prefs): realign NodePrefs to upstream byte offsets

Keep upstream's persisted layout verbatim (rx_boosted_gain 290 ..
cad_enabled 294) and append the EastMesh-only fields after it, rather
than interleaving fan_mode/fan_timeout_secs into upstream's range.
Minimises CommonCLI.cpp conflicts on every upstream sync.

EastMesh fields now occupy 295..524: fan_mode, fan_timeout_secs, and
bridge_peer_*. Existing prefs files written by prior EastMesh firmware
will be misread from offset 292 onward and need reconfiguring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jared Dohrman
2026-07-09 17:10:04 +10:00
co-authored by Claude Opus 4.8
parent 3d460106ee
commit 2358245c04
2 changed files with 28 additions and 35 deletions
+22 -30
View File
@@ -88,38 +88,29 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
file.read((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
file.read((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
file.read((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
if (file.available() >= (int)sizeof(_prefs->rx_boosted_gain)) {
file.read((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
}
if (file.available() >= (int)sizeof(_prefs->flood_max_unscoped)) {
file.read((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
}
file.read((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
file.read((uint8_t *)&_prefs->radio_fem_rxgain, sizeof(_prefs->radio_fem_rxgain)); // 293
file.read((uint8_t *)&_prefs->cad_enabled, sizeof(_prefs->cad_enabled)); // 294
// upstream layout ends at 295; EastMesh-only fields are appended below
if (file.available() >= (int)sizeof(_prefs->fan_mode)) {
file.read((uint8_t *)&_prefs->fan_mode, sizeof(_prefs->fan_mode)); // 292
file.read((uint8_t *)&_prefs->fan_mode, sizeof(_prefs->fan_mode)); // 295
}
if (file.available() >= (int)sizeof(_prefs->fan_timeout_secs)) {
file.read((uint8_t *)&_prefs->fan_timeout_secs, sizeof(_prefs->fan_timeout_secs)); // 293
}
if (file.available() >= (int)sizeof(_prefs->flood_max_advert)) {
file.read((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 295
file.read((uint8_t *)&_prefs->fan_timeout_secs, sizeof(_prefs->fan_timeout_secs)); // 296
}
if (file.available() >= (int)sizeof(_prefs->bridge_peer_host)) {
file.read((uint8_t *)&_prefs->bridge_peer_host, sizeof(_prefs->bridge_peer_host)); // 296
file.read((uint8_t *)&_prefs->bridge_peer_host, sizeof(_prefs->bridge_peer_host)); // 298
}
if (file.available() >= (int)sizeof(_prefs->bridge_peer_port)) {
file.read((uint8_t *)&_prefs->bridge_peer_port, sizeof(_prefs->bridge_peer_port)); // 360
file.read((uint8_t *)&_prefs->bridge_peer_port, sizeof(_prefs->bridge_peer_port)); // 362
}
if (file.available() >= (int)sizeof(_prefs->bridge_peer_username)) {
file.read((uint8_t *)&_prefs->bridge_peer_username, sizeof(_prefs->bridge_peer_username)); // 362
file.read((uint8_t *)&_prefs->bridge_peer_username, sizeof(_prefs->bridge_peer_username)); // 364
}
if (file.available() >= (int)sizeof(_prefs->bridge_peer_password)) {
file.read((uint8_t *)&_prefs->bridge_peer_password, sizeof(_prefs->bridge_peer_password)); // 427
}
if (file.available() >= (int)sizeof(_prefs->radio_fem_rxgain)) {
file.read((uint8_t *)&_prefs->radio_fem_rxgain, sizeof(_prefs->radio_fem_rxgain)); // 523
}
if (file.available() >= (int)sizeof(_prefs->cad_enabled)) {
file.read((uint8_t *)&_prefs->cad_enabled, sizeof(_prefs->cad_enabled)); // 524
file.read((uint8_t *)&_prefs->bridge_peer_password, sizeof(_prefs->bridge_peer_password)); // 429
}
// next: 525
@@ -151,10 +142,10 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
// sanitise settings
_prefs->rx_boosted_gain = constrain(_prefs->rx_boosted_gain, 0, 1); // boolean
_prefs->fan_mode = constrain(_prefs->fan_mode, 0, 2);
_prefs->fan_timeout_secs = constrain(_prefs->fan_timeout_secs, 0, 600);
_prefs->radio_fem_rxgain = constrain(_prefs->radio_fem_rxgain, 0, 1); // boolean
_prefs->cad_enabled = constrain(_prefs->cad_enabled, 0, 1); // boolean
_prefs->fan_mode = constrain(_prefs->fan_mode, 0, 2);
_prefs->fan_timeout_secs = constrain(_prefs->fan_timeout_secs, 0, 600);
file.close();
}
@@ -217,15 +208,16 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
file.write((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
file.write((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
file.write((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
file.write((uint8_t *)&_prefs->fan_mode, sizeof(_prefs->fan_mode)); // 292
file.write((uint8_t *)&_prefs->fan_timeout_secs, sizeof(_prefs->fan_timeout_secs)); // 293
file.write((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 295
file.write((uint8_t *)&_prefs->bridge_peer_host, sizeof(_prefs->bridge_peer_host)); // 296
file.write((uint8_t *)&_prefs->bridge_peer_port, sizeof(_prefs->bridge_peer_port)); // 360
file.write((uint8_t *)&_prefs->bridge_peer_username, sizeof(_prefs->bridge_peer_username)); // 362
file.write((uint8_t *)&_prefs->bridge_peer_password, sizeof(_prefs->bridge_peer_password)); // 427
file.write((uint8_t *)&_prefs->radio_fem_rxgain, sizeof(_prefs->radio_fem_rxgain)); // 523
file.write((uint8_t *)&_prefs->cad_enabled, sizeof(_prefs->cad_enabled)); // 524
file.write((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
file.write((uint8_t *)&_prefs->radio_fem_rxgain, sizeof(_prefs->radio_fem_rxgain)); // 293
file.write((uint8_t *)&_prefs->cad_enabled, sizeof(_prefs->cad_enabled)); // 294
// upstream layout ends at 295; EastMesh-only fields are appended below
file.write((uint8_t *)&_prefs->fan_mode, sizeof(_prefs->fan_mode)); // 295
file.write((uint8_t *)&_prefs->fan_timeout_secs, sizeof(_prefs->fan_timeout_secs)); // 296
file.write((uint8_t *)&_prefs->bridge_peer_host, sizeof(_prefs->bridge_peer_host)); // 298
file.write((uint8_t *)&_prefs->bridge_peer_port, sizeof(_prefs->bridge_peer_port)); // 362
file.write((uint8_t *)&_prefs->bridge_peer_username, sizeof(_prefs->bridge_peer_username)); // 364
file.write((uint8_t *)&_prefs->bridge_peer_password, sizeof(_prefs->bridge_peer_password)); // 429
// next: 525
file.close();
+2 -1
View File
@@ -64,13 +64,14 @@ struct NodePrefs { // persisted to file
uint8_t radio_fem_rxgain; // LoRa FEM RX gain setting
uint8_t path_hash_mode; // which path mode to use when sending
uint8_t loop_detect;
uint8_t cad_enabled; // hardware Channel Activity Detection before TX (boolean)
// EastMesh-only fields, appended after the upstream layout
uint8_t fan_mode;
uint16_t fan_timeout_secs;
char bridge_peer_host[64]; // peer MQTT broker host (MQTT bridge only)
uint16_t bridge_peer_port; // peer MQTT broker port (MQTT bridge only, default 1883)
char bridge_peer_username[65]; // peer MQTT broker username (MQTT bridge only)
char bridge_peer_password[96]; // peer MQTT broker password (MQTT bridge only)
uint8_t cad_enabled; // hardware Channel Activity Detection before TX (boolean)
};
class CommonCLICallbacks {