Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ The format follows Keep a Changelog and the project adheres to Semantic Versioni
## [Unreleased]
### Changed
- Removed the library-provided inline `timer` instance. Sketches should now declare their own `ESPTimer` objects (global, static, or as class members) before calling `init()`, enabling multiple independent timer managers.
- Added `clearTimeout(id)` for explicit timeout cancellation and kept `clearTimer(id)` as a backward-compatible alias.
- Standardized teardown around `deinit()` + `isInitialized()` and removed the `clearTimer(id)` alias in favor of `clearTimeout(id)`.
- Added `ESPTimerConfig::usePSRAMBuffers` and routed timer-owned persistent/transient vectors through `ESPBufferManager` with safe fallback to default heap.
- Migrated timer lane task creation/lifecycle back to native FreeRTOS task handling (`xTaskCreatePinnedToCore`/`vTaskDelete`).

### Fixed
- Ensured per-second and per-minute countdown timers emit their final tick by rounding up remaining time.
- Added lifecycle test coverage for pre-init `deinit()`, repeated `deinit()`, and `init -> deinit -> init` reinitialization.

### Documentation
- Added an MIT license badge and cross-links to other ESPToolKit libraries in the README.
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Include the umbrella header, create an `ESPTimer` instance, and call `init` once
#include <ESPTimer.h>

ESPTimer timer;
volatile bool shouldShutdownTimers = false;

