|
1 | | -# microtimer |
| 1 | +# microtimer |
2 | 2 |
|
3 | 3 | [](https://github.com/Vanderhell/microtimer/actions/workflows/ci.yml) |
4 | 4 | [](LICENSE) |
5 | 5 | [](https://en.wikipedia.org/wiki/C99) |
6 | 6 |
|
7 | | -Software timer manager for embedded systems. |
| 7 | +`microtimer` is a fixed-capacity software timer manager for C99 projects. |
8 | 8 |
|
9 | | -C99 | Zero dependencies | Zero allocations | Oneshot + Periodic | Portable |
| 9 | +It targets serialized access to one manager from one execution context by default. It does not provide heap allocation, hidden locks, persistence, or general ISR/thread safety. |
10 | 10 |
|
11 | | -## Why microtimer? |
| 11 | +## Support Scope |
12 | 12 |
|
13 | | -Embedded main loops often contain repeated timing checks: |
| 13 | +- C99 and C11 consumers |
| 14 | +- C++ header consumption |
| 15 | +- GCC, Clang, and MSVC builds |
| 16 | +- Main-loop usage |
| 17 | +- ISR-owned usage with strict limits |
| 18 | +- External synchronization around shared access |
| 19 | +- ARM Cortex-M compile-only verification |
| 20 | +- CMake `find_package()` and `add_subdirectory()` consumers |
| 21 | + |
| 22 | +## Quick Start |
14 | 23 |
|
15 | 24 | ```c |
16 | | -if (now - last_blink > 500) { toggle_led(); last_blink = now; } |
17 | | -if (now - last_send > 5000) { send_telemetry(); last_send = now; } |
18 | | -if (now - last_check > 1000) { check_sensors(); last_check = now; } |
19 | | -``` |
| 25 | +#include "mtimer.h" |
20 | 26 |
|
21 | | -`microtimer` replaces this with registered timers and a single tick path: |
| 27 | +static uint32_t app_clock_ms(void) { return platform_millis(); } |
22 | 28 |
|
23 | | -```c |
24 | | -mtimer_create(&tm, "blink", 500, MTIMER_PERIODIC, on_blink, NULL); |
25 | | -mtimer_create(&tm, "send", 5000, MTIMER_PERIODIC, on_send, NULL); |
26 | | -mtimer_create(&tm, "timeout", 3000, MTIMER_ONESHOT, on_timeout, NULL); |
| 29 | +static void blink_cb(uint8_t id, void *ctx) |
| 30 | +{ |
| 31 | + (void)id; |
| 32 | + *(volatile int *)ctx = 1; |
| 33 | +} |
27 | 34 |
|
28 | | -while (1) { |
29 | | - mtimer_tick(&tm); |
| 35 | +int main(void) |
| 36 | +{ |
| 37 | + mtimer_t tm; |
| 38 | + volatile int blink_due = 0; |
| 39 | + int timer_id; |
| 40 | + |
| 41 | + if (mtimer_init(&tm, app_clock_ms) != MTIMER_OK) { |
| 42 | + return 1; |
| 43 | + } |
| 44 | + |
| 45 | + timer_id = mtimer_create(&tm, "blink", 500u, MTIMER_PERIODIC, blink_cb, (void *)&blink_due); |
| 46 | + if (timer_id < 0) { |
| 47 | + return 1; |
| 48 | + } |
| 49 | + |
| 50 | + if (mtimer_start(&tm, (uint8_t)timer_id) != MTIMER_OK) { |
| 51 | + return 1; |
| 52 | + } |
| 53 | + |
| 54 | + for (;;) { |
| 55 | + int tick_rc = mtimer_tick(&tm); |
| 56 | + if (tick_rc < 0) { |
| 57 | + return 1; |
| 58 | + } |
| 59 | + if (blink_due) { |
| 60 | + blink_due = 0; |
| 61 | + toggle_led(); |
| 62 | + } |
| 63 | + } |
30 | 64 | } |
31 | 65 | ``` |
32 | 66 |
|
33 | | -## Features |
| 67 | +## Key Contracts |
34 | 68 |
|
35 | | -- Oneshot timers that auto-stop after firing. |
36 | | -- Periodic timers with drift correction. |
37 | | -- Pause/resume with remaining-time preservation. |
38 | | -- Dynamic interval changes at runtime. |
39 | | -- Slot reuse through destroy/create. |
40 | | -- Named timer lookup for diagnostics and shell commands. |
41 | | -- Per-timer and global fire counters. |
| 69 | +- Clock units are milliseconds on an unsigned 32-bit modulo counter. |
| 70 | +- Natural `uint32_t` wraparound is supported if the clock is not reset while timers are active. |
| 71 | +- `mtimer_tick()` fires each running timer at most once per successful call. |
| 72 | +- Missed periodic intervals are skipped without callback bursts; phase is retained when only one interval is due. |
| 73 | +- Timer names are optional and caller-owned. Non-`NULL` names must remain valid, immutable, and unique per manager. |
| 74 | +- Timer IDs are slot indexes. Destroying a timer invalidates its ID, and later creates may reuse that slot. |
| 75 | +- Same-manager mutation during callbacks returns `MTIMER_ERR_BUSY`. |
42 | 76 |
|
43 | | -## Build and Test |
| 77 | +## Build |
44 | 78 |
|
45 | | -Requirements: |
46 | | -- C99 compiler (`gcc` or `clang`) |
47 | | -- `make` |
48 | | - |
49 | | -Run tests: |
| 79 | +### CMake |
50 | 80 |
|
51 | 81 | ```bash |
52 | | -# clone microtest next to this repository root |
53 | | -# expected path: ../microtest/include |
54 | | -make -C tests |
| 82 | +cmake -S . -B build -DMICROTIMER_BUILD_TESTS=ON |
| 83 | +cmake --build build |
| 84 | +ctest --test-dir build --output-on-failure |
55 | 85 | ``` |
56 | 86 |
|
57 | | -## Public API |
58 | | - |
59 | | -Key functions: |
60 | | -- `mtimer_init` |
61 | | -- `mtimer_create`, `mtimer_destroy` |
62 | | -- `mtimer_start`, `mtimer_stop`, `mtimer_pause`, `mtimer_resume` |
63 | | -- `mtimer_set_interval` |
64 | | -- `mtimer_tick` |
65 | | -- `mtimer_count`, `mtimer_find`, `mtimer_remaining` |
66 | | - |
67 | | -See [`include/mtimer.h`](include/mtimer.h) for full API details. |
68 | | - |
69 | | -## Repository Layout |
| 87 | +### Make |
70 | 88 |
|
71 | | -- `include/mtimer.h` - public API |
72 | | -- `src/mtimer.c` - implementation |
73 | | -- `tests/test_all.c` - unit tests |
74 | | -- `docs/DESIGN.md` - design rationale |
75 | | - |
76 | | -## Ecosystem |
77 | | - |
78 | | -- [microhealth](https://github.com/Vanderhell/microhealth) |
79 | | -- [microwdt](https://github.com/Vanderhell/microwdt) |
80 | | -- [microres](https://github.com/Vanderhell/microres) |
81 | | -- [microsh](https://github.com/Vanderhell/microsh) |
82 | | - |
83 | | -## Configuration |
84 | | - |
85 | | -- `MTIMER_MAX_TIMERS` (default: `8`) |
86 | | - |
87 | | -## Contributing |
88 | | - |
89 | | -See [CONTRIBUTING.md](CONTRIBUTING.md). |
| 89 | +```bash |
| 90 | +make |
| 91 | +``` |
90 | 92 |
|
91 | | -## Changelog |
| 93 | +Caller-provided `CC`, `CPPFLAGS`, `CFLAGS`, and `LDFLAGS` are honored by the Makefiles. |
92 | 94 |
|
93 | | -See [CHANGELOG.md](CHANGELOG.md). |
| 95 | +## Documentation |
94 | 96 |
|
95 | | -## License |
| 97 | +- [API reference](docs/API_REFERENCE.md) |
| 98 | +- [Cookbook](docs/COOKBOOK.md) |
| 99 | +- [Design notes](docs/DESIGN.md) |
| 100 | +- [Issues and troubleshooting](docs/ISSUES.md) |
| 101 | +- [Porting guide](docs/PORTING_GUIDE.md) |
| 102 | +- [Verification status](docs/VERIFICATION.md) |
| 103 | +- [Contributing](CONTRIBUTING.md) |
| 104 | +- [Security reporting](SECURITY.md) |
| 105 | +- [Changelog](CHANGELOG.md) |
96 | 106 |
|
97 | | -MIT - see [LICENSE](LICENSE). |
| 107 | +Releases are tag-driven through `.github/workflows/release.yml` and are only published from pushed `v*` tags. |
0 commit comments