mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 22:02:17 +01:00
fix: give every NVS user its own Preferences handle
loop() and the async web server task shared one global Preferences. A begin() from one task failed while the other had a namespace open, and the clear() or remove() after it then hit the other task's namespace: saving the radio settings while a command committed its rolling code could erase every rolling code. Each function now opens NVS with a local Preferences. NVS serializes access internally and the destructor closes the handle, so no lock is added (see docs/adr/0001). No new tests: nothing here builds natively, and deleting the global makes any missed use a compile error. The read-then-commit races on rolling codes across tasks remain and are tracked in docs/KNOWN_ISSUES.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
4135f21ee7
commit
c1b47f898c
6 changed files with 94 additions and 27 deletions
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
static const char *TAG = "Somfy";
|
||||
|
||||
extern Preferences pref;
|
||||
extern SomfyShadeController somfy;
|
||||
extern SocketEmitter sockEmit;
|
||||
extern ConfigSettings settings;
|
||||
|
|
@ -154,6 +153,7 @@ void SomfyShadeController::updateGroupFlags() {
|
|||
}
|
||||
#ifdef USE_NVS
|
||||
bool SomfyShadeController::loadLegacy() {
|
||||
Preferences pref;
|
||||
ESP_LOGI(TAG, "Loading Legacy shades using NVS");
|
||||
pref.begin("Shades", true);
|
||||
pref.getBytes("shadeIds", this->m_shadeIds, sizeof(this->m_shadeIds));
|
||||
|
|
@ -203,6 +203,7 @@ bool SomfyShadeController::loadLegacy() {
|
|||
}
|
||||
#endif
|
||||
bool SomfyShadeController::begin() {
|
||||
Preferences pref;
|
||||
// Load up all the configuration data.
|
||||
//ShadeConfigFile::getAppVersion(this->appVersion);
|
||||
ESP_LOGI(TAG, "App Version:%u.%u.%u", settings.appVersion.major, settings.appVersion.minor, settings.appVersion.build);
|
||||
|
|
@ -357,6 +358,7 @@ void SomfyGroup::clear() {
|
|||
memset(&this->linkedShades, 0x00, sizeof(this->linkedShades));
|
||||
}
|
||||
bool SomfyShade::linkRemote(uint32_t address, uint16_t rollingCode) {
|
||||
Preferences pref;
|
||||
// Check to see if the remote is already linked. If it is
|
||||
// just return true after setting the rolling code
|
||||
for(uint8_t i = 0; i < SOMFY_MAX_LINKED_REMOTES; i++) {
|
||||
|
|
@ -409,6 +411,7 @@ bool SomfyGroup::linkShade(uint8_t shadeId) {
|
|||
}
|
||||
void SomfyShade::commit() { somfy.commit(); }
|
||||
void SomfyShade::commitShadePosition() {
|
||||
Preferences pref;
|
||||
somfy.isDirty = true;
|
||||
#ifdef USE_NVS
|
||||
char shadeKey[15];
|
||||
|
|
@ -422,6 +425,7 @@ void SomfyShade::commitShadePosition() {
|
|||
#endif
|
||||
}
|
||||
void SomfyShade::commitMyPosition() {
|
||||
Preferences pref;
|
||||
somfy.isDirty = true;
|
||||
#ifdef USE_NVS
|
||||
if(somfy.useNVS()) {
|
||||
|
|
@ -435,6 +439,7 @@ void SomfyShade::commitMyPosition() {
|
|||
#endif
|
||||
}
|
||||
void SomfyShade::commitTiltPosition() {
|
||||
Preferences pref;
|
||||
somfy.isDirty = true;
|
||||
#ifdef USE_NVS
|
||||
if(somfy.useNVS()) {
|
||||
|
|
@ -448,6 +453,7 @@ void SomfyShade::commitTiltPosition() {
|
|||
#endif
|
||||
}
|
||||
bool SomfyShade::unlinkRemote(uint32_t address) {
|
||||
Preferences pref;
|
||||
for(uint8_t i = 0; i < SOMFY_MAX_LINKED_REMOTES; i++) {
|
||||
if(this->linkedRemotes[i].getRemoteAddress() == address) {
|
||||
this->linkedRemotes[i].setRemoteAddress(0);
|
||||
|
|
@ -917,6 +923,7 @@ void SomfyShade::checkMovement() {
|
|||
}
|
||||
#ifdef USE_NVS
|
||||
void SomfyShade::load() {
|
||||
Preferences pref;
|
||||
char shadeKey[15];
|
||||
uint32_t linkedAddresses[SOMFY_MAX_LINKED_REMOTES];
|
||||
memset(linkedAddresses, 0x00, sizeof(uint32_t) * SOMFY_MAX_LINKED_REMOTES);
|
||||
|
|
@ -2708,6 +2715,7 @@ bool SomfyShade::moveToTarget(float pos, float tilt) {
|
|||
return true;
|
||||
}
|
||||
bool SomfyShade::save() {
|
||||
Preferences pref;
|
||||
#ifdef USE_NVS
|
||||
if(somfy.useNVS()) {
|
||||
char shadeKey[15];
|
||||
|
|
@ -3285,6 +3293,7 @@ SomfyShade *SomfyShadeController::addShade(JsonObject &obj) {
|
|||
return shade;
|
||||
}
|
||||
SomfyShade *SomfyShadeController::addShade() {
|
||||
Preferences pref;
|
||||
uint8_t shadeId = this->getNextShadeId();
|
||||
// So the next shade id will be the first one we run into with an id of 255 so
|
||||
// if it gets deleted in the middle then it will get the first slot that is empty.
|
||||
|
|
@ -3527,6 +3536,7 @@ uint32_t SomfyShadeController::sendFrame(somfy_frame_t &frame, uint8_t repeat, u
|
|||
return this->transceiver.submitTx(job, priority, delayMs);
|
||||
}
|
||||
bool SomfyShadeController::deleteShade(uint8_t shadeId) {
|
||||
Preferences pref;
|
||||
for(uint8_t i = 0; i < SOMFY_MAX_SHADES; i++) {
|
||||
if(this->shades[i].getShadeId() == shadeId) {
|
||||
shades[i].emitState("shadeRemoved");
|
||||
|
|
@ -3594,6 +3604,7 @@ bool SomfyShadeController::loadShadesFile(const char *filename) { return ShadeCo
|
|||
// it has been queued. After that lastRollingCode holds what NVS does.
|
||||
uint16_t SomfyRemote::peekNextRollingCode() {
|
||||
return nextRollingCode(this->m_rollingCodeSynced, this->lastRollingCode, [this]() {
|
||||
Preferences pref;
|
||||
if(!pref.begin("ShadeCodes")) {
|
||||
ESP_LOGE(TAG, "peekNextRollingCode() pref.begin(ShadeCodes) FAILED");
|
||||
}
|
||||
|
|
@ -3603,6 +3614,7 @@ uint16_t SomfyRemote::peekNextRollingCode() {
|
|||
});
|
||||
}
|
||||
void SomfyRemote::commitRollingCode(uint16_t code) {
|
||||
Preferences pref;
|
||||
if(!pref.begin("ShadeCodes")) {
|
||||
ESP_LOGE(TAG, "commitRollingCode() pref.begin(ShadeCodes) FAILED");
|
||||
}
|
||||
|
|
@ -3617,6 +3629,7 @@ uint16_t SomfyRemote::p_lastRollingCode(uint16_t code) {
|
|||
return old;
|
||||
}
|
||||
uint16_t SomfyRemote::setRollingCode(uint16_t code) {
|
||||
Preferences pref;
|
||||
if(this->lastRollingCode != code) {
|
||||
pref.begin("ShadeCodes");
|
||||
pref.putUShort(this->m_remotePrefId, code);
|
||||
|
|
@ -4295,6 +4308,7 @@ void transceiver_config_t::toJSON(JsonObject& obj) {
|
|||
}
|
||||
*/
|
||||
void transceiver_config_t::save() {
|
||||
Preferences pref;
|
||||
pref.begin("CC1101");
|
||||
pref.clear();
|
||||
pref.putUChar("type", this->type);
|
||||
|
|
@ -4343,13 +4357,14 @@ void transceiver_config_t::save() {
|
|||
|
||||
ESP_LOGI(TAG, "Save Radio Settings SCK:%u MISO:%u MOSI:%u CSN:%u RX:%u TX:%u", this->SCKPin, this->MISOPin, this->MOSIPin, this->CSNPin, this->RXPin, this->TXPin);
|
||||
}
|
||||
void transceiver_config_t::removeNVSKey(const char *key) {
|
||||
void transceiver_config_t::removeNVSKey(Preferences &pref, const char *key) {
|
||||
if(pref.isKey(key)) {
|
||||
ESP_LOGD(TAG, "Removing NVS Key: CC1101.%s", key);
|
||||
pref.remove(key);
|
||||
}
|
||||
}
|
||||
void transceiver_config_t::load() {
|
||||
Preferences pref;
|
||||
esp_chip_info_t ci;
|
||||
esp_chip_info(&ci);
|
||||
switch(ci.model) {
|
||||
|
|
@ -4413,32 +4428,33 @@ void transceiver_config_t::load() {
|
|||
this->rxBandwidth = pref.getFloat("rxBandwidth", this->rxBandwidth);
|
||||
this->proto = static_cast<radio_proto>(pref.getChar("proto", static_cast<uint8_t>(this->proto)));
|
||||
this->noiseDetection = pref.getBool("noiseDetect", false);
|
||||
this->removeNVSKey("internalCCMode");
|
||||
this->removeNVSKey("modulationMode");
|
||||
this->removeNVSKey("channel");
|
||||
this->removeNVSKey("channelSpacing");
|
||||
this->removeNVSKey("dataRate");
|
||||
this->removeNVSKey("syncMode");
|
||||
this->removeNVSKey("syncWordHigh");
|
||||
this->removeNVSKey("syncWordLow");
|
||||
this->removeNVSKey("addrCheckMode");
|
||||
this->removeNVSKey("checkAddr");
|
||||
this->removeNVSKey("dataWhitening");
|
||||
this->removeNVSKey("pktFormat");
|
||||
this->removeNVSKey("pktLengthMode");
|
||||
this->removeNVSKey("pktLength");
|
||||
this->removeNVSKey("useCRC");
|
||||
this->removeNVSKey("autoFlushCRC");
|
||||
this->removeNVSKey("disableDCFilter");
|
||||
this->removeNVSKey("enableManchester");
|
||||
this->removeNVSKey("enableFEC");
|
||||
this->removeNVSKey("minPreambleBytes");
|
||||
this->removeNVSKey("pqtThreshold");
|
||||
this->removeNVSKey("appendStatus");
|
||||
this->removeNVSKey(pref, "internalCCMode");
|
||||
this->removeNVSKey(pref, "modulationMode");
|
||||
this->removeNVSKey(pref, "channel");
|
||||
this->removeNVSKey(pref, "channelSpacing");
|
||||
this->removeNVSKey(pref, "dataRate");
|
||||
this->removeNVSKey(pref, "syncMode");
|
||||
this->removeNVSKey(pref, "syncWordHigh");
|
||||
this->removeNVSKey(pref, "syncWordLow");
|
||||
this->removeNVSKey(pref, "addrCheckMode");
|
||||
this->removeNVSKey(pref, "checkAddr");
|
||||
this->removeNVSKey(pref, "dataWhitening");
|
||||
this->removeNVSKey(pref, "pktFormat");
|
||||
this->removeNVSKey(pref, "pktLengthMode");
|
||||
this->removeNVSKey(pref, "pktLength");
|
||||
this->removeNVSKey(pref, "useCRC");
|
||||
this->removeNVSKey(pref, "autoFlushCRC");
|
||||
this->removeNVSKey(pref, "disableDCFilter");
|
||||
this->removeNVSKey(pref, "enableManchester");
|
||||
this->removeNVSKey(pref, "enableFEC");
|
||||
this->removeNVSKey(pref, "minPreambleBytes");
|
||||
this->removeNVSKey(pref, "pqtThreshold");
|
||||
this->removeNVSKey(pref, "appendStatus");
|
||||
pref.end();
|
||||
//this->printBuffer = somfy.transceiver.printBuffer;
|
||||
}
|
||||
void transceiver_config_t::apply() {
|
||||
Preferences pref;
|
||||
// A transmission in flight stops after its current frame so the radio can
|
||||
// be reconfigured. Queued frames are already encoded and go out with the
|
||||
// new settings.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue