Unverified Commit f764af0d authored by Dirk O. Kaar's avatar Dirk O. Kaar Committed by GitHub

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: default avatarLucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
parent ead76fd3
/*
* 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() {
}
/*
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() {
}
/*
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() {
}
......@@ -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
......@@ -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<void*>(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<Ticker*>(arg);
if (_this && _this->_callback_function)
_this->_callback_function();
}
......@@ -28,79 +28,110 @@
extern "C" {
#include "esp_timer.h"
}
#include <functional>
class Ticker
{
public:
Ticker();
~Ticker();
typedef void (*callback_t)(void);
typedef void (*callback_with_arg_t)(void*);
typedef std::function<void(void)> 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_with_arg_t>(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_with_arg_t>(callback), 0);
_callback_function = std::move(callback);
_attach_us(micros, true, _static_callback, this);
}
template<typename TArg>
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_with_arg_t>(callback), arg32);
_attach_us(1000000ULL * seconds, true, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
}
template<typename TArg>
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_with_arg_t>(callback), reinterpret_cast<void*>(arg));
}
template<typename TArg>
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_with_arg_t>(callback), arg32);
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(float seconds, callback_t callback)
void once(float seconds, callback_function_t callback)
{
_attach_ms(seconds * 1000, 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(uint32_t milliseconds, callback_t callback)
void once_ms(uint64_t milliseconds, callback_function_t callback)
{
_attach_ms(milliseconds, false, reinterpret_cast<callback_with_arg_t>(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<typename TArg>
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_with_arg_t>(callback), arg32);
static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)");
_attach_us(1000000ULL * seconds, false, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
}
template<typename TArg>
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_with_arg_t>(callback), reinterpret_cast<void*>(arg));
}
template<typename TArg>
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_with_arg_t>(callback), arg32);
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();
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);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment