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
cmsis_os2_stk.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 "stk.h"
11#include "sync/stk_sync.h"
12#include "time/stk_time.h"
13#include "memory/stk_memory.h"
14
15// See design notes, API coverage and other details in cmsis_os2.h.
16
17#include "cmsis_os2.h"
18
19// -----------------------------------------------------------------------------
20// Kernel version / identification
21// -----------------------------------------------------------------------------
22
23#define STK_WRAPPER_API_VERSION 20030000UL // 2.3.0
24#define STK_WRAPPER_KERNEL_VERSION 20030000UL
25#define STK_WRAPPER_KERNEL_ID "STK RTOS2 Wrapper v1.0"
26
27// -----------------------------------------------------------------------------
28// Kernel configuration
29// -----------------------------------------------------------------------------
30
31// Number of task slots in the global kernel instance.
32// Increase if more concurrent threads are needed.
33#ifndef CMSIS_STK_MAX_THREADS
34#define CMSIS_STK_MAX_THREADS (16U)
35#endif
36
37// Default stack size (in Words) when the caller passes stack_size == 0.
38#ifndef CMSIS_STK_DEFAULT_STACK_WORDS
39#define CMSIS_STK_DEFAULT_STACK_WORDS (256U)
40#endif
41
42// Minimum stack size (in Words) – mirrors STK's own STACK_SIZE_MIN.
43#define CMSIS_STK_MIN_STACK_WORDS (STK_STACK_SIZE_MIN)
44
45// Returns a size of memory in stk::Word elements required for object allocation.
46template <typename T> static constexpr size_t StkGetWordCountForType()
47{
48 return ((sizeof(T) + sizeof(stk::Word) - 1U) / sizeof(stk::Word));
49}
50
51// Custom strlen replacement.
52static size_t CmsisStrlen(const char str[]) // MISRA: declared as array, not pointer to allow indexed access
53{
54 size_t total_len = 0U;
55
56 while (str[total_len] != '\0')
57 {
58 total_len++;
59 }
60
61 return total_len;
62}
63
64// Private memory allocators (we define malloc, free here to overcome absence of declaration in
65// case of -ffreestanding compiler flag).
66extern "C" void *malloc(size_t size);
67extern "C" void free(void *ptr);
68void *stk::memory::MemoryAllocator::Allocate(size_t size) { return malloc(size); }
69void stk::memory::MemoryAllocator::Free(void *ptr) { free(ptr); }
70
71// -----------------------------------------------------------------------------
72// Priority mapping:
73// CMSIS range: osPriorityIdle(1) .. osPriorityISR(56) -> 57 levels
74// STK FP32 range: 0 .. 31 -> 32 levels
75// Linear map: stk_prio = (cmsis_prio * 31) / 56
76// -----------------------------------------------------------------------------
78{
79 int32_t result;
80
81 if (p <= osPriorityIdle)
82 {
83 result = 0;
84 }
85 else if (p >= osPriorityISR)
86 {
87 result = 31;
88 }
89 else
90 {
91 result = ((static_cast<int32_t>(p) * 31) / 56);
92 }
93
94 return result;
95}
97{
98 // Inverse: cmsis_prio = (stk_prio * 56) / 31
99 int32_t r = (p * 56) / 31;
100 if (r < static_cast<int32_t>(osPriorityIdle))
101 {
102 r = static_cast<int32_t>(osPriorityIdle);
103 }
104
105 if (r > static_cast<int32_t>(osPriorityISR))
106 {
107 r = static_cast<int32_t>(osPriorityISR);
108 }
109
110 return static_cast<osPriority_t>(r);
111}
112
113// -----------------------------------------------------------------------------
114// Convert CMSIS timeout (ticks) -> STK timeout (ticks / milliseconds).
115//
116// CMSIS ticks == STK ticks when tick resolution is 1 ms (PERIODICITY_DEFAULT).
117// For other resolutions the conversion uses the kernel's tick resolution.
118// osWaitForever -> WAIT_INFINITE.
119// -----------------------------------------------------------------------------
121{
122 stk::Timeout result;
123
124 if (ticks > static_cast<uint32_t>(stk::WAIT_INFINITE))
125 {
126 result = stk::WAIT_INFINITE;
127 }
128 else if (ticks == 0U)
129 {
130 result = stk::NO_WAIT;
131 }
132 else
133 {
134 // CMSIS ticks are kernel ticks – pass through directly as STK ticks
135 result = static_cast<stk::Timeout>(ticks);
136 }
137
138 return result;
139}
140
141// -----------------------------------------------------------------------------
142// ISR context check
143// -----------------------------------------------------------------------------
145{
146 return stk::hw::IsInsideISR();
147}
148
149// -----------------------------------------------------------------------------
150// Global kernel type alias
151// -----------------------------------------------------------------------------
153#if STK_TICKLESS_IDLE
155#endif
157
159static uint32_t g_StkKernelLocked = 0U;
160
161// -----------------------------------------------------------------------------
162// Thread control block
163//
164// StkThread wraps a single CMSIS thread.
165//
166// Stack memory is provided either by the caller (static allocation) or
167// allocated dynamically from operator new[] (heap allocation).
168//
169// The CMSIS function pointer + argument are stored here; the STK task's
170// Run() method simply calls func(argument).
171//
172// Priority is stored as STK weight (0..31) and returned via GetWeight().
173// -----------------------------------------------------------------------------
174
175class StkThread final : public stk::ITask
176{
178
179public:
180 // --- Join support ---
181 enum class JoinState : uint8_t
182 {
183 Detached, // osThreadDetach() was called, or created with osThreadDetached
184 Joinable, // created with osThreadJoinable, not yet joined or exited
185 Exited, // Run() has returned; OnExit() has fired; not yet joined
186 Joined, // a joiner has already collected the result; further joins are errors
187 };
188
189 explicit StkThread()
190 : m_func(nullptr), m_argument(nullptr), m_name(nullptr),
192 m_stack(nullptr), m_stack_size(0U), m_join_state(JoinState::Detached),
193 m_stack_owned(false), m_suspended(false), m_cb_owned(true)
194 {}
195
196 virtual ~StkThread()
197 {
198 if (m_stack_owned && (m_stack != nullptr))
199 {
200 delete[] m_stack;
201 m_stack = nullptr;
202 }
203 }
204
205 void Run() override
206 {
208
209 // KERNEL_DYNAMIC: returning from Run() removes the task automatically.
210 }
211
212 void OnExit() override
213 {
215
216 // wake any osThreadJoin() caller
217 m_join_cv.NotifyAll();
218 }
219
220 // ---- IStackMemory ----
221 const stk::Word *GetStack() const override { return m_stack; }
222 size_t GetStackSize() const override { return m_stack_size; }
223 size_t GetStackSizeBytes() const override { return m_stack_size * sizeof(stk::Word); }
224
225 // ---- ITask ----
227 void OnDeadlineMissed(uint32_t) override {}
228 int32_t GetWeight() const override { return m_stk_priority; }
229 const char *GetTraceName() const override { return m_name; }
230
232 {
233 // tid is hw::PtrToWord(this) where 'this' is the StkThread* - cast it back.
234 return reinterpret_cast<osThreadId_t>(static_cast<void *>(
235 reinterpret_cast<StkThread *>(static_cast<uintptr_t>(tid))));
236 }
237
238 // ---- Members ----
241 const char *m_name;
242 volatile int32_t m_stk_priority; // STK priority level 0..31
243 stk::Word *m_stack; // pointer to stack memory (may be owned)
244 size_t m_stack_size; // stack size in Words
245 volatile JoinState m_join_state; // guarded by m_join_mutex between other tasks
247 stk::sync::EventFlags m_thread_flags; // Per-thread event flags - backed by STK's native 32-bit EventFlags primitive.
248 bool m_stack_owned; // true if we allocated the stack ourselves
249 bool m_suspended; // true if suspended
250 bool m_cb_owned; // true -> heap-allocated control block, delete on Terminate(), false -> caller-supplied cb_mem, call destructor explicitly
251};
252
253// -----------------------------------------------------------------------------
254// Mutex control block
255// -----------------------------------------------------------------------------
256
258{
259 explicit StkMutex(const char *n = nullptr) : m_mutex(), m_cb_owned(true)
260 {
261 m_mutex.SetTraceName(n);
262 }
263
264 // ---- Members ----
266 bool m_cb_owned; // true -> heap-allocated, false -> placement-new in caller memory
267};
268
269// -----------------------------------------------------------------------------
270// Semaphore control block
271// -----------------------------------------------------------------------------
272
274{
275 explicit StkSemaphore(uint16_t initial, uint16_t max_count, const char *n = nullptr)
276 : m_semaphore(initial, max_count), m_cb_owned(true)
277 {
278 m_semaphore.SetTraceName(n);
279 }
280
281 // ---- Members ----
283 bool m_cb_owned; // true -> heap-allocated, false -> placement-new in caller memory
284};
285
286// -----------------------------------------------------------------------------
287// Event flags control block
288//
289// Backed directly by stk::sync::EventFlags - STK's native 32-bit multi-flag
290// synchronization primitive (Set/Clear/Get/Wait with ANY/ALL/NO_CLEAR options,
291// ISR-safe Set/Clear, absolute-deadline wait loop).
292// -----------------------------------------------------------------------------
293
295{
296 explicit StkEventFlags(const char *n = nullptr) : m_ef(0U), m_cb_owned(true)
297 {
298 m_ef.SetTraceName(n);
299 }
300
301 // ---- Members ----
303 bool m_cb_owned; // true -> heap-allocated, false -> placement-new in caller memory
304};
305
306// -----------------------------------------------------------------------------
307// Timer control block
308//
309// CMSIS timers are backed by stk::time::TimerHost.
310// A single global TimerHost is created on first osTimerNew().
311// -----------------------------------------------------------------------------
312
315
317{
319
320public:
321 explicit StkTimer(osTimerFunc_t const func, osTimerType_t tt, void *arg, const char *name)
322 : m_func(func), m_argument(arg), m_type(tt), m_name(name), m_period_ticks(0U), m_cb_owned(true)
323 {}
324 virtual ~StkTimer() = default;
325
326 void OnExpired(stk::time::TimerHost * /*host*/) override
327 {
329 }
330
332 {
333 if (g_TimerHost == nullptr)
334 {
337 }
338 }
339
340 // ---- Members ----
344 const char *m_name;
345 uint32_t m_period_ticks; // stored period for restart
346 bool m_cb_owned; // true -> heap-allocated, false -> placement-new in caller memory
347};
348
349// -----------------------------------------------------------------------------
350// Memory pool control block
351//
352// Backed directly by stk::memory::BlockMemoryPool.
353// -----------------------------------------------------------------------------
354
356{
358
359public:
360 // Construct with caller-supplied pool storage (storage_owned = false).
361 explicit StkMemPool(uint32_t cap, uint32_t raw_block_size,
362 const char *name, uint8_t *ext_storage)
363 : m_mpool(static_cast<size_t>(cap),
364 static_cast<size_t>(raw_block_size),
365 ext_storage,
366 cap * stk::memory::BlockMemoryPool::AlignBlockSize(raw_block_size),
367 name),
368 m_cb_owned(true)
369 {}
370
371 // Construct with heap-allocated pool storage (storage_owned = true).
372 explicit StkMemPool(uint32_t cap, uint32_t raw_block_size, const char *name)
373 : m_mpool(static_cast<size_t>(cap),
374 static_cast<size_t>(raw_block_size),
375 name),
376 m_cb_owned(true)
377 {}
378
379 // ---- Members ----
381 bool m_cb_owned; // true -> heap-allocated; false -> placement-new in caller memory
382};
383
384// -----------------------------------------------------------------------------
385// Message queue control block
386//
387// Backed by stk::sync::MessageQueue - STK's native fixed-capacity, fixed-
388// message-size FIFO ring-buffer with integrated blocking semantics (Put/Get
389// with WAIT_INFINITE / NO_WAIT / timed variants, ISR-safe TryPut/TryGet).
390//
391// Two independent memory regions are managed:
392//
393// Control block (cb_mem / cb_size in osMessageQueueAttr_t):
394// Policy identical to all other object types - PlacementNewOrHeap selects
395// placement-new into caller memory when cb_mem != nullptr and cb_size is
396// sufficient, otherwise heap. m_cb_owned tracks whether to free on Delete().
397//
398// Data buffer (mq_mem / mq_size in osMessageQueueAttr_t):
399// 1. Caller-supplied: attr->mq_mem / attr->mq_size are used as-is when the
400// region is large enough to hold (msg_count * msg_size) bytes.
401// 2. Dynamic fallback: heap buffer of (msg_count * msg_size) bytes.
402// Allocated buffer is freed in the destructor.
403// -----------------------------------------------------------------------------
404
406{
408
409public:
410 // Construct with a caller-supplied data buffer.
411 explicit StkMessageQueue(uint32_t cap, uint32_t msz, const char *name,uint8_t *ext_buf)
412 : m_mq(ext_buf, static_cast<size_t>(cap), static_cast<size_t>(msz)),
413 m_bf_owned(false), m_cb_owned(true)
414 {
415 m_mq.SetTraceName(name);
416 }
417
418 // Construct with a heap-allocated data buffer.
419 explicit StkMessageQueue(uint32_t cap, uint32_t msz, const char *name)
420 : m_mq(AllocBuffer(cap, msz), static_cast<size_t>(cap), static_cast<size_t>(msz)),
421 m_bf_owned(m_mq.IsStorageValid()), m_cb_owned(true)
422 {
423 m_mq.SetTraceName(name);
424 }
425
427 {
428 if (m_bf_owned)
429 {
430 delete[] m_mq.GetBuffer();
431 }
432 }
433
434 static uint8_t *AllocBuffer(uint32_t cap, uint32_t msz)
435 {
436 uint8_t *const ret = new (std::nothrow) uint8_t[static_cast<size_t>(cap) * msz];
437 STK_ASSERT(ret != nullptr); // fail in Debug: increase Heap size in linker settings
438 return ret;
439 }
440
441 // ---- Members ----
442 stk::sync::MessageQueue m_mq; // STK native message queue (owns blocking semantics)
443 bool m_bf_owned; // true -> when we heap-allocated the data buffer, false otherwise
444 bool m_cb_owned; // true -> heap-allocated control block (delete on Delete())
445 // false -> placement-new in caller memory (call dtor only)
446};
447
448// -----------------------------------------------------------------------------
449// Internal helpers
450// -----------------------------------------------------------------------------
451
452// Placement-new helper: construct T in caller-supplied memory when the block
453// is large enough; otherwise fall back to heap (operator new).
454// Sets obj->m_cb_owned = false for caller-supplied, true for heap.
455// Returns nullptr if heap fallback is needed but allocation fails.
456template <typename T, typename... Args>
457static T *PlacementNewOrHeap(void *mem, size_t size, const Args &... args)
458{
459 T *obj;
460
461 if ((mem != nullptr) && (size >= sizeof(T)))
462 {
463 obj = new (mem) T(args...);
464 obj->m_cb_owned = false;
465 }
466 else
467 {
468 obj = new (std::nothrow) T(args...);
469 // m_cb_owned is already true from the constructor default
470 STK_ASSERT(obj != nullptr);
471 }
472
473 return obj;
474}
475
476// Destroy an object created by PlacementNewOrHeap:
477// - m_cb_owned == false -> call destructor only (memory is caller's)
478// - m_cb_owned == true -> delete (destructor + free)
479template <typename T>
480static void ObjDestroy(T *obj)
481{
482 if (obj->m_cb_owned)
483 {
484 delete obj;
485 }
486 else
487 {
488 obj->~T();
489 }
490}
491
492// Helper: map CMSIS flags options -> STK EventFlags options bitmask.
493static __stk_forceinline uint32_t CmsisFlagsOptionsToStk(uint32_t options)
494{
495 uint32_t stk_opts = stk::sync::EventFlags::OPT_WAIT_ANY; // default
496
497 if ((options & osFlagsWaitAll) != 0U)
498 {
500 }
501
502 if ((options & osFlagsNoClear) != 0U)
503 {
505 }
506
507 return stk_opts;
508}
509
510// Helper: map STK EventFlags error sentinel -> CMSIS flags error code.
511static __stk_forceinline uint32_t StkFlagsResultToCmsis(uint32_t result)
512{
513 uint32_t cmsis_result;
514
516 {
517 cmsis_result = result;
518 }
519 else if (result == stk::sync::EventFlags::ERROR_TIMEOUT)
520 {
521 cmsis_result = osFlagsErrorTimeout;
522 }
524 {
525 cmsis_result = osFlagsErrorParameter;
526 }
527 else if (result == stk::sync::EventFlags::ERROR_ISR)
528 {
529 cmsis_result = osFlagsErrorISR;
530 }
531 else
532 {
533 cmsis_result = osFlagsErrorUnknown;
534 }
535
536 return cmsis_result;
537}
538
539
540// ===========================================================================
541// ==== Kernel Management Functions ====
542// ===========================================================================
543
545{
546 osStatus_t result;
547
548 if (IsIrqContext())
549 {
550 result = osErrorISR;
551 }
553 {
554 result = osError;
555 }
556 else
557 {
558 g_StkKernel.Initialize(); // default 1 ms tick resolution
559 result = osOK;
560 }
561
562 return result;
563}
564
565osStatus_t osKernelGetInfo(osVersion_t *version, char *id_buf, uint32_t id_size)
566{
567 if (version != nullptr)
568 {
569 version->api = STK_WRAPPER_API_VERSION;
571 }
572
573 if ((id_buf != nullptr) && (id_size > 0U))
574 {
575 const char *const id = STK_WRAPPER_KERNEL_ID;
576 size_t copy_len = id_size - 1U;
577 const size_t id_len = CmsisStrlen(id);
578 if (copy_len > id_len)
579 {
580 copy_len = id_len;
581 }
582
583 STK_MEMCPY(id_buf, id, copy_len);
584 id_buf[copy_len] = '\0';
585 }
586
587 return osOK;
588}
589
591{
592 osKernelState_t state;
593
594 if (g_StkKernelLocked != 0U)
595 {
596 state = osKernelLocked;
597 }
598 else
599 {
600 switch (g_StkKernel.GetState())
601 {
603 state = osKernelInactive;
604 break;
606 state = osKernelReady;
607 break;
609 state = osKernelRunning;
610 break;
612 state = osKernelSuspended;
613 break;
614 default:
615 state = osKernelError;
616 break;
617 }
618 }
619
620 return state;
621}
622
624{
625 osStatus_t result;
626
627 if (IsIrqContext())
628 {
629 result = osErrorISR;
630 }
631 else if (osKernelGetState() != osKernelReady)
632 {
633 result = osError;
634 }
635 else
636 {
637 // Start() does not return for KERNEL_STATIC;
638 // for KERNEL_DYNAMIC it returns when all tasks exit.
639 g_StkKernel.Start();
640 result = osOK;
641 }
642
643 return result;
644}
645
646int32_t osKernelLock(void)
647{
648 int32_t result;
649
650 if (IsIrqContext())
651 {
652 result = static_cast<int32_t>(osErrorISR);
653 }
654 else
655 {
658 result = 0;
659 }
660
661 return result;
662}
663
664int32_t osKernelUnlock(void)
665{
666 int32_t result;
667
668 if (IsIrqContext())
669 {
670 result = static_cast<int32_t>(osErrorISR);
671 }
672 else if (g_StkKernelLocked == 0U)
673 {
674 result = static_cast<int32_t>(osErrorResource);
675 }
676 else
677 {
680 result = 0;
681 }
682
683 return result;
684}
685
686int32_t osKernelRestoreLock(int32_t lock)
687{
688 int32_t result;
689
690 if (IsIrqContext())
691 {
692 result = static_cast<int32_t>(osErrorISR);
693 }
694 else if (lock == 1)
695 {
698 result = lock;
699 }
700 else if (g_StkKernelLocked == 0U)
701 {
702 result = static_cast<int32_t>(osErrorResource);
703 }
704 else
705 {
708 result = lock;
709 }
710
711 return result;
712}
713
714uint32_t osKernelSuspend(void)
715{
716 uint32_t result;
717
718#if STK_TICKLESS_IDLE
720 {
721 result = 0U;
722 }
723 else
724 {
725 result = static_cast<uint32_t>(stk::IKernelService::GetInstance()->Suspend());
726 }
727#else
728 // Not supported in non-tickless kernel.
729 result = 0U;
730#endif
731
732 return result;
733}
734
735void osKernelResume(uint32_t sleep_ticks)
736{
737#if STK_TICKLESS_IDLE
739 {
741 }
742#else
743 // Not supported in non-tickless kernel.
744 STK_UNUSED(sleep_ticks);
745#endif
746}
747
749{
750 uint32_t result;
751
753 {
754 result = 0U;
755 }
756 else
757 {
758 result = static_cast<uint32_t>(stk::GetTicks());
759 }
760
761 return result;
762}
763
765{
766 uint32_t result;
767
769 {
770 result = 1000U; // default 1 kHz
771 }
772 else
773 {
774 const int32_t res_us = stk::GetTickResolution(); // us per tick
775 if (res_us <= 0)
776 {
777 result = 1000U;
778 }
779 else
780 {
781 result = (1000000U / static_cast<uint32_t>(res_us));
782 }
783 }
784
785 return result;
786}
787
789{
790 return static_cast<uint32_t>(stk::GetSysTimerCount());
791}
792
794{
795 return stk::GetSysTimerCount();
796}
797
799{
801}
802
803
804// ===========================================================================
805// ==== Thread Management Functions ====
806// ===========================================================================
807
808osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)
809{
810 osThreadId_t result = nullptr;
811
812 const bool is_irq = IsIrqContext();
813 const osKernelState_t kernel_state = osKernelGetState();
814
815 // validate environment and arguments
816 bool is_valid = (!is_irq && (func != nullptr) && (kernel_state != osKernelInactive));
817
818 // validate priority value
819 osPriority_t cmsis_prio = osPriorityNormal;
820 if (is_valid && (attr != nullptr))
821 {
822 if (attr->priority != osPriorityNone)
823 {
824 cmsis_prio = attr->priority;
825 }
826
827 if ((cmsis_prio < osPriorityIdle) || (cmsis_prio > osPriorityISR))
828 {
829 is_valid = false; // invalidate object creation
830 }
831 }
832
833 if (is_valid)
834 {
835 const bool is_joinable = (attr != nullptr) && ((attr->attr_bits & osThreadJoinable) != 0U);
836 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
837 const uint32_t cb_size = ((attr != nullptr) ? attr->cb_size : 0U);
838
839 StkThread *th = PlacementNewOrHeap<StkThread>(cb_mem, cb_size);
840 if (th != nullptr)
841 {
842 th->m_func = func;
843 th->m_argument = argument;
844 th->m_name = (attr != nullptr) ? attr->name : nullptr;
846
847 // stack configuration
848 if (attr != nullptr)
849 {
850 if ((attr->stack_mem != nullptr) && (attr->stack_size != 0U))
851 {
852 th->m_stack = static_cast<stk::Word *>(attr->stack_mem);
854 th->m_stack_owned = false;
855 }
856 }
857
858 // allocate stack memory if not caller-provided
859 if (th->m_stack == nullptr)
860 {
861 const size_t stack_words = CMSIS_STK_DEFAULT_STACK_WORDS;
862
863 th->m_stack = new (std::nothrow) stk::Word[stack_words];
864 STK_ASSERT(th->m_stack != nullptr);
865
866 if (th->m_stack == nullptr)
867 {
868 ObjDestroy(th);
869 th = nullptr;
870 }
871 else
872 {
873 th->m_stack_size = stack_words;
874 th->m_stack_owned = true;
875 }
876 }
877
878 // finalize and register the thread
879 if (th != nullptr)
880 {
881 th->m_stk_priority = CmsisPrioToStk(cmsis_prio);
882 g_StkKernel.AddTask(th);
883 result = static_cast<osThreadId_t>(th);
884 }
885 }
886 }
887
888 return result; // The solitary exit point
889}
890
891const char *osThreadGetName(osThreadId_t thread_id)
892{
893 const char *result;
894
895 if (thread_id == nullptr)
896 {
897 result = nullptr;
898 }
899 else
900 {
901 result = static_cast<StkThread *>(thread_id)->m_name;
902 }
903
904 return result;
905}
906
908{
909 osThreadId_t threadId = nullptr;
910
911 const osKernelState_t kernel_state = osKernelGetState();
912 const bool is_irq = IsIrqContext();
913
914 if ((kernel_state != osKernelInactive) && !is_irq)
915 {
916 // STK's GetTid() returns the ITask pointer cast to Word.
918 }
919
920 return threadId;
921}
922
924{
925 osThreadState_t threadState = osThreadError;
926
927 if (!IsIrqContext() && (thread_id != nullptr))
928 {
929 const StkThread *const th = static_cast<StkThread *>(thread_id);
930
931 if (th->m_suspended)
932 {
933 threadState = osThreadBlocked;
934 }
935 else if (thread_id == osThreadGetId())
936 {
937 threadState = osThreadRunning;
938 }
939 else
940 {
941 threadState = osThreadReady;
942 }
943 }
944
945 return threadState;
946}
947
949{
950 uint32_t result;
951
952 if (thread_id == nullptr)
953 {
954 result = 0U;
955 }
956 else
957 {
958 StkThread *const th = static_cast<StkThread *>(thread_id);
959 result = static_cast<uint32_t>(th->GetStackSizeBytes());
960 }
961
962 return result;
963}
964
966{
967 uint32_t result;
968
969 if (thread_id == nullptr)
970 {
971 result = 0U;
972 }
973 else
974 {
975 StkThread *const th = static_cast<StkThread *>(thread_id);
976 result = static_cast<uint32_t>(th->GetStackSpace() * sizeof(stk::Word));
977 }
978
979 return result;
980}
981
983{
984 osStatus_t result;
985
986 if (IsIrqContext())
987 {
988 result = osErrorISR;
989 }
990 else if (thread_id == nullptr)
991 {
992 result = osErrorParameter;
993 }
994 else if ((priority < osPriorityIdle) || (priority > osPriorityISR))
995 {
996 result = osErrorParameter;
997 }
998 else
999 {
1000 StkThread *const th = static_cast<StkThread *>(thread_id);
1001 th->m_stk_priority = CmsisPrioToStk(priority);
1002 result = osOK;
1003 }
1004
1005 return result;
1006}
1007
1009{
1010 osPriority_t result;
1011
1012 if (IsIrqContext() || (thread_id == nullptr))
1013 {
1014 result = osPriorityError;
1015 }
1016 else
1017 {
1018 StkThread *const th = static_cast<StkThread *>(thread_id);
1019 result = StkPrioToCmsis(th->m_stk_priority);
1020 }
1021
1022 return result;
1023}
1024
1026{
1027 osStatus_t result;
1028
1029 if (IsIrqContext())
1030 {
1031 result = osErrorISR;
1032 }
1033 else if (osKernelGetState() == osKernelInactive)
1034 {
1035 result = osError;
1036 }
1037 else
1038 {
1039 stk::Yield();
1040 result = osOK;
1041 }
1042
1043 return result;
1044}
1045
1047{
1048 osStatus_t result;
1049
1050 if (IsIrqContext())
1051 {
1052 result = osErrorISR;
1053 }
1054 else if (thread_id == nullptr)
1055 {
1056 result = osErrorParameter;
1057 }
1058 else if (osKernelGetState() == osKernelInactive)
1059 {
1060 result = osErrorParameter;
1061 }
1062 else
1063 {
1064 StkThread *const th = static_cast<StkThread *>(thread_id);
1065 g_StkKernel.SuspendTask(th, th->m_suspended);
1066 result = osOK;
1067 }
1068
1069 return result;
1070}
1071
1073{
1074 osStatus_t result;
1075
1076 if (IsIrqContext())
1077 {
1078 result = osErrorISR;
1079 }
1080 else if (thread_id == nullptr)
1081 {
1082 result = osErrorParameter;
1083 }
1084 else if (osKernelGetState() == osKernelInactive)
1085 {
1086 result = osErrorParameter;
1087 }
1088 else
1089 {
1090 StkThread *const th = static_cast<StkThread *>(thread_id);
1091
1093
1094 if (!th->m_suspended)
1095 {
1096 result = osOK; // not suspended, nothing to do
1097 }
1098 else
1099 {
1100 g_StkKernel.ResumeTask(th);
1101 th->m_suspended = false;
1102 result = osOK;
1103 }
1104 }
1105
1106 return result;
1107}
1108
1110{
1111 osStatus_t result;
1112
1113 if (IsIrqContext())
1114 {
1115 result = osErrorISR;
1116 }
1117 else if (thread_id == nullptr)
1118 {
1119 result = osErrorParameter;
1120 }
1121 else
1122 {
1123 StkThread *const th = static_cast<StkThread *>(thread_id);
1124
1126
1127 switch (th->m_join_state)
1128 {
1130 // already detached - CMSIS spec says this is an error
1131 result = osError;
1132 break;
1133
1135 // already joined - cannot detach
1136 result = osError;
1137 break;
1138
1140 // thread finished but nobody joined yet, transition to Detached
1141 // and free the control block now, since no joiner will ever do it
1143 ObjDestroy(th); // safe: task slot already freed by the kernel
1144 result = osOK;
1145 break;
1146
1148 // normal case: thread is still running or just hasn't been joined
1150 result = osOK;
1151 break;
1152
1153 default:
1154 result = osError;
1155 break;
1156 }
1157 }
1158
1159 return result;
1160}
1161
1163{
1164 osStatus_t result;
1165
1166 if (IsIrqContext())
1167 {
1168 result = osErrorISR;
1169 }
1170 else if (thread_id == nullptr)
1171 {
1172 result = osErrorParameter;
1173 }
1174 // Self-join is undefined behavior per POSIX / CMSIS spec.
1175 else if (thread_id == osThreadGetId())
1176 {
1177 result = osErrorParameter;
1178 }
1179 else
1180 {
1181 StkThread *th = static_cast<StkThread *>(thread_id);
1182
1184
1185 // Only joinable threads can be joined.
1187 {
1188 result = osError;
1189 }
1190 // Double-join: second caller always gets an error.
1192 {
1193 result = osError;
1194 }
1195 else
1196 {
1198
1199 // Block until OnExit() fires (transitions state to Exited).
1200 // m_join_cv.Wait() atomically releases m_join_mutex and suspends.
1202 {
1203 // WAIT_INFINITE - CMSIS osThreadJoin has no timeout parameter.
1205 }
1206
1207 // At this point m_join_state == Exited (or Detached if someone
1208 // raced osThreadDetach - treat that as an error).
1210 {
1211 result = osError;
1212 }
1213 else
1214 {
1215 // Free the control block - the kernel has already freed the slot.
1216 ObjDestroy(th);
1217 result = osOK;
1218 }
1219 }
1220 }
1221
1222 return result;
1223}
1224
1226{
1227 StkThread *const th = static_cast<StkThread *>(osThreadGetId());
1228
1229 g_StkKernel.ScheduleTaskRemoval(th);
1230
1231 // Wait for removal.
1232 for (;;)
1233 {
1234 stk::Yield();
1235 }
1236}
1237
1239{
1241 const bool is_active = (osKernelGetState() != osKernelInactive);
1242
1243 if ((thread_id != nullptr) && !is_active)
1244 {
1245 StkThread *const th = static_cast<StkThread *>(thread_id);
1246
1247 // avoid race conditions during termination
1249
1250 // RemoveTask triggers the STATE_REMOVE_PENDING path in the kernel,
1251 // which will call OnExit() before freeing the slot.
1252 g_StkKernel.ScheduleTaskRemoval(th);
1253
1254 // For detached threads, free immediately (no joiner expected).
1255 // For joinable threads, OnExit() will wake the joiner; the joiner
1256 // calls ObjDestroy(). Do NOT free here.
1258 {
1259 ObjDestroy(th);
1260 }
1261 // else: joiner owns the lifetime
1262
1263 status = osOK;
1264 }
1265
1266 return status;
1267}
1268
1269uint32_t osThreadGetCount(void)
1270{
1271 uint32_t count = 0U;
1272
1274 {
1275 // avoid race with OnTick
1277
1278 count = static_cast<uint32_t>(g_StkKernel.GetSwitchStrategy()->GetSize());
1279 }
1280
1281 return count;
1282}
1283
1284uint32_t osThreadEnumerate(osThreadId_t *thread_array, uint32_t array_items)
1285{
1286 uint32_t result_count = 0U;
1287 const osKernelState_t kstate = osKernelGetState();
1288
1289 // kernel must be active and buffer must be valid
1290 if ((kstate != osKernelInactive) && (thread_array != nullptr) && (array_items != 0U))
1291 {
1292 // cast the raw pointer array to the expected ITask* destination type
1293 stk::ITask **const tasks_destination = reinterpret_cast<stk::ITask **>(
1294 reinterpret_cast<void *>(thread_array));
1295
1296 // bind raw destination buffer into a temporary ArrayView object
1297 const size_t count = g_StkKernel.EnumerateTasks(
1298 stk::ArrayView<stk::ITask *>(tasks_destination, static_cast<size_t>(array_items)));
1299
1300 result_count = static_cast<uint32_t>(count);
1301 }
1302
1303 return result_count;
1304}
1305
1306// ===========================================================================
1307// ==== Thread Flags Functions ====
1308// ===========================================================================
1309
1310uint32_t osThreadFlagsSet(osThreadId_t thread_id, uint32_t flags)
1311{
1312 uint32_t result;
1313
1314 if ((thread_id == nullptr) || ((flags & osFlagsError) != 0U))
1315 {
1316 result = osFlagsErrorParameter;
1317 }
1318 else
1319 {
1320 StkThread *th = static_cast<StkThread *>(thread_id);
1321 result = StkFlagsResultToCmsis(th->m_thread_flags.Set(flags));
1322 }
1323
1324 return result;
1325}
1326
1327uint32_t osThreadFlagsClear(uint32_t flags)
1328{
1329 uint32_t result;
1330
1331 osThreadId_t const self = osThreadGetId();
1332 if (self == nullptr)
1333 {
1334 result = osFlagsErrorUnknown;
1335 }
1336 else
1337 {
1338 StkThread *th = static_cast<StkThread *>(self);
1339 result = StkFlagsResultToCmsis(th->m_thread_flags.Clear(flags));
1340 }
1341
1342 return result;
1343}
1344
1345uint32_t osThreadFlagsGet(void)
1346{
1347 uint32_t result;
1348
1349 osThreadId_t const self = osThreadGetId();
1350 if (self == nullptr)
1351 {
1352 result = 0U;
1353 }
1354 else
1355 {
1356 result = static_cast<StkThread *>(self)->m_thread_flags.Get();
1357 }
1358
1359 return result;
1360}
1361
1362uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout)
1363{
1364 uint32_t result;
1365
1366 if (IsIrqContext())
1367 {
1368 result = osFlagsErrorISR;
1369 }
1370 else
1371 {
1372 osThreadId_t const self = osThreadGetId();
1373 if (self == nullptr)
1374 {
1375 result = osFlagsErrorUnknown;
1376 }
1377 else
1378 {
1379 StkThread *th = static_cast<StkThread *>(self);
1380 result = StkFlagsResultToCmsis(th->m_thread_flags.Wait(flags,
1381 CmsisFlagsOptionsToStk(options), CmsisTimeoutToStk(timeout)));
1382 }
1383 }
1384
1385 return result;
1386}
1387
1388
1389// ===========================================================================
1390// ==== Generic Wait Functions ====
1391// ===========================================================================
1392
1393osStatus_t osDelay(uint32_t ticks)
1394{
1395 osStatus_t result;
1396
1397 if (IsIrqContext())
1398 {
1399 result = osErrorISR;
1400 }
1401 else if (osKernelGetState() == osKernelInactive)
1402 {
1403 result = osError;
1404 }
1405 else
1406 {
1408 result = osOK;
1409 }
1410
1411 return result;
1412}
1413
1415{
1416 osStatus_t result;
1417
1418 if (IsIrqContext())
1419 {
1420 result = osErrorISR;
1421 }
1422 else if (osKernelGetState() == osKernelInactive)
1423 {
1424 result = osError;
1425 }
1426 else
1427 {
1428 result = (stk::SleepUntil(static_cast<stk::Ticks>(ticks)) ? osOK : osError);
1429 }
1430
1431 return result;
1432}
1433
1434
1435// ===========================================================================
1436// ==== Timer Management Functions ====
1437// ===========================================================================
1438
1440 const osTimerAttr_t *attr)
1441{
1442 osTimerId_t result;
1443
1444 if (IsIrqContext() || (func == nullptr))
1445 {
1446 result = nullptr;
1447 }
1448 else if (osKernelGetState() == osKernelInactive)
1449 {
1450 result = nullptr;
1451 }
1452 else
1453 {
1454 const char *const name = ((attr != nullptr) ? attr->name : nullptr);
1455 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
1456 const uint32_t cb_sz = ((attr != nullptr) ? attr->cb_size : 0U);
1457
1459
1460 StkTimer *const tmr = PlacementNewOrHeap<StkTimer>(cb_mem, cb_sz, func, type, argument, name);
1461 result = static_cast<osTimerId_t>(tmr);
1462 }
1463
1464 return result;
1465}
1466
1467const char *osTimerGetName(osTimerId_t timer_id)
1468{
1469 const char *result;
1470
1471 if (timer_id == nullptr)
1472 {
1473 result = nullptr;
1474 }
1475 else
1476 {
1477 result = static_cast<StkTimer *>(timer_id)->m_name;
1478 }
1479
1480 return result;
1481}
1482
1483osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks)
1484{
1485 osStatus_t result;
1486
1487 if (IsIrqContext())
1488 {
1489 result = osErrorISR;
1490 }
1491 else if ((timer_id == nullptr) || (g_TimerHost == nullptr))
1492 {
1493 result = osErrorParameter;
1494 }
1495 else
1496 {
1497 StkTimer *const tmr = static_cast<StkTimer *>(timer_id);
1498
1499 const uint32_t period_ticks = ((tmr->m_type == osTimerPeriodic) ? ticks : 0U);
1500 tmr->m_period_ticks = period_ticks;
1501
1502 const bool ok = g_TimerHost->Restart(*tmr, ticks, period_ticks);
1503 result = (ok ? osOK : osError);
1504 }
1505
1506 return result;
1507}
1508
1510{
1511 osStatus_t result;
1512
1513 if (IsIrqContext())
1514 {
1515 result = osErrorISR;
1516 }
1517 else if ((timer_id == nullptr) || (g_TimerHost == nullptr))
1518 {
1519 result = osErrorParameter;
1520 }
1521 else
1522 {
1523 StkTimer *const tmr = static_cast<StkTimer *>(timer_id);
1524
1525 if (!tmr->IsActive())
1526 {
1527 result = osErrorResource;
1528 }
1529 else
1530 {
1531 result = (g_TimerHost->Stop(*tmr) ? osOK : osError);
1532 }
1533 }
1534
1535 return result;
1536}
1537
1539{
1540 uint32_t result;
1541
1542 if (timer_id == nullptr)
1543 {
1544 result = 0U;
1545 }
1546 else
1547 {
1548 result = (static_cast<StkTimer *>(timer_id)->IsActive() ? 1U : 0U);
1549 }
1550
1551 return result;
1552}
1553
1555{
1556 osStatus_t result;
1557
1558 if (IsIrqContext())
1559 {
1560 result = osErrorISR;
1561 }
1562 else if ((timer_id == nullptr) || (g_TimerHost == nullptr))
1563 {
1564 result = osErrorParameter;
1565 }
1566 else
1567 {
1568 result = osOK;
1569
1570 StkTimer *const tmr = static_cast<StkTimer *>(timer_id);
1571
1572 if (tmr->IsActive())
1573 {
1574 if (!g_TimerHost->Stop(*tmr))
1575 {
1576 result = osError;
1577 }
1578 }
1579
1580 if (result == osOK)
1581 {
1582 ObjDestroy(tmr);
1583 }
1584 }
1585
1586 return result;
1587}
1588
1589
1590// ===========================================================================
1591// ==== Event Flags Management Functions ====
1592// ===========================================================================
1593
1595{
1596 osEventFlagsId_t result;
1597
1598 if (IsIrqContext())
1599 {
1600 result = nullptr;
1601 }
1602 else
1603 {
1604 const char *const name = ((attr != nullptr) ? attr->name : nullptr);
1605 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
1606 const uint32_t cb_sz = ((attr != nullptr) ? attr->cb_size : 0U);
1607
1608 StkEventFlags *const ef = PlacementNewOrHeap<StkEventFlags>(cb_mem, cb_sz, name);
1609 result = static_cast<osEventFlagsId_t>(ef);
1610 }
1611
1612 return result;
1613}
1614
1616{
1617 const char *result;
1618
1619 if (ef_id == nullptr)
1620 {
1621 result = nullptr;
1622 }
1623 else
1624 {
1625 result = static_cast<StkEventFlags *>(ef_id)->m_ef.GetTraceName();
1626 }
1627
1628 return result;
1629}
1630
1631uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags)
1632{
1633 uint32_t result;
1634
1635 if ((ef_id == nullptr) || ((flags & osFlagsError) != 0U))
1636 {
1637 result = osFlagsErrorParameter;
1638 }
1639 else
1640 {
1641 result = StkFlagsResultToCmsis(static_cast<StkEventFlags *>(ef_id)->m_ef.Set(flags));
1642 }
1643
1644 return result;
1645}
1646
1647uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags)
1648{
1649 uint32_t result;
1650
1651 if ((ef_id == nullptr) || ((flags & osFlagsError) != 0U))
1652 {
1653 result = osFlagsErrorParameter;
1654 }
1655 else
1656 {
1657 result = StkFlagsResultToCmsis(static_cast<StkEventFlags *>(ef_id)->m_ef.Clear(flags));
1658 }
1659
1660 return result;
1661}
1662
1664{
1665 uint32_t result;
1666
1667 if (ef_id == nullptr)
1668 {
1669 result = 0U;
1670 }
1671 else
1672 {
1673 result = static_cast<StkEventFlags *>(ef_id)->m_ef.Get();
1674 }
1675
1676 return result;
1677}
1678
1679uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options,
1680 uint32_t timeout)
1681{
1682 uint32_t result;
1683
1684 if ((ef_id == nullptr) || ((flags & osFlagsError) != 0U))
1685 {
1686 result = osFlagsErrorParameter;
1687 }
1688 else
1689 {
1690 result = StkFlagsResultToCmsis(static_cast<StkEventFlags *>(ef_id)->m_ef.Wait(flags,
1691 CmsisFlagsOptionsToStk(options), CmsisTimeoutToStk(timeout)));
1692 }
1693
1694 return result;
1695}
1696
1698{
1699 osStatus_t result;
1700
1701 if (IsIrqContext())
1702 {
1703 result = osErrorISR;
1704 }
1705 else if (ef_id == nullptr)
1706 {
1707 result = osErrorParameter;
1708 }
1709 else
1710 {
1711 ObjDestroy(static_cast<StkEventFlags *>(ef_id));
1712 result = osOK;
1713 }
1714
1715 return result;
1716}
1717
1718
1719// ===========================================================================
1720// ==== Mutex Management Functions ====
1721// ===========================================================================
1722
1724{
1725 osMutexId_t result;
1726
1727 if (IsIrqContext())
1728 {
1729 result = nullptr;
1730 }
1731 else
1732 {
1733 // osMutexPrioInherit: ignored, supported by default.
1734 // osMutexRecursive: ignored, sync::Mutex is always recursive.
1735 // osMutexRobust: will assert as unsafe code.
1736 const char *const name = ((attr != nullptr) ? attr->name : nullptr);
1737 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
1738 const uint32_t cb_sz = ((attr != nullptr) ? attr->cb_size : 0U);
1739 const bool robust = ((attr != nullptr) && ((attr->attr_bits & osMutexRobust) != 0U));
1740
1741 // disallow osMutexRobust
1742 STK_ASSERT(!robust);
1743 if (robust)
1744 {
1745 result = nullptr;
1746 }
1747 else
1748 {
1749 StkMutex *const m = PlacementNewOrHeap<StkMutex>(cb_mem, cb_sz, name);
1750 result = static_cast<osMutexId_t>(m);
1751 }
1752 }
1753
1754 return result;
1755}
1756
1757const char *osMutexGetName(osMutexId_t mutex_id)
1758{
1759 const char *result;
1760
1761 if (mutex_id == nullptr)
1762 {
1763 result = nullptr;
1764 }
1765 else
1766 {
1767 result = static_cast<StkMutex *>(mutex_id)->m_mutex.GetTraceName();
1768 }
1769
1770 return result;
1771}
1772
1773osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout)
1774{
1775 osStatus_t result;
1776
1777 if (IsIrqContext())
1778 {
1779 result = osErrorISR;
1780 }
1781 else if (mutex_id == nullptr)
1782 {
1783 result = osErrorParameter;
1784 }
1785 else
1786 {
1787 StkMutex *m = static_cast<StkMutex *>(mutex_id);
1788 const stk::Timeout stk_timeout = CmsisTimeoutToStk(timeout);
1789
1790 const bool acquired = m->m_mutex.TimedLock(stk_timeout);
1791 if (!acquired)
1792 {
1793 result = ((stk_timeout == stk::NO_WAIT) ? osErrorResource : osErrorTimeout);
1794 }
1795 else
1796 {
1797 result = osOK;
1798 }
1799 }
1800
1801 return result;
1802}
1803
1805{
1806 osStatus_t result;
1807
1808 if (IsIrqContext())
1809 {
1810 result = osErrorISR;
1811 }
1812 else if (mutex_id == nullptr)
1813 {
1814 result = osErrorParameter;
1815 }
1816 else
1817 {
1818 static_cast<StkMutex *>(mutex_id)->m_mutex.Unlock();
1819 result = osOK;
1820 }
1821
1822 return result;
1823}
1824
1826{
1827 osThreadId_t result;
1828
1829 if (mutex_id == nullptr)
1830 {
1831 result = nullptr;
1832 }
1833 else
1834 {
1836 static_cast<StkMutex *>(mutex_id)->m_mutex.GetOwner());
1837 }
1838
1839 return result;
1840}
1841
1843{
1844 osStatus_t result;
1845
1846 if (IsIrqContext())
1847 {
1848 result = osErrorISR;
1849 }
1850 else if (mutex_id == nullptr)
1851 {
1852 result = osErrorParameter;
1853 }
1854 else
1855 {
1856 ObjDestroy(static_cast<StkMutex *>(mutex_id));
1857 result = osOK;
1858 }
1859
1860 return result;
1861}
1862
1863
1864// ===========================================================================
1865// ==== Semaphore Management Functions ====
1866// ===========================================================================
1867
1868osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count,
1869 const osSemaphoreAttr_t *attr)
1870{
1871 osSemaphoreId_t result;
1872
1873 if (IsIrqContext() || (max_count == 0U) || (initial_count > max_count))
1874 {
1875 result = nullptr;
1876 }
1877 else
1878 {
1879 // STK Semaphore uses uint16_t counters, clamp to stk::sync::Semaphore::COUNT_MAX.
1880 const uint16_t mc = static_cast<uint16_t>(stk::Min(max_count, static_cast<uint32_t>(stk::sync::Semaphore::COUNT_MAX)));
1881 const uint16_t ic = static_cast<uint16_t>(stk::Min(initial_count, static_cast<uint32_t>(stk::sync::Semaphore::COUNT_MAX)));
1882
1883 const char *const name = ((attr != nullptr) ? attr->name : nullptr);
1884 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
1885 const uint32_t cb_sz = ((attr != nullptr) ? attr->cb_size : 0U);
1886
1887 StkSemaphore *const sem = PlacementNewOrHeap<StkSemaphore>(cb_mem, cb_sz, ic, mc, name);
1888 result = static_cast<osSemaphoreId_t>(sem);
1889 }
1890
1891 return result;
1892}
1893
1894const char *osSemaphoreGetName(osSemaphoreId_t semaphore_id)
1895{
1896 const char *result;
1897
1898 if (semaphore_id == nullptr)
1899 {
1900 result = nullptr;
1901 }
1902 else
1903 {
1904 result = static_cast<StkSemaphore *>(semaphore_id)->m_semaphore.GetTraceName();
1905 }
1906
1907 return result;
1908}
1909
1910osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout)
1911{
1912 osStatus_t result;
1913
1914 if (semaphore_id == nullptr)
1915 {
1916 result = osErrorParameter;
1917 }
1918 else if (IsIrqContext() && (timeout != 0U))
1919 {
1920 result = osErrorISR;
1921 }
1922 else
1923 {
1924 StkSemaphore *sem = static_cast<StkSemaphore *>(semaphore_id);
1925 const stk::Timeout stk_timeout = CmsisTimeoutToStk(timeout);
1926
1927 const bool acquired = sem->m_semaphore.Wait(stk_timeout);
1928 if (!acquired)
1929 {
1930 result = ((stk_timeout == stk::NO_WAIT) ? osErrorResource : osErrorTimeout);
1931 }
1932 else
1933 {
1934 result = osOK;
1935 }
1936 }
1937
1938 return result;
1939}
1940
1942{
1943 osStatus_t result;
1944
1945 if (semaphore_id == nullptr)
1946 {
1947 result = osErrorParameter;
1948 }
1949 else
1950 {
1951 static_cast<StkSemaphore *>(semaphore_id)->m_semaphore.Signal();
1952 result = osOK;
1953 }
1954
1955 return result;
1956}
1957
1959{
1960 uint32_t result;
1961
1962 if (semaphore_id == nullptr)
1963 {
1964 result = 0U;
1965 }
1966 else
1967 {
1968 result = static_cast<uint32_t>(
1969 static_cast<StkSemaphore *>(semaphore_id)->m_semaphore.GetCount());
1970 }
1971
1972 return result;
1973}
1974
1976{
1977 osStatus_t result;
1978
1979 if (IsIrqContext())
1980 {
1981 result = osErrorISR;
1982 }
1983 else if (semaphore_id == nullptr)
1984 {
1985 result = osErrorParameter;
1986 }
1987 else
1988 {
1989 ObjDestroy(static_cast<StkSemaphore *>(semaphore_id));
1990 result = osOK;
1991 }
1992
1993 return result;
1994}
1995
1996
1997// ===========================================================================
1998// ==== Memory Pool Management Functions ====
1999// ===========================================================================
2000
2001osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size,
2002 const osMemoryPoolAttr_t *attr)
2003{
2004 osMemoryPoolId_t result;
2005
2006 // ISR context: forbidden per CMSIS spec.
2007 // Zero capacity or zero block size are meaningless.
2008 if (IsIrqContext() || (block_count == 0U) || (block_size == 0U))
2009 {
2010 result = nullptr;
2011 }
2012 else
2013 {
2014 const char *const name = ((attr != nullptr) ? attr->name : nullptr);
2015 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
2016 const uint32_t cb_sz = ((attr != nullptr) ? attr->cb_size : 0U);
2017 void *const mp_mem = ((attr != nullptr) ? attr->mp_mem : nullptr);
2018 const uint32_t mp_sz = ((attr != nullptr) ? attr->mp_size : 0U);
2019
2020 // Compute the aligned block size and required storage byte count.
2021 const uint32_t aligned_blk = stk::memory::BlockMemoryPool::AlignBlockSize(block_size);
2022 const uint32_t storage_required = (block_count * aligned_blk);
2023
2024 StkMemPool *pool;
2025
2026 if ((mp_mem != nullptr) && (mp_sz >= storage_required))
2027 {
2028 // Caller-supplied pool storage - BlockMemoryPool external-storage ctor.
2029 pool = PlacementNewOrHeap<StkMemPool>(cb_mem, cb_sz,
2030 block_count, block_size, name, static_cast<uint8_t *>(mp_mem));
2031 }
2032 else
2033 {
2034 // Heap-allocated pool storage - BlockMemoryPool heap ctor.
2035 pool = PlacementNewOrHeap<StkMemPool>(cb_mem, cb_sz,
2036 block_count, block_size, name);
2037
2038 // If the heap ctor failed to allocate storage, clean up and bail.
2039 if ((pool != nullptr) && !pool->m_mpool.IsStorageValid())
2040 {
2041 ObjDestroy(pool);
2042 pool = nullptr;
2043 }
2044 }
2045
2046 result = static_cast<osMemoryPoolId_t>(pool);
2047 }
2048
2049 return result;
2050}
2051
2053{
2054 const char *result;
2055
2056 if (mp_id == nullptr)
2057 {
2058 result = nullptr;
2059 }
2060 else
2061 {
2062 result = static_cast<StkMemPool *>(mp_id)->m_mpool.GetTraceName();
2063 }
2064
2065 return result;
2066}
2067
2068void *osMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout)
2069{
2070 void *result;
2071
2072 if (mp_id == nullptr)
2073 {
2074 result = nullptr;
2075 }
2076 // ISR context is only valid with timeout == 0 (NO_WAIT / TryAlloc).
2077 else if (IsIrqContext() && (timeout != 0U))
2078 {
2079 result = nullptr;
2080 }
2081 else
2082 {
2083 result = static_cast<StkMemPool *>(mp_id)->m_mpool.TimedAlloc(CmsisTimeoutToStk(timeout));
2084 }
2085
2086 return result;
2087}
2088
2090{
2091 osStatus_t result;
2092
2093 if ((mp_id == nullptr) || (block == nullptr))
2094 {
2095 result = osErrorParameter;
2096 }
2097 else if (!static_cast<StkMemPool *>(mp_id)->m_mpool.Free(block))
2098 {
2099 result = osErrorParameter; // ptr not from this pool
2100 }
2101 else
2102 {
2103 result = osOK;
2104 }
2105
2106 return result;
2107}
2108
2110{
2111 uint32_t result;
2112
2113 if (mp_id == nullptr)
2114 {
2115 result = 0U;
2116 }
2117 else
2118 {
2119 result = static_cast<StkMemPool *>(mp_id)->m_mpool.GetCapacity();
2120 }
2121
2122 return result;
2123}
2124
2126{
2127 uint32_t result;
2128
2129 if (mp_id == nullptr)
2130 {
2131 result = 0U;
2132 }
2133 else
2134 {
2135 result = static_cast<uint32_t>(static_cast<StkMemPool *>(mp_id)->m_mpool.GetBlockSize());
2136 }
2137
2138 return result;
2139}
2140
2142{
2143 uint32_t result;
2144
2145 if (mp_id == nullptr)
2146 {
2147 result = 0U;
2148 }
2149 else
2150 {
2151 result = static_cast<StkMemPool *>(mp_id)->m_mpool.GetUsedCount();
2152 }
2153
2154 return result;
2155}
2156
2158{
2159 uint32_t result;
2160
2161 if (mp_id == nullptr)
2162 {
2163 result = 0U;
2164 }
2165 else
2166 {
2167 result = static_cast<StkMemPool *>(mp_id)->m_mpool.GetFreeCount();
2168 }
2169
2170 return result;
2171}
2172
2174{
2175 osStatus_t result;
2176
2177 if (IsIrqContext())
2178 {
2179 result = osErrorISR;
2180 }
2181 else if (mp_id == nullptr)
2182 {
2183 result = osErrorParameter;
2184 }
2185 else
2186 {
2187 ObjDestroy(static_cast<StkMemPool *>(mp_id));
2188 result = osOK;
2189 }
2190
2191 return result;
2192}
2193
2194
2195// ===========================================================================
2196// ==== Message Queue Management Functions ====
2197// ===========================================================================
2198
2199osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size,
2200 const osMessageQueueAttr_t *attr)
2201{
2202 osMessageQueueId_t result;
2203
2204 if (IsIrqContext() || (msg_count == 0U) || (msg_size == 0U) ||
2206 {
2207 result = nullptr;
2208 }
2209 else
2210 {
2211 const char *const name = ((attr != nullptr) ? attr->name : nullptr);
2212 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
2213 const uint32_t cb_sz = ((attr != nullptr) ? attr->cb_size : 0U);
2214 void *const ext_buf = ((attr != nullptr) ? attr->mq_mem : nullptr);
2215 const uint32_t ext_buf_size = ((attr != nullptr) ? attr->mq_size : 0U);
2216
2217 const uint32_t buf_required = (msg_count * msg_size);
2218
2219 StkMessageQueue *mq;
2220
2221 if ((ext_buf != nullptr) && (ext_buf_size >= buf_required))
2222 {
2223 // Data buffer: use caller-supplied memory.
2224 mq = PlacementNewOrHeap<StkMessageQueue>(cb_mem, cb_sz,
2225 msg_count, msg_size, name, static_cast<uint8_t *>(ext_buf));
2226 }
2227 else
2228 {
2229 // Data buffer: heap-allocated inside StkMessageQueue constructor.
2230 mq = PlacementNewOrHeap<StkMessageQueue>(cb_mem, cb_sz,
2231 msg_count, msg_size, name);
2232
2233 // Validate
2234 if (mq != nullptr)
2235 {
2236 if (mq->m_mq.GetBuffer() == nullptr)
2237 {
2238 ObjDestroy(mq);
2239 mq = nullptr;
2240 }
2241 }
2242 }
2243
2244 result = static_cast<osMessageQueueId_t>(mq);
2245 }
2246
2247 return result;
2248}
2249
2251{
2252 const char *result;
2253
2254 if (mq_id == nullptr)
2255 {
2256 result = nullptr;
2257 }
2258 else
2259 {
2260 result = static_cast<StkMessageQueue *>(mq_id)->m_mq.GetTraceName();
2261 }
2262
2263 return result;
2264}
2265
2267 uint8_t /*msg_prio*/, uint32_t timeout)
2268{
2269 osStatus_t result;
2270
2271 if ((mq_id == nullptr) || (msg_ptr == nullptr))
2272 {
2273 result = osErrorParameter;
2274 }
2275 else if (IsIrqContext() && (timeout != 0U))
2276 {
2277 result = osErrorISR;
2278 }
2279 else
2280 {
2281 const stk::Timeout stk_timeout = CmsisTimeoutToStk(timeout);
2282
2283 if (!static_cast<StkMessageQueue *>(mq_id)->m_mq.Put(msg_ptr, stk_timeout))
2284 {
2285 result = ((stk_timeout == stk::NO_WAIT) ? osErrorResource : osErrorTimeout);
2286 }
2287 else
2288 {
2289 result = osOK;
2290 }
2291 }
2292
2293 return result;
2294}
2295
2297 uint8_t *msg_prio, uint32_t timeout)
2298{
2299 osStatus_t result;
2300
2301 if ((mq_id == nullptr) || (msg_ptr == nullptr))
2302 {
2303 result = osErrorParameter;
2304 }
2305 else if (IsIrqContext() && (timeout != 0U))
2306 {
2307 result = osErrorISR;
2308 }
2309 else
2310 {
2311 const stk::Timeout stk_timeout = CmsisTimeoutToStk(timeout);
2312
2313 if (!static_cast<StkMessageQueue *>(mq_id)->m_mq.Get(msg_ptr, stk_timeout))
2314 {
2315 result = ((stk_timeout == stk::NO_WAIT) ? osErrorResource : osErrorTimeout);
2316 }
2317 else
2318 {
2319 if (msg_prio != nullptr)
2320 {
2321 *msg_prio = 0U; // STK queues have no priority lanes.
2322 }
2323 result = osOK;
2324 }
2325 }
2326
2327 return result;
2328}
2329
2331{
2332 uint32_t result;
2333
2334 if (mq_id == nullptr)
2335 {
2336 result = 0U;
2337 }
2338 else
2339 {
2340 result = static_cast<uint32_t>(static_cast<StkMessageQueue *>(mq_id)->m_mq.GetCapacity());
2341 }
2342
2343 return result;
2344}
2345
2347{
2348 uint32_t result;
2349
2350 if (mq_id == nullptr)
2351 {
2352 result = 0U;
2353 }
2354 else
2355 {
2356 result = static_cast<uint32_t>(static_cast<StkMessageQueue *>(mq_id)->m_mq.GetMsgSize());
2357 }
2358
2359 return result;
2360}
2361
2363{
2364 uint32_t result;
2365
2366 if (mq_id == nullptr)
2367 {
2368 result = 0U;
2369 }
2370 else
2371 {
2372 result = static_cast<uint32_t>(static_cast<StkMessageQueue *>(mq_id)->m_mq.GetCount());
2373 }
2374
2375 return result;
2376}
2377
2379{
2380 uint32_t result;
2381
2382 if (mq_id == nullptr)
2383 {
2384 result = 0U;
2385 }
2386 else
2387 {
2388 result = static_cast<uint32_t>(static_cast<StkMessageQueue *>(mq_id)->m_mq.GetSpace());
2389 }
2390
2391 return result;
2392}
2393
2395{
2396 osStatus_t result;
2397
2398 if (IsIrqContext())
2399 {
2400 result = osErrorISR;
2401 }
2402 else if (mq_id == nullptr)
2403 {
2404 result = osErrorParameter;
2405 }
2406 else
2407 {
2408 static_cast<StkMessageQueue *>(mq_id)->m_mq.Reset();
2409 result = osOK;
2410 }
2411
2412 return result;
2413}
2414
2416{
2417 osStatus_t result;
2418
2419 if (IsIrqContext())
2420 {
2421 result = osErrorISR;
2422 }
2423 else if (mq_id == nullptr)
2424 {
2425 result = osErrorParameter;
2426 }
2427 else
2428 {
2429 ObjDestroy(static_cast<StkMessageQueue *>(mq_id));
2430 result = osOK;
2431 }
2432
2433 return result;
2434}
Collection of memory-related primitives (stk::memory namespace).
Top-level STK include. Provides the Kernel class template and all built-in task-switching strategies.
static __stk_forceinline void STK_MEMCPY(void *const dest, const void *const src, const size_t size)
A wrapper for a built-in memcpy, redefine to your own if required.
Definition stk_arch.h:534
#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 synchronization primitives (stk::sync namespace).
Collection of time-related primitives (stk::time namespace).
static constexpr size_t StkGetWordCountForType()
void * malloc(size_t size)
void free(void *ptr)
CMSIS RTOS2 interface for SuperTinyKernel RTOS.
#define __NO_RETURN
Definition cmsis_os2.h:80
static size_t CmsisStrlen(const char str[])
stk::Kernel< stk::KERNEL_DYNAMIC|stk::KERNEL_SYNC|stk::KERNEL_TICKLESS,(16U), stk::SwitchStrategyFP32, stk::PlatformDefault > StkKernel
static uint32_t g_StkKernelLocked
static StkKernel g_StkKernel
static __stk_forceinline bool IsIrqContext()
static __stk_forceinline uint32_t StkFlagsResultToCmsis(uint32_t result)
static stk::time::TimerHost * g_TimerHost
static constexpr size_t StkGetWordCountForType()
#define CMSIS_STK_MIN_STACK_WORDS
#define CMSIS_STK_MAX_THREADS
static stk::Word g_TimerHostBuf[StkGetWordCountForType< stk::time::TimerHost >()]
static __stk_forceinline stk::Timeout CmsisTimeoutToStk(uint32_t ticks)
void * malloc(size_t size)
static void ObjDestroy(T *obj)
#define CMSIS_STK_DEFAULT_STACK_WORDS
#define STK_WRAPPER_KERNEL_VERSION
#define STK_WRAPPER_KERNEL_ID
static __stk_forceinline osPriority_t StkPrioToCmsis(int32_t p)
static __stk_forceinline uint32_t CmsisFlagsOptionsToStk(uint32_t options)
static __stk_forceinline int32_t CmsisPrioToStk(osPriority_t p)
static T * PlacementNewOrHeap(void *mem, size_t size, const Args &... args)
#define STK_WRAPPER_API_VERSION
void free(void *ptr)
#define osFlagsError
Error indicator.
Definition cmsis_os2.h:254
uint32_t osMemoryPoolGetSpace(osMemoryPoolId_t mp_id)
osKernelState_t
Kernel state.
Definition cmsis_os2.h:155
osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id)
osPriority_t osThreadGetPriority(osThreadId_t thread_id)
const char * osMutexGetName(osMutexId_t mutex_id)
void * osMessageQueueId_t
Definition cmsis_os2.h:329
#define osThreadJoinable
Thread created in joinable mode.
Definition cmsis_os2.h:264
osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr)
void * osMutexId_t
Definition cmsis_os2.h:320
osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr)
#define osFlagsErrorTimeout
osErrorTimeout (-2).
Definition cmsis_os2.h:256
osStatus_t osThreadTerminate(osThreadId_t thread_id)
uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags)
#define osFlagsErrorUnknown
osError (-1).
Definition cmsis_os2.h:255
osStatus_t osDelayUntil(uint32_t ticks)
osStatus_t osThreadResume(osThreadId_t thread_id)
osStatus_t osThreadJoin(osThreadId_t thread_id)
osKernelState_t osKernelGetState(void)
osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)
uint32_t osThreadGetCount(void)
osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr)
uint64_t osKernelGetSysTimerCount64(void)
uint32_t osKernelGetSysTimerFreq(void)
uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout)
uint32_t osThreadEnumerate(osThreadId_t *thread_array, uint32_t array_items)
const char * osEventFlagsGetName(osEventFlagsId_t ef_id)
void * osSemaphoreId_t
Definition cmsis_os2.h:323
void * osThreadId_t
Definition cmsis_os2.h:311
uint32_t osThreadFlagsClear(uint32_t flags)
uint32_t osTimerIsRunning(osTimerId_t timer_id)
uint32_t osMessageQueueGetCount(osMessageQueueId_t mq_id)
osStatus_t
Status code values returned by CMSIS-RTOS functions.
Definition cmsis_os2.h:297
osStatus_t osKernelGetInfo(osVersion_t *version, char *id_buf, uint32_t id_size)
uint32_t osThreadFlagsSet(osThreadId_t thread_id, uint32_t flags)
uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id)
void osThreadExit(void)
Terminate execution of current running thread.
void(* osTimerFunc_t)(void *argument)
Timer callback function.
Definition cmsis_os2.h:237
const char * osTimerGetName(osTimerId_t timer_id)
uint32_t osKernelGetTickFreq(void)
osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id)
osTimerType_t
Timer type.
Definition cmsis_os2.h:240
osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout)
osThreadId_t osMutexGetOwner(osMutexId_t mutex_id)
osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id)
uint32_t osKernelGetTickCount(void)
uint32_t osThreadFlagsGet(void)
osStatus_t osThreadSetPriority(osThreadId_t thread_id, osPriority_t priority)
#define osFlagsWaitAll
Wait for all flags.
Definition cmsis_os2.h:250
uint32_t osEventFlagsGet(osEventFlagsId_t ef_id)
osStatus_t osMemoryPoolDelete(osMemoryPoolId_t mp_id)
void osKernelResume(uint32_t sleep_ticks)
osThreadId_t osThreadGetId(void)
void * osMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout)
void(* osThreadFunc_t)(void *argument)
Entry point of a thread.
Definition cmsis_os2.h:234
uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags)
int32_t osKernelLock(void)
const char * osSemaphoreGetName(osSemaphoreId_t semaphore_id)
uint32_t osMemoryPoolGetCount(osMemoryPoolId_t mp_id)
uint32_t osMessageQueueGetMsgSize(osMessageQueueId_t mq_id)
osStatus_t osKernelStart(void)
uint32_t osThreadGetStackSpace(osThreadId_t thread_id)
osStatus_t osMessageQueuePut(osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout)
#define osFlagsErrorParameter
osErrorParameter (-4).
Definition cmsis_os2.h:258
osStatus_t osThreadSuspend(osThreadId_t thread_id)
osStatus_t osThreadDetach(osThreadId_t thread_id)
#define osFlagsNoClear
Do not clear flags which have been specified to wait for.
Definition cmsis_os2.h:251
osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr)
uint32_t osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id)
const char * osMemoryPoolGetName(osMemoryPoolId_t mp_id)
osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks)
osMutexId_t osMutexNew(const osMutexAttr_t *attr)
uint32_t osThreadGetStackSize(osThreadId_t thread_id)
osStatus_t osMessageQueueDelete(osMessageQueueId_t mq_id)
osStatus_t osMemoryPoolFree(osMemoryPoolId_t mp_id, void *block)
osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout)
osStatus_t osTimerStop(osTimerId_t timer_id)
void * osMemoryPoolId_t
Definition cmsis_os2.h:326
osStatus_t osMutexDelete(osMutexId_t mutex_id)
uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout)
void * osTimerId_t
Definition cmsis_os2.h:314
uint32_t osMessageQueueGetCapacity(osMessageQueueId_t mq_id)
const char * osThreadGetName(osThreadId_t thread_id)
osStatus_t osMessageQueueReset(osMessageQueueId_t mq_id)
osThreadState_t osThreadGetState(osThreadId_t thread_id)
osStatus_t osTimerDelete(osTimerId_t timer_id)
osStatus_t osThreadYield(void)
osThreadState_t
Thread state.
Definition cmsis_os2.h:166
osPriority_t
Priority values.
Definition cmsis_os2.h:177
osTimerId_t osTimerNew(osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr)
uint32_t osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id)
osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout)
uint32_t osMessageQueueGetSpace(osMessageQueueId_t mq_id)
uint32_t osKernelGetSysTimerCount(void)
uint32_t osKernelSuspend(void)
const char * osMessageQueueGetName(osMessageQueueId_t mq_id)
int32_t osKernelRestoreLock(int32_t lock)
osStatus_t osKernelInitialize(void)
#define osFlagsErrorISR
osErrorISR (-6).
Definition cmsis_os2.h:259
osStatus_t osMutexRelease(osMutexId_t mutex_id)
void * osEventFlagsId_t
Definition cmsis_os2.h:317
#define osMutexRobust
Robust mutex.
Definition cmsis_os2.h:280
int32_t osKernelUnlock(void)
osStatus_t osDelay(uint32_t ticks)
@ osKernelLocked
Locked.
Definition cmsis_os2.h:159
@ osKernelError
Error.
Definition cmsis_os2.h:161
@ osKernelSuspended
Suspended.
Definition cmsis_os2.h:160
@ osKernelReady
Ready.
Definition cmsis_os2.h:157
@ osKernelRunning
Running.
Definition cmsis_os2.h:158
@ osKernelInactive
Inactive.
Definition cmsis_os2.h:156
@ osErrorISR
Not allowed in ISR context: the function cannot be called from interrupt service routines.
Definition cmsis_os2.h:304
@ osErrorResource
Resource not available.
Definition cmsis_os2.h:301
@ osErrorTimeout
Operation not completed within the timeout period.
Definition cmsis_os2.h:300
@ osOK
Operation completed successfully.
Definition cmsis_os2.h:298
@ osError
Unspecified RTOS error: run-time error but no other error message fits.
Definition cmsis_os2.h:299
@ osErrorParameter
Parameter error.
Definition cmsis_os2.h:302
@ osTimerPeriodic
Repeating timer.
Definition cmsis_os2.h:242
@ osThreadBlocked
Blocked.
Definition cmsis_os2.h:170
@ osThreadRunning
Running.
Definition cmsis_os2.h:169
@ osThreadError
Error.
Definition cmsis_os2.h:172
@ osThreadReady
Ready.
Definition cmsis_os2.h:168
@ osPriorityISR
Reserved for ISR deferred thread.
Definition cmsis_os2.h:228
@ osPriorityNormal
Priority: normal.
Definition cmsis_os2.h:196
@ osPriorityIdle
Reserved for Idle thread.
Definition cmsis_os2.h:179
@ osPriorityNone
No priority (not initialized).
Definition cmsis_os2.h:178
@ osPriorityError
System cannot determine priority or illegal priority.
Definition cmsis_os2.h:229
Namespace of STK package.
uintptr_t Word
Native processor word type.
Definition stk_common.h:115
static void Yield()
Notify scheduler to switch to the next runnable task.
Definition stk_helper.h:408
SwitchStrategyFixedPriority< 32 > SwitchStrategyFP32
Shorthand alias for SwitchStrategyFixedPriority<32>: 32 priority levels (0..31), using a single 32-bi...
static void Sleep(Timeout tick_count)
Put calling process into a sleep state.
Definition stk_helper.h:364
EAccessMode
Hardware access mode by the user task.
Definition stk_common.h:32
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
Definition stk_common.h:34
constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:189
int64_t Ticks
Ticks value.
Definition stk_common.h:130
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:125
static constexpr T Max(T a, T b)
Compile-time maximum of two values.
Definition stk_defs.h:625
static bool SleepUntil(Ticks timestamp)
Put calling process into a sleep state until the specified timestamp.
Definition stk_helper.h:389
static uint32_t GetTickResolution()
Get number of microseconds in one tick.
Definition stk_helper.h:253
static uint32_t GetSysTimerFrequency()
Get system timer frequency.
Definition stk_helper.h:353
static Ticks GetTicks()
Get number of ticks elapsed since kernel start.
Definition stk_helper.h:319
PlatformArmCortexM PlatformDefault
Default platform implementation.
constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:183
static TId GetTid()
Get task/thread Id of the calling task.
Definition stk_helper.h:243
static constexpr T Min(T a, T b)
Compile-time minimum of two values.
Definition stk_defs.h:619
static Cycles GetSysTimerCount()
Get system timer count value.
Definition stk_helper.h:344
Word TId
Task (thread) id.
Definition stk_common.h:120
@ KERNEL_TICKLESS
Tickless mode. To use this mode STK_TICKLESS_IDLE must be defined to 1 in stk_config....
Definition stk_common.h:46
@ KERNEL_SYNC
Synchronization support (see Event).
Definition stk_common.h:45
@ KERNEL_DYNAMIC
Tasks can be added or removed and therefore exit when done.
Definition stk_common.h:43
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
static void Free(void *ptr) __stk_weak
Free the memory chunk.
static void * Allocate(size_t size) __stk_weak
Allocate the memory chunk.
Fixed-size block allocator with O(1) alloc/free and proper task-blocking semantics.
bool IsStorageValid() const
Verify that the backing storage is valid and the pool is ready for use.
static constexpr size_t AlignBlockSize(size_t raw_size)
Round a raw block size up to the nearest multiple of BLOCK_ALIGN.
size_t GetBlockSize() const
Get the aligned block size used internally by the allocator.
Concrete implementation of IKernel.
Definition stk.h:85
static void Enter()
Enter a critical section.
static void Exit()
Exit a critical section.
Lightweight, non-owning view over a contiguous sequence of elements.
Definition stk_common.h:226
virtual size_t GetStackSpace() const
Get available stack space.
Definition stk_common.h:319
Interface for a user task.
Definition stk_common.h:599
@ KSTATE_RUNNING
Initialized and running, IKernel::Start() was called successfully.
@ KSTATE_SUSPENDED
Scheduling is suspended with IKernelService::Suspend().
@ KSTATE_INACTIVE
Not ready, IKernel::Initialize() must be called.
@ KSTATE_READY
Ready to start, IKernel::Start() must be called.
static IKernelService * GetInstance()
Get CPU-local instance of the kernel service.
virtual void Resume(Timeout elapsed_ticks)=0
Resume scheduling after a prior Suspend() call.
virtual Timeout Suspend()=0
Suspend scheduling.
RAII-style low-level synchronization primitive for atomic code execution. Used as building brick for ...
Definition stk_sync_cs.h:54
Condition Variable primitive for signaling between tasks based on specific predicates.
Definition stk_sync_cv.h:68
bool Wait(IMutex &mutex, Timeout timeout_ticks=WAIT_INFINITE)
Wait for a signal.
32-bit event flags group for multi-flag synchronization between tasks.
uint32_t Wait(uint32_t flags, uint32_t options=OPT_WAIT_ANY, Timeout timeout_ticks=WAIT_INFINITE)
Wait for one or more flags to be set.
static const uint32_t ERROR_ISR
Return sentinel: called from an ISR with a blocking timeout.
static const uint32_t ERROR_TIMEOUT
Return sentinel: wait timed out before the flags condition was met.
static bool IsError(uint32_t result)
Checks if a return value from Set(), Clear(), or Wait() is an error.
static const uint32_t OPT_NO_CLEAR
Do not clear matched flags after a successful wait.
static const uint32_t ERROR_PARAMETER
Return sentinel: invalid flags argument (bit 31 set).
static const uint32_t OPT_WAIT_ALL
Wait for ALL of the specified flags to be set simultaneously (AND semantics).
uint32_t Clear(uint32_t flags)
Clear one or more flags.
static const uint32_t OPT_WAIT_ANY
Wait for ANY of the specified flags to be set (OR semantics, default).
uint32_t Set(uint32_t flags)
Set one or more flags.
Fixed-capacity, fixed-message-size FIFO queue for inter-task communication.
size_t GetCapacity() const
Get the maximum number of messages the queue can hold.
static const size_t CAPACITY_MAX
Max capacity supported (number of messages).
size_t GetMsgSize() const
Get the size of each message in bytes.
size_t GetSpace() const
Get the number of free slots currently available.
size_t GetCount() const
Get the current number of messages in the queue.
uint8_t * GetBuffer()
Get pointer to the message buffer.
Recursive mutex primitive that allows the same thread to acquire the lock multiple times.
bool TimedLock(Timeout timeout_ticks)
Acquire lock.
Counting semaphore primitive for resource management and signaling.
uint16_t GetCount() const
Get current counter value.
static const uint16_t COUNT_MAX
Max count value supported.
bool Wait(Timeout timeout_ticks=WAIT_INFINITE)
Wait for a signal (decrement counter).
Software timer multiplexer that manages multiple Timer instances on top of a small fixed set of kerne...
Abstract base class for a timer managed by TimerHost.
bool IsActive() const
Check whether the timer is currently active.
Version information.
Definition cmsis_os2.h:149
uint32_t api
API version (major.minor.rev: mmnnnrrrr dec).
Definition cmsis_os2.h:150
uint32_t kernel
Kernel version (major.minor.rev: mmnnnrrrr dec).
Definition cmsis_os2.h:151
Attributes structure for thread.
Definition cmsis_os2.h:340
void * cb_mem
memory for control block
Definition cmsis_os2.h:343
uint32_t attr_bits
attribute bits
Definition cmsis_os2.h:342
uint32_t cb_size
size of provided memory for control block
Definition cmsis_os2.h:344
void * stack_mem
memory for stack
Definition cmsis_os2.h:345
osPriority_t priority
initial thread priority (default: osPriorityNormal)
Definition cmsis_os2.h:347
uint32_t stack_size
size of stack
Definition cmsis_os2.h:346
const char * name
name of the thread
Definition cmsis_os2.h:341
Attributes structure for timer.
Definition cmsis_os2.h:353
void * cb_mem
memory for control block
Definition cmsis_os2.h:356
const char * name
name of the timer
Definition cmsis_os2.h:354
uint32_t cb_size
size of provided memory for control block
Definition cmsis_os2.h:357
Attributes structure for event flags.
Definition cmsis_os2.h:361
uint32_t cb_size
size of provided memory for control block
Definition cmsis_os2.h:365
const char * name
name of the event flags
Definition cmsis_os2.h:362
void * cb_mem
memory for control block
Definition cmsis_os2.h:364
Attributes structure for mutex.
Definition cmsis_os2.h:369
uint32_t cb_size
size of provided memory for control block
Definition cmsis_os2.h:373
uint32_t attr_bits
attribute bits
Definition cmsis_os2.h:371
const char * name
name of the mutex
Definition cmsis_os2.h:370
void * cb_mem
memory for control block
Definition cmsis_os2.h:372
Attributes structure for semaphore.
Definition cmsis_os2.h:377
const char * name
name of the semaphore
Definition cmsis_os2.h:378
uint32_t cb_size
size of provided memory for control block
Definition cmsis_os2.h:381
void * cb_mem
memory for control block
Definition cmsis_os2.h:380
Attributes structure for memory pool.
Definition cmsis_os2.h:385
uint32_t mp_size
size of provided memory for data storage
Definition cmsis_os2.h:391
const char * name
name of the memory pool
Definition cmsis_os2.h:386
void * cb_mem
memory for control block
Definition cmsis_os2.h:388
uint32_t cb_size
size of provided memory for control block
Definition cmsis_os2.h:389
void * mp_mem
memory for data storage
Definition cmsis_os2.h:390
Attributes structure for message queue.
Definition cmsis_os2.h:395
const char * name
name of the message queue
Definition cmsis_os2.h:396
void * cb_mem
memory for control block
Definition cmsis_os2.h:398
uint32_t mq_size
size of provided memory for data storage
Definition cmsis_os2.h:401
uint32_t cb_size
size of provided memory for control block
Definition cmsis_os2.h:399
void * mq_mem
memory for data storage
Definition cmsis_os2.h:400
const stk::Word * GetStack() const override
Get pointer to the stack memory.
int32_t GetWeight() const override
Get static base weight of the task.
void OnExit() override
Called by the kernel before removal from the scheduling (see stk::KERNEL_DYNAMIC).
size_t GetStackSizeBytes() const override
Get size of the memory in bytes.
stk::Word * m_stack
size_t m_stack_size
STK_NONCOPYABLE_CLASS(StkThread)
const char * GetTraceName() const override
Get task trace name set by application.
volatile JoinState m_join_state
static osThreadId_t ConvertTIdToThreadId(const stk::TId tid)
size_t GetStackSize() const override
Get number of elements of the stack memory array.
stk::sync::EventFlags m_thread_flags
void Run() override
Entry point of the user task.
stk::sync::ConditionVariable m_join_cv
volatile int32_t m_stk_priority
osThreadFunc_t m_func
const char * m_name
stk::EAccessMode GetAccessMode() const override
Get hardware access mode of the user task.
virtual ~StkThread()
void * m_argument
void OnDeadlineMissed(uint32_t) override
Called by the scheduler if deadline of the task is missed when Kernel is operating in Hard Real-Time ...
StkMutex(const char *n=nullptr)
stk::sync::Mutex m_mutex
stk::sync::Semaphore m_semaphore
StkSemaphore(uint16_t initial, uint16_t max_count, const char *n=nullptr)
stk::sync::EventFlags m_ef
StkEventFlags(const char *n=nullptr)
STK_NONCOPYABLE_CLASS(StkTimer)
static void EnsureTimerHostCreated()
void OnExpired(stk::time::TimerHost *) override
Callback invoked by the handler task when this timer expires.
virtual ~StkTimer()=default
StkTimer(osTimerFunc_t const func, osTimerType_t tt, void *arg, const char *name)
osTimerType_t m_type
void * m_argument
const char * m_name
osTimerFunc_t m_func
uint32_t m_period_ticks
StkMemPool(uint32_t cap, uint32_t raw_block_size, const char *name)
STK_NONCOPYABLE_CLASS(StkMemPool)
stk::memory::BlockMemoryPool m_mpool
StkMemPool(uint32_t cap, uint32_t raw_block_size, const char *name, uint8_t *ext_storage)
StkMessageQueue(uint32_t cap, uint32_t msz, const char *name, uint8_t *ext_buf)
StkMessageQueue(uint32_t cap, uint32_t msz, const char *name)
static uint8_t * AllocBuffer(uint32_t cap, uint32_t msz)
STK_NONCOPYABLE_CLASS(StkMessageQueue)
stk::sync::MessageQueue m_mq