EEBoom - простая и удобная arduino библиотека для эмуляции EEPROM на ESP32 ESP8266

radionik

✩✩✩✩✩✩✩
19 Янв 2024
10
0
Всем привет. Появилась новая библиотека для удобной типизированной работы с "EEPROM" эмулированной во flash памяти.

Из очевидных преимуществ:
  • реально удобный и простой интерфейс
  • можно создать несколько независимых объектов с разной структурой в разных областях flash памяти
  • ротация не только между страницами, но и внутри одной страницы - в десятки и сотни раз снижает износ памяти
  • максимально легкая и компактная реализация - функционал вынесен в *.cpp модуль, что хорошо для многофайловых проектов
  • поддержка ESP8266 ESP32 (STM32 планируется)
Если функционал зайдет, можно перетащить принцип и на работу с внешними EEPROM микросхемами и на работу с родной EEPROM у AVR.
Здесь можно задавать вопросы.

Страница проекта - EEBoom

C++:
#include <eeboom.h>

struct EE {
    int         devID = 0XEFBEADDA;     //установить значение по умолчанию
    short       step;                   //для певрой инициализации
};

EEBoom<EE>      ee;                        //создал объект с типом своей структуры

void setup() {
    ee.begin();                         //инит по умолчанию с 2 секторами
}

void loop() {
    ee.data.step++;                     //сохраняем каждую секунду - с нашей структурой
    ee.commit();                        //страница закончится только через 6 мин!
    delay(1000);
}
Больше примеров и инструкции на странице репозитория.
 

vortigont

★★★★★★✩
24 Апр 2020
1,014
531
Saint-Petersburg, Russia
посмотрел - оч своеборазная либа если честно.

C++:
EEBoom<AppParam>    param;                //common device parameters
EEBoom<uint32_t>    engHours;             //nparamd be commit very often
есть два объекта - в какие сектора они будут писаться? Оба в один по очереди или в разные?
Если нужно хранить с дюжину переменных типа инт, не связанных в одну структуру, нужно создавать дюжину разных объектов EEBoom?
Не нашел как в секторе определяется начало и конец последнего актуального объекта, т.е. где находится валидное значение?
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,220
1,291
Москва
А чем плоха обычная EEPROM для esp32 ? Вернее даже так, чем ЭТА лучше чем обычная ?
В код для нано добавляется
EEPROM.begin(1024);
и дальше без изменений.
 

radionik

✩✩✩✩✩✩✩
19 Янв 2024
10
0
Сектора выбираются на этапе begin().
begin() без параметров возьмет в работу 2 сектора по умолчанию. Для ESP8266 4MB например это будет 1019 и 1018. Для ESP32 - последние 2 сектора партишена spiffs.
Сектора можно задать явно - begin(1000, 10); - домашний сектор 1000й и от него вниз 10шт - 1000, 999, 998 ...

Если нужно хранить дюжину интов - создается структура и в ней либо сами инты, либо массив с интами.
Смысл библиотеки в том, что не нужно шарить по файлам все инты - можно лишь сделать
extern EEBoom<AppParam> param;
и везде, где нужно -
param.data.myFirstInt++;
param.data.arrOfInt[11] = 10;
Вообще пример с голым интом показан, что так можно делать - обычно нужно больше сущностей.
Вместо AppParam и uint32_t в вашем примере могут быть любые типы - можно определить свой на 200 байт и хранить в нем что угодно опять считая смещения... Но структура же удобнее.
Считаете, что есть сложности или неудобства с созданием структуры?

Не понял суть вопроса. Если смотреть со стороны пользователя библиотеки - всё происходит само сабой на этапе begin()
Если вопрос о том, как реализовано - по шаг за шагом по всем страницам ищется последняя валидная структура (прозрачно для пользователя считается crc) - она и копируется в RAM и с ней взаимодействует пользователь. Если нужно изменить - меняется копия в RAM -
param.data.myInt++;
затем обновленная структура сохраняеется во флеш (или не сохраняется - зависит от стратегии программы)
param.commit();
 

radionik

