From 385a89507bca7ef11eaf0c0f103a705ceb3f0729 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 25 Jun 2023 10:45:37 -0500 Subject: [PATCH] Fix crash when flash is written too frequently (#18) --- base.yaml | 3 +++ components/ratgdo/ratgdo.cpp | 29 ++++++++++++++++------------- components/ratgdo/ratgdo.h | 4 ++-- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/base.yaml b/base.yaml index 05a998b..3997d50 100644 --- a/base.yaml +++ b/base.yaml @@ -6,6 +6,9 @@ external_components: url: https://github.com/esphome-ratgdo/esphome-ratgdo refresh: 1s +preferences: + flash_write_interval: 5s + ratgdo: id: ${id_prefix} input_gdo_pin: ${uart_rx_pin} diff --git a/components/ratgdo/ratgdo.cpp b/components/ratgdo/ratgdo.cpp index 4d5e17a..ad5e992 100644 --- a/components/ratgdo/ratgdo.cpp +++ b/components/ratgdo/ratgdo.cpp @@ -22,7 +22,17 @@ namespace ratgdo { static const char* const TAG = "ratgdo"; static const int SYNC_DELAY = 2000; - static const uint8_t MAX_CODES_WITHOUT_FLASH_WRITE = 3; + // + // MAX_CODES_WITHOUT_FLASH_WRITE is a bit of a guess + // since we write the flash at most every every 5s + // + // We want the rolling counter to be high enough that the + // GDO will accept the command after an unexpected reboot + // that did not save the counter to flash in time which + // results in the rolling counter being behind what the GDO + // expects. + // + static const uint8_t MAX_CODES_WITHOUT_FLASH_WRITE = 5; static const uint32_t FLASH_WRITE_INTERVAL = 10000; void IRAM_ATTR HOT RATGDOStore::isrObstruction(RATGDOStore* arg) @@ -55,9 +65,6 @@ namespace ratgdo { this->input_obst_pin_->attach_interrupt(RATGDOStore::isrObstruction, &this->store_, gpio::INTERRUPT_ANY_EDGE); - // save counter to flash every 10s if it changed - set_interval(FLASH_WRITE_INTERVAL, std::bind(&RATGDOComponent::saveCounter, this, 1)); - ESP_LOGV(TAG, "Syncing rolling code counter after reboot..."); // many things happening at startup, use some delay for sync @@ -447,7 +454,7 @@ namespace ratgdo { delayMicroseconds(1260); // "LOW" pulse duration before the message start this->swSerial.write(this->txRollingCode, CODE_LENGTH); - saveCounter(MAX_CODES_WITHOUT_FLASH_WRITE); + saveCounter(); } void RATGDOComponent::sync() @@ -545,16 +552,12 @@ namespace ratgdo { transmit(command::LOCK, data::TOGGLE); } - void RATGDOComponent::saveCounter(int threshold) + void RATGDOComponent::saveCounter() { this->pref_.save(&this->rollingCodeCounter); - if (!this->lastSyncedRollingCodeCounter || this->rollingCodeCounter - this->lastSyncedRollingCodeCounter >= threshold) { - // do flash write outside of the component loop - defer([=] { - this->lastSyncedRollingCodeCounter = this->rollingCodeCounter; - global_preferences->sync(); - }); - } + // Forcing a sync results in a soft reset if there are too many + // writes to flash in a short period of time. To avoid this, + // we have configured preferences to write every 5s } void RATGDOComponent::register_child(RATGDOClient* obj) diff --git a/components/ratgdo/ratgdo.h b/components/ratgdo/ratgdo.h index e47fd86..6503480 100644 --- a/components/ratgdo/ratgdo.h +++ b/components/ratgdo/ratgdo.h @@ -160,7 +160,7 @@ namespace ratgdo { void obstructionLoop(); void statusUpdateLoop(); - void saveCounter(int threshold); + void saveCounter(); void doorCommand(uint32_t data); @@ -176,7 +176,7 @@ namespace ratgdo { void toggleLock(); void lock(); void unlock(); - + void query_status(); void query_openings();