diff --git a/zephcore/app/CompanionMesh.cpp b/zephcore/app/CompanionMesh.cpp index 7bc7f96..5fac529 100644 --- a/zephcore/app/CompanionMesh.cpp +++ b/zephcore/app/CompanionMesh.cpp @@ -1205,7 +1205,7 @@ uint32_t CompanionMesh::getDirectRetransmitDelay(const mesh::Packet *packet) /* Jitter around Arduino direct factor 0.3 using a per-packet factor * in the range [0.25, 0.40]. */ uint32_t factor_milli = (uint32_t)getRNG()->nextInt(250, 401); - uint32_t max_jitter = (5 * airtime * factor_milli) / 1000; + uint32_t max_jitter = (airtime * factor_milli) / 1000; /* Floor: give downstream nodes time to finish RX processing * and return to RX mode before we TX (~20ms settle + jitter) */ return 20 + getRNG()->nextInt(0, max_jitter + 1); diff --git a/zephcore/app/RepeaterDataStore.cpp b/zephcore/app/RepeaterDataStore.cpp index 0a2a755..e4d9abc 100644 --- a/zephcore/app/RepeaterDataStore.cpp +++ b/zephcore/app/RepeaterDataStore.cpp @@ -191,9 +191,10 @@ bool RepeaterDataStore::loadPrefs(NodePrefs& prefs) { fs_read(&file, &prefs.discovery_mod_timestamp, sizeof(prefs.discovery_mod_timestamp)); fs_read(&file, &prefs.adc_multiplier, sizeof(prefs.adc_multiplier)); fs_read(&file, prefs.owner_info, sizeof(prefs.owner_info)); - /* ZephCore extensions — absent in old 290-byte files; fs_read returns 0 at EOF, - * leaving these fields at 0. The upgrade block below corrects any that have - * non-zero repeater defaults (rx_boost, rx_duty_cycle, path_hash_mode, loop_detect). */ + /* ZephCore extensions — absent in old 290-byte files; fs_read past EOF is a + * no-op so these fields keep the initNodePrefs() defaults the caller passed + * in (rx_boost=1, rx_duty_cycle=0, apc_enabled=0, apc_margin=16). The + * upgrade block below forces repeater-specific values for old files. */ fs_read(&file, &prefs.rx_boost, sizeof(prefs.rx_boost)); fs_read(&file, &prefs.rx_duty_cycle, sizeof(prefs.rx_duty_cycle)); fs_read(&file, &prefs.apc_enabled, sizeof(prefs.apc_enabled)); diff --git a/zephcore/app/RepeaterMesh.cpp b/zephcore/app/RepeaterMesh.cpp index ffbc52d..d53cdc6 100644 --- a/zephcore/app/RepeaterMesh.cpp +++ b/zephcore/app/RepeaterMesh.cpp @@ -576,7 +576,7 @@ uint32_t RepeaterMesh::getDirectRetransmitDelay(const mesh::Packet* packet) { /* Jitter around Arduino direct factor 0.3 using a per-packet factor * in the range [0.25, 0.40]. */ uint32_t factor_milli = (uint32_t)getRNG()->nextInt(250, 401); - uint32_t max_jitter = (5 * airtime * factor_milli) / 1000; + uint32_t max_jitter = (airtime * factor_milli) / 1000; /* Floor: give downstream nodes time to finish RX processing * and return to RX mode before we TX (~20ms settle + jitter). */ return 20 + getRNG()->nextInt(0, max_jitter + 1); @@ -1028,6 +1028,13 @@ void RepeaterMesh::applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_ revert_radio_at = futureMillis(2000 + timeout_mins * 60 * 1000); } +void RepeaterMesh::freezeRadioParams(float freq, float bw, uint8_t sf, uint8_t cr) { + auto& radio = getRadioDriver(_radio); + if (!radio.hasRadioOverride()) { + radio.setRadioOverride(freq, bw, sf, cr); + } +} + bool RepeaterMesh::formatFileSystem() { if (_store) { return _store->formatFileSystem(); diff --git a/zephcore/app/RepeaterMesh.h b/zephcore/app/RepeaterMesh.h index 940fc36..6844d24 100644 --- a/zephcore/app/RepeaterMesh.h +++ b/zephcore/app/RepeaterMesh.h @@ -208,6 +208,7 @@ public: void savePrefs() override; void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) override; + void freezeRadioParams(float freq, float bw, uint8_t sf, uint8_t cr) override; bool formatFileSystem() override; void sendSelfAdvertisement(int delay_millis, bool flood) override; void updateAdvertTimer() override; diff --git a/zephcore/helpers/CommonCLI.cpp b/zephcore/helpers/CommonCLI.cpp index 3a09cd0..6276369 100644 --- a/zephcore/helpers/CommonCLI.cpp +++ b/zephcore/helpers/CommonCLI.cpp @@ -629,11 +629,21 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch uint8_t cr = num > 3 ? atoi(parts[3]) : 0; if (freq >= 150.0f && freq <= 2500.0f && sf >= 5 && sf <= 12 && cr >= 5 && cr <= 8 && bw >= 7.0f && bw <= 500.0f) { + /* Snapshot old params, then mutate _prefs and save so later + * savePrefs() calls (set af, set name, ...) don't clobber + * the new values with stale RAM. Freeze the running radio on + * the old params via override so the on-air config doesn't + * change until reboot. */ + float old_freq = _prefs->freq; + float old_bw = _prefs->bw; + uint8_t old_sf = _prefs->sf; + uint8_t old_cr = _prefs->cr; _prefs->freq = freq; _prefs->bw = bw; _prefs->sf = sf; _prefs->cr = cr; _callbacks->savePrefs(); + _callbacks->freezeRadioParams(old_freq, old_bw, old_sf, old_cr); strcpy(reply, "OK - reboot to apply"); } else { strcpy(reply, "Error: freq 150-2500, bw 7-500, sf 5-12, cr 5-8"); diff --git a/zephcore/helpers/CommonCLI.h b/zephcore/helpers/CommonCLI.h index b8c3244..4f31cc8 100644 --- a/zephcore/helpers/CommonCLI.h +++ b/zephcore/helpers/CommonCLI.h @@ -46,6 +46,11 @@ public: virtual void saveIdentity(const mesh::LocalIdentity& new_id) = 0; virtual void clearStats() = 0; virtual void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) = 0; + /* Freeze the live radio on the given (old) params via radio override so the + * caller can mutate _prefs to new values, savePrefs(), and have any later + * savePrefs() call write the new values without clobbering the running radio. + * No-op if an override is already active (tempradio takes precedence). */ + virtual void freezeRadioParams(float freq, float bw, uint8_t sf, uint8_t cr) { (void)freq; (void)bw; (void)sf; (void)cr; } // Adaptive contention window virtual float getContentionEstimate() const { return -1.0f; }