✩✩✩✩✩✩✩
19 Янв 2024
10
0
А чем плоха обычная EEPROM для esp32 ? Вернее даже так, чем ЭТА лучше чем обычная ?
Из очевидных преимуществ:
  • реально удобный и простой интерфейс
  • можно создать несколько независимых объектов с разной структурой в разных областях flash памяти
  • ротация не только между страницами, но и внутри одной страницы - в десятки и сотни раз снижает износ памяти
  • максимально легкая и компактная реализация - функционал вынесен в *.cpp модуль, что хорошо для многофайловых проектов
  • поддержка ESP8266 ESP32 (STM32 планируется)
Вроде постарался подробно расписать... Попробуйте задать конкретные вопросы с примерами - будем разбираться)
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,220
1,291
Москва
реально удобный и простой интерфейс
Сомнительно, чем он проще и удобнее стандартного ? Для перевода старого кода мне стандартный удобнее.

можно создать несколько независимых объектов с разной структурой в разных областях flash памяти
Зачем ? Если делать что то по новой я бы вообще не связывался с типом EEPROM, есть файловая система, есть файлы конфигурации.

ротация не только между страницами, но и внутри одной страницы - в десятки и сотни раз снижает износ памяти
Это хорошо. Хочу пример где память меняет свою страницу каждые 5 считываний. Всего 3 места для записи, что бы они по кругу м енялись. Т.е. 1-2-3-4-5 - 1-ая страница, 1-2-3-4-5 - 2-ая страница, 1-2-3-4-5 - 3-я страница, 1-2-3-4-5 - 1-ая страница, и т.д.

максимально легкая и компактная реализация - функционал вынесен в *.cpp модуль, что хорошо для многофайловых проектов
Возможно.

поддержка ESP8266 ESP32 (STM32 планируется)
Пхых... Так себе аргумент.
 

vortigont

★★★★★★✩
24 Апр 2020
1,014
531
Saint-Petersburg, Russia
begin() без параметров возьмет в работу 2 сектора по умолчанию
так если два объекта созданы конструктором по-умолчанию то куда они будут писать данные? В один сектор в перемешку? Как тогда объекты разной структуры находят хвос своего соседа?

есть сложности или неудобства с созданием структуры?
конечно есть. Простенькая глобальная структура с набором переменных на все случаи жизни это "ардуино-стайл".
Т.е. понадобилось добавить переменную - меняется структура, меняется тип вашего объекта и он уже не сможет считать обратно записанные данные. Обычно нужно сохранять какие-то члены разных классов которые не зависят друг отдруга.
Вообще зря вы сделали класс EEBoom шаблоном от типа хранимой структуры - внутри все равно вы эту структуру обрабатываете как массив байт определенной длинны. Использовать ваш объект вместо своей структуры пользователь не сможет, поэтому придется держать два объекта - и свою структуру и ваш ЕЕбум и копировать одно в другое. Смысла заводить шаблон нет никакого - каждый класс по шаблону от уникально типа имеет уникальную сигнатуру. Это сильно затрудняет работу с указателями и деривативами.
 

radionik

✩✩✩✩✩✩✩
19 Янв 2024
10
0
Сомнительно, чем он проще и удобнее стандартного ? Для перевода старого кода мне стандартный удобнее.
Странно. Мне казалось это очевидным... Вам же в стандартной библиотеке для каждой переменной нужно запоминать размер смещения, чтобы потом её достать из памяти... Ну и на всякий случай уточню - вы же поняли, что речь об эмулированной во флеш eeprom?
есть файловая система, есть файлы конфигурации
Если сохраняешь 1-2 раза в месяц - да, можно. И да на ESP много памяти и можно позволить себе иметь файловую систему и хранить там текстовый файл с конфигурацией... Но какую работу делает FS при перезаписи этого файла, какие в итоге временные лаги, как часто перетираются страницы флеш... Это же очень большой и универсальный софт. А если нужно обновлять переменную с моточасами раз в минуту или чаще?
Хочу пример где память меняет свою страницу каждые 5 считываний.
Работает немного по-другому. Библиотека на старте рассчитывает сколько раз структура пользователя помещается в секторе памяти. И будет перезаписывать эту структуру в этом секторе, пока не дойдет до конца - например 100 раз. На этом этапе на текущей странице находится вся история изменений пользовательских данных (последние 100 копий). При инициализации, разумеется, загрузится последняя копия. При следующем commit() сначала запишется новая копия на новую страницу и лишь после этого сотрется старая страница. Таким образом исключаются моменты времени, когда данные находятся в только в РАМ и нет их копии на флеш. (если только вы не выбрали для работы один единственный сектор). Возвращаясь к вашему вопросу. Если хочется увидеть ровно 5 записей, нужно создать структуру, которая примерно в 5 раз меньше размера сектора - например 800 байт
C++:
struct EE{
    char  blob[800];
};
EEBoom<EE> ee;
ee.begin(1019, 3);            //3 сектора по 5 перезаписей в каждом
Честно говоря долго не хотел заморачиваться с шаблонами и вообще у меня всё работало прекрасно на си. А тут убил не один день, чтобы шаблону оставить типизацию, а весь функционал вынести в нешаблонный класс, сделав возможным его компиляцию в отдельном *.cpp модуле.
Я же без ножей. Описал как есть
так если два объекта созданы конструктором по-умолчанию то куда они будут писать данные?
C++:
EEBoom<MyStruct>    structEE;          //первый объект
EEBoom<char>        charEE;            //второй объект

