Skip to content

Commit d031cd4

Browse files
authored
Merge pull request #2 from ESPToolKit/feature/esp-timer/teardown/teardown-contract-esp-timer
Implement teardown contract for ESPTimer
2 parents b6c6202 + 82588f5 commit d031cd4

7 files changed

Lines changed: 81 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ The format follows Keep a Changelog and the project adheres to Semantic Versioni
77
## [Unreleased]
88
### Changed
99
- 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.
10-
- Added `clearTimeout(id)` for explicit timeout cancellation and kept `clearTimer(id)` as a backward-compatible alias.
10+
- Standardized teardown around `deinit()` + `isInitialized()` and removed the `clearTimer(id)` alias in favor of `clearTimeout(id)`.
1111
- Added `ESPTimerConfig::usePSRAMBuffers` and routed timer-owned persistent/transient vectors through `ESPBufferManager` with safe fallback to default heap.
1212
- Migrated timer lane task creation/lifecycle back to native FreeRTOS task handling (`xTaskCreatePinnedToCore`/`vTaskDelete`).
1313

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

1718
### Documentation
1819
- Added an MIT license badge and cross-links to other ESPToolKit libraries in the README.

README.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Include the umbrella header, create an `ESPTimer` instance, and call `init` once
2121
#include <ESPTimer.h>
2222

2323
ESPTimer timer;
24+
volatile bool shouldShutdownTimers = false;
2425

