|
15 | 15 | #include <stdbool.h> |
16 | 16 | #include <assert.h> |
17 | 17 |
|
18 | | -/*! \file stk_c.h |
19 | | - \brief C language binding/interface for SuperTinyKernel (STK). |
| 18 | +/*! \file stk_c.h |
| 19 | + \brief C language binding/interface for SuperTinyKernel (STK). |
20 | 20 |
|
21 | 21 | This header provides a pure C API to create, configure and run STK kernel |
22 | 22 | from C code. |
@@ -122,11 +122,11 @@ typedef void (*stk_task_entry_t)(void *arg); |
122 | 122 | /* Available kernel type definitions: |
123 | 123 |
|
124 | 124 | Kernel mode flags (may be OR-combined, subject to the constraints listed below): |
125 | | - KERNEL_STATIC — fixed task list; tasks must never return from their entry function. |
126 | | - KERNEL_DYNAMIC — tasks may be added/removed at runtime and may return when done. |
127 | | - KERNEL_HRT — Hard Real-Time mode; must be combined with KERNEL_STATIC or KERNEL_DYNAMIC. |
128 | | - KERNEL_SYNC — enables synchronization primitives (Mutex, Event, Semaphore, etc.). |
129 | | - KERNEL_TICKLESS — tickless low-power idle; suppresses the SysTick when all tasks sleep. |
| 125 | + KERNEL_STATIC - fixed task list; tasks must never return from their entry function. |
| 126 | + KERNEL_DYNAMIC - tasks may be added/removed at runtime and may return when done. |
| 127 | + KERNEL_HRT - Hard Real-Time mode; must be combined with KERNEL_STATIC or KERNEL_DYNAMIC. |
| 128 | + KERNEL_SYNC - enables synchronization primitives (Mutex, Event, Semaphore, etc.). |
| 129 | + KERNEL_TICKLESS - tickless low-power idle; suppresses the SysTick when all tasks sleep. |
130 | 130 | Requires STK_TICKLESS_IDLE=1 in stk_config.h. |
131 | 131 | INCOMPATIBLE with KERNEL_HRT (HRT requires a continuous tick). |
132 | 132 |
|
@@ -202,7 +202,7 @@ Kernel<KERNEL_DYNAMIC | KERNEL_TICKLESS | KERNEL_SYNC, STK_C_KERNEL_MAX_TASKS, S |
202 | 202 | #define STK_C_KERNEL_TYPE_CPU_6 Kernel<KERNEL_STATIC, STK_C_KERNEL_MAX_TASKS, SwitchStrategyRR, PlatformDefault> |
203 | 203 | #define STK_C_KERNEL_TYPE_CPU_7 Kernel<KERNEL_STATIC, STK_C_KERNEL_MAX_TASKS, SwitchStrategyRR, PlatformDefault> |
204 | 204 |
|
205 | | - // Tickless example — CPU enters low-power state when all tasks are sleeping: |
| 205 | + // Tickless example - CPU enters low-power state when all tasks are sleeping: |
206 | 206 | #define STK_C_KERNEL_TYPE_CPU_0 Kernel<KERNEL_STATIC | KERNEL_TICKLESS, STK_C_KERNEL_MAX_TASKS, SwitchStrategyRR, PlatformDefault> |
207 | 207 | \endcode |
208 | 208 | */ |
@@ -307,7 +307,7 @@ void stk_kernel_schedule_task_removal(stk_kernel_t *k, stk_task_t *task); |
307 | 307 | \param[in] task: Task to suspend. |
308 | 308 | \param[out] suspended: Set to true if the task was successfully suspended (was awake), |
309 | 309 | false if the task was already sleeping (e.g. blocked on a mutex or timed Sleep). |
310 | | - \note Do not hold a critical section when suspending the calling task — this will deadlock. |
| 310 | + \note Do not hold a critical section when suspending the calling task - this will deadlock. |
311 | 311 | \note If the task suspends itself, the call blocks until the kernel switches it out. |
312 | 312 | */ |
313 | 313 | void stk_kernel_suspend_task(stk_kernel_t *k, stk_task_t *task, bool *suspended); |
@@ -600,12 +600,12 @@ void stk_tls_set(void *ptr); |
600 | 600 |
|
601 | 601 | // ───── Critical Section ────────────────────────────────────────────────────── |
602 | 602 |
|
603 | | -/*! \brief Enter critical section — disable context switches on current core. |
| 603 | +/*! \brief Enter critical section - disable context switches on current core. |
604 | 604 | \note Supports nesting (number of enter calls must match number of exit calls). |
605 | 605 | */ |
606 | 606 | void stk_critical_section_enter(void); |
607 | 607 |
|
608 | | -/*! \brief Leave critical section — re-enable context switches. |
| 608 | +/*! \brief Leave critical section - re-enable context switches. |
609 | 609 | \note Must be called once for each previous stk_critical_section_enter(). |
610 | 610 | */ |
611 | 611 | void stk_critical_section_exit(void); |
@@ -1030,6 +1030,174 @@ size_t stk_pipe_read_bulk(stk_pipe_t *pipe, stk_word_t *dst, size_t count, int32 |
1030 | 1030 | */ |
1031 | 1031 | size_t stk_pipe_get_size(stk_pipe_t *pipe); |
1032 | 1032 |
|
| 1033 | +// ───── MessageQueue ────────────────────────────────────────────────────────── |
| 1034 | + |
| 1035 | +/*! \brief A memory size (multiples of stk_word_t) required for a MessageQueue instance. |
| 1036 | + \details Covers the fixed-overhead fields of stk::sync::MessageQueue: |
| 1037 | + six size_t members (buffer ptr, capacity, msg_size, count, head, tail) |
| 1038 | + plus two ConditionVariable objects (cv_not_empty, cv_not_full) and |
| 1039 | + optional debug-name word. |
| 1040 | + \note The backing data buffer is allocated separately by the caller and |
| 1041 | + passed to stk_msgq_create() via the \a buf / \a buf_size parameters. |
| 1042 | +*/ |
| 1043 | +#define STK_MSGQ_IMPL_SIZE (6 + (2 * STK_CV_IMPL_SIZE) + (STK_SYNC_DEBUG_NAMES ? 1 : 0)) |
| 1044 | + |
| 1045 | +/*! \brief Opaque memory container for a MessageQueue instance. |
| 1046 | +*/ |
| 1047 | +typedef struct stk_msgq_mem_t { |
| 1048 | + stk_word_t data[STK_MSGQ_IMPL_SIZE] __stk_c_stack_attr; |
| 1049 | +} stk_msgq_mem_t; |
| 1050 | + |
| 1051 | +/*! \brief Opaque handle to a MessageQueue instance. |
| 1052 | +*/ |
| 1053 | +typedef struct stk_msgq_t stk_msgq_t; |
| 1054 | + |
| 1055 | +/*! \def STK_MSGQ_BUF_SIZE(capacity, msg_size) |
| 1056 | + \brief Compute the required data-buffer size (in bytes) for a MessageQueue. |
| 1057 | + \param[in] capacity: Maximum number of messages. |
| 1058 | + \param[in] msg_size: Size of each message in bytes. |
| 1059 | + \note Use this macro when declaring the \c uint8_t buffer passed to |
| 1060 | + stk_msgq_create(): |
| 1061 | + \code |
| 1062 | + #define MY_QUEUE_CAP 8 |
| 1063 | + #define MY_MSG_SIZE sizeof(MyMsg_t) |
| 1064 | +
|
| 1065 | + static uint8_t s_msgq_buf[STK_MSGQ_BUF_SIZE(MY_QUEUE_CAP, MY_MSG_SIZE)]; |
| 1066 | + static stk_msgq_mem_t s_msgq_mem; |
| 1067 | + stk_msgq_t *g_queue = stk_msgq_create(&s_msgq_mem, sizeof(s_msgq_mem), |
| 1068 | + s_msgq_buf, sizeof(s_msgq_buf), |
| 1069 | + MY_QUEUE_CAP, MY_MSG_SIZE); |
| 1070 | + \endcode |
| 1071 | +*/ |
| 1072 | +#define STK_MSGQ_BUF_SIZE(capacity, msg_size) ((capacity) * (msg_size)) |
| 1073 | + |
| 1074 | +/*! \brief Create a MessageQueue (using provided memory). |
| 1075 | + \details Constructs a stk::sync::MessageQueue in-place inside \a memory. |
| 1076 | + The queue will hold up to \a capacity messages, each \a msg_size bytes |
| 1077 | + wide. The backing storage for messages must be supplied by the caller |
| 1078 | + via \a buf / \a buf_size. |
| 1079 | +
|
| 1080 | + \param[in] memory: Pointer to static memory container for the queue object. |
| 1081 | + Must be at least sizeof(stk_msgq_mem_t) bytes. |
| 1082 | + \param[in] memory_size: Size of \a memory in bytes (must be >= sizeof(stk_msgq_mem_t)). |
| 1083 | + \param[in] buf: Pointer to the message data buffer. |
| 1084 | + Must be at least \a capacity * \a msg_size bytes. |
| 1085 | + \param[in] buf_size: Size of \a buf in bytes (used only for the safety assertion; must equal |
| 1086 | + \a capacity * \a msg_size). |
| 1087 | + \param[in] capacity: Maximum number of messages [1, 65534]. |
| 1088 | + \param[in] msg_size: Size of each individual message in bytes (>= 1). |
| 1089 | + \return MessageQueue handle, or NULL if any size assertion fails. |
| 1090 | +
|
| 1091 | + \note Convenience macro STK_MSGQ_BUF_SIZE(capacity, msg_size) computes |
| 1092 | + the required \a buf_size. |
| 1093 | + \note Only available when kernel is compiled with \a KERNEL_SYNC mode enabled. |
| 1094 | +*/ |
| 1095 | +stk_msgq_t *stk_msgq_create(stk_msgq_mem_t *memory, |
| 1096 | + uint32_t memory_size, |
| 1097 | + uint8_t *buf, |
| 1098 | + uint32_t buf_size, |
| 1099 | + size_t capacity, |
| 1100 | + size_t msg_size); |
| 1101 | + |
| 1102 | +/*! \brief Destroy a MessageQueue. |
| 1103 | + \param[in] mq: MessageQueue handle. |
| 1104 | + \note Any tasks still blocked on Put/Get at destruction time are considered |
| 1105 | + a logic error; an assertion is triggered in debug builds. |
| 1106 | +*/ |
| 1107 | +void stk_msgq_destroy(stk_msgq_t *mq); |
| 1108 | + |
| 1109 | +/*! \brief Put a message into the queue. |
| 1110 | + \details Copies \a msg_size bytes from \a msg into the next available slot. |
| 1111 | + Blocks if the queue is full until space becomes available or the |
| 1112 | + timeout expires. |
| 1113 | + \param[in] mq: MessageQueue handle. |
| 1114 | + \param[in] msg: Pointer to the message payload (must be >= msg_size bytes). |
| 1115 | + \param[in] timeout: Max time to wait (ticks). Use \c STK_WAIT_INFINITE to block |
| 1116 | + indefinitely, \c STK_NO_WAIT for a non-blocking attempt. |
| 1117 | + \return True if the message was enqueued, False on timeout. |
| 1118 | + \warning ISR-safe only with \a timeout = \c STK_NO_WAIT. |
| 1119 | +*/ |
| 1120 | +bool stk_msgq_put(stk_msgq_t *mq, const void *msg, int32_t timeout); |
| 1121 | + |
| 1122 | +/*! \brief Attempt to put a message into the queue without blocking. |
| 1123 | + \param[in] mq: MessageQueue handle. |
| 1124 | + \param[in] msg: Pointer to the message payload. |
| 1125 | + \return True if enqueued, False if the queue was full. |
| 1126 | + \warning ISR-safe. |
| 1127 | +*/ |
| 1128 | +bool stk_msgq_tryput(stk_msgq_t *mq, const void *msg); |
| 1129 | + |
| 1130 | +/*! \brief Get a message from the queue. |
| 1131 | + \details Copies the oldest message into \a msg. Blocks if the queue is |
| 1132 | + empty until a message arrives or the timeout expires. |
| 1133 | + \param[in] mq: MessageQueue handle. |
| 1134 | + \param[out] msg: Destination buffer (must be >= msg_size bytes). |
| 1135 | + \param[in] timeout: Max time to wait (ticks). Use \c STK_WAIT_INFINITE to block |
| 1136 | + indefinitely, \c STK_NO_WAIT for a non-blocking attempt. |
| 1137 | + \return True if a message was retrieved, False on timeout. |
| 1138 | + \warning ISR-safe only with \a timeout = \c STK_NO_WAIT. |
| 1139 | +*/ |
| 1140 | +bool stk_msgq_get(stk_msgq_t *mq, void *msg, int32_t timeout); |
| 1141 | + |
| 1142 | +/*! \brief Attempt to get a message from the queue without blocking. |
| 1143 | + \param[in] mq: MessageQueue handle. |
| 1144 | + \param[out] msg: Destination buffer. |
| 1145 | + \return True if a message was retrieved, False if the queue was empty. |
| 1146 | + \warning ISR-safe. |
| 1147 | +*/ |
| 1148 | +bool stk_msgq_tryget(stk_msgq_t *mq, void *msg); |
| 1149 | + |
| 1150 | +/*! \brief Discard all messages and reset the queue to the empty state. |
| 1151 | + \details Tasks blocked in Put() are woken so they can re-enqueue into the |
| 1152 | + now-empty queue. |
| 1153 | + \param[in] mq: MessageQueue handle. |
| 1154 | + \warning Messages that were in the queue are silently discarded. |
| 1155 | + \warning ISR-safe. |
| 1156 | +*/ |
| 1157 | +void stk_msgq_reset(stk_msgq_t *mq); |
| 1158 | + |
| 1159 | +/*! \brief Get the maximum number of messages the queue can hold. |
| 1160 | + \param[in] mq: MessageQueue handle. |
| 1161 | + \return Construction-time capacity. |
| 1162 | + \note ISR-safe. |
| 1163 | +*/ |
| 1164 | +size_t stk_msgq_get_capacity(const stk_msgq_t *mq); |
| 1165 | + |
| 1166 | +/*! \brief Get the size of each message in bytes. |
| 1167 | + \param[in] mq: MessageQueue handle. |
| 1168 | + \return Construction-time message size. |
| 1169 | + \note ISR-safe. |
| 1170 | +*/ |
| 1171 | +size_t stk_msgq_get_msg_size(const stk_msgq_t *mq); |
| 1172 | + |
| 1173 | +/*! \brief Get the current number of messages waiting in the queue. |
| 1174 | + \param[in] mq: MessageQueue handle. |
| 1175 | + \return Point-in-time snapshot of the message count. |
| 1176 | + \note ISR-safe on targets where a size_t-aligned read is atomic. |
| 1177 | +*/ |
| 1178 | +size_t stk_msgq_get_count(const stk_msgq_t *mq); |
| 1179 | + |
| 1180 | +/*! \brief Get the number of free slots currently available. |
| 1181 | + \param[in] mq: MessageQueue handle. |
| 1182 | + \return Point-in-time snapshot of the free-slot count. |
| 1183 | + \note ISR-safe. |
| 1184 | +*/ |
| 1185 | +size_t stk_msgq_get_space(const stk_msgq_t *mq); |
| 1186 | + |
| 1187 | +/*! \brief Check whether the queue is currently empty. |
| 1188 | + \param[in] mq: MessageQueue handle. |
| 1189 | + \return True if the queue contains no messages. |
| 1190 | + \note ISR-safe. |
| 1191 | +*/ |
| 1192 | +bool stk_msgq_is_empty(const stk_msgq_t *mq); |
| 1193 | + |
| 1194 | +/*! \brief Check whether the queue is currently full. |
| 1195 | + \param[in] mq: MessageQueue handle. |
| 1196 | + \return True if the queue contains \a capacity messages. |
| 1197 | + \note ISR-safe. |
| 1198 | +*/ |
| 1199 | +bool stk_msgq_is_full(const stk_msgq_t *mq); |
| 1200 | + |
1033 | 1201 | // ───── RWMutex (Reader-Writer Lock) ────────────────────────────────────────── |
1034 | 1202 |
|
1035 | 1203 | /*! \brief A memory size (multiples of stk_word_t) required for RWMutex instance. |
|
0 commit comments