structEE.begin(1019,2);                //первый будет жить в 1018-1019 секторах
charEE.begin(1017, 2);                 //второй - в 1017-1016 секторах
...это "ардуино-стайл". Т.е. понадобилось добавить переменную ...
Обычно структура пишется в 5 - 10 строчек под нужны конкретного приложения, а не на все случаи жизни... какие еще случаи?
Если вам нужно подобие чего-то динамичного, то, наверное и тут можно использовать EEBoom c его преимуществами.
Принцип такой. Выделяете под свои хотелки, например 200 байт массивом. В этом блобе делаете, что душе угодно, хоть String храните. А EEBoom уже будет заниматься тиражированием и ротацией этого блоба по пулу выделенных секторов.
Но вообще я не думал о таком. Было желание сделать для простых людей простейший интерфейс с простым подключением и инициализацией:
C++:
ee.data.var1++;
Serial.println(ee.data.ssid);
Обычно нужно сохранять какие-то члены разных классов которые не зависят друг отдруга. Вообще зря вы сделали класс EEBoom шаблоном от типа хранимой структуры
Честно говоря, звучит, как что-то надуманное... Мне сложно представить, какие вы задачи решаете, что сталкиваетесь с такими проблемами. В чем проблема хранить копии 10-15 переменных в одном месте, которое библиотека использует для собственных нужд фактически? Выше уже описал. если имеете такуюспецифику - выделите блоб и делайте в нем, что хотите.
Смысла заводить шаблон нет никакого - каждый класс по шаблону от уникально типа имеет уникальную сигнатуру. Это сильно затрудняет работу с указателями и деривативами.
Тут без примеров ваших затруднений - никак. Однако замечу, что шаблонной является только верхняя часть, а весь функционал реализован без шаблона. Это позволяет , в том числе, избегать дублирования кода для разных типов шаблона.

Хочу заметить, что EEBoom не создавалась с целью закрыть все задачи всех пользователей. Цель была закрыть (по правилу 80/20) 80% задач 80% пользователей.
И да, спасибо за внимание и критику.
 

radionik

✩✩✩✩✩✩✩
19 Янв 2024
10
0
И да, еще такой вопрос
C++:
struct EE {
    int         devID = 0XEFBEADDA;     //установить значение по умолчанию
    short       step;                   //для певрой инициализации
};

EEBoom<EE>      ee;                     //создал объект с типом своей структуры
Сейчас подумал, что со стороны может быть не очевидно, что вся пользовательская структура по сути интегрируется в объект и доступна из поля data объекта по точке?
доступ.png
 

vortigont

★★★★★★✩
24 Апр 2020
1,014
531
Saint-Petersburg, Russia
речь об эмулированной во флеш eeprom
вот как раз это и не получается эмулированный еепром. Если вы что-то эмулируете, то интерфейс должен быть такой же как у объекта который вы эмулируете. Т.е. должна быть возможноть обращаться к конкретным ячейкам по адресам, или в абстрактном случае по некоему ключу, которым может быть в частности некий виртуальный адрес.

