Возможности:
- удобная работа с временными интервалами и таймерами
- расширяемость с помощью событий
- все(
Warning библиотека расчитана на однопоточное выполнение и не безопасна при многопоточном использовании
class:
- EventLoop - объект цикла событий
- Event - объект родитель для всех евентов
- Interval - выполняет callback с заданным интервалом
- Timer - по истечении времени выполнит один раз свой callback
Пример с интервалами
#include <event_loop.h>
#include <interval.h>
// функция тикер, для проверки временных промежутков Интервала и Таймера
uint32_t tiker() {
return millis();
}
EventLoop event_loop;
void setup() {
Serial.begin(115200);
// создаем события интервала
int counter = 0;
event_t new_event1((Event*) new Interval([&event_loop, &counter](){
Serial.println("interval 1");
counter++;
if (counter >= 2) {
event_loop.stop(); // останавливаем цикл событий
}
}, 3000, tiker)); // 3 секунды
event_t new_event2 ((Event*) new Interval([](){
Serial.println("interval 2");
}, 1000, tiker)); // 1 секунда
event_t new_event3 ((Event*) new Interval([](){
Serial.println("interval 3");
}, 2000, tiker)); // 2 секунды
// добавляем события
event_loop.addEvent(new_event1);
event_loop.addEvent(new_event2);
event_loop.addEvent(new_event3);
event_loop.exec(); // запускаем цикл событий
}
void loop() { }
Вывод:
(порядок может немного отличаться в зависимости от реализации пула евентов)
interval 2
interval 3
interval 2
interval 1
interval 2
interval 3
interval 2
interval 2
interval 3
interval 1
Пример с использованием таймера и интервала
#include <event_loop.h>
#include <interval.h>
#include <timer.h>
// функция тикер, для проверки временных промежутков Интервала и Таймера
uint32_t tiker() {
return millis();
}
EventLoop event_loop;
void setup() {
Serial.begin(115200);
// создаем события интервала
int counter = 0;
// добавляем события
event_loop.addEvent(makeInterval([&event_loop, &counter](){
Serial.print("interval "),
Serial.println(counter);
event_loop.addEvent(makeTimer([counter, &event_loop](){
Serial.print("timeout after interval with counter - ");
Serial.println(counter);
if (counter >= 5) event_loop.stop();
}, 1500, tiker)); // 1,5 секунды
counter++;
}, 3000, tiker) ); // интервал в 3 секунды
event_loop.exec(); // запускаем цикл событий
Serial.println("i am after event loop");
}
void loop() { }
Вывод
16:48:48.121 -> interval 0
16:48:49.631 -> timeout after interval with counter - 0
16:48:51.118 -> interval 1
16:48:52.618 -> timeout after interval with counter - 1
16:48:54.130 -> interval 2
16:48:55.604 -> timeout after interval with counter - 2
16:48:57.121 -> interval 3
16:48:58.605 -> timeout after interval with counter - 3
16:49:00.122 -> interval 4
16:49:01.624 -> timeout after interval with counter - 4
16:49:03.119 -> interval 5
16:49:04.618 -> timeout after interval with counter - 5
16:49:04.618 -> i am after event loop
EventLoop можно останавливать вызвав метод stop()
, готовые события далее не будут обрабатываться
метод exec()
начинает обрабатывать события
event_id_t addEvent(event_t event)
- добавляет событие и возвращает его айди
void removeEvent(event_id_t id)
- удаляет событие при его наличии
Все параметры задаются при создании
Параметры:
(callback_t callback, uint32_t interval, tiker_t time_cheker)
callback_t
- функция, функтор и лямбда не принимающая и не возвращающая значений
void function_name(void) {
...
}
tiker_t
- функция, функтор и лямбда не принимающая значений и возвращающая uint32_t
EventLoop event_loop;
void setInterval(callback_t callback, uint32_t time) {
event_loop.addEvent(makeInterval(callback, time, millis));
}
void setTimeout(callback_t callback, uint32_t time) {
event_loop.addEvent(makeTimer(callback, time, millis));
}
???
Profit!!!
используется также как и в js
void setup() {
Serial.begin(115200);
// добавляем события
setInterval([](){
static int counter = 0;
Serial.print("interval "),
Serial.println(counter);
setTimeout([counter](){
Serial.print("timeout after interval with counter - ");
Serial.println(counter);
if (counter >= 5) event_loop.stop();
}, 1500); // 1,5 секунды
counter++;
}, 3000); // интервал в 3 секунды
event_loop.exec(); // запускаем цикл событий
}
void loop() { }
class Event {
public:
virtual void run() = 0;
virtual bool isReady() = 0;
virtual void startTracking() = 0;
virtual void stopTracking() = 0;
virtual bool needRemove() = 0;
virtual ~Event() {}
};
Цикл событий поддерживает любые события отнаследованные от класса Event
. Это позволяет писать свои события а также делать из них функторы, циклы событий и так далее, ограничитель - ваше воображение и возможности вашей платформы
Ньюансы:
Как видно ниже нужно учитывать что перед срабатыванием метода run() вызвается stopTraking(), после чего проверяется необходимость удаления, и заново стратует отслеживание.
void exec() {
runing = true;
while (runing) {
if (events.hasReadyEvent()) {
auto event_pair = events.getReadyEvent();
auto event = event_pair.second;
event->stopTracking();
event->run();
if (event->needRemove()) {
events.removeEvent(event_pair.first);
} else {
event->startTracking();
}
}
}
}
Если пытаться быть корректным, то у esp есть процессы выполняющие работу в перерыве между вызовом функции loop
, во время вызова delay
или yield
, тк цикл событий блокирует вызовы функции loop
то esp думает что мы зависли из-за чего происходит перезагрузка и вывод ошибки.
Решение:
проблема при использовании esp, решается добавлением интервала:
void setup() {
...
event_loop.addEvent(makeInterval(yield, 200, millis));
...
event_loop.exec();
}
либо можно использовать неблокирующий цикл, но тогда некоторые методы могут работать не так как задумывалось и я не поощряю данный способ.
void setup() {
...
}
void loop() {
event_loop.runNext();
}