From c4472ba8e83ef30b08b511f778afe8ea80a7afea Mon Sep 17 00:00:00 2001 From: cjkas Date: Mon, 12 Oct 2026 18:33:59 +0200 Subject: [PATCH] fix: set the radio up for a new config before anything transmits on it setConfig() swapped the config in and released the radio lock, and apply() only ran later from save(), so the radio task could send queued jobs with the new TX pin and settings on a CC1101 that wasn't set up for them. setConfig() now swaps, saves and applies under one lock and save() goes. Co-Authored-By: Claude Opus 5.5 --- src/ConfigFile.cpp | 1 - src/Somfy.cpp | 16 ++++++++-------- src/Somfy.h | 2 +- src/Web.cpp | 1 - 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/ConfigFile.cpp b/src/ConfigFile.cpp index cd56e9e..b012400 100644 --- a/src/ConfigFile.cpp +++ b/src/ConfigFile.cpp @@ -612,7 +612,6 @@ bool ShadeConfigFile::restoreFile(SomfyShadeController *s, const char *filename, transceiver_config_t cfg = s->transceiver.config; this->readTransRecord(cfg); s->transceiver.setConfig(cfg); - s->transceiver.save(); } if(opts.settings || opts.network) settings.save(); if(opts.settings) settings.NTP.save(); diff --git a/src/Somfy.cpp b/src/Somfy.cpp index 451ce0b..5deb257 100644 --- a/src/Somfy.cpp +++ b/src/Somfy.cpp @@ -4254,12 +4254,17 @@ bool Transceiver::fromJSON(JsonObject& obj) { return true; } void Transceiver::setConfig(const transceiver_config_t &cfg) { - // Swap the whole config in once any transmission in flight has stopped so the - // radio task never sees a half updated one. Queued jobs are kept and go out - // with the new settings. + // Swap the whole config in, save it and set the radio up with it once any + // transmission in flight has stopped, all under one lock, so the radio task + // never sees a half updated config or transmits before the radio is set up + // for the new one. Queued jobs are kept and go out with the new settings. + // Saving first means a radio that locks up while applying comes back with + // the new config after the reboot. RadioLock lock(portMAX_DELAY, true); if(this->config.enabled && this->config.TXPin != cfg.TXPin) pinMode(this->config.TXPin, INPUT); this->config = cfg; + this->config.save(); + this->config.apply(); } bool Transceiver::usesPin(uint8_t pin) { if(this->config.enabled) { @@ -4273,11 +4278,6 @@ bool Transceiver::usesPin(uint8_t pin) { } return false; } -bool Transceiver::save() { - this->config.save(); - this->config.apply(); - return true; -} bool Transceiver::end() { // Nothing may transmit (and re-enable receive) after this. It is not // resumed since the only caller is OTA, which reboots when the upload diff --git a/src/Somfy.h b/src/Somfy.h index edd948b..e67d215 100644 --- a/src/Somfy.h +++ b/src/Somfy.h @@ -482,8 +482,8 @@ class Transceiver { bool printBuffer = false; //bool toJSON(JsonObject& obj); bool fromJSON(JsonObject& obj); + // Swaps in, saves and applies the config. void setConfig(const transceiver_config_t &cfg); - bool save(); bool begin(); void loop(); bool end(); diff --git a/src/Web.cpp b/src/Web.cpp index 4803d27..2da4208 100644 --- a/src/Web.cpp +++ b/src/Web.cpp @@ -2411,7 +2411,6 @@ void Web::begin() { } JsonObject obj = json.as(); somfy.transceiver.fromJSON(obj); - somfy.transceiver.save(); AsyncJsonResp resp; resp.beginResponse(request, g_async_content, sizeof(g_async_content)); resp.beginObject();