если нужно обновлять переменную с моточасами раз в минуту или чаще?
вот с этого и нужно начинать. Вы сделали некую обертку, которая по сути занимается flash rollover. И, КМК, вам так её и нужно позиционировать, а не как эмулятор еепром. У вас получается запись данных в скользящее окно, т.е. при циклической записи достуны последние n значений. Задач на подобные хранилища дововольно много - всевозможные data series, данные с датчиков, метрики, результаты расчетов и пр. где нужна история за некоторый последний период. И КМК это будет более восстребованый сценарий использовать вашу либу чем как эмулятор еепром. Придется, правда, добавить методы доступа ко всем блокам данных, но это решаемо. Если интересно - посмотрите мою реализацию подобного контейнера в памяти.
Замена еепром у вас не получилась - задачу выравнивания записи вы решили, а задачу произвольного поадресного доступа - нет.

structEE.begin(1019,2); //первый будет жить в 1018-1019 секторах
charEE.begin(1017, 2); //второй - в 1017-1016 секторах
тогда у вас в примере ошибка: param.begin(1000, 2); //5 sectors 1000 -> 999. Должно быть или 2 сектора или (1000, 5)
Но в целом я понял, под каждый объект ебум нужно выделять отдельные сектора, если выделать минимум 2, то это 8к.

Обычно структура пишется в 5 - 10 строчек под нужны конкретного приложения, а не на все случаи жизни... какие еще случаи?
приведу пример:
ардуино-стайл - создается некая струкрута для моего "скетча" и она же пишется через Ебум
C++:
struct AppParam {
    uint32_t    devID = 0x12345678;       //default value for zero init
    uint16_t    minSpparamd = 10;
    uint16_t    maxSpparamd = 60;
    uint16_t    maxTemp = 85;
    uint8_t     lastOffSrc = 0x00;
    uint8_t     arr[10];
    char        ssid[20] = "Empty_SSID";
    char        pass[20] = "Empty_PASS";
};
Скетч работает, все рады. Теперь мне захотелось добавить функционал с энкодером, нужно писать в "конфиг" пины для энкодера, я меняю структуру, добавляю 2 члена
C++:
struct AppParam {
    uint32_t    devID = 0x12345678;       //default value for zero init
    uint16_t    minSpparamd = 10;
    uint16_t    maxSpparamd = 60;
    uint16_t    maxTemp = 85;
    uint8_t     lastOffSrc = 0x00;
    uint8_t     arr[10];
    char        ssid[20] = "Empty_SSID";
    char        pass[20] = "Empty_PASS";
    int encoder_clk;
    int encoder_data;
};
в итоге старые данные в "еепром" становятся невалидными и мы получаем "чистый" конфиг. Несмертельно, но для конечного пользователя оч неприятно и это следует отметить в примерах/документации. Придется делать еще какой-то параллельный способ сохранять конфиг в независимый файл и переписывать данные туда-сюда.

Альтернативный вариант - заводить отдельную структуру и выделять под нее еще 8к. В случае мало-мальски приличного проекта а не "скетча",
подобное массовое заведение глобальных объектов станет проблемой в поддержке кода. Дабы не быть голословным приведу пример на код из проекта лампы от vvip. Можно оценить количество переменных, хранимых в псевдо-еепром. Понятно что можно раскидать по структурам и уменьшить число объектов раз в 5, но тут и вылезет дилемма между постоянно обнуляемыми данными или количества секторов и объектов, которые нужно держать в памяти.

Мне сложно представить, какие вы задачи решаете, что сталкиваетесь с такими проблемами.
Это не проблемы это задачи возникающие в проектах, которые чуть сложнее чем "ардуино-скетч" на помигать светодиодом.
Количество и типы данных, которые нужно сохранять растет, их упорядочивание становится более насущной задачей чем иметь глобальный конфиг в виде струкруты. Возникает необходимость передавать структуры с конфигами/данными между объектами. В "конфиге" появятся объекты типа String или char* которые либа не переварит и нужно будет на местах создавать какие-то костыли в виде "завести где-то еще отдельно String, потом скопировать из нее в струкруту массив чаров и не забыть учесть максимальный размер." Т.е. для сериализации пригодны только структуры PoD, а другие объекты придется пристегивать как-то сбоку. При большом количестве строк это будет жутко раздувать память структуры местом "про запас".


