Ticker updated to match extensions in ESP8266 API (#2849)

* Update Ticker API to compatibility with ESP8266, prepares for co-op loop Scheduler

* Fixing Build server complaints

* Fix omitted casts in template member function

* Changes after review

* Expose µs resolution of OS API in Ticker class

* Return Ticker to libraries only for modularity.

* Unify Ticker examples.

* Default for LED_BUILTIN

* In Ticker, the *scheduled functions become available in another development branch.

* Astyle from ESP8266

* Fixed Arduino keywords.txt

* 64bit integers instead of 32bits, timer functions on ESP32 accept 64bit integers.

* Move code from header into compiliation unit.

Reformat.

* Test case same as ESP8266

* Implementing inline in header saves 204+ bytes program size.

* Examples

* Fix a compiler warning due to c-style casting.

* Revert formatting changes

* More format reversions

* Revert

* Revert

* Revert

---------

Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
This commit is contained in:
Dirk O. Kaar 2024-01-31 11:53:56 +01:00 committed by GitHub
parent ead76fd395
commit f764af0d1c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 178 additions and 82 deletions

View file

@ -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 <Arduino.h>
#include <Ticker.h>
// 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() {
}

View file

@ -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 <Ticker.h>
#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() {
}

View file

@ -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 <Ticker.h>
#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() {
}

View file

@ -10,5 +10,9 @@ Ticker KEYWORD1
attach KEYWORD2 attach KEYWORD2
attach_ms KEYWORD2 attach_ms KEYWORD2
attach_us KEYWORD2
once KEYWORD2 once KEYWORD2
once_ms KEYWORD2
once_us KEYWORD2
detach KEYWORD2 detach KEYWORD2
active KEYWORD2

View file

@ -31,7 +31,7 @@ Ticker::~Ticker() {
detach(); 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; esp_timer_create_args_t _timerConfig;
_timerConfig.arg = reinterpret_cast<void*>(arg); _timerConfig.arg = reinterpret_cast<void*>(arg);
_timerConfig.callback = callback; _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); esp_timer_create(&_timerConfig, &_timer);
if (repeat) { if (repeat) {
esp_timer_start_periodic(_timer, milliseconds * 1000ULL); esp_timer_start_periodic(_timer, micros);
} else { } 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_stop(_timer);
esp_timer_delete(_timer); esp_timer_delete(_timer);
_timer = nullptr; _timer = nullptr;
_callback_function = nullptr;
} }
} }
bool Ticker::active() { bool Ticker::active() const {
if (!_timer) return false; if (!_timer) return false;
return esp_timer_is_active(_timer); return esp_timer_is_active(_timer);
} }
void Ticker::_static_callback(void* arg)
{
Ticker* _this = reinterpret_cast<Ticker*>(arg);
if (_this && _this->_callback_function)
_this->_callback_function();
}

View file

@ -28,79 +28,110 @@
extern "C" { extern "C" {
#include "esp_timer.h" #include "esp_timer.h"
} }
#include <functional>
class Ticker class Ticker
{ {
public: public:
Ticker(); Ticker();
~Ticker(); ~Ticker();
typedef void (*callback_t)(void);
typedef void (*callback_with_arg_t)(void*);
void attach(float seconds, callback_t callback) typedef void (*callback_with_arg_t)(void*);
typedef std::function<void(void)> callback_function_t;
void attach(float seconds, callback_function_t callback)
{ {
_attach_ms(seconds * 1000, true, reinterpret_cast<callback_with_arg_t>(callback), 0); _callback_function = std::move(callback);
_attach_us(1000000ULL * seconds, true, _static_callback, this);
} }
void attach_ms(uint32_t milliseconds, callback_t callback) void attach_ms(uint64_t milliseconds, callback_function_t callback)
{ {
_attach_ms(milliseconds, true, reinterpret_cast<callback_with_arg_t>(callback), 0); _callback_function = std::move(callback);
_attach_us(1000ULL * milliseconds, true, _static_callback, this);
}
void attach_us(uint64_t micros, callback_function_t callback)
{
_callback_function = std::move(callback);
_attach_us(micros, true, _static_callback, this);
} }
template<typename TArg> template<typename TArg>
void attach(float seconds, void (*callback)(TArg), TArg arg) 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: // C-cast serves two purposes:
// static_cast for smaller integer types, // static_cast for smaller integer types,
// reinterpret_cast + const_cast for pointer types // reinterpret_cast + const_cast for pointer types
uint32_t arg32 = (uint32_t)arg; _attach_us(1000000ULL * seconds, true, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
_attach_ms(seconds * 1000, true, reinterpret_cast<callback_with_arg_t>(callback), arg32);
} }
template<typename TArg> template<typename TArg>
void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) void attach_ms(uint64_t milliseconds, void (*callback)(TArg), TArg arg)
{ {
static_assert(sizeof(TArg) <= sizeof(uint32_t), "attach_ms() callback argument size must be <= 4 bytes"); static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)");
uint32_t arg32 = (uint32_t)arg; _attach_us(1000ULL * milliseconds, true, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
_attach_ms(milliseconds, true, reinterpret_cast<callback_with_arg_t>(callback), arg32);
} }
void once(float seconds, callback_t callback) template<typename TArg>
void attach_us(uint64_t micros, void (*callback)(TArg), TArg arg)
{ {
_attach_ms(seconds * 1000, false, reinterpret_cast<callback_with_arg_t>(callback), 0); static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)");
_attach_us(micros, true, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
} }
void once_ms(uint32_t milliseconds, callback_t callback) void once(float seconds, callback_function_t callback)
{ {
_attach_ms(milliseconds, false, reinterpret_cast<callback_with_arg_t>(callback), 0); _callback_function = std::move(callback);
_attach_us(1000000ULL * seconds, false, _static_callback, this);
}
void once_ms(uint64_t milliseconds, callback_function_t callback)
{
_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<typename TArg> template<typename TArg>
void once(float seconds, void (*callback)(TArg), TArg arg) void once(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*)");
uint32_t arg32 = (uint32_t)(arg); _attach_us(1000000ULL * seconds, false, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
_attach_ms(seconds * 1000, false, reinterpret_cast<callback_with_arg_t>(callback), arg32);
} }
template<typename TArg> template<typename TArg>
void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg) void once_ms(uint64_t milliseconds, void (*callback)(TArg), TArg arg)
{ {
static_assert(sizeof(TArg) <= sizeof(uint32_t), "attach_ms() callback argument size must be <= 4 bytes"); static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)");
uint32_t arg32 = (uint32_t)(arg); _attach_us(1000ULL * milliseconds, false, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
_attach_ms(milliseconds, false, reinterpret_cast<callback_with_arg_t>(callback), arg32); }
template<typename TArg>
void once_us(uint64_t micros, void (*callback)(TArg), TArg arg)
{
static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)");
_attach_us(micros, false, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
} }
void detach(); void detach();
bool active(); bool active() const;
protected: 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; esp_timer_handle_t _timer;
private:
void _attach_us(uint64_t micros, bool repeat, callback_with_arg_t callback, void* arg);
}; };