Сохранение и загрузка переменных в SPIFFS
- Войдите на сайт для отправки комментариев
Пнд, 13/05/2019 - 23:07
Подскажите, как правильно сделать. Хочу загружать данные с встроенной памяти (ESP8266) в переменные(статические настройки сети и пр.). Вижу два варианта:
1.json. Пробовала, но там непонятно с типами данных. Во всех примерах можно загрузить только char, в самом коде библиотеки, можно преобзовывать json["val-name"].is<int>(); но на практике это не работает.
2. либо читать построково через саму ФС ESP8266. Но ненашла примера... как именно считать строку... Подскажите, будьте добры!
Скоко данных?
1.json. ... но на практике это не работает.
2. Но не нашла примера... как именно считать строку...
1. Да ну?
2. Объект файл унаследован от Stream, со всеми вытекающими.
https://github.com/gmag11/FSBrowserNG Вот это у меня для теста собраное на столе лежит. Исходник нужно переделать под JSON6. Я сейчас порт к плате пробросил у себя на сервере: mycortez.ru:22280/admin. Утром выключу. Можно насладиться. ;))) Сама плата - то есть объект издевательств - тестовый NodeMCU Amica. с 4 Мегами, два из них отдано FFS.
Сама программа - просто пример от автора кода (поклон ему) по ссылке, только переделанный под новую версию json библиотеки. Так что всё там работает. Просто нужны руки не из жопы.
--------------
ЗЫ: в 10-30 отключил порт
Скоко данных?
Мало. Не более 10-15-ти переменных.
Пишите в эмулируемый EEPROM структурой (struct) и читайте так же.
Пишите в эмулируемый EEPROM структурой (struct) и читайте так же.
Тем более, что в случае с ESP, по сути, это одно и тоже.
Вот и я о том же - чего дуремарствовать с JSON-ами из-за простого конфига.
JSON оно понятно лишнее. Но с SPIFFS есть засада https://habr.com/ru/post/409911/ . Может это и случилось у ТС.
Ребята! Это ESP, а не AVR. Тут памяти бесконечно. Можно нормально пользоваться и Стрингами и реально ОЧЕНЬ профессиональной JSON библиотекой. Кто кодит на С++ не в микроконтроллерах может оценить код JSON 6. Наследование темплейты, автокастинг, умные перегрузки... ну вот сам-бы стал писать - не стал бы так аккуратно делать, потому что лень! ;)))
5-ая версия была классика - отдельно аррей и отдельно объект. В 6-ой они слили в единый интерфейс всё. Просто песня. Очень удобно пользоваться.
Еще раз, для доходчивости - это ESP, тут не надо плясать с бубном и экономить байты и такты. И для кода и для рантайма тут более чем достаточно памяти.
JSON оно понятно лишнее. Но с SPIFFS есть засада https://habr.com/ru/post/409911/ . Может это и случилось у ТС.
Чудо в перьях! Ты дату публикации на хабре смотрел?
Всем спасибо! Нашла вот такую библиотечку https://github.com/bneedhamia/sdconfigfile , может кому понадобится.
JSON оно понятно лишнее. Но с SPIFFS есть засада https://habr.com/ru/post/409911/ . Может это и случилось у ТС.
Чудо в перьях! Ты дату публикации на хабре смотрел?
аяяя.. 2018год! Для тебя, додик в стрингах наверно очень старое. Хотя видно попаболь после последнего общения заставляет искать хоть какой повод чтоб тявкнуть ))) Это пройдет.
бла-бла-бла
Больной? Ты написал векторную "8" на 17 байт, не я. И считаешь себя програмистом? Ну молодец! Мамка похвалит.
Самое смешное, что у тебя хватает тупости хвастать этим, с позволения сказать, кодом.
------------------------
Ну и в том общении я не помню "соревнований", чтобы кто-то победил или проиграл. Ты "наехал" на компилятор - это всегда принак тупости и непрофессионализма. Ровно так Архат уже делал. А я-то причем? Ты пафосно пиздил о "раздолбаях, пишуших компилятор". Вероятно сравнивая их с собой... и 17 байтами на код символа "8".
повод чтоб тявкнуть ))) Это пройдет.
У тебя - пройдет желание влезть с "Очень Ценным Мнением" в тему, в которой ты ничего не понимаешь. Странно, но снова напоминает Архата.
По заметке сразу видно, что ты не пишешь ничего для ESP. Иначе бы знал, что ESP-7 - давно нигде не используется и проблемы у тех украинских ребят были только от жадности - купили самый дешевый модуль, о чем в коментах к той заметке и написано.
А тебе нужно было в лужу пернуть... а то ведь позабудут... апидна, да?
-----------------------
=====================
Я, к сожалению, забыл ветку где ты векторные шрифты изобретаешь. Поэтому тут уж добавлю, тема обсуждения все равно закрыта.
С памятью AVR задача не нужна. Ну такая же глупость, как "интернет радио" и половина мастурбации у нас в "проектах". Ты в своем проекте никогда не будешь использовать все 160 символов. Нарисуй вектора с Move,Line и Quad, для тех символов, которые нужны в проекте.
Если тебе нужна продвинутая графика - то это уже не 128х64 дюймовик. И контроллер тогда с нормальной памятью в котором можно рендерить TTF. И да - наезды на СТМ - это уже клоунада... и да снова копия Архата. ;)
(а может ты это он??? ;)))) )
Ты сам раньше выступал за разумность (помню спор "список vs перебор"), а тут тебя заклинило.
Ребята! Это ESP, а не AVR. Тут памяти бесконечно. Можно нормально пользоваться и Стрингами и реально ОЧЕНЬ профессиональной JSON библиотекой. Кто кодит на С++ не в микроконтроллерах может оценить код JSON 6. Наследование темплейты, автокастинг, умные перегрузки... ну вот сам-бы стал писать - не стал бы так аккуратно делать, потому что лень! ;)))
5-ая версия была классика - отдельно аррей и отдельно объект. В 6-ой они слили в единый интерфейс всё. Просто песня. Очень удобно пользоваться.
Еще раз, для доходчивости - это ESP, тут не надо плясать с бубном и экономить байты и такты. И для кода и для рантайма тут более чем достаточно памяти.
На 5-ой версии пытался разбирать форекасты получаемые от openweathermap, текущая погода не очень интересовала, а прогнозы были интересны.
форекасты на 5 суток с 3-х часовым интервалом, весят под 13К, динамик буфер в примерах в два раза больше длины строки указывали, для чего не ясно.
На модуле свободного хипа оставалось чуть больше 30К, строка с джейсоном в 13К + динамик буфер 26К и памяти не осталось.
Зная структуру данных, резал масив и парсил частями.
Памяти много не бывает :)
Ну-ну... Памяти как оказалось немножко не бесконечно, нехватило чуток, нужно было бесконечно+10К
..
Памяти много не бывает :)
Та понятное дело. Тут любой подпишется под этим, а на хрень от wdrakula не обращай внимания, у него просто старые раны зудят, заживают наверное, вот он и поносит в тему.
Ну-ну... Памяти как оказалось немножко не бесконечно, нехватило чуток, нужно было бесконечно+10К
..
Памяти много не бывает :)
Та понятное дело. Тут любой подпишется под этим, а на хрень от wdrakula не обращай внимания, у него просто старые раны зудят, заживают наверное, вот он и поносит в тему.
Кстати, и о погоде ;) Я когда ковырял модем A6 в режиме TCP (это здесь - http://arduino.ru/forum/apparatnye-voprosy/gsm-modem-a6-v-rezhime-tcp ), то тоже прогноз тянул с прогнозных сайтов, не по их API (мне интересен именно модем, а не API), а как страницу HTTP, то там и сотни КБ получались. а это атмега 328р. Потому память - сразу решил не пытатся сохранять, парсить с лёту. Так что похоже "парсил частями" - наше все, хоть AVR, хоть ESP.
а на хрень от wdrakula не обращай внимания
Ты держи перед глазами: "17 байт на символ 8" и радуйся. Програмист, my ass!
...my ass!
Болит, понимаю, маж его чемто )))) От жеж недоумок!
https://arduinojson.org/
serializeJson(doc, myFile.csv);//Запись
...
deserializeJson(doc, myFile.csv);//Чтение
С этим выяснили.
А как структуру в файл записать?
file.write(myStruct, len);
file.read( myStruct, len);
Так будет работать?
Кастануть её к байтовому массиву?
del
Не вариант. Согласен.
Нагуглил следующее: https://www.jarutex.com/index.php/2022/01/10/9366/
lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, const void *buffer, lfs_size_t size);
Правильно понтмаю что эта функция может записать структуру в фс?
Не могу разобраться как пользоваться.
Еще из идей, пока не знаю как, узнать адресс начала файла и функцией mencpy скопировать структуру.
Подскажите как записать структуру в littleFS?
Несколько часов гуглю безрезультатно(.
Вариант с граблями разыскал.
Суть такая:
1. Имеем структуру.
2. byte tmp;
3. Цикл побайтного копирования и побайтной записи в файл. memcopy(&struct, &tmp,1) и file.print(tmp) или file.write.
4. Файл сохранен.
5. Читаем в обратной последовательности. Сначала в байт, потом memcpy в структуру.
Вместо байта можно создать массив байтов[sizeof(struct)]. Но тут ОЗУ съедим sizeof(struct)
Некрасивый вариант. Хочется без промежуточных переменных записывать в файл. Копаю дальше.
(byte*) myStruct
Спасибо. Получилось. Но осталось несколько вопросов:
while (file.available()) { byte tmp = file.read(); memcpy((byte*)outStruct + file.position()-1, &tmp, sizeof(byte)); }1. Как обойтись без tmp?
2. Какие типы нельзя использовать в структуре при записи в ФС? То что вычитал: нельзя использовать типы данных в виде ссылок, т.е. маcсивы данных и char[].
Собственно результат:
#include <FS.h> #include <LittleFS.h> #define settingsfile "/settings.bin" //путь к файлу для хранения данных typedef struct Data_struct { // Тип структуры которую будем сохранять uint8_t x; uint16_t y; uint32_t z; float a; String str; char dd[10]; } Data_struct; Data_struct WriteStruct = {255, 12, 12345, 3.14, "Hallo world"}; //Создаем и наполняем исходную структуру Data_struct ReadStruct;//Создаем структуру, куда будем записывать данные из файловой системы. Можно писать в исходную. bool WriteLFS(const char * path, Data_struct * inStruct) { File file = LittleFS.open(path, "w"); if (!file) return false; file.write((byte*)inStruct, sizeof(Data_struct) / sizeof(byte)); file.close(); return true; } bool ReadLFS(const char * path, Data_struct * outStruct) { File file = LittleFS.open(path, "r"); if (!file) return 0; while (file.available()) { byte tmp = file.read(); memcpy((byte*)outStruct + file.position()-1, &tmp, sizeof(byte)); } file.close(); return true; } void setup() { Serial.begin(115200); if (!LittleFS.begin()) { Serial.println("LittleFS mount failed. Formating..."); LittleFS.format(); ESP.restart(); } delay(3000); // Задержка на открытие com порта на ПК. if (WriteLFS(settingsfile, &WriteStruct)) { // передаю имя файла и адресс в памяти где хранится исходная структура с данными Serial.println("WriteLFS Ok"); } else { Serial.println("WriteLFS failed"); } if (ReadLFS(settingsfile, &ReadStruct)) { Serial.println("ReadLFS Ok"); } else { Serial.println("ReadLFS failed"); } Serial.printf("Result: %2d, %2d, %2d, %2.2f, %", ReadStruct.x, ReadStruct.y, ReadStruct.z, ReadStruct.a, ReadStruct.str); //Result: 255, 12, 12345, 3.14, Hallo world ESP.deepSleep(0); } void loop() { }2. Какие типы нельзя использовать в структуре при записи в ФС? То что вычитал: нельзя использовать типы данных в виде ссылок, т.е. маcсивы данных и char[].
Чойта? Когда в структуре - там пофиг какие данные и какие типы (на сколько я знаю). Все равно по-байтово читается/пишется.
BOOM, Протестировал. Все работает включая массивы. Опробовано на ESP8266.
Код сохраняет структуру с разными типами данных в файловую систему микроконтроллера и потом считывает эти данные в другую структуру:
#include <FS.h> #include <LittleFS.h> #define settingsfile "/settings.bin" //путь к файлу для хранения данных typedef struct Data_struct { // Тип структуры которую будем сохранять uint8_t x; uint16_t y; uint32_t z; float a; uint8_t intArr[10]; char charArr[8]; String str; } Data_struct; Data_struct WriteStruct = {255, 12, 12345, 3.14, {1,2,3,4,5,6,7,8,9,10}, "charArr", "String"}; //Создаем и наполняем исходную структуру Data_struct ReadStruct;//Создаем структуру, куда будем записывать данные из файловой системы. Можно писать в исходную. bool WriteLFS(const char * path, Data_struct * inStruct) { File file = LittleFS.open(path, "w"); if (!file) return false; file.write((byte*)inStruct, sizeof(Data_struct) / sizeof(byte)); file.close(); return true; } bool ReadLFS(const char * path, Data_struct * outStruct) { File file = LittleFS.open(path, "r"); if (!file) return false; file.read((byte*)outStruct, file.size()); file.close(); return true; } void setup() { Serial.begin(115200); if (!LittleFS.begin()) { Serial.println("LittleFS mount failed. Formating..."); LittleFS.format(); ESP.restart(); } delay(3000); // Задержка на открытие com порта на ПК. if (WriteLFS(settingsfile, &WriteStruct)) { // передаю имя файла и адресс в памяти где хранится исходная структура с данными Serial.println("WriteLFS Ok"); } else { Serial.println("WriteLFS failed"); } if (ReadLFS(settingsfile, &ReadStruct)) { Serial.println("ReadLFS Ok"); } else { Serial.println("ReadLFS failed"); } Serial.printf("Result: %2d, %2d, %2d, %2.2f, %2d, %2s, %2s", ReadStruct.x, ReadStruct.y, ReadStruct.z, ReadStruct.a, ReadStruct.intArr[0], ReadStruct.charArr, ReadStruct.str); //Result: 255, 12, 12345, 3.14, 1, charArr, String ESP.deepSleep(0); } void loop() {}p-a-h-a, писать отдельную функцию для записи и чтения конкретной структуры - это глупость. Правильнее создать функцию записи байтового массива, принимающего ссылку на массив и размер.
Эта функция сможет писать и читать из файла абсолютно любой тип данных, так как любой тип в МК - одинарная переменная, массив, структура, класс - может быть представлена как байтовый массив.
всего-то надо поменять пару символов в твоей функции:
bool WriteLFS(const char * path, byte* buf, uint16_t len) { File file = LittleFS.open(path, "w"); if (!file) return false; file.write(buf, len); file.close(); return true; }писать отдельную функцию для записи и чтения конкретной структуры - это глупость.
Нужно делать как удобнее в конкретном случае. И незачем усложнять на ровном месте.
Никакого усложнения нет в этом случае. Вызов функции рихтуем примерно под такую конфигурацию: WriteLFS(..., (byte*) &myStruct, sizeof(myStruct)) и всё.
Переписал функции чтения/записи во флеш разных типов данных.
template<class T1, class T2> bool WriteLFS(const char * path, T1* const &DATA, T2 const &lenght) {//Запись в файл File file = LittleFS.open(path, "w"); if (!file or lenght < 1) { file.close(); return false; } file.write((uint8_t*)DATA, sizeof(T1) * lenght); file.close(); return true; } template<class T1, class T2> bool ReadLFS(const char * path, T1* &DATA, T2 &lenght) {//Чтение из файла с заполнением DATA и lenght File file = LittleFS.open(path, "r"); if (!file or !file.size() or (file.size() % sizeof(T1))) { file.close(); return false; } lenght = file.size() / sizeof(T1); delete[] DATA; DATA = new T1[lenght];//Создаем массив необходимого размера file.read((uint8_t*)DATA, file.size()); file.close(); return true; }Сохранение одной переменной:
Сохранение динамического массива из 10 ячеек:
Сохранение динамического массива структур:
typedef struct data { //Тип структуры пользовательский uint32_t var1 = NULL; uint16_t var2 = NULL; } data; int lenght = 10; data *a = new data[lenght]; a[1].var1 = 5; WriteLFS(settingsfile, a, lenght);//Сохраняем массив В ФС data *b; ReadLFS(settingsfile, b, lenght);// Тут входящий массив удаляется и создается по новой из ФС, меняется lenght Serial.println(b[1].var1);//5 }Сохранение структуры (также можно объект класса сохранить)
typedef struct data { //Тип структуры пользовательский uint32_t var1 = NULL; uint16_t var2 = NULL; } data; data *myStruct = new data; (*myStruct).var1=5; int lenght = sizeof(data); WriteLFS(settingsfile, myStruct, lenght);//Сохраняем В ФС data *newStruct; ReadLFS(settingsfile, newStruct, lenght); Serial.println((*newStruct).var1);//5 }И само собой необходимые заголовки
#include <FS.h> #include <LittleFS.h> const char* settingsfile PROGMEM = "/settings.bin"; void setup() { Serial.begin(115200); LittleFS.begin(); }10data *b;11ReadLFS(settingsfile, b, lenght);// Тут входящий массив удаляется и создается по новой из ФС, меняется lenghtты уверен? Памойму, ты просто срёшь за указатель sizeof(int)*(lenght-1) байт. С виду то оно всё целое, но дьявол кроеца в деталях
Где ошибка? Какие пути исправления и избавления от говнокода? Разбираюсь потихоньку. Задача построить всеядные функции для сохранения и чтения любых объектов/переменных в ФС, желательно без перегрузок. len использую для динамических массивов, размер которых просто так не узнать. При этом не понимаю откуда оператор delete [] знает сколько ячеек памяти удалять.
Где ошибка?
не стоит пересоздавать динамическую переменную в процедуре чтения, это чревато ошибками. Общепринятая практика - память должна быть выделена заранее.
Вот это вот все лишнее
Кроме того, подумайте над тем, что будет, если len =1. Вообще-то T1 и T1[1] - это разные типы переменных.
ЗЫ а еще интересно - вы постоянно хаете здешний форум и тут и на гайвере... но продолжаете сюда ходить. Это как у вас в мозгу - сочетаетеся?
b707, благодарю за дельные советы. С выделением памяти заранее можно добавить отдельную функцию, возвращающую file.size() и создавать массив в общем коде исходя из размера. Размер может меняться в ходе работы, например хранится информация для каждого пользователя с возможностью добавления пользователей.
Еслиlen == 1 создаcться массив на одну ячейку int *a=new int[1]; что равнозначно int *a=new int; В обоих случаях a[0] = 5; будет работать.С T и T[1] внимательно разобрался (дальше в коде понятно станет). Хорошо что обратили внимание. Понял некоторые вещи. Правильно у меня в коде было т.к. sizeof(int[0]) == NULL:
{ uint8_t *a = new uint8_t[5]; Serial.println(sizeof(a));// == 4; Serial.println(sizeof(a[0]));// ==1; foo(a); foo2(a); } template<class T> void foo(T* &a){ // разименованная ссылка на указатель. как раз первый элемент массива с типом uint8_t Serial.println(sizeof(T)); // ==1 //sizeof(uint8_t) Serial.println(sizeof(T[0])); // ==0 //sizeof(uint8_t[0]) Serial.println(sizeof(a[0])); // ==1 Serial.println(sizeof(a)); // ==4 } template<class T> void foo2(T &a){ // ссылка на указатель uint32_t хранящая адрес памяти первой ячейки дин. массива Serial.println(sizeof(T)); // ==4 Serial.println(sizeof(T[0])); // ==0 Serial.println(sizeof(a[0])); // ==1 Serial.println(sizeof(a)); // ==4 }PS Я не форум хаю, а отношение конкретных людей. По началу было непривычно что мешают с калом начинания и непонимание простых вещей. Сейчас просто пропускаю брань мимо себя. Давно это было.
PS Я не форум хаю, а отношение конкретных людей. По началу было непривычно что мешают с калом начинания и непонимание простых вещей. Сейчас просто пропускаю брань мимо себя. Давно это было.
я обратил внимание, что, несмотря на "поливание грязью" здесь и отсутсвие этого "там" - вы, однако, даже не пытаетесь задавать вопросы по программированию на гайвере, а ходите сюда. С чего бы это?
Советую задуматься об этом феномене.