Выделяете под свои хотелки, например 200 байт массивом. В этом блобе делаете, что душе угодно, хоть String храните. А EEBoom уже будет заниматься тиражированием и ротацией этого блоба по пулу выделенных секторов.
С блобом это понятно что можно накрутить что угодно. Но тут опять же но. Существующий у вас сейчас интерфейс для этого очень неудобен, если вообще пригоден.
Как создать блоб на 200 байт? EEBoom<uint8_t*> blobcfg; создаст сруктуру с указателем, а не с данными, которую затем не сможет сериализовать.
Как-то так?
Код:
struct MyBlob {
   uint8_t raw[200];
}
EEBoom<MyBlob>    blobcfg;
Ну допустим, но работать потом с raw как указателем на uint8_t ппц как неудобно. Над ним нужно будет сооружать каку-то надстройку, которая (например) будет в него побайтово переписывать ту же AppParam из кода выше. Плюс размер блоба опять же фиксированный, плюс блоб надо держать в памяти параллельно с основной структурой AppParam т.к. копи-конструктора нет. Что вообще сводит всю затею на нет.
Как по мне, то для блобов вам нужно сделать отдельный класс без шаблона, который будет:
а) иметь конструктор с указателем на массив байт и его размер
б) не содержит копии данных который пишет/читает, а делает это по указателю
в) будет способен писать/читать в сектор данные произвольной длинны, хотя бы в пределах сектора чтобы не думать загодя о проблеме роста и не писать лишнего. Тогда получится класс который делает то что умеет - выравнивание записи над сырыми данными без лишних затрат. Он может быть короткоживущим - создал, прочитал/записал, уничтожил или долгоживущим т.к. не жрет место под копию данных а содержит только указатель. И его можно будет использовать под хранение сериализованных объектов, напр через json или messagepack. Это будет реально полезно, т.к. приложений, хранящих данные в джейсонах на файловой системе навалом. И да, это тяжеловато, у литлФС большой перерасход на хранение мелких файлов, хотя выравнивание тоже есть.

Тут без примеров ваших затруднений - никак. Однако замечу, что шаблонной является только верхняя часть, а весь функционал реализован без шаблона.
Это не мои затруднения это требования языка.
Пример - я пишу некий базовый класс, который вычитывает и отдает (или принимает и сохраняет) "конфиг" для некоего объекта по ключу.
Т.е. напр кофиги для энкодера, дисплея, сенсоров и пр., которые лежат где-то на постоянном носителе, на ФС, флеше, в еепром и пр.
Абстрактно
C++:
class Configurator {

  const &T getConfig(config_t module);
  void setConfig(config_t module, const &T);
}
}
Где Т это некий объект с неизвестной структурой (конфиги то у нас разные).

В качестве Т может выступать, например JsonVariant из библиотеки ArduinoJson. В таком случае можно получать и скармливать конфигуратору произвольно струкрурированные объекты, которые затем сериализуются и пишутся куда-то там...
В случае с вашим EEBoom это не получится, т.к. в него еще нужен тип данных EEBoom<Type>, т.е. методы getConfig();, setConfig() неспособны работать с объектами ебум. Придется или конфигуратор тоже шаблонизировать или вообще отказаться от подобного подхода.
И это при том что внутри EEBoom для своей основной задачи сериализации/десериализации никак не использует тип струкруты которую читает/пишет, для него всё это массив байт. Единственное для чего ему нужен шаблонизированный тип, это создать копию хранимого объекта внутри себя.
Это указывает на изначально плохой дизайн.

Понятно что ваш проект ориентирован на простые задачки хранения чего-то понемножку для нетребовательного пользователя. Задел хороший, продолжайте совершенствоваться. Я просто указываю на архитектурные недостатки для, на первый взгляд, простых и очевидных решений.

Вы, наверное, в курсе про реализацию NVS в esp32, если внимательно присмотритесь, то поймёте почему там используется такой сложный формат записей. Но, в итоге, получается довольно мощный key:value сторадж с выравниванием записи, который не привязан к PoD структурам и который легко адаптируется к задачам сериализации/десериализации.
 
  • Лойс +1
Реакции: Старик Похабыч

radionik