void setup() {
Serial.begin(115200);
Expand Down Expand Up @@ -48,9 +49,18 @@ void setup() {

timer.pauseInterval(intervalId);
timer.resumeInterval(intervalId);

timer.setTimeout([](){
shouldShutdownTimers = true;
}, 30000);
}

void loop() {}
void loop() {
if (shouldShutdownTimers && timer.isInitialized()) {
timer.deinit();
shouldShutdownTimers = false;
}
}
```

Explore `examples/Basic/Basic.ino` for a complete sketch that demonstrates all timer types.
Expand All @@ -64,6 +74,8 @@ Explore `examples/Basic/Basic.ino` for a complete sketch that demonstrates all t

## API Reference
- `void init(const ESPTimerConfig& cfg = {})` – allocate mutexes and spawn each timer worker with the provided stack/priority/core settings.
- `void deinit()` – idempotently stop all timer workers, clear active timers/counters, and free runtime resources.
- `bool isInitialized() const` – `true` when timer workers and synchronization primitives are active.
- Scheduling helpers
- `uint32_t setTimeout(std::function<void()> cb, uint32_t delayMs)`
- `uint32_t setInterval(std::function<void()> cb, uint32_t periodMs)`
Expand All @@ -72,7 +84,6 @@ Explore `examples/Basic/Basic.ino` for a complete sketch that demonstrates all t
- `uint32_t setMinCounter(std::function<void(int)> cb, uint32_t totalMs)`
- Control helpers: `pause*`, `resume*`, `toggleRunStatus*`, `clear*`, `ESPTimerStatus getStatus(id)`.
- Timeout-specific clear: `clearTimeout(id)`.
- Backward-compatible alias: `clearTimer(id)` (same behavior as `clearTimeout(id)`).

`ESPTimerConfig` knobs (per task type):
- Stack sizes (`stackSizeTimeout`, `stackSizeInterval`, `stackSizeSec`, `stackSizeMs`, `stackSizeMin`).
Expand Down
12 changes: 12 additions & 0 deletions examples/Basic/Basic.ino
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <ESPTimer.h>

ESPTimer timer; // Create your own instance
volatile bool shouldDeinit = false;

void setup() {
Serial.begin(115200);
Expand Down Expand Up @@ -59,8 +60,19 @@ void setup() {
auto s = timer.getStatus(t1);
Serial.printf("Timeout status: %d\n", static_cast<int>(s));
}, 2000);

// Request teardown from loop context (not from timer worker tasks).
timer.setTimeout([]() {
shouldDeinit = true;
}, 15000);
}

void loop() {
if (shouldDeinit && timer.isInitialized()) {
timer.deinit();
shouldDeinit = false;
Serial.println("Timer runtime deinitialized");
}

// App code does other things; timers run in background FreeRTOS tasks
}
13 changes: 12 additions & 1 deletion examples/PauseResume/PauseResume.ino
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <ESPTimer.h>

ESPTimer timer;
volatile bool shouldDeinit = false;

uint32_t intervalId;

Expand Down Expand Up @@ -39,6 +40,16 @@ void setup() {
auto s = timer.getStatus(intervalId);
Serial.printf("Status now: %d (Invalid=0 if removed)\n", (int)s);
}, 10000);

timer.setTimeout([]() {
shouldDeinit = true;
}, 12000);
}

void loop() {}
void loop() {
if (shouldDeinit && timer.isInitialized()) {
timer.deinit();
shouldDeinit = false;
Serial.println("ESPTimer deinitialized");
}
}
1 change: 0 additions & 1 deletion src/esp_timer/timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,6 @@ bool ESPTimer::toggleRunStatusMinCounter(uint32_t id) {
}

bool ESPTimer::clearTimeout(uint32_t id) { return clearItem(Type::Timeout, id); }
bool ESPTimer::clearTimer(uint32_t id) { return clearTimeout(id); }
bool ESPTimer::clearInterval(uint32_t id) { return clearItem(Type::Interval, id); }
bool ESPTimer::clearSecCounter(uint32_t id) { return clearItem(Type::Sec, id); }
bool ESPTimer::clearMsCounter(uint32_t id) { return clearItem(Type::Ms, id); }
Expand Down
4 changes: 1 addition & 3 deletions src/esp_timer/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class ESPTimer {

void init(const ESPTimerConfig& cfg = ESPTimerConfig());
void deinit();
bool initialized() const { return initialized_; }
bool isInitialized() const { return initialized_; }

// Scheduling
uint32_t setTimeout(std::function<void()> cb, uint32_t delayMs);
Expand Down Expand Up @@ -84,8 +84,6 @@ class ESPTimer {

// Clear (stop and remove) timers; returns true on success
bool clearTimeout(uint32_t id);
// Backward-compatible alias for clearTimeout
bool clearTimer(uint32_t id);
bool clearInterval(uint32_t id);
bool clearSecCounter(uint32_t id);
bool clearMsCounter(uint32_t id);
Expand Down
44 changes: 41 additions & 3 deletions test/test_basic/test_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
#include <ESPTimer.h>
#include <unity.h>

ESPTimer timer;

void test_api_compiles() {
ESPTimer timer;
ESPTimerConfig cfg;
cfg.usePSRAMBuffers = true;
timer.init(cfg);
TEST_ASSERT_TRUE(timer.isInitialized());

auto id1 = timer.setTimeout([]() {}, 1000);
auto id2 = timer.setInterval([]() {}, 20);
Expand All @@ -34,16 +34,54 @@ void test_api_compiles() {
TEST_ASSERT_TRUE(running);

TEST_ASSERT_TRUE(timer.clearTimeout(id1));
TEST_ASSERT_TRUE(timer.clearTimer(id6));
TEST_ASSERT_TRUE(timer.clearTimeout(id6));

// Clear should return true once
TEST_ASSERT_TRUE(timer.clearInterval(id2));

timer.deinit();
TEST_ASSERT_FALSE(timer.isInitialized());
}

void test_deinit_pre_init_is_safe_and_idempotent() {
ESPTimer timer;

TEST_ASSERT_FALSE(timer.isInitialized());
timer.deinit();
TEST_ASSERT_FALSE(timer.isInitialized());
timer.deinit();
TEST_ASSERT_FALSE(timer.isInitialized());
}

void test_reinit_lifecycle() {
ESPTimer timer;

timer.init();
TEST_ASSERT_TRUE(timer.isInitialized());
auto firstId = timer.setTimeout([]() {}, 5);
TEST_ASSERT_TRUE(firstId > 0);

timer.deinit();
TEST_ASSERT_FALSE(timer.isInitialized());
timer.deinit();
TEST_ASSERT_FALSE(timer.isInitialized());

timer.init();
TEST_ASSERT_TRUE(timer.isInitialized());
auto secondId = timer.setInterval([]() {}, 5);
TEST_ASSERT_TRUE(secondId > 0);
TEST_ASSERT_TRUE(timer.clearInterval(secondId));

timer.deinit();
TEST_ASSERT_FALSE(timer.isInitialized());
}

void setup() {
delay(2000);
UNITY_BEGIN();
RUN_TEST(test_api_compiles);
RUN_TEST(test_deinit_pre_init_is_safe_and_idempotent);
RUN_TEST(test_reinit_lifecycle);
UNITY_END();
}

Expand Down