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 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-12 18:33:59 +02:00
parent 0ba5260d1d
commit c4472ba8e8
4 changed files with 9 additions and 11 deletions

View file

@ -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();

View file

@ -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

View file

@ -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();

View file

@ -2411,7 +2411,6 @@ void Web::begin() {
}
JsonObject obj = json.as<JsonObject>();
somfy.transceiver.fromJSON(obj);
somfy.transceiver.save();
AsyncJsonResp resp;
resp.beginResponse(request, g_async_content, sizeof(g_async_content));
resp.beginObject();