Динамическая бинарная таблица для Arduino
- Поддерживает все численные типы данных в любом сочетании
- Динамическое добавление строк, прокрутка и прочие удобные фичи для ведения логов
- Автоматическая запись в файл при изменении (esp)
- Возможность добавления строк без чтения файла
- Вес в среднем в 2 раза меньше, чем у текстовой CSV
Совместима со всеми Arduino платформами (используются Arduino-функции)
- GTL
- StreamIO
Тип данных ячейки
cell_t::None
cell_t::Int8
cell_t::Uint8
cell_t::Int16
cell_t::Uint16
cell_t::Int32
cell_t::Uint32
cell_t::Int64
cell_t::Uint64
cell_t::FloatTable();
// строк, столбцов, типы данных ячеек
Table(uint16_t rows, uint8_t cols, ...);
// создать таблицу (строк, столбцов, типы данных ячеек)
bool create(uint16_t rows, uint8_t cols, ...);
// инициализировать количество и типы столбцов (не изменит таблицу если совпадает)
bool init(uint8_t cols, ...);
// получить строку таблицы. Отрицательные числа - получить с конца
tbl::Row operator[](int row);
// получить строку таблицы. Отрицательные числа - получить с конца
tbl::Row get(int row);
// получить ячейку
tbl::Cell get(int row, uint8_t col);
// вывести таблицу в print
void dump(Print& p);
// вывести как CSV
String toCSV(char separator = ';', uint8_t dec = 2);
// количество строк
uint16_t rows();
// количество столбцов
uint8_t cols();
// очистить ячейки (установить 0)
void clear();
// хоть одна из ячеек была изменена. Автосброс
bool changed();
// изменить количество строк
bool resize(uint16_t rows);
// зарезервировать количество строк
bool reserve(uint16_t rows);
// добавить пустую строку в конец
bool add();
// добавить строку со значениями в конец
bool append(...);
// установить лимит кол-ва строк для add/append, будет прокручивать при превышении. 0 - отключить
void setLimit(uint16_t limit);
// сместить таблицу вверх и записать значения в конец
void shift(...);
// удалить строку. Отрицательные - с конца
bool remove(int row);
// удалить все строки
void removeAll();
// дублировать последнюю строку и добавить в конец
bool dupLast();
// прокрутить строки вверх на 1 строку
void scrollUp();
// прокрутить строки вниз на 1 строку
void scrollDown();
// полностью освободить память
void reset();
// экспортный размер таблицы (для writeTo)
size_t writeSize();
// экспортировать таблицу в size_t write(uint8_t*, size_t)
template <typename T>
bool writeTo(T& writer);
// экспортировать таблицу в write(uint8_t, size_t)
bool writeTo(T& stream);
// экспортировать таблицу в буфер размера writeSize()
bool writeTo(uint8_t* buffer);
// импортировать таблицу из Stream (напр. файл)
bool readFrom(Stream& stream, size_t len);
// импортировать таблицу из буфера
bool readFrom(const uint8_t* buffer, size_t len);
// тип ячейки
cell_t type(uint16_t row, uint8_t col);Наследует Table. Автоматическая запись в файл при изменении по таймауту
// указать файловую систему, путь к файлу и таймаут в мс
TableFile(fs::FS* nfs = nullptr, const char* path = nullptr, uint32_t tout = 10000);
// установить файловую систему и имя файла
void setFS(fs::FS* nfs, const char* path);
// установить таймаут записи, мс (умолч. 10000)
void setTimeout(uint32_t tout = 10000);
// прочитать данные
bool begin();
// обновить данные в файле
bool update();
// тикер, вызывать в loop. Сам обновит данные при изменении и выходе таймаута, вернёт true
bool tick();Добавление данных в файл таблицы без чтения самой таблицы
// указать файловую систему, путь к файлу
TableFileStatic(fs::FS* nfs, const char* path);
// инициализировать в файле
bool init(uint8_t cols, ...);
// добавить строку к таблице
bool append(...);строка таблицы
// доступ к ячейке
Cell operator[](uint8_t col);
// записать в строку
template <typename... Args>
void write(Args... args);Ячейка таблицы
// тип ячейки
cell_t type();
// напечатать в print
size_t printTo(Print& p);
// присвоить любой тип
template <typename T>
T operator=(T val);
// в int32
int32_t toInt();
// в float
float toFloat();
// а также операторы сравнения и измененияБазовый пример
// 4 строки, 3 столбца
Table table(4, 3, cell_t::Int8, cell_t::Uint8, cell_t::Float);
// запись в первую строку [строка][столбец]
table[0][0] = -123;
table[0][1] = 123;
table[0][2] = 123.456;
// запись в последнюю строку в ячейку 0 (отрицательные строки - с конца таблицы)
table[-1][0] = -123;
// запись всей строки сразу (функция принимает любое кол-во аргументов)
table[1].write(-123, 123, -123.456);
// вывод таблицы
table.dump(Serial);
// вывод ячеек
Serial.println(table[0][0]); // печатается
int8_t v = table[0][1]; // авто конвертация
table[0][2].toFloat(); // ручная конвертация
(int32_t)table[0][2]; // ручная конвертация
// изменение ячеек
// любые операции сравнения и операторы
table[0][0] == 3;
table[0][0] > 3;
table[0][0] *= 3;
table[0][0]++;Динамическая таблица
// таблица 3 столбца без ячеек
Table table;
table.init(3, cell_t::Int8, cell_t::Uint8, cell_t::Float);
// добавляем строки с данными
table.append(1, 2, 3);
table.append(4, 5, 6);
table.dump(Serial);Пример ведения ограниченного лога: запись всегда в последнюю строку с динамическим увеличением таблицы до 5, затем перемотка таблицы при каждой новой записи:
// изначально 0 строк
Table t(0, 2, cell_t::Int8, cell_t::Float);
// лимит строк 5
t.setLimit(5);
for (int i = 0; i < 10; i++) t.append(i, i / 10.0);
t.dump(Serial);Добавление новой строки как копии последней строки и её изменение
Table t(0, 2, cell_t::Int8, cell_t::Float);
t.append(1, 3.14);
for (int i = 0; i < 5; i++) {
t.dupLast();
t[-1][0] += 5;
}
t.dump(Serial);Пример с TableFile
#include <LittleFS.h>
#include <TableFile.h>
TableFile t(&LittleFS, "table.tbl");
void setup() {
LittleFS.begin();
// прочитать таблицу в оперативку
t.begin();
// инициализация кол-ва столбцов и типов, если таблица ещё не существует
t.init(3, cell_t::Uint32, cell_t::Int16, cell_t::Float);
// добавить строку
t.append(1, 2, 3.14);
}
void loop() {
// вызывать тикер в лупе, таблица сама запишется в файл при изменениях
t.tick();
}Пример с добавления строк в файл без чтения таблицы
#include <LittleFS.h>
#include <TableFileStatic.h>
void setup() {
Serial.begin(115200);
#ifdef ESP32
LittleFS.begin(true);
#else
LittleFS.begin();
#endif
TableFileStatic table(&LittleFS, "/table2.tbl");
// begin не вызываем
// инициализация кол-ва столбцов и типов, если файл ещё не существует
table.init(3, cell_t::Uint32, cell_t::Int16, cell_t::Float);
// добавить данные напрямую в файл
table.append(1, 2, 3);
// таким образом можно вести лог прямо в файле, не ограничиваясь объёмом оперативной памяти
// чтение и вывод
//table.begin();
//table.dump(Serial);
}
void loop() {
}- v1.0
- v1.1.0
- Библиотеку можно найти по названию Table и установить через менеджер библиотек в:
- Arduino IDE
- Arduino IDE v2
- PlatformIO
- Скачать библиотеку .zip архивом для ручной установки:
- Распаковать и положить в C:\Program Files (x86)\Arduino\libraries (Windows x64)
- Распаковать и положить в C:\Program Files\Arduino\libraries (Windows x32)
- Распаковать и положить в Документы/Arduino/libraries/
- (Arduino IDE) автоматическая установка из .zip: Скетч/Подключить библиотеку/Добавить .ZIP библиотеку… и указать скачанный архив
- Читай более подробную инструкцию по установке библиотек здесь
- Рекомендую всегда обновлять библиотеку: в новых версиях исправляются ошибки и баги, а также проводится оптимизация и добавляются новые фичи
- Через менеджер библиотек IDE: найти библиотеку как при установке и нажать "Обновить"
- Вручную: удалить папку со старой версией, а затем положить на её место новую. "Замену" делать нельзя: иногда в новых версиях удаляются файлы, которые останутся при замене и могут привести к ошибкам!
При нахождении багов создавайте Issue, а лучше сразу пишите на почту alex@alexgyver.ru
Библиотека открыта для доработки и ваших Pull Request'ов!
При сообщении о багах или некорректной работе библиотеки нужно обязательно указывать:
- Версия библиотеки
- Какой используется МК
- Версия SDK (для ESP)
- Версия Arduino IDE
- Корректно ли работают ли встроенные примеры, в которых используются функции и конструкции, приводящие к багу в вашем коде
- Какой код загружался, какая работа от него ожидалась и как он работает в реальности
- В идеале приложить минимальный код, в котором наблюдается баг. Не полотно из тысячи строк, а минимальный код