/Table

Dynamic table for Arduino

Primary LanguageC++MIT LicenseMIT

latest PIO Foo Foo Foo

Foo

Table

Динамическая бинарная таблица для Arduino

  • Поддерживает все численные типы данных в любом сочетании
  • Динамическое добавление строк, прокрутка и прочие удобные фичи для ведения логов
  • Автоматическая запись в файл при изменении (esp)
  • Возможность добавления строк без чтения файла
  • Вес в среднем в 2 раза меньше, чем у текстовой CSV

Совместимость

Совместима со всеми Arduino платформами (используются Arduino-функции)

Зависимости

  • GTL
  • StreamIO

Содержание

Документация

cell_t

Тип данных ячейки

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::Float

Table

Table();

// строк, столбцов, типы данных ячеек
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);

TableFile

Наследует 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

Добавление данных в файл таблицы без чтения самой таблицы

// указать файловую систему, путь к файлу
TableFileStatic(fs::FS* nfs, const char* path);

// инициализировать в файле
bool init(uint8_t cols, ...);

// добавить строку к таблице
bool append(...);

Row

строка таблицы

// доступ к ячейке
Cell operator[](uint8_t col);

// записать в строку
template <typename... Args>
void write(Args... args);

Cell

Ячейка таблицы

// тип ячейки
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
  • Корректно ли работают ли встроенные примеры, в которых используются функции и конструкции, приводящие к багу в вашем коде
  • Какой код загружался, какая работа от него ожидалась и как он работает в реальности
  • В идеале приложить минимальный код, в котором наблюдается баг. Не полотно из тысячи строк, а минимальный код