From 00a084048fa51ae7b227939d66232b6affa56264 Mon Sep 17 00:00:00 2001 From: cjkas Date: Sun, 11 Oct 2026 12:46:40 +0200 Subject: [PATCH] fix: swap restored radio config under the radio lock Restoring a backup wrote the transceiver config in place from the async task while the radio task could be transmitting with it. Read the record into a copy and swap it in through the new Transceiver::setConfig, which Transceiver::fromJSON now uses as well. Co-Authored-By: Claude Opus 5.5 --- src/ConfigFile.cpp | 5 ++++- src/Somfy.cpp | 16 ++++++++++------ src/Somfy.h | 1 + 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/ConfigFile.cpp b/src/ConfigFile.cpp index 5dc1801..cd56e9e 100644 --- a/src/ConfigFile.cpp +++ b/src/ConfigFile.cpp @@ -608,7 +608,10 @@ bool ShadeConfigFile::restoreFile(SomfyShadeController *s, const char *filename, if(opts.shades) s->commit(); if(opts.transceiver) { - this->readTransRecord(s->transceiver.config); + // Read into a copy so the radio task never transmits on a half restored config. + transceiver_config_t cfg = s->transceiver.config; + this->readTransRecord(cfg); + s->transceiver.setConfig(cfg); s->transceiver.save(); } if(opts.settings || opts.network) settings.save(); diff --git a/src/Somfy.cpp b/src/Somfy.cpp index a4b2cc3..238a514 100644 --- a/src/Somfy.cpp +++ b/src/Somfy.cpp @@ -4812,17 +4812,21 @@ bool Transceiver::toJSON(JsonObject& obj) { bool Transceiver::fromJSON(JsonObject& obj) { if (!obj["config"].isNull()) { JsonObject objConfig = obj["config"]; - // Parse into a copy so the radio task never sees a half updated config, - // then swap it in once any transmission in flight has stopped. Queued - // jobs are kept and go out with the new settings. + // Parse into a copy so the radio task never sees a half updated config. transceiver_config_t cfg = this->config; cfg.fromJSON(objConfig); - RadioLock lock(portMAX_DELAY, true); - if(this->config.enabled && this->config.TXPin != cfg.TXPin) pinMode(this->config.TXPin, INPUT); - this->config = cfg; + this->setConfig(cfg); } 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. + RadioLock lock(portMAX_DELAY, true); + if(this->config.enabled && this->config.TXPin != cfg.TXPin) pinMode(this->config.TXPin, INPUT); + this->config = cfg; +} bool Transceiver::usesPin(uint8_t pin) { if(this->config.enabled) { if(this->config.SCKPin == pin || diff --git a/src/Somfy.h b/src/Somfy.h index 3630dbf..bf7dd46 100644 --- a/src/Somfy.h +++ b/src/Somfy.h @@ -559,6 +559,7 @@ class Transceiver { bool printBuffer = false; //bool toJSON(JsonObject& obj); bool fromJSON(JsonObject& obj); + void setConfig(const transceiver_config_t &cfg); bool save(); bool begin(); void loop();