DataBaseManager
Повна документація класу DataBaseManager з детальним описом усіх публічних, приватних та допоміжних методів.
Клас DataBaseManager (простір імен flowercare::storage) відповідає за...
Публічні методи
DataBaseManager()
DataBaseManager()
Конструктор класу. Створює новий екземпляр та скидає вказівник партиції _part у nullptr.
begin()
bool begin()
Ініціалізує менеджер сховища.
- Шукає партицію
storageу flash-пам'яті (типESP_PARTITION_TYPE_DATA, підтип0x99). - Валідує стан RTC пам'яті через
isRtcStateValid(). - Визначає та оновлює
rebootIdчерезmanageRebootId(). - Якщо RTC валідний: відновлює
_currentSectorта_currentOffsetпрямо з RTC без звернення до flash. - Якщо RTC невалідний: запускає бінарний пошук
findLastWritePositionBinary()по всій партиції, щоб визначити останню позицію запису та обчислити наступні сектор та зсув, після чого оновлює RTC.
- Повертає:
trueпри успішній знахідці партиції та вирахуванні позиції;false, якщо партиція відсутня.
writeRecord()
bool writeRecord(const uint8_t* sensorData)
Формує та записує новий дельта-запис у flash-пам'ять.
- Якщо
_currentOffset == 0, виконує прання поточного сектора flash-пам'яті (esp_partition_erase_range). - Створює структуру
DataRecord, заповнює їїrebootId, поточним штампом часуgetTimestamp()та копіюєsensorData. - Записує структуру у flash за адресою поточного сектора та зсуву.
- Інкрементує
_currentOffset. Якщо сектор заповнено, переходить до наступного сектора (з кільцевим поверненням до0). - Зберігає новий стан у RTC через
updateRtcState().
-
Параметри:
-
sensorData— вказівник на масив даних із датчиків розміромDATA_SIZE_WITHOUT_TIMESTAMP. -
Повертає:
true, якщо запис пройшов успішно, інакшеfalse.
findIndexByTargetKey()
uint32_t findIndexByTargetKey(uint32_t targetTimestamp, uint32_t targetRebootId)
Шукає індекс запису в пам'яті за цільовим комбінованим ключем (пара rebootId та timestamp).
- Формує 64-бітний ключ
(targetRebootId << 32) | targetTimestamp. - Знаходить межі записаних даних у кільцевому буфері (найстаріший
firstIdxта найновішийlastIdx). - Виконує послідовне зіставлення ключів від
firstIdxдоlastIdx.
-
Параметри:
-
targetTimestamp— часовий штамп запису для пошуку. -
targetRebootId— ID сесії/перезавантаження пристрою. -
Повертає:
-
firstIdx, якщо ключ менший або дорівнює найстарішому. -
_totalMaxRecords, якщо ключ більший за останній записаний. -
Знайдений індекс запису у кільцевому буфері.
getLastRecordIndex()
uint32_t getLastRecordIndex() const
Розраховує абсолютний індекс останнього записаного елемента на основі поточних _currentSector та _currentOffset.
- Повертає:
uint32_t— індекс останнього записаного елемента у діапазоні0.._totalMaxRecords - 1.
readRecordsPacket()
size_t readRecordsPacket(uint32_t ¤tIdx, DataRecord* outBuffer, size_t maxRecordsToRead)
Зчитує пакет із декількох послідовних записів з пам'яті у наданий буфер.
- Обчислює фізичну адресу кожного запису за індексом
currentIdx. - Зчитує дані з flash-пам'яті в
outBuffer. - Зупиняє зчитування, якщо досягнуто неініціалізованої пам'яті (
timestamp == 0xFFFFFFFF) або останнього записуlastIdx. - Зміщує значення
currentIdxна наступну позицію після кожного прочитаного елемента (якщо досягнуто кінця — встановлює в_totalMaxRecords).
-
Параметри:
-
currentIdx(in/out) — посилання на індекс, з якого починати зчитування. Значення модифікується під час зчитування. -
outBuffer— вказівник на масив/буфер пам'яті для збереженняDataRecord. -
maxRecordsToRead— максимальна кількість елементів для зчитування. -
Повертає:
size_t— фактично зчитану кількість записів.
Приватні методи
updateRtcState()
void DataBaseManager::updateRtcState()
Оновлює змінні стану у структурі rtcStorageState в RTC SRAM:
- Записує магічний ключ
RTC_MAGIC_KEY. - Записує поточні значення
_currentSectorта_currentOffset. - Розраховує контрольну суму CRC32 для всієї структури RTC та зберігає її у
rtcStorageState.checksum.
getTimestamp()
uint32_t DataBaseManager::getTimestamp()
Обчислює час у секундах, що минув від моменту старту/перезавантаження пристрою.
- Використовує низькорівневі функції ESP32
rtc_time_get()таrtc_time_slowclk_to_us()для перетворення тіків RTC-таймера в мікросекунди, а потім у секунди. - Повертає:
uint32_t— кількість секунд з моменту запуску.
isRtcStateValid() const
bool DataBaseManager::isRtcStateValid() const
Перевіряє цілісність даних у RTC SRAM після перезапуску:
- Перевіряє наявність
RTC_MAGIC_KEY. - Перевіряє, чи не виходять значення сектора та зсуву за припустимі межі partition layout.
- Порівнює збережену чексуму з щойно розрахованою контрольною сумою CRC32.
- Повертає:
true, якщо стан у RTC правильний і йому можна довіряти.
calculateRtcChecksum() const
uint32_t DataBaseManager::calculateRtcChecksum() const
Обчислює CRC32 для вмісту структури FlowerCareRTCData (за винятком самого поля checksum).
- Повертає:
uint32_t— розраховане значення контрольної суми.
manageRebootId()
uint32_t DataBaseManager::manageRebootId(bool rtcValid)
Керує ідентифікатором сесії/перезапуску пристрою (rebootId):
- Якщо причина скидання —
ESP_RST_DEEPSLEEPі стан RTC є валідним, повертає збереженийrtcStorageState.rebootId. - При холодному старті (Cold Boot) або пошкодженні RTC:
- Відкриває NVS через
Preferences(простірstorage_data). - Інкрементує збережений
reboot_id. - Оновлює
rtcStorageState.rebootIdта фіксує початковий часrtcStorageState.startRtcTicks.
- Параметри:
rtcValid— прапорець валідності даних у RTC. - Повертає:
uint32_t— активнийrebootId.
getCombinedKeyAtIndex()
uint64_t DataBaseManager::getCombinedKeyAtIndex(uint32_t index)
Зчитує з flash-пам'яті перші 8 байт запису за вказаним індексом.
- Зчитувані 8 байт відповідають полям
rebootId(4 байти) таtimestamp(4 байти), утворюючи складений 64-бітний ключ. - Параметри:
index— абсолютний індекс запису у сховищі. - Повертає:
uint64_t— значення комбінованого ключа, абоUINT64_MAXу разі помилки читання або якщо індекс перевищує_totalMaxRecords.
findLastWritePositionBinary()
uint32_t DataBaseManager::findLastWritePositionBinary()
Виконує двопрохідний бінарний пошук по flash-пам'яті для визначення індексу останнього записаного елемента у кільцевому буфері.
- Враховує два сценарії:
- Буфер заповнений частково (пошук межі між записаними даними та незаписаною пам'яттю
UINT64_MAX). - Буфер заповнений повністю з інверсією ключів (пошук точки переходу/переповнення кільцевого буфера, де
currentKey > nextKey).
- Повертає:
uint32_t— індекс останнього дійсного запису у пам'яті.
Внутрішні утиліти (Anonymous Namespace)
Функції та змінні, що визначені у файлі реалізації .cpp в анонімному просторі імен і недоступні ззовні модуля:
calculate_crc32()
uint32_t calculate_crc32(const uint8_t *data, size_t length)
Реалізація стандартного алгоритму обчислення IEEE 802.3 CRC32 з поліномом 0xEDB88320. Використовується для перевірки цілісності структури стан-RTC.
Локальні змінні
RTC_DATA_ATTR flowercare::FlowerCareRTCData rtcStorageState— структура даних у швидкій пам'яті RTC SRAM, яка зберігає свій вміст під час Deep Sleep.Preferences prefs— об'єкт для роботи з енергонезалежною пам'яттю NVS (використовується для збереженняreboot_id).
Приклад використання
#include "DataBaseManager.hpp"
void setup() {
Serial.begin(115200);
// 1. Ініціалізація сховища
if (!flowercare::storage::db.begin()) {
Serial.println("Помилка ініціалізації сховища!");
return;
}
// 2. Запис даних з сенсора
uint8_t rawData[12] = {0x01, 0x02, 0x03, 0x04};
flowercare::storage::db.writeRecord(rawData);
// 3. Зчитування останнього запису
uint32_t lastIdx = flowercare::storage::db.getLastRecordIndex();
// 4. Пакетне зчитування
DataRecord buffer[5];
uint32_t readIndex = 0;
size_t readCount = flowercare::storage::db.readRecordsPacket(readIndex, buffer, 5);
Serial.printf("Зчитано записів: %d, Наступний індекс: %u\n", readCount, readIndex);
}