mirror of
https://github.com/esphome/esphome.git
synced 2024-11-10 09:17:46 +01:00
Implement RP2040 preferences (#3946)
This commit is contained in:
parent
f97252b93a
commit
9865cb7f55
3 changed files with 122 additions and 8 deletions
|
@ -15,6 +15,7 @@ namespace ota {
|
||||||
OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) {
|
OTAResponseTypes ArduinoRP2040OTABackend::begin(size_t image_size) {
|
||||||
bool ret = Update.begin(image_size, U_FLASH);
|
bool ret = Update.begin(image_size, U_FLASH);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
rp2040::preferences_prevent_write(true);
|
||||||
return OTA_RESPONSE_OK;
|
return OTA_RESPONSE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +47,10 @@ OTAResponseTypes ArduinoRP2040OTABackend::end() {
|
||||||
return OTA_RESPONSE_OK;
|
return OTA_RESPONSE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArduinoRP2040OTABackend::abort() { Update.end(); }
|
void ArduinoRP2040OTABackend::abort() {
|
||||||
|
Update.end();
|
||||||
|
rp2040::preferences_prevent_write(false);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ota
|
} // namespace ota
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
#ifdef USE_RP2040
|
#ifdef USE_RP2040
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <hardware/flash.h>
|
||||||
|
#include <hardware/sync.h>
|
||||||
|
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -12,33 +17,137 @@ namespace rp2040 {
|
||||||
|
|
||||||
static const char *const TAG = "rp2040.preferences";
|
static const char *const TAG = "rp2040.preferences";
|
||||||
|
|
||||||
|
static bool s_prevent_write = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
static uint8_t *s_flash_storage = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
static bool s_flash_dirty = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
|
static const uint32_t RP2040_FLASH_STORAGE_SIZE = 512;
|
||||||
|
|
||||||
|
extern "C" uint8_t _EEPROM_start;
|
||||||
|
|
||||||
|
template<class It> uint8_t calculate_crc(It first, It last, uint32_t type) {
|
||||||
|
std::array<uint8_t, 4> type_array = decode_value(type);
|
||||||
|
uint8_t crc = type_array[0] ^ type_array[1] ^ type_array[2] ^ type_array[3];
|
||||||
|
while (first != last) {
|
||||||
|
crc ^= (*first++);
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
class RP2040PreferenceBackend : public ESPPreferenceBackend {
|
class RP2040PreferenceBackend : public ESPPreferenceBackend {
|
||||||
public:
|
public:
|
||||||
bool save(const uint8_t *data, size_t len) override { return true; }
|
size_t offset = 0;
|
||||||
bool load(uint8_t *data, size_t len) override { return false; }
|
uint32_t type = 0;
|
||||||
|
|
||||||
|
bool save(const uint8_t *data, size_t len) override {
|
||||||
|
std::vector<uint8_t> buffer;
|
||||||
|
buffer.resize(len + 1);
|
||||||
|
memcpy(buffer.data(), data, len);
|
||||||
|
buffer[buffer.size() - 1] = calculate_crc(buffer.begin(), buffer.end() - 1, type);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < len + 1; i++) {
|
||||||
|
uint32_t j = offset + i;
|
||||||
|
if (j >= RP2040_FLASH_STORAGE_SIZE)
|
||||||
|
return false;
|
||||||
|
uint8_t v = buffer[i];
|
||||||
|
uint8_t *ptr = &s_flash_storage[j];
|
||||||
|
if (*ptr != v)
|
||||||
|
s_flash_dirty = true;
|
||||||
|
*ptr = v;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool load(uint8_t *data, size_t len) override {
|
||||||
|
std::vector<uint8_t> buffer;
|
||||||
|
buffer.resize(len + 1);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len + 1; i++) {
|
||||||
|
uint32_t j = offset + i;
|
||||||
|
if (j >= RP2040_FLASH_STORAGE_SIZE)
|
||||||
|
return false;
|
||||||
|
buffer[i] = s_flash_storage[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t crc = calculate_crc(buffer.begin(), buffer.end() - 1, type);
|
||||||
|
if (buffer[buffer.size() - 1] != crc) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data, buffer.data(), len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class RP2040Preferences : public ESPPreferences {
|
class RP2040Preferences : public ESPPreferences {
|
||||||
public:
|
public:
|
||||||
|
uint32_t current_flash_offset = 0;
|
||||||
|
|
||||||
|
RP2040Preferences() : eeprom_sector_(&_EEPROM_start) {}
|
||||||
|
void setup() {
|
||||||
|
s_flash_storage = new uint8_t[RP2040_FLASH_STORAGE_SIZE]; // NOLINT
|
||||||
|
ESP_LOGVV(TAG, "Loading preferences from flash...");
|
||||||
|
memcpy(s_flash_storage, this->eeprom_sector_, RP2040_FLASH_STORAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override {
|
ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override {
|
||||||
auto *pref = new RP2040PreferenceBackend(); // NOLINT(cppcoreguidelines-owning-memory)
|
return make_preference(length, type);
|
||||||
return ESPPreferenceObject(pref);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ESPPreferenceObject make_preference(size_t length, uint32_t type) override {
|
ESPPreferenceObject make_preference(size_t length, uint32_t type) override {
|
||||||
|
uint32_t start = this->current_flash_offset;
|
||||||
|
uint32_t end = start + length + 1;
|
||||||
|
if (end > RP2040_FLASH_STORAGE_SIZE) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
auto *pref = new RP2040PreferenceBackend(); // NOLINT(cppcoreguidelines-owning-memory)
|
auto *pref = new RP2040PreferenceBackend(); // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
return ESPPreferenceObject(pref);
|
pref->offset = start;
|
||||||
|
pref->type = type;
|
||||||
|
current_flash_offset = end;
|
||||||
|
return {pref};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sync() override { return true; }
|
bool sync() override {
|
||||||
|
if (!s_flash_dirty)
|
||||||
|
return true;
|
||||||
|
if (s_prevent_write)
|
||||||
|
return false;
|
||||||
|
|
||||||
bool reset() override { return true; }
|
ESP_LOGD(TAG, "Saving preferences to flash...");
|
||||||
|
|
||||||
|
{
|
||||||
|
InterruptLock lock;
|
||||||
|
::rp2040.idleOtherCore();
|
||||||
|
flash_range_erase((intptr_t) eeprom_sector_ - (intptr_t) XIP_BASE, 4096);
|
||||||
|
flash_range_program((intptr_t) eeprom_sector_ - (intptr_t) XIP_BASE, s_flash_storage, RP2040_FLASH_STORAGE_SIZE);
|
||||||
|
::rp2040.resumeOtherCore();
|
||||||
|
}
|
||||||
|
|
||||||
|
s_flash_dirty = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reset() override {
|
||||||
|
ESP_LOGD(TAG, "Cleaning up preferences in flash...");
|
||||||
|
{
|
||||||
|
InterruptLock lock;
|
||||||
|
::rp2040.idleOtherCore();
|
||||||
|
flash_range_erase((intptr_t) eeprom_sector_ - (intptr_t) XIP_BASE, 4096);
|
||||||
|
::rp2040.resumeOtherCore();
|
||||||
|
}
|
||||||
|
s_prevent_write = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t *eeprom_sector_;
|
||||||
};
|
};
|
||||||
|
|
||||||
void setup_preferences() {
|
void setup_preferences() {
|
||||||
auto *prefs = new RP2040Preferences(); // NOLINT(cppcoreguidelines-owning-memory)
|
auto *prefs = new RP2040Preferences(); // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
|
prefs->setup();
|
||||||
global_preferences = prefs;
|
global_preferences = prefs;
|
||||||
}
|
}
|
||||||
|
void preferences_prevent_write(bool prevent) { s_prevent_write = prevent; }
|
||||||
|
|
||||||
} // namespace rp2040
|
} // namespace rp2040
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace esphome {
|
||||||
namespace rp2040 {
|
namespace rp2040 {
|
||||||
|
|
||||||
void setup_preferences();
|
void setup_preferences();
|
||||||
|
void preferences_prevent_write(bool prevent);
|
||||||
|
|
||||||
} // namespace rp2040
|
} // namespace rp2040
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
Loading…
Reference in a new issue