SuperTinyKernel™ RTOS 1.05.3
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk_c_time.cpp
Go to the documentation of this file.
1/*
2 * SuperTinyKernel(TM) RTOS: Lightweight High-Performance Deterministic C++ RTOS for Embedded Systems.
3 *
4 * Source: https://github.com/SuperTinyKernel-RTOS
5 *
6 * Copyright (c) 2022-2026 Neutron Code Limited <stk@neutroncode.com>. All Rights Reserved.
7 * License: MIT License, see LICENSE for a full text.
8 */
9
10#include <cstddef> // for std::size_t
11
12#include <stk_config.h>
13#include <stk.h>
14#include "stk_c.h"
15#include "stk_c_time.h"
16
17#define STK_C_TIMERS_TOTAL (STK_C_TIMER_MAX * STK_C_CPU_COUNT)
18
19// Override STK_TIMER_COUNT_MAX with STK_C_TIMER_MAX.
20#undef STK_TIMER_COUNT_MAX
21#define STK_TIMER_COUNT_MAX (STK_C_TIMER_MAX)
22// Override STK_TIMER_HANDLER_STACK_SIZE with STK_C_TIMER_HANDLER_STACK_SIZE.
23#undef STK_TIMER_HANDLER_STACK_SIZE
24#define STK_TIMER_HANDLER_STACK_SIZE (STK_C_TIMER_HANDLER_STACK_SIZE)
25#include <time/stk_time_timer.h>
26
27inline void *operator new(std::size_t, void *ptr) noexcept { return ptr; }
28inline void operator delete(void *, void *) noexcept { /* nothing for placement delete */ }
29
30using namespace stk;
31using namespace stk::time;
32
33// ---------------------------------------------------------------------------
34// Internal concrete Timer subclass that bridges C++ OnExpired() -> C callback
35// ---------------------------------------------------------------------------
36
38{
39public:
40 CTimerWrapper() : m_host_handle(nullptr), m_callback(nullptr), m_user_data(nullptr)
41 {}
42
43 void Initialize(stk_timer_callback_t callback, void *user_data)
44 {
45 STK_ASSERT(callback != nullptr);
46
47 m_callback = callback;
48 m_user_data = user_data;
49 }
50
51 // Update the host association without touching callback/user_data.
52 // Called every time the timer is rearmed so the expiration callback
53 // always receives the correct host pointer.
54 void SetHostHandle(stk_timerhost_t *host_handle) { m_host_handle = host_handle; }
55
56 // Clear all fields so the slot can be reused after stk_timer_destroy().
57 void Reset()
58 {
59 m_callback = nullptr;
60 m_user_data = nullptr;
61 m_host_handle = nullptr;
62 }
63
65 void *GetUserData() const { return m_user_data; }
67
68 void OnExpired(TimerHost */*host*/)
69 {
70 if (m_callback != nullptr)
71 m_callback(m_host_handle, reinterpret_cast<stk_timer_t *>(this), m_user_data);
72 }
73
74private:
78};
79
80// ---------------------------------------------------------------------------
81// stk_timer_t — public opaque type maps 1:1 to CTimerWrapper
82// ---------------------------------------------------------------------------
83
88
89// ---------------------------------------------------------------------------
90// Timer slot pool
91// ---------------------------------------------------------------------------
92
93static struct TimerSlot
94{
95 TimerSlot() : timer(), busy(false)
96 {}
97
99 bool busy;
100}
102
103// ---------------------------------------------------------------------------
104// stk_timerhost_t — wraps a TimerHost instance
105//
106// One instance per CPU core, held in s_TimerHosts[]. The struct is opaque to
107// C callers.
108// ---------------------------------------------------------------------------
109
114
115// Static pool: one host per core, indexed by core_nr (0 ... STK_C_CPU_COUNT-1).
117
118// ---------------------------------------------------------------------------
119// C-interface
120// ---------------------------------------------------------------------------
121extern "C" {
122
123// ─────────────────────────────────────────────────────────────────────────────
124// TimerHost
125// ─────────────────────────────────────────────────────────────────────────────
126
128{
129 if (core_nr >= STK_C_CPU_COUNT)
130 return nullptr;
131
132 return &s_TimerHosts[core_nr];
133}
134
136 stk_kernel_t *kernel,
137 bool privileged)
138{
139 STK_ASSERT(host != nullptr);
140 STK_ASSERT(kernel != nullptr);
141
142 host->handle.Initialize(reinterpret_cast<IKernel *>(kernel),
143 (privileged ? ACCESS_PRIVILEGED : ACCESS_USER));
144}
145
147{
148 STK_ASSERT(host != nullptr);
149
150 return host->handle.Shutdown();
151}
152
154{
155 STK_ASSERT(host != nullptr);
156
157 return host->handle.IsEmpty();
158}
159
161{
162 STK_ASSERT(host != nullptr);
163
164 return host->handle.GetSize();
165}
166
168{
169 STK_ASSERT(host != nullptr);
170
171 return (int64_t)host->handle.GetTimeNow();
172}
173
174// ─────────────────────────────────────────────────────────────────────────────
175// Timer lifecycle
176// ─────────────────────────────────────────────────────────────────────────────
177
179{
180 STK_ASSERT(callback != nullptr);
181
183
184 for (uint32_t i = 0; i < STK_C_TIMERS_TOTAL; ++i)
185 {
186 if (!s_Timers[i].busy)
187 {
188 s_Timers[i].busy = true;
189 s_Timers[i].timer.handle.Initialize(callback, user_data);
190
191 return &s_Timers[i].timer;
192 }
193 }
194
195 // pool exhausted, you must increase STK_C_TIMER_MAX
196 STK_ASSERT(false);
197 return nullptr;
198}
199
201{
202 STK_ASSERT(timer != nullptr);
203
204 // destroying an active timer is a programming error
205 STK_ASSERT(!timer->handle.IsActive());
206
208
209 for (uint32_t i = 0; i < STK_C_TIMERS_TOTAL; ++i)
210 {
211 if (s_Timers[i].busy && (&s_Timers[i].timer == timer))
212 {
213 timer->handle.Reset();
214 s_Timers[i].busy = false;
215 return;
216 }
217 }
218
219 // timer not found in the pool: indicates a double-free or corruption
220 STK_ASSERT(false);
221}
222
223// ─────────────────────────────────────────────────────────────────────────────
224// Timer control helpers
225//
226// Every control function that rearms a timer also refreshes the host handle
227// stored in the wrapper so the C callback always receives the correct host.
228// ─────────────────────────────────────────────────────────────────────────────
229
231 stk_timer_t *timer,
232 uint32_t delay,
233 uint32_t period)
234{
235 STK_ASSERT(host != nullptr);
236 STK_ASSERT(timer != nullptr);
237
238 // refresh host association before timer can fire
239 timer->handle.SetHostHandle(host);
240
241 return host->handle.Start(timer->handle, delay, period);
242}
243
245{
246 STK_ASSERT(host != nullptr);
247 STK_ASSERT(timer != nullptr);
248
249 return host->handle.Stop(timer->handle);
250}
251
253{
254 STK_ASSERT(host != nullptr);
255 STK_ASSERT(timer != nullptr);
256
257 return host->handle.Reset(timer->handle);
258}
259
260bool stk_timer_restart(stk_timerhost_t *host, stk_timer_t *timer, uint32_t delay, uint32_t period)
261{
262 STK_ASSERT(host != nullptr);
263 STK_ASSERT(timer != nullptr);
264
265 // refresh host association before timer can fire
266 timer->handle.SetHostHandle(host);
267
268 return host->handle.Restart(timer->handle, delay, period);
269}
270
271bool stk_timer_start_or_reset(stk_timerhost_t *host, stk_timer_t *timer, uint32_t delay, uint32_t period)
272{
273 STK_ASSERT(host != nullptr);
274 STK_ASSERT(timer != nullptr);
275
276 // refresh host association (harmless if timer is already active on host)
277 timer->handle.SetHostHandle(host);
278
279 return host->handle.StartOrReset(timer->handle, delay, period);
280}
281
282bool stk_timer_set_period(stk_timerhost_t *host, stk_timer_t *timer, uint32_t period)
283{
284 STK_ASSERT(host != nullptr);
285 STK_ASSERT(timer != nullptr);
286
287 return host->handle.SetPeriod(timer->handle, period);
288}
289
290// ─────────────────────────────────────────────────────────────────────────────
291// Timer query
292// ─────────────────────────────────────────────────────────────────────────────
293
295{
296 STK_ASSERT(timer != nullptr);
297
298 return timer->handle.IsActive();
299}
300
301uint32_t stk_timer_get_period(const stk_timer_t *timer)
302{
303 STK_ASSERT(timer != nullptr);
304
305 return timer->handle.GetPeriod();
306}
307
309{
310 STK_ASSERT(timer != nullptr);
311
312 return (int64_t)timer->handle.GetDeadline();
313}
314
316{
317 STK_ASSERT(timer != nullptr);
318
319 return (int64_t)timer->handle.GetTimestamp();
320}
321
323{
324 STK_ASSERT(timer != nullptr);
325
326 return timer->handle.GetRemainingTime();
327}
328
329// ─────────────────────────────────────────────────────────────────────────────
330// PeriodicTrigger
331// ─────────────────────────────────────────────────────────────────────────────
332
333#include <time/stk_time_util.h>
334
339
341 uint32_t memory_size,
342 uint32_t period,
343 bool started)
344{
345 STK_ASSERT(memory != nullptr);
346 STK_ASSERT(memory_size >= sizeof(stk_periodic_trigger_t));
347 if (memory == nullptr || memory_size < sizeof(stk_periodic_trigger_t))
348 return nullptr;
349
350 return new (memory->data) stk_periodic_trigger_t{ time::PeriodicTrigger(static_cast<Ticks>(period), started) };
351}
352
354{
355 if (trig != nullptr)
356 trig->~stk_periodic_trigger_t();
357}
358
360{
361 STK_ASSERT(trig != nullptr);
362
363 return trig->handle.Poll();
364}
365
367{
368 STK_ASSERT(trig != nullptr);
369
370 trig->handle.SetPeriod(static_cast<Ticks>(period));
371}
372
374{
375 STK_ASSERT(trig != nullptr);
376
377 trig->handle.Restart();
378}
379
381{
382 STK_ASSERT(trig != nullptr);
383
384 return static_cast<uint32_t>(trig->handle.GetPeriod());
385}
386
387} // extern "C"
Top-level STK include. Provides the Kernel class template and all built-in task-switching strategies.
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:330
Implementation of stk::time::TimerHost, a software timer multiplexer that manages multiple stk::time:...
Time-related utilities: stk::time::PeriodicTrigger.
C language binding/interface for SuperTinyKernel (STK).
C language binding for stk::time::TimerHost and stk::time::TimerHost::Timer.
static stk_timerhost_t s_TimerHosts[(1)]
#define STK_C_TIMERS_TOTAL
static struct TimerSlot s_Timers[(32 *(1))]
struct stk_kernel_t stk_kernel_t
Opaque handle to a kernel instance.
Definition stk_c.h:91
#define STK_C_CPU_COUNT
Number of kernel instances / CPU cores supported (default: 1).
Definition stk_c.h:51
void(* stk_timer_callback_t)(stk_timerhost_t *host, stk_timer_t *timer, void *user_data)
Timer expiration callback invoked from within the TimerHost handler task.
Definition stk_c_time.h:74
bool stk_timer_stop(stk_timerhost_t *host, stk_timer_t *timer)
Stop a running timer.
uint32_t stk_timer_get_period(const stk_timer_t *timer)
Get the timer's reload period.
bool stk_timer_start_or_reset(stk_timerhost_t *host, stk_timer_t *timer, uint32_t delay, uint32_t period)
Start the timer if inactive, or reset its deadline if already active and periodic.
bool stk_timerhost_is_empty(const stk_timerhost_t *host)
Return true when no timers are currently active on this host.
bool stk_timer_reset(stk_timerhost_t *host, stk_timer_t *timer)
Reset a periodic timer's deadline (re-arm from now).
bool stk_timer_set_period(stk_timerhost_t *host, stk_timer_t *timer, uint32_t period)
Change the period of a running periodic timer without affecting the current deadline.
stk_timer_t * stk_timer_create(stk_timer_callback_t callback, void *user_data)
Allocate a timer from the static pool.
int64_t stk_timer_get_timestamp(const stk_timer_t *timer)
Get the tick count at which the timer last expired.
bool stk_timer_restart(stk_timerhost_t *host, stk_timer_t *timer, uint32_t delay, uint32_t period)
Atomically stop and re-start a timer.
bool stk_timer_start(stk_timerhost_t *host, stk_timer_t *timer, uint32_t delay, uint32_t period)
Start a timer.
void stk_timerhost_init(stk_timerhost_t *host, stk_kernel_t *kernel, bool privileged)
Initialize the TimerHost and register its internal tasks with the kernel.
size_t stk_timerhost_get_size(const stk_timerhost_t *host)
Return the number of currently active timers on this host.
bool stk_timer_is_active(const stk_timer_t *timer)
Check whether a timer is currently active (started and not yet expired/stopped).
bool stk_timerhost_shutdown(stk_timerhost_t *host)
Gracefully shut down the TimerHost.
int64_t stk_timer_get_deadline(const stk_timer_t *timer)
Get the absolute expiration tick count of the timer's next deadline.
uint32_t stk_timer_get_remaining_time(const stk_timer_t *timer)
Get remaining ticks until next expiration.
void stk_timer_destroy(stk_timer_t *timer)
Return a timer handle back to the static pool.
stk_timerhost_t * stk_timerhost_get(uint8_t core_nr)
Obtain the pre-allocated TimerHost for the given CPU core.
int64_t stk_timerhost_get_time_now(const stk_timerhost_t *host)
Return the last tick count snapshot maintained by the host's tick task.
void stk_periodic_trigger_set_period(stk_periodic_trigger_t *trig, uint32_t period)
Change the trigger period while preserving phase.
uint32_t stk_periodic_trigger_get_period(const stk_periodic_trigger_t *trig)
Get currently configured trigger period.
void stk_periodic_trigger_restart(stk_periodic_trigger_t *trig)
Reset and start the trigger from the current tick count.
stk_periodic_trigger_t * stk_periodic_trigger_create(stk_periodic_trigger_mem_t *memory, uint32_t memory_size, uint32_t period, bool started)
Construct PeriodicTrigger instance in the supplied memory buffer.
void stk_periodic_trigger_destroy(stk_periodic_trigger_t *trig)
Destroy instance (calls the C++ destructor in-place).
bool stk_periodic_trigger_poll(stk_periodic_trigger_t *trig)
Check whether the scheduled trigger time has been reached.
Namespace of STK package.
int64_t Ticks
Ticks value.
Definition stk_common.h:150
@ ACCESS_USER
Unprivileged access mode (access to some hardware is restricted, see CPU manual for details).
Definition stk_common.h:32
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
Definition stk_common.h:33
Time-related primitives.
Interface for the implementation of the kernel of the scheduler. It supports Soft and Hard Real-Time ...
Definition stk_common.h:854
RAII-style low-level synchronization primitive for atomic code execution. Used as building brick for ...
Definition stk_sync_cs.h:54
Software timer multiplexer that manages multiple Timer instances on top of a small fixed set of kerne...
bool Reset(Timer &timer)
Reset periodic timer's deadline.
bool SetPeriod(Timer &timer, uint32_t period)
Change the period of a running periodic timer without affecting its current deadline.
void Initialize(IKernel *kernel, EAccessMode mode)
Initialize timer host instance.
bool IsEmpty() const
Return true if no timers are currently active.
Ticks GetTimeNow() const
Get current time.
size_t GetSize() const
Return number of currently active timers.
bool Shutdown()
Shutdown host instance. All timers are stopped and removed from the host.
bool Restart(Timer &timer, uint32_t delay, uint32_t period=0)
Atomically stop and re-start timer.
bool StartOrReset(Timer &timer, uint32_t delay, uint32_t period=0)
Start timer if inactive, or reset its deadline if already active and periodic.
bool Stop(Timer &timer)
Stop running timer.
bool Start(Timer &timer, uint32_t delay, uint32_t period=0)
Start timer.
Abstract base class for a timer managed by TimerHost.
uint32_t GetRemainingTime() const
Get remaining ticks until the timer next expires.
Lightweight periodic trigger: returns true once per configured period when polled.
uint32_t GetPeriod() const
Get currently configured trigger period.
void Restart()
Reset the trigger and start.
void SetPeriod(uint32_t period)
Change the trigger period while preserving phase.
bool Poll()
Check whether the scheduled trigger time has been reached.
Opaque memory container for a stk_periodic_trigger_t instance.
Definition stk_c_time.h:292
void Initialize(stk_timer_callback_t callback, void *user_data)
stk_timerhost_t * m_host_handle
C-level host, forwarded to the callback.
stk_timer_callback_t GetCallback() const
stk_timer_callback_t m_callback
stk_timerhost_t * GetHostHandle() const
void * GetUserData() const
void * m_user_data
void SetHostHandle(stk_timerhost_t *host_handle)
void OnExpired(TimerHost *)
CTimerWrapper handle
stk_timer_t timer
time::PeriodicTrigger handle