diff --git a/libraries/Ticker/examples/Arguments/Arguments.ino b/libraries/Ticker/examples/Arguments/Arguments.ino deleted file mode 100644 index 7f5bc5cde21..00000000000 --- a/libraries/Ticker/examples/Arguments/Arguments.ino +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This example demonstrates used of Ticker with arguments. - * You can call the same callback function with different argument on different times. - * Based on the argument the callback can perform different tasks. - */ - -#include -#include - -// Arguments for the function must remain valid (not run out of scope) otherwise the function would read garbage data. -int LED_PIN_1 = 4; -#ifdef LED_BUILTIN - int LED_PIN_2 = LED_BUILTIN; -#else - int LED_PIN_2 = 8; -#endif - -Ticker tickerSetHigh; -Ticker tickerSetLow; - -// Argument to callback must always be passed a reference -void swapState(int *pin) { - static int led_1_state = 1; - static int led_2_state = 1; - if(*pin == LED_PIN_1){ - Serial.printf("[%lu ms] set pin %d to state: %d\n", millis(), *pin, led_1_state); - digitalWrite(*pin, led_1_state); - led_1_state = led_1_state ? 0 : 1; // reverse for next pass - }else if(*pin == LED_PIN_2){ - Serial.printf("[%lu ms] set pin %d to state: %d\n", millis(), *pin, led_2_state); - digitalWrite(*pin, led_2_state); - led_2_state = led_2_state ? 0 : 1; // reverse for next pass - } -} - -void setup() { - Serial.begin(115200); - pinMode(LED_PIN_1, OUTPUT); - pinMode(LED_PIN_2, OUTPUT); - //digitalWrite(1, LOW); - - // Blink LED every 500 ms on LED_PIN_1 - tickerSetLow.attach_ms(500, swapState, &LED_PIN_1); - - // Blink LED every 1000 ms on LED_PIN_2 - tickerSetHigh.attach_ms(1000, swapState, &LED_PIN_2); -} - -void loop() { - -} diff --git a/libraries/Ticker/examples/TickerBasic/TickerBasic.ino b/libraries/Ticker/examples/TickerBasic/TickerBasic.ino new file mode 100644 index 00000000000..8de5a1282ad --- /dev/null +++ b/libraries/Ticker/examples/TickerBasic/TickerBasic.ino @@ -0,0 +1,49 @@ +/* + Basic Ticker usage + + Ticker is an object that will call a given function with a certain period. + Each Ticker calls one function. You can have as many Tickers as you like, + memory being the only limitation. + + A function may be attached to a ticker and detached from the ticker. + There are two variants of the attach function: attach and attach_ms. + The first one takes period in seconds, the second one in milliseconds. + + The built-in LED will be blinking. +*/ + +#include + +#ifndef LED_BUILTIN +#define LED_BUILTIN 13 +#endif + +Ticker flipper; + +int count = 0; + +void flip() { + int state = digitalRead(LED_BUILTIN); // get the current state of GPIO1 pin + digitalWrite(LED_BUILTIN, !state); // set pin to the opposite state + + ++count; + // when the counter reaches a certain value, start blinking like crazy + if (count == 20) { + flipper.attach(0.1, flip); + } + // when the counter reaches yet another value, stop blinking + else if (count == 120) { + flipper.detach(); + } +} + +void setup() { + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, LOW); + + // flip the pin every 0.3s + flipper.attach(0.3, flip); +} + +void loop() { +} diff --git a/libraries/Ticker/examples/TickerParameter/TickerParameter.ino b/libraries/Ticker/examples/TickerParameter/TickerParameter.ino new file mode 100644 index 00000000000..ceb79e32f54 --- /dev/null +++ b/libraries/Ticker/examples/TickerParameter/TickerParameter.ino @@ -0,0 +1,54 @@ +/* + Passing paramters to Ticker callbacks + + Apart from void(void) functions, the Ticker library supports + functions taking one argument. This argument's size has to be less or + equal to 4 bytes (so char, short, int, float, void*, char* types will do). + + This sample runs two tickers that both call one callback function, + but with different arguments. + + The built-in LED will be pulsing. +*/ + +#include + +#ifndef LED_BUILTIN +#define LED_BUILTIN 13 +#endif + +Ticker tickerSetLow; +Ticker tickerSetHigh; +Ticker tickerSetChar; + +void setPinLow() { + digitalWrite(LED_BUILTIN, 0); +} + +void setPinHigh() { + digitalWrite(LED_BUILTIN, 1); +} + +void setPin(int state) { + digitalWrite(LED_BUILTIN, state); +} + +void setPinChar(char state) { + digitalWrite(LED_BUILTIN, state); +} + +void setup() { + pinMode(LED_BUILTIN, OUTPUT); + + // every 25 ms, call setPinLow() + tickerSetLow.attach_ms(25, setPinLow); + + // every 26 ms, call setPinHigh() + tickerSetHigh.attach_ms(26, setPinHigh); + + // every 54 ms, call setPinChar(1) + tickerSetChar.attach_ms(26, setPinChar, (char)1); +} + +void loop() { +} diff --git a/libraries/Ticker/keywords.txt b/libraries/Ticker/keywords.txt index 81cce2c8ea5..f5f1266516d 100644 --- a/libraries/Ticker/keywords.txt +++ b/libraries/Ticker/keywords.txt @@ -10,5 +10,9 @@ Ticker KEYWORD1 attach KEYWORD2 attach_ms KEYWORD2 +attach_us KEYWORD2 once KEYWORD2 +once_ms KEYWORD2 +once_us KEYWORD2 detach KEYWORD2 +active KEYWORD2 diff --git a/libraries/Ticker/src/Ticker.cpp b/libraries/Ticker/src/Ticker.cpp index 629361b2dd0..6c996ed56b3 100644 --- a/libraries/Ticker/src/Ticker.cpp +++ b/libraries/Ticker/src/Ticker.cpp @@ -31,7 +31,7 @@ Ticker::~Ticker() { detach(); } -void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback, uint32_t arg) { +void Ticker::_attach_us(uint64_t micros, bool repeat, callback_with_arg_t callback, void* arg) { esp_timer_create_args_t _timerConfig; _timerConfig.arg = reinterpret_cast(arg); _timerConfig.callback = callback; @@ -43,9 +43,9 @@ void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t } esp_timer_create(&_timerConfig, &_timer); if (repeat) { - esp_timer_start_periodic(_timer, milliseconds * 1000ULL); + esp_timer_start_periodic(_timer, micros); } else { - esp_timer_start_once(_timer, milliseconds * 1000ULL); + esp_timer_start_once(_timer, micros); } } @@ -54,10 +54,19 @@ void Ticker::detach() { esp_timer_stop(_timer); esp_timer_delete(_timer); _timer = nullptr; + _callback_function = nullptr; } } -bool Ticker::active() { +bool Ticker::active() const { if (!_timer) return false; return esp_timer_is_active(_timer); } + +void Ticker::_static_callback(void* arg) +{ + Ticker* _this = reinterpret_cast(arg); + if (_this && _this->_callback_function) + _this->_callback_function(); +} + diff --git a/libraries/Ticker/src/Ticker.h b/libraries/Ticker/src/Ticker.h index 82804e0f37d..50ab424c275 100644 --- a/libraries/Ticker/src/Ticker.h +++ b/libraries/Ticker/src/Ticker.h @@ -28,79 +28,110 @@ extern "C" { #include "esp_timer.h" } +#include class Ticker { public: Ticker(); ~Ticker(); - typedef void (*callback_t)(void); + typedef void (*callback_with_arg_t)(void*); + typedef std::function callback_function_t; + + void attach(float seconds, callback_function_t callback) + { + _callback_function = std::move(callback); + _attach_us(1000000ULL * seconds, true, _static_callback, this); + } - void attach(float seconds, callback_t callback) + void attach_ms(uint64_t milliseconds, callback_function_t callback) { - _attach_ms(seconds * 1000, true, reinterpret_cast(callback), 0); + _callback_function = std::move(callback); + _attach_us(1000ULL * milliseconds, true, _static_callback, this); } - void attach_ms(uint32_t milliseconds, callback_t callback) + void attach_us(uint64_t micros, callback_function_t callback) { - _attach_ms(milliseconds, true, reinterpret_cast(callback), 0); + _callback_function = std::move(callback); + _attach_us(micros, true, _static_callback, this); } template void attach(float seconds, void (*callback)(TArg), TArg arg) { - static_assert(sizeof(TArg) <= sizeof(uint32_t), "attach() callback argument size must be <= 4 bytes"); + static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); // C-cast serves two purposes: // static_cast for smaller integer types, // reinterpret_cast + const_cast for pointer types - uint32_t arg32 = (uint32_t)arg; - _attach_ms(seconds * 1000, true, reinterpret_cast(callback), arg32); + _attach_us(1000000ULL * seconds, true, reinterpret_cast(callback), reinterpret_cast(arg)); + } + + template + void attach_ms(uint64_t milliseconds, void (*callback)(TArg), TArg arg) + { + static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); + _attach_us(1000ULL * milliseconds, true, reinterpret_cast(callback), reinterpret_cast(arg)); } template - void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) + void attach_us(uint64_t micros, void (*callback)(TArg), TArg arg) { - static_assert(sizeof(TArg) <= sizeof(uint32_t), "attach_ms() callback argument size must be <= 4 bytes"); - uint32_t arg32 = (uint32_t)arg; - _attach_ms(milliseconds, true, reinterpret_cast(callback), arg32); + static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); + _attach_us(micros, true, reinterpret_cast(callback), reinterpret_cast(arg)); } - void once(float seconds, callback_t callback) + void once(float seconds, callback_function_t callback) { - _attach_ms(seconds * 1000, false, reinterpret_cast(callback), 0); + _callback_function = std::move(callback); + _attach_us(1000000ULL * seconds, false, _static_callback, this); } - void once_ms(uint32_t milliseconds, callback_t callback) + void once_ms(uint64_t milliseconds, callback_function_t callback) { - _attach_ms(milliseconds, false, reinterpret_cast(callback), 0); + _callback_function = std::move(callback); + _attach_us(1000ULL * milliseconds, false, _static_callback, this); + } + + void once_us(uint64_t micros, callback_function_t callback) + { + _callback_function = std::move(callback); + _attach_us(micros, false, _static_callback, this); } template void once(float seconds, void (*callback)(TArg), TArg arg) { - static_assert(sizeof(TArg) <= sizeof(uint32_t), "attach() callback argument size must be <= 4 bytes"); - uint32_t arg32 = (uint32_t)(arg); - _attach_ms(seconds * 1000, false, reinterpret_cast(callback), arg32); + static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); + _attach_us(1000000ULL * seconds, false, reinterpret_cast(callback), reinterpret_cast(arg)); + } + + template + void once_ms(uint64_t milliseconds, void (*callback)(TArg), TArg arg) + { + static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); + _attach_us(1000ULL * milliseconds, false, reinterpret_cast(callback), reinterpret_cast(arg)); } template - void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) + void once_us(uint64_t micros, void (*callback)(TArg), TArg arg) { - static_assert(sizeof(TArg) <= sizeof(uint32_t), "attach_ms() callback argument size must be <= 4 bytes"); - uint32_t arg32 = (uint32_t)(arg); - _attach_ms(milliseconds, false, reinterpret_cast(callback), arg32); + static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)"); + _attach_us(micros, false, reinterpret_cast(callback), reinterpret_cast(arg)); } void detach(); - bool active(); + bool active() const; protected: - void _attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback, uint32_t arg); + static void _static_callback(void* arg); + callback_function_t _callback_function = nullptr; -protected: esp_timer_handle_t _timer; + +private: + void _attach_us(uint64_t micros, bool repeat, callback_with_arg_t callback, void* arg); };