✩✩✩✩✩✩✩
19 Янв 2024
10
0
Понятно что ваш проект ориентирован на простые задачки хранения чего-то понемножку для нетребовательного пользователя.
Я очень рад, что вы поняли:) Еще раз - я и не планировал перекрыть ВСЕ задачи ВСЕХ инженеров. Просто по работе часто сталкиваюсь с необходимостью такого рода хранилища - простого, лаконичного. Я искренно верю, что такая реализация способна закрыть 95% поделок уровня Arduino (не пойму что плохого, что люди после работы не бухают/смотрят телевизор, а занимаются творчеством).
А серьезные ребята всегда напишут для своего серьезного проекта свою серьезную реализацию;)
про реализацию NVS в esp32
В Readme, который по ощущениям меньше чем наши посты в этой ветке, об этом сказано. Нужна динамика - пожалуйста, там есть поддержка, стрингов и блобов... и для них nvs пожалуй не так плох. Но для статики, когда под char каждый раз будет перетираться 32 байта... считаю слишком. Ну и простой Arduino-style любитель не станет менять размеры раздела, который по умолчанию только 5 секторов и так же не пригоден для частой перезаписи...
вот как раз это и не получается эмулированный еепром
Соглашусь. Имеется лукавство. Расчет на то, что люди будут натыкаться на эту реализацию, когда будут гуглить проблему eeprom для esp. И, повторюсь, считаю, что для большинства попробовавших - это будет гораздо удобнее, чем стандартная реализация. Которая кстати еще и по функциональности сильно хромает - натурально сделали заляпуху, чтобы было. Хосе Перес попытался решить вопрос со своей eeprom_rotate, но не сильно ушел вперед. Тот же убогий интерфейс (ради совместимости) и трем страницу после каждого commit()

Кстати доступна только последняя копия сохраненных данных - для пользователя EEBoom это eeprom память размером sizeof(myStruct)

На счет fifo хранилища вопрос уже решен - так же очень экономично и типизированно. Сейчас в проекте трудится на 400 секеторах, запись каждые 3-5 секунд. В рам писать не вариант, потому что устройство бывает офлайн, а данные для сервера. Но это еще более узко и специфично. Если этот проект зайдет народу, может и тот опубликую.

Сектор может быть и один. Это будет работать, но в момент когда сектор нужно стереть целиком устройство рискует остаться без валидных данных.

я меняю структуру, добавляю 2 члена
на мой взгляд это называется - я изменил прошивку. И да в этом случае программа стартанет с данными по умолчанию. Если в вашем проекте это критично - реализуйте что-то необходимое для себя поверх.

Есть очень приличные проекты (а не "скетчи"), которые вовсе не используют eeprom... И так же есть очень приличные проекты, которым нужно сохранить 1-2 переменных, не усложняя при этом структуру кода...

можно раскидать по структурам и уменьшить число объектов раз в 5, но тут и вылезет дилемма между постоянно обнуляемыми данными или количества секторов и объектов, которые нужно держать в памяти.
В этом примере неприятность состоит в том (вы это и имели ввиду?), чтобы не хранить эти 1,5кB настроек еще и в RAM? Соглашусь. Хоть памяти и вагон у меня, такой кусок жалко.

Задачу произвольного поадресного доступа я не решал - я от этого убожества убегал.

Как по мне, то для блобов вам нужно сделать отдельный класс без шаблона, который будет:
а) иметь конструктор с указателем на массив байт и его размер
б) не содержит копии данных который пишет/читает, а делает это по указателю
в) будет способен писать/читать в сектор данные произвольной длинны, хотя бы в пределах сектора чтобы не думать загодя о проблеме роста и не писать лишнего.
Интересно, подумаю. Но боюсь, что NVS уже написана)

тогда у вас в примере ошибка: param.begin(1000, 2); //5 sectors 1000 -> 999
не могу найти, где такое написано у меня? подскажите, исправлю
т.е. методы getConfig();, setConfig() неспособны работать с объектами ебум.
почему не работать с instanse.data.myObj?
Единственное для чего ему нужен шаблонизированный тип, это создать копию хранимого объекта внутри себя.
Нужно узнать размер пользовательских данных и выровнять их, и да, создать копию.

Примеры ваши весьма убедительны, спасибо. Возможно часть описанных вами задач получится решить в контексте этой библиотеки.
Еще один момент, говорю как есть, без обид. Мне не понятны эти выпады (показалось может) в сторону ардуинщиков, arduino-style, "скетчей", задачек и в этом духе. Я человек новый на форуме. Может так принято здесь. Но насколько могу судить форум как раз для людей, занимающимися arduino в качестве хобби... Ничего плохого в ардуино и этих людях не вижу. Я не разрабатываю eeprom фреймворк с абонентской платой, а хочу сделать жизнь большого количества ардуинщиков чуть легче
 