2526
void setup() {
2627
Serial.begin(115200);
@@ -48,9 +49,18 @@ void setup() {
4849

4950
timer.pauseInterval(intervalId);
5051
timer.resumeInterval(intervalId);
52+
53+
timer.setTimeout([](){
54+
shouldShutdownTimers = true;
55+
}, 30000);
5156
}
5257

53-
void loop() {}
58+
void loop() {
59+
if (shouldShutdownTimers && timer.isInitialized()) {
60+
timer.deinit();
61+
shouldShutdownTimers = false;
62+
}
63+
}
5464
```
5565

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

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

7788
`ESPTimerConfig` knobs (per task type):
7889
- Stack sizes (`stackSizeTimeout`, `stackSizeInterval`, `stackSizeSec`, `stackSizeMs`, `stackSizeMin`).

examples/Basic/Basic.ino

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <ESPTimer.h>
44

55
ESPTimer timer; // Create your own instance
6+
volatile bool shouldDeinit = false;
67

78
void setup() {
89
Serial.begin(115200);
@@ -59,8 +60,19 @@ void setup() {
5960
auto s = timer.getStatus(t1);
6061
Serial.printf("Timeout status: %d\n", static_cast<int>(s));
6162
}, 2000);
63+
64+
// Request teardown from loop context (not from timer worker tasks).
65+
timer.setTimeout([]() {
66+
shouldDeinit = true;
67+
}, 15000);
6268
}
6369

6470
void loop() {
71+
if (shouldDeinit && timer.isInitialized()) {
72+
timer.deinit();
73+
shouldDeinit = false;
74+
Serial.println("Timer runtime deinitialized");
75+
}
76+
6577
// App code does other things; timers run in background FreeRTOS tasks
6678
}

examples/PauseResume/PauseResume.ino

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <ESPTimer.h>
44

55
ESPTimer timer;
6+
volatile bool shouldDeinit = false;
67

78
uint32_t intervalId;
89

@@ -39,6 +40,16 @@ void setup() {
3940
auto s = timer.getStatus(intervalId);
4041
Serial.printf("Status now: %d (Invalid=0 if removed)\n", (int)s);
4142
}, 10000);
43+
44+
timer.setTimeout([]() {
45+
shouldDeinit = true;
46+
}, 12000);
4247
}
4348

44-
void loop() {}
49+
void loop() {
50+
if (shouldDeinit && timer.isInitialized()) {
51+
timer.deinit();
52+
shouldDeinit = false;
53+
Serial.println("ESPTimer deinitialized");
54+
}
55+
}

src/esp_timer/timer.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,6 @@ bool ESPTimer::toggleRunStatusMinCounter(uint32_t id) {
370370
}
371371

372372
bool ESPTimer::clearTimeout(uint32_t id) { return clearItem(Type::Timeout, id); }
373-
bool ESPTimer::clearTimer(uint32_t id) { return clearTimeout(id); }
374373
bool ESPTimer::clearInterval(uint32_t id) { return clearItem(Type::Interval, id); }
375374
bool ESPTimer::clearSecCounter(uint32_t id) { return clearItem(Type::Sec, id); }
376375
bool ESPTimer::clearMsCounter(uint32_t id) { return clearItem(Type::Ms, id); }

src/esp_timer/timer.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class ESPTimer {
5252

5353
void init(const ESPTimerConfig& cfg = ESPTimerConfig());
5454
void deinit();
55-
bool initialized() const { return initialized_; }
55+
bool isInitialized() const { return initialized_; }
5656

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

8585
// Clear (stop and remove) timers; returns true on success
8686
bool clearTimeout(uint32_t id);
87-
// Backward-compatible alias for clearTimeout
88-
bool clearTimer(uint32_t id);
8987
bool clearInterval(uint32_t id);
9088
bool clearSecCounter(uint32_t id);
9189
bool clearMsCounter(uint32_t id);

test/test_basic/test_main.cpp

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
#include <ESPTimer.h>
33
#include <unity.h>
44

5-
ESPTimer timer;
6-
75
void test_api_compiles() {
6+
ESPTimer timer;
87
ESPTimerConfig cfg;
98
cfg.usePSRAMBuffers = true;
109
timer.init(cfg);
10+
TEST_ASSERT_TRUE(timer.isInitialized());
1111

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

3636
TEST_ASSERT_TRUE(timer.clearTimeout(id1));
37-
TEST_ASSERT_TRUE(timer.clearTimer(id6));
37+
TEST_ASSERT_TRUE(timer.clearTimeout(id6));
3838

3939
// Clear should return true once
4040
TEST_ASSERT_TRUE(timer.clearInterval(id2));
41+
42+
timer.deinit();
43+
TEST_ASSERT_FALSE(timer.isInitialized());
44+
}
45+
46+
void test_deinit_pre_init_is_safe_and_idempotent() {
47+
ESPTimer timer;
48+
49+
TEST_ASSERT_FALSE(timer.isInitialized());
50+
timer.deinit();
51+
TEST_ASSERT_FALSE(timer.isInitialized());
52+
timer.deinit();
53+
TEST_ASSERT_FALSE(timer.isInitialized());
54+
}
55+
56+
void test_reinit_lifecycle() {
57+
ESPTimer timer;
58+
59+
timer.init();
60+
TEST_ASSERT_TRUE(timer.isInitialized());
61+
auto firstId = timer.setTimeout([]() {}, 5);
62+
TEST_ASSERT_TRUE(firstId > 0);
63+
64+
timer.deinit();
65+
TEST_ASSERT_FALSE(timer.isInitialized());
66+
timer.deinit();
67+
TEST_ASSERT_FALSE(timer.isInitialized());
68+
69+
timer.init();
70+
TEST_ASSERT_TRUE(timer.isInitialized());
71+
auto secondId = timer.setInterval([]() {}, 5);
72+
TEST_ASSERT_TRUE(secondId > 0);
73+
TEST_ASSERT_TRUE(timer.clearInterval(secondId));
74+
75+
timer.deinit();
76+
TEST_ASSERT_FALSE(timer.isInitialized());
4177
}
4278

4379
void setup() {
4480
delay(2000);
4581
UNITY_BEGIN();
4682
RUN_TEST(test_api_compiles);
83+
RUN_TEST(test_deinit_pre_init_is_safe_and_idempotent);
84+
RUN_TEST(test_reinit_lifecycle);
4785
UNITY_END();
4886
}
4987

0 commit comments

Comments
 (0)