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
224 // ---- ITask ----
226 void OnDeadlineMissed(uint32_t) override {}
227 int32_t GetWeight() const override { return m_stk_priority; }
228 const char *GetTraceName() const override { return m_name; }
229
231 {
232 // tid is hw::PtrToWord(this) where 'this' is the StkThread* - cast it back.
233 return reinterpret_cast<osThreadId_t>(static_cast<void *>(
234 reinterpret_cast<StkThread *>(static_cast<uintptr_t>(tid))));
235 }
236
237 // ---- Members ----
240 const char *m_name;
241 volatile int32_t m_stk_priority; // STK priority level 0..31
242 stk::Word *m_stack; // pointer to stack memory (may be owned)
243 size_t m_stack_size; // stack size in Words
244 volatile JoinState m_join_state; // guarded by m_join_mutex between other tasks
246 stk::sync::EventFlags m_thread_flags; // Per-thread event flags - backed by STK's native 32-bit EventFlags primitive.
247 bool m_stack_owned; // true if we allocated the stack ourselves
248 bool m_suspended; // true if suspended
249 bool m_cb_owned; // true -> heap-allocated control block, delete on Terminate(), false -> caller-supplied cb_mem, call destructor explicitly
250};
251
252// -----------------------------------------------------------------------------
253// Mutex control block
254// -----------------------------------------------------------------------------
255
257{
258 explicit StkMutex(const char *n = nullptr) : m_mutex(), m_cb_owned(true)
259 {
260 m_mutex.SetTraceName(n);
261 }
262
263 // ---- Members ----
265 bool m_cb_owned; // true -> heap-allocated, false -> placement-new in caller memory
266};
267
268// -----------------------------------------------------------------------------
269// Semaphore control block
270// -----------------------------------------------------------------------------
271
273{
274 explicit StkSemaphore(uint16_t initial, uint16_t max_count, const char *n = nullptr)
275 : m_semaphore(initial, max_count), m_cb_owned(true)
276 {
277 m_semaphore.SetTraceName(n);
278 }
279
280 // ---- Members ----
282 bool m_cb_owned; // true -> heap-allocated, false -> placement-new in caller memory
283};
284
285// -----------------------------------------------------------------------------
286// Event flags control block
287//
288// Backed directly by stk::sync::EventFlags - STK's native 32-bit multi-flag
289// synchronization primitive (Set/Clear/Get/Wait with ANY/ALL/NO_CLEAR options,
290// ISR-safe Set/Clear, absolute-deadline wait loop).
291// -----------------------------------------------------------------------------
292
294{
295 explicit StkEventFlags(const char *n = nullptr) : m_ef(0U), m_cb_owned(true)
296 {
297 m_ef.SetTraceName(n);
298 }
299
300 // ---- Members ----
302 bool m_cb_owned; // true -> heap-allocated, false -> placement-new in caller memory
303};
304
305// -----------------------------------------------------------------------------
306// Timer control block
307//
308// CMSIS timers are backed by stk::time::TimerHost.
309// A single global TimerHost is created on first osTimerNew().
310// -----------------------------------------------------------------------------
311
314
316{
318
319public:
320 explicit StkTimer(osTimerFunc_t const func, osTimerType_t tt, void *arg, const char *name)
321 : m_func(func), m_argument(arg), m_type(tt), m_name(name), m_period_ticks(0U), m_cb_owned(true)
322 {}
323 virtual ~StkTimer() = default;
324
325 void OnExpired(stk::time::TimerHost * /*host*/) override
326 {
328 }
329
331 {
332 if (g_TimerHost == nullptr)
333 {
336 }
337 }
338
339 // ---- Members ----
343 const char *m_name;
344 uint32_t m_period_ticks; // stored period for restart
345 bool m_cb_owned; // true -> heap-allocated, false -> placement-new in caller memory
346};
347
348// -----------------------------------------------------------------------------
349// Memory pool control block
350//
351// Backed directly by stk::memory::BlockMemoryPool.
352// -----------------------------------------------------------------------------
353
355{
357
358public:
359 // Construct with caller-supplied pool storage (storage_owned = false).
360 explicit StkMemPool(uint32_t cap, uint32_t raw_block_size,
361 const char *name, uint8_t *ext_storage)
362 : m_mpool(static_cast<size_t>(cap),
363 static_cast<size_t>(raw_block_size),
364 ext_storage,
365 cap * stk::memory::BlockMemoryPool::AlignBlockSize(raw_block_size),
366 name),
367 m_cb_owned(true)
368 {}
369
370 // Construct with heap-allocated pool storage (storage_owned = true).
371 explicit StkMemPool(uint32_t cap, uint32_t raw_block_size, const char *name)
372 : m_mpool(static_cast<size_t>(cap),
373 static_cast<size_t>(raw_block_size),
374 name),
375 m_cb_owned(true)
376 {}
377
378 // ---- Members ----
380 bool m_cb_owned; // true -> heap-allocated; false -> placement-new in caller memory
381};
382
383// -----------------------------------------------------------------------------
384// Message queue control block
385//
386// Backed by stk::sync::MessageQueue - STK's native fixed-capacity, fixed-
387// message-size FIFO ring-buffer with integrated blocking semantics (Put/Get
388// with WAIT_INFINITE / NO_WAIT / timed variants, ISR-safe TryPut/TryGet).
389//
390// Two independent memory regions are managed:
391//
392// Control block (cb_mem / cb_size in osMessageQueueAttr_t):
393// Policy identical to all other object types - PlacementNewOrHeap selects
394// placement-new into caller memory when cb_mem != nullptr and cb_size is
395// sufficient, otherwise heap. m_cb_owned tracks whether to free on Delete().
396//
397// Data buffer (mq_mem / mq_size in osMessageQueueAttr_t):
398// 1. Caller-supplied: attr->mq_mem / attr->mq_size are used as-is when the
399// region is large enough to hold (msg_count * msg_size) bytes.
400// 2. Dynamic fallback: heap buffer of (msg_count * msg_size) bytes.
401// Allocated buffer is freed in the destructor.
402// -----------------------------------------------------------------------------
403
405{
407
408public:
409 // Construct with a caller-supplied data buffer.
410 explicit StkMessageQueue(uint32_t cap, uint32_t msz, const char *name,uint8_t *ext_buf)
411 : m_mq(ext_buf, static_cast<size_t>(cap), static_cast<size_t>(msz)),
412 m_bf_owned(false), m_cb_owned(true)
413 {
414 m_mq.SetTraceName(name);
415 }
416
417 // Construct with a heap-allocated data buffer.
418 explicit StkMessageQueue(uint32_t cap, uint32_t msz, const char *name)
419 : m_mq(AllocBuffer(cap, msz), static_cast<size_t>(cap), static_cast<size_t>(msz)),
420 m_bf_owned(m_mq.IsStorageValid()), m_cb_owned(true)
421 {
422 m_mq.SetTraceName(name);
423 }
424
426 {
427 if (m_bf_owned)
428 {
429 delete[] m_mq.GetBuffer();
430 }
431 }
432
433 static uint8_t *AllocBuffer(uint32_t cap, uint32_t msz)
434 {
435 uint8_t *const ret = new (std::nothrow) uint8_t[static_cast<size_t>(cap) * msz];
436 STK_ASSERT(ret != nullptr); // fail in Debug: increase Heap size in linker settings
437 return ret;
438 }
439
440 // ---- Members ----
441 stk::sync::MessageQueue m_mq; // STK native message queue (owns blocking semantics)
442 bool m_bf_owned; // true -> when we heap-allocated the data buffer, false otherwise
443 bool m_cb_owned; // true -> heap-allocated control block (delete on Delete())
444 // false -> placement-new in caller memory (call dtor only)
445};
446
447// -----------------------------------------------------------------------------
448// Internal helpers
449// -----------------------------------------------------------------------------
450
451// Placement-new helper: construct T in caller-supplied memory when the block
452// is large enough; otherwise fall back to heap (operator new).
453// Sets obj->m_cb_owned = false for caller-supplied, true for heap.
454// Returns nullptr if heap fallback is needed but allocation fails.
455template <typename T, typename... Args>
456static T *PlacementNewOrHeap(void *mem, size_t size, const Args &... args)
457{
458 T *obj;
459
460 if ((mem != nullptr) && (size >= sizeof(T)))
461 {
462 obj = new (mem) T(args...);
463 obj->m_cb_owned = false;
464 }
465 else
466 {
467 obj = new (std::nothrow) T(args...);
468 // m_cb_owned is already true from the constructor default
469 STK_ASSERT(obj != nullptr);
470 }
471
472 return obj;
473}
474
475// Destroy an object created by PlacementNewOrHeap:
476// - m_cb_owned == false -> call destructor only (memory is caller's)
477// - m_cb_owned == true -> delete (destructor + free)
478template <typename T>
479static void ObjDestroy(T *obj)
480{
481 if (obj->m_cb_owned)
482 {
483 delete obj;
484 }
485 else
486 {
487 obj->~T();
488 }
489}
490
491// Helper: map CMSIS flags options -> STK EventFlags options bitmask.
492static __stk_forceinline uint32_t CmsisFlagsOptionsToStk(uint32_t options)
493{
494 uint32_t stk_opts = stk::sync::EventFlags::OPT_WAIT_ANY; // default
495
496 if ((options & osFlagsWaitAll) != 0U)
497 {
499 }
500
501 if ((options & osFlagsNoClear) != 0U)
502 {
504 }
505
506 return stk_opts;
507}
508
509// Helper: map STK EventFlags error sentinel -> CMSIS flags error code.
510static __stk_forceinline uint32_t StkFlagsResultToCmsis(uint32_t result)
511{
512 uint32_t cmsis_result;
513
515 {
516 cmsis_result = result;
517 }
518 else if (result == stk::sync::EventFlags::ERROR_TIMEOUT)
519 {
520 cmsis_result = osFlagsErrorTimeout;
521 }
523 {
524 cmsis_result = osFlagsErrorParameter;
525 }
526 else if (result == stk::sync::EventFlags::ERROR_ISR)
527 {
528 cmsis_result = osFlagsErrorISR;
529 }
530 else
531 {
532 cmsis_result = osFlagsErrorUnknown;
533 }
534
535 return cmsis_result;
536}
537
538
539// ===========================================================================
540// ==== Kernel Management Functions ====
541// ===========================================================================
542
544{
545 osStatus_t result;
546
547 if (IsIrqContext())
548 {
549 result = osErrorISR;
550 }
552 {
553 result = osError;
554 }
555 else
556 {
557 g_StkKernel.Initialize(); // default 1 ms tick resolution
558 result = osOK;
559 }
560
561 return result;
562}
563
564osStatus_t osKernelGetInfo(osVersion_t *version, char *id_buf, uint32_t id_size)
565{
566 if (version != nullptr)
567 {
568 version->api = STK_WRAPPER_API_VERSION;
570 }
571
572 if ((id_buf != nullptr) && (id_size > 0U))
573 {
574 const char *const id = STK_WRAPPER_KERNEL_ID;
575 size_t copy_len = id_size - 1U;
576 const size_t id_len = CmsisStrlen(id);
577 if (copy_len > id_len)
578 {
579 copy_len = id_len;
580 }
581
582 STK_MEMCPY(id_buf, id, copy_len);
583 id_buf[copy_len] = '\0';
584 }
585
586 return osOK;
587}
588
590{
591 osKernelState_t state;
592
593 if (g_StkKernelLocked != 0U)
594 {
595 state = osKernelLocked;
596 }
597 else
598 {
599 switch (g_StkKernel.GetState())
600 {
602 state = osKernelInactive;
603 break;
605 state = osKernelReady;
606 break;
608 state = osKernelRunning;
609 break;
611 state = osKernelSuspended;
612 break;
613 default:
614 state = osKernelError;
615 break;
616 }
617 }
618
619 return state;
620}
621
623{
624 osStatus_t result;
625
626 if (IsIrqContext())
627 {
628 result = osErrorISR;
629 }
630 else if (osKernelGetState() != osKernelReady)
631 {
632 result = osError;
633 }
634 else
635 {
636 // Start() does not return for KERNEL_STATIC;
637 // for KERNEL_DYNAMIC it returns when all tasks exit.
638 g_StkKernel.Start();
639 result = osOK;
640 }
641
642 return result;
643}
644
645int32_t osKernelLock(void)
646{
647 int32_t result;
648
649 if (IsIrqContext())
650 {
651 result = static_cast<int32_t>(osErrorISR);
652 }
653 else
654 {
657 result = 0;
658 }
659
660 return result;
661}
662
663int32_t osKernelUnlock(void)
664{
665 int32_t result;
666
667 if (IsIrqContext())
668 {
669 result = static_cast<int32_t>(osErrorISR);
670 }
671 else if (g_StkKernelLocked == 0U)
672 {
673 result = static_cast<int32_t>(osErrorResource);
674 }
675 else
676 {
679 result = 0;
680 }
681
682 return result;
683}
684
685int32_t osKernelRestoreLock(int32_t lock)
686{
687 int32_t result;
688
689 if (IsIrqContext())
690 {
691 result = static_cast<int32_t>(osErrorISR);
692 }
693 else if (lock == 1)
694 {
697 result = lock;
698 }
699 else if (g_StkKernelLocked == 0U)
700 {
701 result = static_cast<int32_t>(osErrorResource);
702 }
703 else
704 {
707 result = lock;
708 }
709
710 return result;
711}
712
713uint32_t osKernelSuspend(void)
714{
715 uint32_t result;
716
717#if STK_TICKLESS_IDLE
719 {
720 result = 0U;
721 }
722 else
723 {
724 result = static_cast<uint32_t>(stk::IKernelService::GetInstance()->Suspend());
725 }
726#else
727 // Not supported in non-tickless kernel.
728 result = 0U;
729#endif
730
731 return result;
732}
733
734void osKernelResume(uint32_t sleep_ticks)
735{
736#if STK_TICKLESS_IDLE
738 {
740 }
741#else
742 // Not supported in non-tickless kernel.
743 STK_UNUSED(sleep_ticks);
744#endif
745}
746
748{
749 uint32_t result;
750
752 {
753 result = 0U;
754 }
755 else
756 {
757 result = static_cast<uint32_t>(stk::GetTicks());
758 }
759
760 return result;
761}
762
764{
765 uint32_t result;
766
768 {
769 result = 1000U; // default 1 kHz
770 }
771 else
772 {
773 const int32_t res_us = stk::GetTickResolution(); // us per tick
774 if (res_us <= 0)
775 {
776 result = 1000U;
777 }
778 else
779 {
780 result = (1000000U / static_cast<uint32_t>(res_us));
781 }
782 }
783
784 return result;
785}
786
788{
789 return static_cast<uint32_t>(stk::GetSysTimerCount());
790}
791
793{
794 return stk::GetSysTimerCount();
795}
796
798{
800}
801
802
803// ===========================================================================
804// ==== Thread Management Functions ====
805// ===========================================================================
806
807osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)
808{
809 osThreadId_t result = nullptr;
810
811 const bool is_irq = IsIrqContext();
812 const osKernelState_t kernel_state = osKernelGetState();
813
814 // validate environment and arguments
815 bool is_valid = (!is_irq && (func != nullptr) && (kernel_state != osKernelInactive));
816
817 // validate priority value
818 osPriority_t cmsis_prio = osPriorityNormal;
819 if (is_valid && (attr != nullptr))
820 {
821 if (attr->priority != osPriorityNone)
822 {
823 cmsis_prio = attr->priority;
824 }
825
826 if ((cmsis_prio < osPriorityIdle) || (cmsis_prio > osPriorityISR))
827 {
828 is_valid = false; // invalidate object creation
829 }
830 }
831
832 if (is_valid)
833 {
834 const bool is_joinable = (attr != nullptr) && ((attr->attr_bits & osThreadJoinable) != 0U);
835 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
836 const uint32_t cb_size = ((attr != nullptr) ? attr->cb_size : 0U);
837
838 StkThread *th = PlacementNewOrHeap<StkThread>(cb_mem, cb_size);
839 if (th != nullptr)
840 {
841 th->m_func = func;
842 th->m_argument = argument;
843 th->m_name = (attr != nullptr) ? attr->name : nullptr;
845
846 // stack configuration
847 if (attr != nullptr)
848 {
849 if ((attr->stack_mem != nullptr) && (attr->stack_size != 0U))
850 {
851 th->m_stack = static_cast<stk::Word *>(attr->stack_mem);
853 th->m_stack_owned = false;
854 }
855 }
856
857 // allocate stack memory if not caller-provided
858 if (th->m_stack == nullptr)
859 {
860 const size_t stack_words = CMSIS_STK_DEFAULT_STACK_WORDS;
861
862 th->m_stack = new (std::nothrow) stk::Word[stack_words];
863 STK_ASSERT(th->m_stack != nullptr);
864
865 if (th->m_stack == nullptr)
866 {
867 ObjDestroy(th);
868 th = nullptr;
869 }
870 else
871 {
872 th->m_stack_size = stack_words;
873 th->m_stack_owned = true;
874 }
875 }
876
877 // finalize and register the thread
878 if (th != nullptr)
879 {
880 th->m_stk_priority = CmsisPrioToStk(cmsis_prio);
881 g_StkKernel.AddTask(th);
882 result = static_cast<osThreadId_t>(th);
883 }
884 }
885 }
886
887 return result; // The solitary exit point
888}
889
890const char *osThreadGetName(osThreadId_t thread_id)
891{
892 const char *result;
893
894 if (thread_id == nullptr)
895 {
896 result = nullptr;
897 }
898 else
899 {
900 result = static_cast<StkThread *>(thread_id)->m_name;
901 }
902
903 return result;
904}
905
907{
908 osThreadId_t threadId = nullptr;
909
910 const osKernelState_t kernel_state = osKernelGetState();
911 const bool is_irq = IsIrqContext();
912
913 if ((kernel_state != osKernelInactive) && !is_irq)
914 {
915 // STK's GetTid() returns the ITask pointer cast to Word.
917 }
918
919 return threadId;
920}
921
923{
924 osThreadState_t threadState = osThreadError;
925
926 if (!IsIrqContext() && (thread_id != nullptr))
927 {
928 const StkThread *const th = static_cast<StkThread *>(thread_id);
929
930 if (th->m_suspended)
931 {
932 threadState = osThreadBlocked;
933 }
934 else if (thread_id == osThreadGetId())
935 {
936 threadState = osThreadRunning;
937 }
938 else
939 {
940 threadState = osThreadReady;
941 }
942 }
943
944 return threadState;
945}
946
948{
949 uint32_t result;
950
951 if (thread_id == nullptr)
952 {
953 result = 0U;
954 }
955 else
956 {
957 StkThread *const th = static_cast<StkThread *>(thread_id);
958 result = static_cast<uint32_t>(th->GetStackSize()) * sizeof(stk::Word);
959 }
960
961 return result;
962}
963
965{
966 uint32_t result;
967
968 if (thread_id == nullptr)
969 {
970 result = 0U;
971 }
972 else
973 {
974 StkThread *const th = static_cast<StkThread *>(thread_id);
975 result = static_cast<uint32_t>(th->GetStackSpace() * sizeof(stk::Word));
976 }
977
978 return result;
979}
980
982{
983 osStatus_t result;
984
985 if (IsIrqContext())
986 {
987 result = osErrorISR;
988 }
989 else if (thread_id == nullptr)
990 {
991 result = osErrorParameter;
992 }
993 else if ((priority < osPriorityIdle) || (priority > osPriorityISR))
994 {
995 result = osErrorParameter;
996 }
997 else
998 {
999 StkThread *const th = static_cast<StkThread *>(thread_id);
1000 th->m_stk_priority = CmsisPrioToStk(priority);
1001 result = osOK;
1002 }
1003
1004 return result;
1005}
1006
1008{
1009 osPriority_t result;
1010
1011 if (IsIrqContext() || (thread_id == nullptr))
1012 {
1013 result = osPriorityError;
1014 }
1015 else
1016 {
1017 StkThread *const th = static_cast<StkThread *>(thread_id);
1018 result = StkPrioToCmsis(th->m_stk_priority);
1019 }
1020
1021 return result;
1022}
1023
1025{
1026 osStatus_t result;
1027
1028 if (IsIrqContext())
1029 {
1030 result = osErrorISR;
1031 }
1032 else if (osKernelGetState() == osKernelInactive)
1033 {
1034 result = osError;
1035 }
1036 else
1037 {
1038 stk::Yield();
1039 result = osOK;
1040 }
1041
1042 return result;
1043}
1044
1046{
1047 osStatus_t result;
1048
1049 if (IsIrqContext())
1050 {
1051 result = osErrorISR;
1052 }
1053 else if (thread_id == nullptr)
1054 {
1055 result = osErrorParameter;
1056 }
1057 else if (osKernelGetState() == osKernelInactive)
1058 {
1059 result = osErrorParameter;
1060 }
1061 else
1062 {
1063 StkThread *const th = static_cast<StkThread *>(thread_id);
1064 g_StkKernel.SuspendTask(th, th->m_suspended);
1065 result = osOK;
1066 }
1067
1068 return result;
1069}
1070
1072{
1073 osStatus_t result;
1074
1075 if (IsIrqContext())
1076 {
1077 result = osErrorISR;
1078 }
1079 else if (thread_id == nullptr)
1080 {
1081 result = osErrorParameter;
1082 }
1083 else if (osKernelGetState() == osKernelInactive)
1084 {
1085 result = osErrorParameter;
1086 }
1087 else
1088 {
1089 StkThread *const th = static_cast<StkThread *>(thread_id);
1090
1092
1093 if (!th->m_suspended)
1094 {
1095 result = osOK; // not suspended, nothing to do
1096 }
1097 else
1098 {
1099 g_StkKernel.ResumeTask(th);
1100 th->m_suspended = false;
1101 result = osOK;
1102 }
1103 }
1104
1105 return result;
1106}
1107
1109{
1110 osStatus_t result;
1111
1112 if (IsIrqContext())
1113 {
1114 result = osErrorISR;
1115 }
1116 else if (thread_id == nullptr)
1117 {
1118 result = osErrorParameter;
1119 }
1120 else
1121 {
1122 StkThread *const th = static_cast<StkThread *>(thread_id);
1123
1125
1126 switch (th->m_join_state)
1127 {
1129 // already detached - CMSIS spec says this is an error
1130 result = osError;
1131 break;
1132
1134 // already joined - cannot detach
1135 result = osError;
1136 break;
1137
1139 // thread finished but nobody joined yet, transition to Detached
1140 // and free the control block now, since no joiner will ever do it
1142 ObjDestroy(th); // safe: task slot already freed by the kernel
1143 result = osOK;
1144 break;
1145
1147 // normal case: thread is still running or just hasn't been joined
1149 result = osOK;
1150 break;
1151
1152 default:
1153 result = osError;
1154 break;
1155 }
1156 }
1157
1158 return result;
1159}
1160
1162{
1163 osStatus_t result;
1164
1165 if (IsIrqContext())
1166 {
1167 result = osErrorISR;
1168 }
1169 else if (thread_id == nullptr)
1170 {
1171 result = osErrorParameter;
1172 }
1173 // Self-join is undefined behavior per POSIX / CMSIS spec.
1174 else if (thread_id == osThreadGetId())
1175 {
1176 result = osErrorParameter;
1177 }
1178 else
1179 {
1180 StkThread *th = static_cast<StkThread *>(thread_id);
1181
1183
1184 // Only joinable threads can be joined.
1186 {
1187 result = osError;
1188 }
1189 // Double-join: second caller always gets an error.
1191 {
1192 result = osError;
1193 }
1194 else
1195 {
1197
1198 // Block until OnExit() fires (transitions state to Exited).
1199 // m_join_cv.Wait() atomically releases m_join_mutex and suspends.
1201 {
1202 // WAIT_INFINITE - CMSIS osThreadJoin has no timeout parameter.
1204 }
1205
1206 // At this point m_join_state == Exited (or Detached if someone
1207 // raced osThreadDetach - treat that as an error).
1209 {
1210 result = osError;
1211 }
1212 else
1213 {
1214 // Free the control block - the kernel has already freed the slot.
1215 ObjDestroy(th);
1216 result = osOK;
1217 }
1218 }
1219 }
1220
1221 return result;
1222}
1223
1225{
1226 StkThread *const th = static_cast<StkThread *>(osThreadGetId());
1227
1228 g_StkKernel.ScheduleTaskRemoval(th);
1229
1230 // Wait for removal.
1231 for (;;)
1232 {
1233 stk::Yield();
1234 }
1235}
1236
1238{
1240 const bool is_active = (osKernelGetState() != osKernelInactive);
1241
1242 if ((thread_id != nullptr) && !is_active)
1243 {
1244 StkThread *const th = static_cast<StkThread *>(thread_id);
1245
1246 // avoid race conditions during termination
1248
1249 // RemoveTask triggers the STATE_REMOVE_PENDING path in the kernel,
1250 // which will call OnExit() before freeing the slot.
1251 g_StkKernel.ScheduleTaskRemoval(th);
1252
1253 // For detached threads, free immediately (no joiner expected).
1254 // For joinable threads, OnExit() will wake the joiner; the joiner
1255 // calls ObjDestroy(). Do NOT free here.
1257 {
1258 ObjDestroy(th);
1259 }
1260 // else: joiner owns the lifetime
1261
1262 status = osOK;
1263 }
1264
1265 return status;
1266}
1267
1268uint32_t osThreadGetCount(void)
1269{
1270 uint32_t count = 0U;
1271
1273 {
1274 // avoid race with OnTick
1276
1277 count = static_cast<uint32_t>(g_StkKernel.GetSwitchStrategy()->GetSize());
1278 }
1279
1280 return count;
1281}
1282
1283uint32_t osThreadEnumerate(osThreadId_t *thread_array, uint32_t array_items)
1284{
1285 uint32_t result_count = 0U;
1286 const osKernelState_t kstate = osKernelGetState();
1287
1288 // kernel must be active and buffer must be valid
1289 if ((kstate != osKernelInactive) && (thread_array != nullptr) && (array_items != 0U))
1290 {
1291 // cast the raw pointer array to the expected ITask* destination type
1292 stk::ITask **const tasks_destination = reinterpret_cast<stk::ITask **>(
1293 reinterpret_cast<void *>(thread_array));
1294
1295 // bind raw destination buffer into a temporary ArrayView object
1296 const size_t count = g_StkKernel.EnumerateTasks(
1297 stk::ArrayView<stk::ITask *>(tasks_destination, static_cast<size_t>(array_items)));
1298
1299 result_count = static_cast<uint32_t>(count);
1300 }
1301
1302 return result_count;
1303}
1304
1305// ===========================================================================
1306// ==== Thread Flags Functions ====
1307// ===========================================================================
1308
1309uint32_t osThreadFlagsSet(osThreadId_t thread_id, uint32_t flags)
1310{
1311 uint32_t result;
1312
1313 if ((thread_id == nullptr) || ((flags & osFlagsError) != 0U))
1314 {
1315 result = osFlagsErrorParameter;
1316 }
1317 else
1318 {
1319 StkThread *th = static_cast<StkThread *>(thread_id);
1320 result = StkFlagsResultToCmsis(th->m_thread_flags.Set(flags));
1321 }
1322
1323 return result;
1324}
1325
1326uint32_t osThreadFlagsClear(uint32_t flags)
1327{
1328 uint32_t result;
1329
1330 osThreadId_t const self = osThreadGetId();
1331 if (self == nullptr)
1332 {
1333 result = osFlagsErrorUnknown;
1334 }
1335 else
1336 {
1337 StkThread *th = static_cast<StkThread *>(self);
1338 result = StkFlagsResultToCmsis(th->m_thread_flags.Clear(flags));
1339 }
1340
1341 return result;
1342}
1343
1344uint32_t osThreadFlagsGet(void)
1345{
1346 uint32_t result;
1347
1348 osThreadId_t const self = osThreadGetId();
1349 if (self == nullptr)
1350 {
1351 result = 0U;
1352 }
1353 else
1354 {
1355 result = static_cast<StkThread *>(self)->m_thread_flags.Get();
1356 }
1357
1358 return result;
1359}
1360
1361uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout)
1362{
1363 uint32_t result;
1364
1365 if (IsIrqContext())
1366 {
1367 result = osFlagsErrorISR;
1368 }
1369 else
1370 {
1371 osThreadId_t const self = osThreadGetId();
1372 if (self == nullptr)
1373 {
1374 result = osFlagsErrorUnknown;
1375 }
1376 else
1377 {
1378 StkThread *th = static_cast<StkThread *>(self);
1379 result = StkFlagsResultToCmsis(th->m_thread_flags.Wait(flags,
1380 CmsisFlagsOptionsToStk(options), CmsisTimeoutToStk(timeout)));
1381 }
1382 }
1383
1384 return result;
1385}
1386
1387
1388// ===========================================================================
1389// ==== Generic Wait Functions ====
1390// ===========================================================================
1391
1392osStatus_t osDelay(uint32_t ticks)
1393{
1394 osStatus_t result;
1395
1396 if (IsIrqContext())
1397 {
1398 result = osErrorISR;
1399 }
1400 else if (osKernelGetState() == osKernelInactive)
1401 {
1402 result = osError;
1403 }
1404 else
1405 {
1407 result = osOK;
1408 }
1409
1410 return result;
1411}
1412
1414{
1415 osStatus_t result;
1416
1417 if (IsIrqContext())
1418 {
1419 result = osErrorISR;
1420 }
1421 else if (osKernelGetState() == osKernelInactive)
1422 {
1423 result = osError;
1424 }
1425 else
1426 {
1427 result = (stk::SleepUntil(static_cast<stk::Ticks>(ticks)) ? osOK : osError);
1428 }
1429
1430 return result;
1431}
1432
1433
1434// ===========================================================================
1435// ==== Timer Management Functions ====
1436// ===========================================================================
1437
1439 const osTimerAttr_t *attr)
1440{
1441 osTimerId_t result;
1442
1443 if (IsIrqContext() || (func == nullptr))
1444 {
1445 result = nullptr;
1446 }
1447 else if (osKernelGetState() == osKernelInactive)
1448 {
1449 result = nullptr;
1450 }
1451 else
1452 {
1453 const char *const name = ((attr != nullptr) ? attr->name : nullptr);
1454 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
1455 const uint32_t cb_sz = ((attr != nullptr) ? attr->cb_size : 0U);
1456
1458
1459 StkTimer *const tmr = PlacementNewOrHeap<StkTimer>(cb_mem, cb_sz, func, type, argument, name);
1460 result = static_cast<osTimerId_t>(tmr);
1461 }
1462
1463 return result;
1464}
1465
1466const char *osTimerGetName(osTimerId_t timer_id)
1467{
1468 const char *result;
1469
1470 if (timer_id == nullptr)
1471 {
1472 result = nullptr;
1473 }
1474 else
1475 {
1476 result = static_cast<StkTimer *>(timer_id)->m_name;
1477 }
1478
1479 return result;
1480}
1481
1482osStatus_t osTimerStart(osTimerId_t timer_id, uint32_t ticks)
1483{
1484 osStatus_t result;
1485
1486 if (IsIrqContext())
1487 {
1488 result = osErrorISR;
1489 }
1490 else if ((timer_id == nullptr) || (g_TimerHost == nullptr))
1491 {
1492 result = osErrorParameter;
1493 }
1494 else
1495 {
1496 StkTimer *const tmr = static_cast<StkTimer *>(timer_id);
1497
1498 const uint32_t period_ticks = ((tmr->m_type == osTimerPeriodic) ? ticks : 0U);
1499 tmr->m_period_ticks = period_ticks;
1500
1501 const bool ok = g_TimerHost->Restart(*tmr, ticks, period_ticks);
1502 result = (ok ? osOK : osError);
1503 }
1504
1505 return result;
1506}
1507
1509{
1510 osStatus_t result;
1511
1512 if (IsIrqContext())
1513 {
1514 result = osErrorISR;
1515 }
1516 else if ((timer_id == nullptr) || (g_TimerHost == nullptr))
1517 {
1518 result = osErrorParameter;
1519 }
1520 else
1521 {
1522 StkTimer *const tmr = static_cast<StkTimer *>(timer_id);
1523
1524 if (!tmr->IsActive())
1525 {
1526 result = osErrorResource;
1527 }
1528 else
1529 {
1530 result = (g_TimerHost->Stop(*tmr) ? osOK : osError);
1531 }
1532 }
1533
1534 return result;
1535}
1536
1538{
1539 uint32_t result;
1540
1541 if (timer_id == nullptr)
1542 {
1543 result = 0U;
1544 }
1545 else
1546 {
1547 result = (static_cast<StkTimer *>(timer_id)->IsActive() ? 1U : 0U);
1548 }
1549
1550 return result;
1551}
1552
1554{
1555 osStatus_t result;
1556
1557 if (IsIrqContext())
1558 {
1559 result = osErrorISR;
1560 }
1561 else if ((timer_id == nullptr) || (g_TimerHost == nullptr))
1562 {
1563 result = osErrorParameter;
1564 }
1565 else
1566 {
1567 result = osOK;
1568
1569 StkTimer *const tmr = static_cast<StkTimer *>(timer_id);
1570
1571 if (tmr->IsActive())
1572 {
1573 if (!g_TimerHost->Stop(*tmr))
1574 {
1575 result = osError;
1576 }
1577 }
1578
1579 if (result == osOK)
1580 {
1581 ObjDestroy(tmr);
1582 }
1583 }
1584
1585 return result;
1586}
1587
1588
1589// ===========================================================================
1590// ==== Event Flags Management Functions ====
1591// ===========================================================================
1592
1594{
1595 osEventFlagsId_t result;
1596
1597 if (IsIrqContext())
1598 {
1599 result = nullptr;
1600 }
1601 else
1602 {
1603 const char *const name = ((attr != nullptr) ? attr->name : nullptr);
1604 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
1605 const uint32_t cb_sz = ((attr != nullptr) ? attr->cb_size : 0U);
1606
1607 StkEventFlags *const ef = PlacementNewOrHeap<StkEventFlags>(cb_mem, cb_sz, name);
1608 result = static_cast<osEventFlagsId_t>(ef);
1609 }
1610
1611 return result;
1612}
1613
1615{
1616 const char *result;
1617
1618 if (ef_id == nullptr)
1619 {
1620 result = nullptr;
1621 }
1622 else
1623 {
1624 result = static_cast<StkEventFlags *>(ef_id)->m_ef.GetTraceName();
1625 }
1626
1627 return result;
1628}
1629
1630uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags)
1631{
1632 uint32_t result;
1633
1634 if ((ef_id == nullptr) || ((flags & osFlagsError) != 0U))
1635 {
1636 result = osFlagsErrorParameter;
1637 }
1638 else
1639 {
1640 result = StkFlagsResultToCmsis(static_cast<StkEventFlags *>(ef_id)->m_ef.Set(flags));
1641 }
1642
1643 return result;
1644}
1645
1646uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags)
1647{
1648 uint32_t result;
1649
1650 if ((ef_id == nullptr) || ((flags & osFlagsError) != 0U))
1651 {
1652 result = osFlagsErrorParameter;
1653 }
1654 else
1655 {
1656 result = StkFlagsResultToCmsis(static_cast<StkEventFlags *>(ef_id)->m_ef.Clear(flags));
1657 }
1658
1659 return result;
1660}
1661
1663{
1664 uint32_t result;
1665
1666 if (ef_id == nullptr)
1667 {
1668 result = 0U;
1669 }
1670 else
1671 {
1672 result = static_cast<StkEventFlags *>(ef_id)->m_ef.Get();
1673 }
1674
1675 return result;
1676}
1677
1678uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options,
1679 uint32_t timeout)
1680{
1681 uint32_t result;
1682
1683 if ((ef_id == nullptr) || ((flags & osFlagsError) != 0U))
1684 {
1685 result = osFlagsErrorParameter;
1686 }
1687 else
1688 {
1689 result = StkFlagsResultToCmsis(static_cast<StkEventFlags *>(ef_id)->m_ef.Wait(flags,
1690 CmsisFlagsOptionsToStk(options), CmsisTimeoutToStk(timeout)));
1691 }
1692
1693 return result;
1694}
1695
1697{
1698 osStatus_t result;
1699
1700 if (IsIrqContext())
1701 {
1702 result = osErrorISR;
1703 }
1704 else if (ef_id == nullptr)
1705 {
1706 result = osErrorParameter;
1707 }
1708 else
1709 {
1710 ObjDestroy(static_cast<StkEventFlags *>(ef_id));
1711 result = osOK;
1712 }
1713
1714 return result;
1715}
1716
1717
1718// ===========================================================================
1719// ==== Mutex Management Functions ====
1720// ===========================================================================
1721
1723{
1724 osMutexId_t result;
1725
1726 if (IsIrqContext())
1727 {
1728 result = nullptr;
1729 }
1730 else
1731 {
1732 // osMutexPrioInherit: ignored, supported by default.
1733 // osMutexRecursive: ignored, sync::Mutex is always recursive.
1734 // osMutexRobust: will assert as unsafe code.
1735 const char *const name = ((attr != nullptr) ? attr->name : nullptr);
1736 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
1737 const uint32_t cb_sz = ((attr != nullptr) ? attr->cb_size : 0U);
1738 const bool robust = ((attr != nullptr) && ((attr->attr_bits & osMutexRobust) != 0U));
1739
1740 // disallow osMutexRobust
1741 STK_ASSERT(!robust);
1742 if (robust)
1743 {
1744 result = nullptr;
1745 }
1746 else
1747 {
1748 StkMutex *const m = PlacementNewOrHeap<StkMutex>(cb_mem, cb_sz, name);
1749 result = static_cast<osMutexId_t>(m);
1750 }
1751 }
1752
1753 return result;
1754}
1755
1756const char *osMutexGetName(osMutexId_t mutex_id)
1757{
1758 const char *result;
1759
1760 if (mutex_id == nullptr)
1761 {
1762 result = nullptr;
1763 }
1764 else
1765 {
1766 result = static_cast<StkMutex *>(mutex_id)->m_mutex.GetTraceName();
1767 }
1768
1769 return result;
1770}
1771
1772osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout)
1773{
1774 osStatus_t result;
1775
1776 if (IsIrqContext())
1777 {
1778 result = osErrorISR;
1779 }
1780 else if (mutex_id == nullptr)
1781 {
1782 result = osErrorParameter;
1783 }
1784 else
1785 {
1786 StkMutex *m = static_cast<StkMutex *>(mutex_id);
1787 const stk::Timeout stk_timeout = CmsisTimeoutToStk(timeout);
1788
1789 const bool acquired = m->m_mutex.TimedLock(stk_timeout);
1790 if (!acquired)
1791 {
1792 result = ((stk_timeout == stk::NO_WAIT) ? osErrorResource : osErrorTimeout);
1793 }
1794 else
1795 {
1796 result = osOK;
1797 }
1798 }
1799
1800 return result;
1801}
1802
1804{
1805 osStatus_t result;
1806
1807 if (IsIrqContext())
1808 {
1809 result = osErrorISR;
1810 }
1811 else if (mutex_id == nullptr)
1812 {
1813 result = osErrorParameter;
1814 }
1815 else
1816 {
1817 static_cast<StkMutex *>(mutex_id)->m_mutex.Unlock();
1818 result = osOK;
1819 }
1820
1821 return result;
1822}
1823
1825{
1826 osThreadId_t result;
1827
1828 if (mutex_id == nullptr)
1829 {
1830 result = nullptr;
1831 }
1832 else
1833 {
1835 static_cast<StkMutex *>(mutex_id)->m_mutex.GetOwner());
1836 }
1837
1838 return result;
1839}
1840
1842{
1843 osStatus_t result;
1844
1845 if (IsIrqContext())
1846 {
1847 result = osErrorISR;
1848 }
1849 else if (mutex_id == nullptr)
1850 {
1851 result = osErrorParameter;
1852 }
1853 else
1854 {
1855 ObjDestroy(static_cast<StkMutex *>(mutex_id));
1856 result = osOK;
1857 }
1858
1859 return result;
1860}
1861
1862
1863// ===========================================================================
1864// ==== Semaphore Management Functions ====
1865// ===========================================================================
1866
1867osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count,
1868 const osSemaphoreAttr_t *attr)
1869{
1870 osSemaphoreId_t result;
1871
1872 if (IsIrqContext() || (max_count == 0U) || (initial_count > max_count))
1873 {
1874 result = nullptr;
1875 }
1876 else
1877 {
1878 // STK Semaphore uses uint16_t counters, clamp to stk::sync::Semaphore::COUNT_MAX.
1879 const uint16_t mc = static_cast<uint16_t>(stk::Min(max_count, static_cast<uint32_t>(stk::sync::Semaphore::COUNT_MAX)));
1880 const uint16_t ic = static_cast<uint16_t>(stk::Min(initial_count, static_cast<uint32_t>(stk::sync::Semaphore::COUNT_MAX)));
1881
1882 const char *const name = ((attr != nullptr) ? attr->name : nullptr);
1883 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
1884 const uint32_t cb_sz = ((attr != nullptr) ? attr->cb_size : 0U);
1885
1886 StkSemaphore *const sem = PlacementNewOrHeap<StkSemaphore>(cb_mem, cb_sz, ic, mc, name);
1887 result = static_cast<osSemaphoreId_t>(sem);
1888 }
1889
1890 return result;
1891}
1892
1893const char *osSemaphoreGetName(osSemaphoreId_t semaphore_id)
1894{
1895 const char *result;
1896
1897 if (semaphore_id == nullptr)
1898 {
1899 result = nullptr;
1900 }
1901 else
1902 {
1903 result = static_cast<StkSemaphore *>(semaphore_id)->m_semaphore.GetTraceName();
1904 }
1905
1906 return result;
1907}
1908
1909osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout)
1910{
1911 osStatus_t result;
1912
1913 if (semaphore_id == nullptr)
1914 {
1915 result = osErrorParameter;
1916 }
1917 else if (IsIrqContext() && (timeout != 0U))
1918 {
1919 result = osErrorISR;
1920 }
1921 else
1922 {
1923 StkSemaphore *sem = static_cast<StkSemaphore *>(semaphore_id);
1924 const stk::Timeout stk_timeout = CmsisTimeoutToStk(timeout);
1925
1926 const bool acquired = sem->m_semaphore.Wait(stk_timeout);
1927 if (!acquired)
1928 {
1929 result = ((stk_timeout == stk::NO_WAIT) ? osErrorResource : osErrorTimeout);
1930 }
1931 else
1932 {
1933 result = osOK;
1934 }
1935 }
1936
1937 return result;
1938}
1939
1941{
1942 osStatus_t result;
1943
1944 if (semaphore_id == nullptr)
1945 {
1946 result = osErrorParameter;
1947 }
1948 else
1949 {
1950 static_cast<StkSemaphore *>(semaphore_id)->m_semaphore.Signal();
1951 result = osOK;
1952 }
1953
1954 return result;
1955}
1956
1958{
1959 uint32_t result;
1960
1961 if (semaphore_id == nullptr)
1962 {
1963 result = 0U;
1964 }
1965 else
1966 {
1967 result = static_cast<uint32_t>(
1968 static_cast<StkSemaphore *>(semaphore_id)->m_semaphore.GetCount());
1969 }
1970
1971 return result;
1972}
1973
1975{
1976 osStatus_t result;
1977
1978 if (IsIrqContext())
1979 {
1980 result = osErrorISR;
1981 }
1982 else if (semaphore_id == nullptr)
1983 {
1984 result = osErrorParameter;
1985 }
1986 else
1987 {
1988 ObjDestroy(static_cast<StkSemaphore *>(semaphore_id));
1989 result = osOK;
1990 }
1991
1992 return result;
1993}
1994
1995
1996// ===========================================================================
1997// ==== Memory Pool Management Functions ====
1998// ===========================================================================
1999
2000osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size,
2001 const osMemoryPoolAttr_t *attr)
2002{
2003 osMemoryPoolId_t result;
2004
2005 // ISR context: forbidden per CMSIS spec.
2006 // Zero capacity or zero block size are meaningless.
2007 if (IsIrqContext() || (block_count == 0U) || (block_size == 0U))
2008 {
2009 result = nullptr;
2010 }
2011 else
2012 {
2013 const char *const name = ((attr != nullptr) ? attr->name : nullptr);
2014 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
2015 const uint32_t cb_sz = ((attr != nullptr) ? attr->cb_size : 0U);
2016 void *const mp_mem = ((attr != nullptr) ? attr->mp_mem : nullptr);
2017 const uint32_t mp_sz = ((attr != nullptr) ? attr->mp_size : 0U);
2018
2019 // Compute the aligned block size and required storage byte count.
2020 const uint32_t aligned_blk = stk::memory::BlockMemoryPool::AlignBlockSize(block_size);
2021 const uint32_t storage_required = (block_count * aligned_blk);
2022
2023 StkMemPool *pool;
2024
2025 if ((mp_mem != nullptr) && (mp_sz >= storage_required))
2026 {
2027 // Caller-supplied pool storage - BlockMemoryPool external-storage ctor.
2028 pool = PlacementNewOrHeap<StkMemPool>(cb_mem, cb_sz,
2029 block_count, block_size, name, static_cast<uint8_t *>(mp_mem));
2030 }
2031 else
2032 {
2033 // Heap-allocated pool storage - BlockMemoryPool heap ctor.
2034 pool = PlacementNewOrHeap<StkMemPool>(cb_mem, cb_sz,
2035 block_count, block_size, name);
2036
2037 // If the heap ctor failed to allocate storage, clean up and bail.
2038 if ((pool != nullptr) && !pool->m_mpool.IsStorageValid())
2039 {
2040 ObjDestroy(pool);
2041 pool = nullptr;
2042 }
2043 }
2044
2045 result = static_cast<osMemoryPoolId_t>(pool);
2046 }
2047
2048 return result;
2049}
2050
2052{
2053 const char *result;
2054
2055 if (mp_id == nullptr)
2056 {
2057 result = nullptr;
2058 }
2059 else
2060 {
2061 result = static_cast<StkMemPool *>(mp_id)->m_mpool.GetTraceName();
2062 }
2063
2064 return result;
2065}
2066
2067void *osMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout)
2068{
2069 void *result;
2070
2071 if (mp_id == nullptr)
2072 {
2073 result = nullptr;
2074 }
2075 // ISR context is only valid with timeout == 0 (NO_WAIT / TryAlloc).
2076 else if (IsIrqContext() && (timeout != 0U))
2077 {
2078 result = nullptr;
2079 }
2080 else
2081 {
2082 result = static_cast<StkMemPool *>(mp_id)->m_mpool.TimedAlloc(CmsisTimeoutToStk(timeout));
2083 }
2084
2085 return result;
2086}
2087
2089{
2090 osStatus_t result;
2091
2092 if ((mp_id == nullptr) || (block == nullptr))
2093 {
2094 result = osErrorParameter;
2095 }
2096 else if (!static_cast<StkMemPool *>(mp_id)->m_mpool.Free(block))
2097 {
2098 result = osErrorParameter; // ptr not from this pool
2099 }
2100 else
2101 {
2102 result = osOK;
2103 }
2104
2105 return result;
2106}
2107
2109{
2110 uint32_t result;
2111
2112 if (mp_id == nullptr)
2113 {
2114 result = 0U;
2115 }
2116 else
2117 {
2118 result = static_cast<StkMemPool *>(mp_id)->m_mpool.GetCapacity();
2119 }
2120
2121 return result;
2122}
2123
2125{
2126 uint32_t result;
2127
2128 if (mp_id == nullptr)
2129 {
2130 result = 0U;
2131 }
2132 else
2133 {
2134 result = static_cast<uint32_t>(static_cast<StkMemPool *>(mp_id)->m_mpool.GetBlockSize());
2135 }
2136
2137 return result;
2138}
2139
2141{
2142 uint32_t result;
2143
2144 if (mp_id == nullptr)
2145 {
2146 result = 0U;
2147 }
2148 else
2149 {
2150 result = static_cast<StkMemPool *>(mp_id)->m_mpool.GetUsedCount();
2151 }
2152
2153 return result;
2154}
2155
2157{
2158 uint32_t result;
2159
2160 if (mp_id == nullptr)
2161 {
2162 result = 0U;
2163 }
2164 else
2165 {
2166 result = static_cast<StkMemPool *>(mp_id)->m_mpool.GetFreeCount();
2167 }
2168
2169 return result;
2170}
2171
2173{
2174 osStatus_t result;
2175
2176 if (IsIrqContext())
2177 {
2178 result = osErrorISR;
2179 }
2180 else if (mp_id == nullptr)
2181 {
2182 result = osErrorParameter;
2183 }
2184 else
2185 {
2186 ObjDestroy(static_cast<StkMemPool *>(mp_id));
2187 result = osOK;
2188 }
2189
2190 return result;
2191}
2192
2193
2194// ===========================================================================
2195// ==== Message Queue Management Functions ====
2196// ===========================================================================
2197
2198osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size,
2199 const osMessageQueueAttr_t *attr)
2200{
2201 osMessageQueueId_t result;
2202
2203 if (IsIrqContext() || (msg_count == 0U) || (msg_size == 0U) ||
2205 {
2206 result = nullptr;
2207 }
2208 else
2209 {
2210 const char *const name = ((attr != nullptr) ? attr->name : nullptr);
2211 void *const cb_mem = ((attr != nullptr) ? attr->cb_mem : nullptr);
2212 const uint32_t cb_sz = ((attr != nullptr) ? attr->cb_size : 0U);
2213 void *const ext_buf = ((attr != nullptr) ? attr->mq_mem : nullptr);
2214 const uint32_t ext_buf_size = ((attr != nullptr) ? attr->mq_size : 0U);
2215
2216 const uint32_t buf_required = (msg_count * msg_size);
2217
2218 StkMessageQueue *mq;
2219
2220 if ((ext_buf != nullptr) && (ext_buf_size >= buf_required))
2221 {
2222 // Data buffer: use caller-supplied memory.
2223 mq = PlacementNewOrHeap<StkMessageQueue>(cb_mem, cb_sz,
2224 msg_count, msg_size, name, static_cast<uint8_t *>(ext_buf));
2225 }
2226 else
2227 {
2228 // Data buffer: heap-allocated inside StkMessageQueue constructor.
2229 mq = PlacementNewOrHeap<StkMessageQueue>(cb_mem, cb_sz,
2230 msg_count, msg_size, name);
2231
2232 // Validate
2233 if (mq != nullptr)
2234 {
2235 if (mq->m_mq.GetBuffer() == nullptr)
2236 {
2237 ObjDestroy(mq);
2238 mq = nullptr;
2239 }
2240 }
2241 }
2242
2243 result = static_cast<osMessageQueueId_t>(mq);
2244 }
2245
2246 return result;
2247}
2248
2250{
2251 const char *result;
2252
2253 if (mq_id == nullptr)
2254 {
2255 result = nullptr;
2256 }
2257 else
2258 {
2259 result = static_cast<StkMessageQueue *>(mq_id)->m_mq.GetTraceName();
2260 }
2261
2262 return result;
2263}
2264
2266 uint8_t /*msg_prio*/, uint32_t timeout)
2267{
2268 osStatus_t result;
2269
2270 if ((mq_id == nullptr) || (msg_ptr == nullptr))
2271 {
2272 result = osErrorParameter;
2273 }
2274 else if (IsIrqContext() && (timeout != 0U))
2275 {
2276 result = osErrorISR;
2277 }
2278 else
2279 {
2280 const stk::Timeout stk_timeout = CmsisTimeoutToStk(timeout);
2281
2282 if (!static_cast<StkMessageQueue *>(mq_id)->m_mq.Put(msg_ptr, stk_timeout))
2283 {
2284 result = ((stk_timeout == stk::NO_WAIT) ? osErrorResource : osErrorTimeout);
2285 }
2286 else
2287 {
2288 result = osOK;
2289 }
2290 }
2291
2292 return result;
2293}
2294
2296 uint8_t *msg_prio, uint32_t timeout)
2297{
2298 osStatus_t result;
2299
2300 if ((mq_id == nullptr) || (msg_ptr == nullptr))
2301 {
2302 result = osErrorParameter;
2303 }
2304 else if (IsIrqContext() && (timeout != 0U))
2305 {
2306 result = osErrorISR;
2307 }
2308 else
2309 {
2310 const stk::Timeout stk_timeout = CmsisTimeoutToStk(timeout);
2311
2312 if (!static_cast<StkMessageQueue *>(mq_id)->m_mq.Get(msg_ptr, stk_timeout))
2313 {
2314 result = ((stk_timeout == stk::NO_WAIT) ? osErrorResource : osErrorTimeout);
2315 }
2316 else
2317 {
2318 if (msg_prio != nullptr)
2319 {
2320 *msg_prio = 0U; // STK queues have no priority lanes.
2321 }
2322 result = osOK;
2323 }
2324 }
2325
2326 return result;
2327}
2328
2330{
2331 uint32_t result;
2332
2333 if (mq_id == nullptr)
2334 {
2335 result = 0U;
2336 }
2337 else
2338 {
2339 result = static_cast<uint32_t>(static_cast<StkMessageQueue *>(mq_id)->m_mq.GetCapacity());
2340 }
2341
2342 return result;
2343}
2344
2346{
2347 uint32_t result;
2348
2349 if (mq_id == nullptr)
2350 {
2351 result = 0U;
2352 }
2353 else
2354 {
2355 result = static_cast<uint32_t>(static_cast<StkMessageQueue *>(mq_id)->m_mq.GetMsgSize());
2356 }
2357
2358 return result;
2359}
2360
2362{
2363 uint32_t result;
2364
2365 if (mq_id == nullptr)
2366 {
2367 result = 0U;
2368 }
2369 else
2370 {
2371 result = static_cast<uint32_t>(static_cast<StkMessageQueue *>(mq_id)->m_mq.GetCount());
2372 }
2373
2374 return result;
2375}
2376
2378{
2379 uint32_t result;
2380
2381 if (mq_id == nullptr)
2382 {
2383 result = 0U;
2384 }
2385 else
2386 {
2387 result = static_cast<uint32_t>(static_cast<StkMessageQueue *>(mq_id)->m_mq.GetSpace());
2388 }
2389
2390 return result;
2391}
2392
2394{
2395 osStatus_t result;
2396
2397 if (IsIrqContext())
2398 {
2399 result = osErrorISR;
2400 }
2401 else if (mq_id == nullptr)
2402 {
2403 result = osErrorParameter;
2404 }
2405 else
2406 {
2407 static_cast<StkMessageQueue *>(mq_id)->m_mq.Reset();
2408 result = osOK;
2409 }
2410
2411 return result;
2412}
2413
2415{
2416 osStatus_t result;
2417
2418 if (IsIrqContext())
2419 {
2420 result = osErrorISR;
2421 }
2422 else if (mq_id == nullptr)
2423 {
2424 result = osErrorParameter;
2425 }
2426 else
2427 {
2428 ObjDestroy(static_cast<StkMessageQueue *>(mq_id));
2429 result = osOK;
2430 }
2431
2432 return result;
2433}
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:540
#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:136
static void Yield()
Notify scheduler to switch to the next runnable task.
Definition stk_helper.h:402
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:358
EAccessMode
Hardware access modes by the task.
Definition stk_common.h:42
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
Definition stk_common.h:44
constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:210
int64_t Ticks
Ticks value.
Definition stk_common.h:151
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:146
static constexpr T Max(T a, T b)
Compile-time maximum of two values.
Definition stk_defs.h:645
static bool SleepUntil(Ticks timestamp)
Put calling process into a sleep state until the specified timestamp.
Definition stk_helper.h:383
static uint32_t GetTickResolution()
Get number of microseconds in one tick.
Definition stk_helper.h:247
static uint32_t GetSysTimerFrequency()
Get system timer frequency.
Definition stk_helper.h:347
static Ticks GetTicks()
Get number of ticks elapsed since kernel start.
Definition stk_helper.h:313
PlatformArmCortexM PlatformDefault
Default platform implementation.
constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:204
static TId GetTid()
Get task/thread Id of the calling task.
Definition stk_helper.h:237
static constexpr T Min(T a, T b)
Compile-time minimum of two values.
Definition stk_defs.h:639
static Cycles GetSysTimerCount()
Get system timer count value.
Definition stk_helper.h:338
Word TId
Task (thread) id.
Definition stk_common.h:141
@ KERNEL_TICKLESS
Tickless mode. To use this mode STK_TICKLESS_IDLE must be defined to 1 in stk_config....
Definition stk_common.h:57
@ KERNEL_SYNC
Synchronization support (see Event).
Definition stk_common.h:56
@ KERNEL_DYNAMIC
Tasks can be added or removed and therefore exit when done.
Definition stk_common.h:54
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:247
virtual size_t GetStackSpace() const
Get available stack space.
Definition stk_common.h:336
Interface for a user task.
Definition stk_common.h:670
@ 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).
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