vortigont

★★★★★★✩
24 Апр 2020
1,014
531
Saint-Petersburg, Russia
Я человек новый на форуме.
Добро пожаловать! На самом деле здесь не оч много людей, которые реально ведут какие-то проекты, а уж тех кто пишет библиотеки или разберется в их коде так вообще по пальцам посчитать. Так что считайте что немножко вас "поклевать" это альтернатива тому что вообще в тему никто ничего не напишет.

не понятны эти выпады (показалось может) в сторону ардуинщиков...
я не говорил что ардуино это плохо, но "ардуино стиль" сильно калечит людям мозги, это прискорбный факт. Само понятие "скетч" означет "черновик, небрежный набросок", ардуино-стиль это накидать глобальных переменных в .ino файл и пачку функций, а потом накидывать ветвистые конструкции ифов в луп(). Это уводит человека в тупик программизма, не учит думать и декомпозировать задачу, выстраивать связи.
Это как приучать ребенка есть фастфуд вместо комплексного меню - легко, быстро, модно, закинул в топку и пошел. Ребенок сам по себе неплохой и фастфуд тоже сам по себе неплохой, но ребенок с малого приученный к фастфуду это проблема.
Если вы пишите скетчи - ну ладно, мож оно вам не сильно надо. Если дошли до написания либ, то, как по мне, пора начинать думать более абстрактно чем идти по пути "легких и быстрых", но сильно ограниченных библиотек для скетчей.

не могу найти, где такое написано у меня? подскажите, исправлю
в примере

Интересно, подумаю. Но боюсь, что NVS уже написана)
нвс есть только под семейство есп32, если у вас замах на 8266 и еще какие-то платформы, то почему бы нет? Еще полно фатиков 8266, им бы сильно пригодилось.

Задачу произвольного поадресного доступа я не решал - я от этого убожества убегал.
произвольный адресный доступ это по сути работа с постоянной памятью как с РАМ, святой Грааль. От него нельзя убежать, к нему можно только прибежать )

на мой взгляд это называется - я изменил прошивку
прошивку да, но не постоянное хранилище! еепром или литлфс раздел не затирается при смене прошивки если это не сделать явно. Пользователь записывает данные и расчитывает считать их оттуда обратно (если уж это псевдо еепром). И для тех кто не вник в принцип работы либы это будет очень неочвидно, поверьте. Важный момент на самом деле и его нужно четко обозначить в документации.

Но для статики, когда под char каждый раз будет перетираться 32 байта... считаю слишком
шутка в том что вы в итоге пришли к тому же ) но по пути вырезали тучу функционала. Берем ваш пример
Код:
struct AppParam {
    uint32_t    devID = 0x12345678;       //default value for zero init
    uint16_t    minSpparamd = 10;
    uint16_t    maxSpparamd = 60;
    uint16_t    maxTemp = 85;
    uint8_t     lastOffSrc = 0x00;
    uint8_t     arr[10];
    char        ssid[20] = "Empty_SSID";
    char        pass[20] = "Empty_PASS";
};
размер структуры около 60 байт плюс минус смотря как ровнять. Меняем одно значение, напр макстемп, и переписываем всю структуру в 60 байт.
И это еще небольшая структура на пол дюжины параметров. Так в чем выигрыш по сравнению с НВС? Я об этом и говорил, в текущей архитектуре встает дилемма между числом объектов еебум (и секторов под каждый) и размером пезаписи на один объект. Увеличиваешь хранимую структуру и растет число холостой перезаписи, увеличиваешь число объектов и растет размер требуемых секторов.
 

radionik

✩✩✩✩✩✩✩
19 Янв 2024
10
0
OK:)

Если появятся желающие протестировать с вопросами, рад буду помочь.
 

radionik

