SuperTinyKernel™ RTOS 1.06.x
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.h"
13#include "memory/stk_memory.h"
14
15#include "stk_c.h"
16#include "stk_c_time.h"
17
18#define STK_C_TIMERS_TOTAL (STK_C_TIMER_MAX * STK_C_CPU_COUNT)
19
20// Override STK_TIMER_COUNT_MAX with STK_C_TIMER_MAX.
21#undef STK_TIMER_COUNT_MAX
22#define STK_TIMER_COUNT_MAX (STK_C_TIMER_MAX)
23// Override STK_TIMER_HANDLER_STACK_SIZE with STK_C_TIMER_HANDLER_STACK_SIZE.
24#undef STK_TIMER_HANDLER_STACK_SIZE
25#define STK_TIMER_HANDLER_STACK_SIZE (STK_C_TIMER_HANDLER_STACK_SIZE)
26#include "time/stk_time.h"
27
28using namespace stk;
29using namespace stk::time;
30
31// -----------------------------------------------------------------------------
32// Internal concrete Timer subclass that bridges C++ OnExpired() -> C callback
33// -----------------------------------------------------------------------------
34
35class CTimerWrapper final : public TimerHost::Timer
36{
37public:
38 CTimerWrapper() : m_host_handle(nullptr), m_callback(nullptr), m_user_data(nullptr)
39 {}
40
41 void Initialize(stk_timer_callback_t const callback, void *user_data)
42 {
43 STK_ASSERT(callback != nullptr);
44
45 m_callback = callback;
46 m_user_data = user_data;
47 }
48
49 // Update the host association without touching callback/user_data.
50 // Called every time the timer is rearmed so the expiration callback
51 // always receives the correct host pointer.
52 void SetHostHandle(stk_timerhost_t *host_handle) { m_host_handle = host_handle; }
53
54 // Clear all fields so the slot can be reused after stk_timer_destroy().
55 void Reset()
56 {
57 m_callback = nullptr;
58 m_user_data = nullptr;
59 m_host_handle = nullptr;
60 }
61
63 void *GetUserData() { return m_user_data; }
65
66 void OnExpired(TimerHost *host) override;
67
68private:
72};
73
78
79// Cast from CTimerWrapper to stk_timer_t without a warning.
81{
82 return reinterpret_cast<stk_timer_t *>(reinterpret_cast<void *>(t));
83}
84
85// Interop-private helpers
86namespace stk {
87namespace interop_c_helper {
88
89extern void InitializeTimerHost(stk_kernel_t *kernel, stk::time::TimerHost *th, EAccessMode amode);
90
91} // interop_c_helper
92} // stk
93
95{
96 STK_UNUSED(host);
97
98 if (m_callback != nullptr)
99 {
101 }
102}
103
104// -----------------------------------------------------------------------------
105// Timer slot pool
106// -----------------------------------------------------------------------------
107static struct TimerSlot
108{
109 TimerSlot() : timer(), busy(false)
110 {}
111
113 bool busy;
114}
116
117// -----------------------------------------------------------------------------
118// stk_timerhost_t — wraps a TimerHost instance
119//
120// One instance per CPU core, held in s_TimerHosts[]. The struct is opaque to
121// C callers.
122// -----------------------------------------------------------------------------
123
128
129// Static pool: one host per core, indexed by core_nr (0 ... STK_C_CPU_COUNT-1).
131
132// =============================================================================
133// C-interface
134// =============================================================================
135extern "C" {
136
137// -----------------------------------------------------------------------------
138// TimerHost
139// -----------------------------------------------------------------------------
140
142{
143 stk_timerhost_t *result = nullptr;
144
145 if (core_nr < STK_C_CPU_COUNT)
146 {
147 result = &s_TimerHosts[core_nr];
148 }
149
150 return result;
151}
152
154 stk_kernel_t *kernel,
155 bool privileged)
156{
157 STK_ASSERT(host != nullptr);
158 STK_ASSERT(kernel != nullptr);
159
161 (privileged ? ACCESS_PRIVILEGED : ACCESS_USER));
162}
163
165{
166 STK_ASSERT(host != nullptr);
167
168 return host->handle.Shutdown();
169}
170
172{
173 STK_ASSERT(host != nullptr);
174
175 return host->handle.IsEmpty();
176}
177
179{
180 STK_ASSERT(host != nullptr);
181
182 return host->handle.GetSize();
183}
184
186{
187 STK_ASSERT(host != nullptr);
188
189 return static_cast<int64_t>(host->handle.GetTimeNow());
190}
191
192// -----------------------------------------------------------------------------
193// Timer lifecycle
194// -----------------------------------------------------------------------------
195
197{
198 STK_ASSERT(callback != nullptr);
199
201
202 stk_timer_t *result = nullptr;
203
204 for (uint32_t i = 0U; i < STK_C_TIMERS_TOTAL; ++i)
205 {
206 if (!s_Timers[i].busy)
207 {
208 s_Timers[i].busy = true;
209 s_Timers[i].timer.handle.Initialize(callback, user_data);
210 result = &s_Timers[i].timer;
211 break;
212 }
213 }
214
215 // pool exhausted, you must increase STK_C_TIMER_MAX
216 STK_ASSERT(result != nullptr);
217
218 return result;
219}
220
222{
223 STK_ASSERT(tmr != nullptr);
224
225 // destroying an active timer is a programming error
226 STK_ASSERT(!tmr->handle.IsActive());
227
229
230 bool found = false;
231
232 for (uint32_t i = 0U; ((i < STK_C_TIMERS_TOTAL) && !found); ++i)
233 {
234 if (s_Timers[i].busy && (&s_Timers[i].timer == tmr))
235 {
236 tmr->handle.Reset();
237 s_Timers[i].busy = false;
238 found = true;
239 }
240 }
241
242 // timer not found in the pool: indicates a double-free or corruption
243 STK_ASSERT(found);
244}
245
246// -----------------------------------------------------------------------------
247// Timer control helpers
248//
249// Every control function that rearms a timer also refreshes the host handle
250// stored in the wrapper so the C callback always receives the correct host.
251// -----------------------------------------------------------------------------
252
254 stk_timer_t *tmr,
255 uint32_t delay,
256 uint32_t period)
257{
258 STK_ASSERT(host != nullptr);
259 STK_ASSERT(tmr != nullptr);
260
261 // refresh host association before timer can fire
262 tmr->handle.SetHostHandle(host);
263
264 return host->handle.Start(tmr->handle, delay, period);
265}
266
268{
269 STK_ASSERT(host != nullptr);
270 STK_ASSERT(tmr != nullptr);
271
272 return host->handle.Stop(tmr->handle);
273}
274
276{
277 STK_ASSERT(host != nullptr);
278 STK_ASSERT(tmr != nullptr);
279
280 return host->handle.Reset(tmr->handle);
281}
282
283bool stk_timer_restart(stk_timerhost_t *host, stk_timer_t *tmr, uint32_t delay, uint32_t period)
284{
285 STK_ASSERT(host != nullptr);
286 STK_ASSERT(tmr != nullptr);
287
288 // refresh host association before timer can fire
289 tmr->handle.SetHostHandle(host);
290
291 return host->handle.Restart(tmr->handle, delay, period);
292}
293
294bool stk_timer_start_or_reset(stk_timerhost_t *host, stk_timer_t *tmr, uint32_t delay, uint32_t period_ticks)
295{
296 STK_ASSERT(host != nullptr);
297 STK_ASSERT(tmr != nullptr);
298
299 // refresh host association (harmless if timer is already active on host)
300 tmr->handle.SetHostHandle(host);
301
302 return host->handle.StartOrReset(tmr->handle, delay, period_ticks);
303}
304
305bool stk_timer_set_period(stk_timerhost_t *host, stk_timer_t *tmr, uint32_t period_ticks)
306{
307 STK_ASSERT(host != nullptr);
308 STK_ASSERT(tmr != nullptr);
309
310 return host->handle.SetPeriod(tmr->handle, period_ticks);
311}
312
313// -----------------------------------------------------------------------------
314// Timer query
315// -----------------------------------------------------------------------------
316
318{
319 STK_ASSERT(tmr != nullptr);
320
321 return tmr->handle.IsActive();
322}
323
325{
326 STK_ASSERT(tmr != nullptr);
327
328 return tmr->handle.GetPeriod();
329}
330
332{
333 STK_ASSERT(tmr != nullptr);
334
335 return static_cast<int64_t>(tmr->handle.GetDeadline());
336}
337
339{
340 STK_ASSERT(tmr != nullptr);
341
342 return static_cast<int64_t>(tmr->handle.GetTimestamp());
343}
344
346{
347 STK_ASSERT(tmr != nullptr);
348
349 return tmr->handle.GetRemainingTicks();
350}
351
352// -----------------------------------------------------------------------------
353// PeriodicTrigger
354// -----------------------------------------------------------------------------
355
357{
358 stk_periodic_trigger_t(uint32_t period, bool start) : handle(period, start)
359 {}
360
362};
363
365 uint32_t membuf_size,
366 uint32_t period_ticks,
367 bool started)
368{
369 STK_ASSERT(membuf != nullptr);
370 STK_ASSERT(membuf_size >= sizeof(stk_periodic_trigger_t));
371
372 stk_periodic_trigger_t *result = nullptr;
373 if (membuf_size >= sizeof(stk_periodic_trigger_t))
374 {
375 result = new (membuf->data) stk_periodic_trigger_t(period_ticks, started);
376 }
377
378 return result;
379}
380
382{
383 if (trig != nullptr)
384 {
385 trig->~stk_periodic_trigger_t();
386 }
387}
388
390{
391 STK_ASSERT(trig != nullptr);
392
393 return trig->handle.Poll();
394}
395
397{
398 STK_ASSERT(trig != nullptr);
399
400 trig->handle.SetPeriod(period_ticks);
401}
402
404{
405 STK_ASSERT(trig != nullptr);
406
407 trig->handle.Restart();
408}
409
411{
412 STK_ASSERT(trig != nullptr);
413
414 return static_cast<uint32_t>(trig->handle.GetPeriod());
415}
416
417// =============================================================================
418} // extern "C"
419// =============================================================================
Collection of memory-related primitives (stk::memory namespace).
Top-level STK include. Provides the Kernel class template and all built-in task-switching strategies.
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:608
#define __stk_forceinline
Forces compiler to always inline the decorated function, regardless of optimisation level.
Definition stk_defs.h:175
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:409
Collection of time-related primitives (stk::time namespace).
C language binding/interface for SuperTinyKernel RTOS.
C language binding for stk::time::TimerHost and stk::time::TimerHost::Timer.
static stk_timerhost_t s_TimerHosts[STK_C_CPU_COUNT]
#define STK_C_TIMERS_TOTAL
static __stk_forceinline stk_timer_t * CastCppTimerWrapperToC(CTimerWrapper *const t)
static struct TimerSlot s_Timers[(STK_C_TIMER_MAX *STK_C_CPU_COUNT)]
struct stk_kernel_t stk_kernel_t
Opaque handle to a kernel instance.
Definition stk_c.h:126
#define STK_C_CPU_COUNT
Number of kernel instances / CPU cores supported (default: 1).
Definition stk_c.h:60
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:77
bool stk_timerhost_is_empty(const stk_timerhost_t *host)
Return true when no timers are currently active on this host.
bool stk_timer_restart(stk_timerhost_t *host, stk_timer_t *tmr, uint32_t delay, uint32_t period)
Atomically stop and re-start a timer.
bool stk_timer_start(stk_timerhost_t *host, stk_timer_t *tmr, uint32_t delay, uint32_t period)
Start a timer.
bool stk_timer_set_period(stk_timerhost_t *host, stk_timer_t *tmr, uint32_t period_ticks)
Change the period of a running periodic timer without affecting the current deadline.
bool stk_timer_is_active(const stk_timer_t *tmr)
Check whether a timer is currently active (started and not yet expired/stopped).
bool stk_timer_stop(stk_timerhost_t *host, stk_timer_t *tmr)
Stop a running timer.
bool stk_timer_start_or_reset(stk_timerhost_t *host, stk_timer_t *tmr, uint32_t delay, uint32_t period_ticks)
Start the timer if inactive, or reset its deadline if already active and periodic.
stk_timer_t * stk_timer_create(stk_timer_callback_t callback, void *user_data)
Allocate a timer from the static pool.
uint32_t stk_timer_get_remaining_ticks(const stk_timer_t *tmr)
Get remaining ticks until next expiration.
int64_t stk_timer_get_timestamp(const stk_timer_t *tmr)
Get the tick count at which the timer last expired.
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.
int64_t stk_timer_get_deadline(const stk_timer_t *tmr)
Get the absolute expiration tick count of the timer's next deadline.
void stk_timer_destroy(stk_timer_t *tmr)
Return a timer handle back to the static pool.
bool stk_timerhost_shutdown(stk_timerhost_t *host)
Gracefully shut down the TimerHost.
bool stk_timer_reset(stk_timerhost_t *host, stk_timer_t *tmr)
Reset a periodic timer's deadline (re-arm from now).
uint32_t stk_timer_get_period(const stk_timer_t *tmr)
Get the timer's reload period.
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_destroy(stk_periodic_trigger_t *const trig)
Destroy instance (calls the C++ destructor in-place).
stk_periodic_trigger_t * stk_periodic_trigger_create(stk_periodic_trigger_mem_t *const membuf, uint32_t membuf_size, uint32_t period_ticks, bool started)
Construct PeriodicTrigger instance in the supplied memory buffer.
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.
struct stk_periodic_trigger_t stk_periodic_trigger_t
Opaque handle to a stk::time::PeriodicTrigger instance.
Definition stk_c_time.h:304
bool stk_periodic_trigger_poll(stk_periodic_trigger_t *trig)
Check whether the scheduled trigger time has been reached.
void stk_periodic_trigger_set_period(stk_periodic_trigger_t *trig, uint32_t period_ticks)
Change the trigger period while preserving phase.
Namespace of STK package.
EAccessMode
Hardware access mode by the user task.
Definition stk_common.h:32
@ ACCESS_USER
Unprivileged access mode (access to some hardware is restricted, see CPU manual for details).
Definition stk_common.h:33
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
Definition stk_common.h:34
Time-related primitives.
void InitializeTimerHost(stk_kernel_t *kernel, stk::time::TimerHost *th, EAccessMode amode)
Definition stk_c.cpp:64
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 SetPeriod(Timer &tmr, uint32_t period)
Change the period of a running periodic timer without affecting its current deadline.
bool IsEmpty() const
Return true if no timers are currently active.
bool Stop(Timer &tmr)
Stop running timer.
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 &tmr, uint32_t delay, uint32_t period=0)
Atomically stop and re-start timer.
bool StartOrReset(Timer &tmr, uint32_t delay, uint32_t period=0)
Start timer if inactive, or reset its deadline if already active and periodic.
bool Reset(Timer &tmr)
Reset periodic timer's deadline.
bool Start(Timer &tmr, uint32_t delay, uint32_t period=0)
Start timer.
Abstract base class for a timer managed by TimerHost.
Ticks GetDeadline() const
Get the absolute time in ticks at which the timer will expire.
uint32_t GetRemainingTicks() const
Get remaining ticks until the timer next expires.
bool IsActive() const
Check whether the timer is currently active.
uint32_t GetPeriod() const
Get the reload period of the timer.
Ticks GetTimestamp() const
Get the tick count at which the timer last expired.
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:298
stk_word_t data[(16U)]
Definition stk_c_time.h:299
void Initialize(stk_timer_callback_t const callback, void *user_data)
stk_timerhost_t * m_host_handle
C-level host, forwarded to the callback.
stk_timer_callback_t m_callback
void * GetUserData()
void * m_user_data
void OnExpired(TimerHost *host) override
Callback invoked by the handler task when this timer expires.
stk_timerhost_t * GetHostHandle()
void SetHostHandle(stk_timerhost_t *host_handle)
stk_timer_callback_t GetCallback()
CTimerWrapper handle
stk_timer_t timer
stk_periodic_trigger_t(uint32_t period, bool start)
time::PeriodicTrigger handle