✩✩✩✩✩✩✩
19 Янв 2024
10
0
В случае мало-мальски приличного проекта а не "скетча",
подобное массовое заведение глобальных объектов станет проблемой в поддержке кода. Дабы не быть голословным приведу пример на код из проекта лампы от vvip.
Сегодня дошли руки посмотреть, что там в проекте, чуть подробнее - очень много вопросов...
Вы мне его привели как пример, куда EEBoom не подойдет по ттх.
Досконально не изучил я его конечно, но сразу видно, что все (или большинство) переменных после извлечения из flash - хранятся в оперативке (а где им еще быть) - определены статически вроде (не знаю там всё в *.h файле). То есть эти 1,5к таки заняты... Но вы только посмотрите на эту портянку из getMatrixMapWidth(); / putMatrixMapWidth();. Их там штук 50.
Один begin() и один commit() общие для всей структуры данных не проще? Вы вообще видели этот eeprom.ino? Как я и говорил, адреса для каждой переменной прописаны руками... изменил одну, запутался - сколько отлаживать?
Ну и самое интересное - чтобы изменить переменную - все равно придется стереть всю страницу целиком - никакого выигрыша... А нет, там полтора кб - с EEBoom можно было бы еще одну копию в этом же секторе записать...

Если автор проекта из местных. Можно связаться - я могу помочь интегрировать EEBoom.
 

vortigont

★★★★★★✩
24 Апр 2020
1,014
531
Saint-Petersburg, Russia
как пример, куда EEBoom не подойдет по ттх
не то что не подойдет по ТТХ, а, КМК, не покажет каких-то очевидных плюсов и при этом покажет очевидные минусы.
Почему там такие портянки и прочее оставим за скобками, может это далеко не самый хороший вариант организации кода в проекте, но нас это не интересует, хозяин - барин. Факт такой что есть задача записи десятков переменных в псевдо еепром - её надо решить наиболее удобным и щадящим для флеша способом.

адреса для каждой переменной прописаны руками... изменил одну, запутался - сколько отлаживать?
в плане запутаться как раз я проблем не вижу - вся карта адресов расписана в одном месте, новые адреса добавляются в конец, старые или заменяется или просто помечаются как неиспользованные. Размер данных сразу виден наглядно, вносить изменения ничем не сложнее чем править определение такой же развесистой структуры написанной в том же файле.

Один begin() и один commit() общие для всей структуры данных не проще?
а чем проще? Также при изменении члена структуры "через точку" придется в стольких же местах кода писать вызов commit(). Если бы ваш класс сам себя проверял на изменения и периодически сбрасывал состояние на флеш, тогда еще понятно было бы удобство. А так число "ручных" вызовов коммит не меняется, обращение что к члену структуры что по определению переменной одинаковое. То что на эти переменные нужно писать еще функции-обёртки для записи переменных в еепром - тут согласен. Но в еепром также можно писать и структуры, в которые группировать переменные. Почему автор этого не делает - я не знаю, наверное ему не влом писать обёртки :)
Я бы от себя добавил что обращение к структуре гораздо удобнее в нормальных IDE по синтаксическим подсказкам, но есть довольно много своеобразных людей которые сидят на ардуино иде и уходить с неё никуда не собираются (как автор этого проекта). Впрочем это замечание к функционалу либы не относится.

чтобы изменить переменную - все равно придется стереть всю страницу целиком - никакого выигрыша...
именно! Точно так же как и в вашем случае - при изменении одного члена структуры нужно будет перезаписать её всю целиком! Псевдоеепром будет запись раскидывать по размеру nvs раздела, вы будете раскидывать в пределах одного(двух) секторов. Под есп32 размер записываемых данных примерно одного порядка в обоих случаях. Под 8266 я не помню точно как там эмулируется еепром, может подскажете если изучали этот вопрос. Вероятно там переписывается один и тот же сектор, но это частный случай конкретной платформы (уже сильно утратившей актуальность).
Т.е. из реального выиграша - выравнивание записи на одной конкретной платформе. Перейдём к "минусам".

Если автор проекта из местных. Можно связаться - я могу помочь интегрировать EEBoom.
Из местных, @vvip он на форуме. Но не думаю что это будет интресно в виду следущих минусов:

  • наверняка ему оч не понравится терять существующие данные каждый раз как он добавит в проекте новую переменную в структуру. Писать каку-то новую схему сериализации и резервирования/восстановления данных куда-то еще на этот случай это отдельная и приличная задача
  • есть риск повреждения данных на литтлфс содержимым еепром и наоборот. Литтлфс в проекте используется
 
Изменено: