diff options
Diffstat (limited to 'lib/chibios/os/hal/osal/os-less/ARMCMx/osal.c')
-rw-r--r-- | lib/chibios/os/hal/osal/os-less/ARMCMx/osal.c | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/lib/chibios/os/hal/osal/os-less/ARMCMx/osal.c b/lib/chibios/os/hal/osal/os-less/ARMCMx/osal.c new file mode 100644 index 000000000..a4cb7aabf --- /dev/null +++ b/lib/chibios/os/hal/osal/os-less/ARMCMx/osal.c | |||
@@ -0,0 +1,467 @@ | |||
1 | /* | ||
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | /** | ||
18 | * @file osal.c | ||
19 | * @brief OSAL module code. | ||
20 | * | ||
21 | * @addtogroup OSAL | ||
22 | * @{ | ||
23 | */ | ||
24 | |||
25 | #include "osal.h" | ||
26 | #include "osal_vt.h" | ||
27 | |||
28 | /*===========================================================================*/ | ||
29 | /* Module local definitions. */ | ||
30 | /*===========================================================================*/ | ||
31 | |||
32 | /*===========================================================================*/ | ||
33 | /* Module exported variables. */ | ||
34 | /*===========================================================================*/ | ||
35 | |||
36 | /** | ||
37 | * @brief Pointer to a halt error message. | ||
38 | * @note The message is meant to be retrieved by the debugger after the | ||
39 | * system halt caused by an unexpected error. | ||
40 | */ | ||
41 | const char *osal_halt_msg; | ||
42 | |||
43 | /*===========================================================================*/ | ||
44 | /* Module local types. */ | ||
45 | /*===========================================================================*/ | ||
46 | |||
47 | /*===========================================================================*/ | ||
48 | /* Module local variables. */ | ||
49 | /*===========================================================================*/ | ||
50 | |||
51 | /*===========================================================================*/ | ||
52 | /* Module local functions. */ | ||
53 | /*===========================================================================*/ | ||
54 | |||
55 | static void callback_timeout(void *p) { | ||
56 | osalSysLockFromISR(); | ||
57 | osalThreadResumeI((thread_reference_t *)p, MSG_TIMEOUT); | ||
58 | osalSysUnlockFromISR(); | ||
59 | } | ||
60 | |||
61 | /*===========================================================================*/ | ||
62 | /* Module exported functions. */ | ||
63 | /*===========================================================================*/ | ||
64 | |||
65 | /** | ||
66 | * @brief OSAL module initialization. | ||
67 | * | ||
68 | * @api | ||
69 | */ | ||
70 | void osalInit(void) { | ||
71 | |||
72 | vtInit(); | ||
73 | |||
74 | OSAL_INIT_HOOK(); | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * @brief System halt with error message. | ||
79 | * | ||
80 | * @param[in] reason the halt message pointer | ||
81 | * | ||
82 | * @api | ||
83 | */ | ||
84 | #if !defined(__DOXYGEN__) | ||
85 | __attribute__((weak, noreturn)) | ||
86 | #endif | ||
87 | void osalSysHalt(const char *reason) { | ||
88 | |||
89 | osalSysDisable(); | ||
90 | osal_halt_msg = reason; | ||
91 | while (true) { | ||
92 | } | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * @brief Polled delay. | ||
97 | * @note The real delay is always few cycles in excess of the specified | ||
98 | * value. | ||
99 | * | ||
100 | * @param[in] cycles number of cycles | ||
101 | * | ||
102 | * @xclass | ||
103 | */ | ||
104 | void osalSysPolledDelayX(rtcnt_t cycles) { | ||
105 | |||
106 | (void)cycles; | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * @brief System timer handler. | ||
111 | * @details The handler is used for scheduling and Virtual Timers management. | ||
112 | * | ||
113 | * @iclass | ||
114 | */ | ||
115 | void osalOsTimerHandlerI(void) { | ||
116 | |||
117 | osalDbgCheckClassI(); | ||
118 | |||
119 | vtDoTickI(); | ||
120 | } | ||
121 | |||
122 | /** | ||
123 | * @brief Checks if a reschedule is required and performs it. | ||
124 | * @note I-Class functions invoked from thread context must not reschedule | ||
125 | * by themselves, an explicit reschedule using this function is | ||
126 | * required in this scenario. | ||
127 | * @note Not implemented in this simplified OSAL. | ||
128 | * | ||
129 | * @sclass | ||
130 | */ | ||
131 | void osalOsRescheduleS(void) { | ||
132 | |||
133 | } | ||
134 | |||
135 | /** | ||
136 | * @brief Current system time. | ||
137 | * @details Returns the number of system ticks since the @p osalInit() | ||
138 | * invocation. | ||
139 | * @note The counter can reach its maximum and then restart from zero. | ||
140 | * @note This function can be called from any context but its atomicity | ||
141 | * is not guaranteed on architectures whose word size is less than | ||
142 | * @p systime_t size. | ||
143 | * | ||
144 | * @return The system time in ticks. | ||
145 | * | ||
146 | * @xclass | ||
147 | */ | ||
148 | systime_t osalOsGetSystemTimeX(void) { | ||
149 | |||
150 | return vtlist.vt_systime; | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * @brief Suspends the invoking thread for the specified time. | ||
155 | * | ||
156 | * @param[in] time the delay in system ticks, the special values are | ||
157 | * handled as follow: | ||
158 | * - @a TIME_INFINITE is allowed but interpreted as a | ||
159 | * normal time specification. | ||
160 | * - @a TIME_IMMEDIATE this value is not allowed. | ||
161 | * . | ||
162 | * | ||
163 | * @sclass | ||
164 | */ | ||
165 | void osalThreadSleepS(sysinterval_t time) { | ||
166 | virtual_timer_t vt; | ||
167 | thread_reference_t tr; | ||
168 | |||
169 | tr = NULL; | ||
170 | vtSetI(&vt, time, callback_timeout, (void *)&tr); | ||
171 | osalThreadSuspendS(&tr); | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * @brief Suspends the invoking thread for the specified time. | ||
176 | * | ||
177 | * @param[in] time the delay in system ticks, the special values are | ||
178 | * handled as follow: | ||
179 | * - @a TIME_INFINITE is allowed but interpreted as a | ||
180 | * normal time specification. | ||
181 | * - @a TIME_IMMEDIATE this value is not allowed. | ||
182 | * . | ||
183 | * | ||
184 | * @api | ||
185 | */ | ||
186 | void osalThreadSleep(sysinterval_t time) { | ||
187 | |||
188 | osalSysLock(); | ||
189 | osalThreadSleepS(time); | ||
190 | osalSysUnlock(); | ||
191 | } | ||
192 | |||
193 | /** | ||
194 | * @brief Sends the current thread sleeping and sets a reference variable. | ||
195 | * @note This function must reschedule, it can only be called from thread | ||
196 | * context. | ||
197 | * | ||
198 | * @param[in] trp a pointer to a thread reference object | ||
199 | * @return The wake up message. | ||
200 | * | ||
201 | * @sclass | ||
202 | */ | ||
203 | msg_t osalThreadSuspendS(thread_reference_t *trp) { | ||
204 | thread_t self = {MSG_WAIT}; | ||
205 | |||
206 | osalDbgCheck(trp != NULL); | ||
207 | |||
208 | *trp = &self; | ||
209 | while (self.message == MSG_WAIT) { | ||
210 | osalSysUnlock(); | ||
211 | /* A state-changing interrupt could occur here and cause the loop to | ||
212 | terminate, an hook macro is executed while waiting.*/ | ||
213 | OSAL_IDLE_HOOK(); | ||
214 | osalSysLock(); | ||
215 | } | ||
216 | |||
217 | return self.message; | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * @brief Sends the current thread sleeping and sets a reference variable. | ||
222 | * @note This function must reschedule, it can only be called from thread | ||
223 | * context. | ||
224 | * | ||
225 | * @param[in] trp a pointer to a thread reference object | ||
226 | * @param[in] timeout the timeout in system ticks, the special values are | ||
227 | * handled as follow: | ||
228 | * - @a TIME_INFINITE the thread enters an infinite sleep | ||
229 | * state. | ||
230 | * - @a TIME_IMMEDIATE the thread is not enqueued and | ||
231 | * the function returns @p MSG_TIMEOUT as if a timeout | ||
232 | * occurred. | ||
233 | * . | ||
234 | * @return The wake up message. | ||
235 | * @retval MSG_TIMEOUT if the operation timed out. | ||
236 | * | ||
237 | * @sclass | ||
238 | */ | ||
239 | msg_t osalThreadSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout) { | ||
240 | msg_t msg; | ||
241 | virtual_timer_t vt; | ||
242 | |||
243 | osalDbgCheck(trp != NULL); | ||
244 | |||
245 | if (TIME_INFINITE == timeout) | ||
246 | return osalThreadSuspendS(trp); | ||
247 | |||
248 | vtSetI(&vt, timeout, callback_timeout, (void *)trp); | ||
249 | msg = osalThreadSuspendS(trp); | ||
250 | if (vtIsArmedI(&vt)) | ||
251 | vtResetI(&vt); | ||
252 | |||
253 | return msg; | ||
254 | } | ||
255 | |||
256 | /** | ||
257 | * @brief Wakes up a thread waiting on a thread reference object. | ||
258 | * @note This function must not reschedule because it can be called from | ||
259 | * ISR context. | ||
260 | * | ||
261 | * @param[in] trp a pointer to a thread reference object | ||
262 | * @param[in] msg the message code | ||
263 | * | ||
264 | * @iclass | ||
265 | */ | ||
266 | void osalThreadResumeI(thread_reference_t *trp, msg_t msg) { | ||
267 | |||
268 | osalDbgCheck(trp != NULL); | ||
269 | |||
270 | if (*trp != NULL) { | ||
271 | (*trp)->message = msg; | ||
272 | *trp = NULL; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * @brief Wakes up a thread waiting on a thread reference object. | ||
278 | * @note This function must reschedule, it can only be called from thread | ||
279 | * context. | ||
280 | * | ||
281 | * @param[in] trp a pointer to a thread reference object | ||
282 | * @param[in] msg the message code | ||
283 | * | ||
284 | * @iclass | ||
285 | */ | ||
286 | void osalThreadResumeS(thread_reference_t *trp, msg_t msg) { | ||
287 | |||
288 | osalDbgCheck(trp != NULL); | ||
289 | |||
290 | if (*trp != NULL) { | ||
291 | (*trp)->message = msg; | ||
292 | *trp = NULL; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | /** | ||
297 | * @brief Enqueues the caller thread. | ||
298 | * @details The caller thread is enqueued and put to sleep until it is | ||
299 | * dequeued or the specified timeouts expires. | ||
300 | * | ||
301 | * @param[in] tqp pointer to the threads queue object | ||
302 | * @param[in] timeout the timeout in system ticks, the special values are | ||
303 | * handled as follow: | ||
304 | * - @a TIME_INFINITE the thread enters an infinite sleep | ||
305 | * state. | ||
306 | * - @a TIME_IMMEDIATE the thread is not enqueued and | ||
307 | * the function returns @p MSG_TIMEOUT as if a timeout | ||
308 | * occurred. | ||
309 | * . | ||
310 | * @return The message from @p osalQueueWakeupOneI() or | ||
311 | * @p osalQueueWakeupAllI() functions. | ||
312 | * @retval MSG_TIMEOUT if the thread has not been dequeued within the | ||
313 | * specified timeout or if the function has been | ||
314 | * invoked with @p TIME_IMMEDIATE as timeout | ||
315 | * specification. | ||
316 | * | ||
317 | * @sclass | ||
318 | */ | ||
319 | msg_t osalThreadEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout) { | ||
320 | msg_t msg; | ||
321 | virtual_timer_t vt; | ||
322 | |||
323 | osalDbgCheck(tqp != NULL); | ||
324 | |||
325 | if (TIME_IMMEDIATE == timeout) | ||
326 | return MSG_TIMEOUT; | ||
327 | |||
328 | tqp->tr = NULL; | ||
329 | |||
330 | if (TIME_INFINITE == timeout) | ||
331 | return osalThreadSuspendS(&tqp->tr); | ||
332 | |||
333 | vtSetI(&vt, timeout, callback_timeout, (void *)&tqp->tr); | ||
334 | msg = osalThreadSuspendS(&tqp->tr); | ||
335 | if (vtIsArmedI(&vt)) | ||
336 | vtResetI(&vt); | ||
337 | |||
338 | return msg; | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * @brief Dequeues and wakes up one thread from the queue, if any. | ||
343 | * | ||
344 | * @param[in] tqp pointer to the threads queue object | ||
345 | * @param[in] msg the message code | ||
346 | * | ||
347 | * @iclass | ||
348 | */ | ||
349 | void osalThreadDequeueNextI(threads_queue_t *tqp, msg_t msg) { | ||
350 | |||
351 | osalDbgCheck(tqp != NULL); | ||
352 | |||
353 | osalThreadResumeI(&tqp->tr, msg); | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * @brief Dequeues and wakes up all threads from the queue. | ||
358 | * | ||
359 | * @param[in] tqp pointer to the threads queue object | ||
360 | * @param[in] msg the message code | ||
361 | * | ||
362 | * @iclass | ||
363 | */ | ||
364 | void osalThreadDequeueAllI(threads_queue_t *tqp, msg_t msg) { | ||
365 | |||
366 | osalDbgCheck(tqp != NULL); | ||
367 | |||
368 | osalThreadResumeI(&tqp->tr, msg); | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * @brief Add flags to an event source object. | ||
373 | * | ||
374 | * @param[in] esp pointer to the event flags object | ||
375 | * @param[in] flags flags to be ORed to the flags mask | ||
376 | * | ||
377 | * @iclass | ||
378 | */ | ||
379 | void osalEventBroadcastFlagsI(event_source_t *esp, eventflags_t flags) { | ||
380 | |||
381 | osalDbgCheck(esp != NULL); | ||
382 | |||
383 | esp->flags |= flags; | ||
384 | if (esp->cb != NULL) { | ||
385 | esp->cb(esp); | ||
386 | } | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * @brief Add flags to an event source object. | ||
391 | * | ||
392 | * @param[in] esp pointer to the event flags object | ||
393 | * @param[in] flags flags to be ORed to the flags mask | ||
394 | * | ||
395 | * @iclass | ||
396 | */ | ||
397 | void osalEventBroadcastFlags(event_source_t *esp, eventflags_t flags) { | ||
398 | |||
399 | osalDbgCheck(esp != NULL); | ||
400 | |||
401 | osalSysLock(); | ||
402 | osalEventBroadcastFlagsI(esp, flags); | ||
403 | osalSysUnlock(); | ||
404 | } | ||
405 | |||
406 | /** | ||
407 | * @brief Event callback setup. | ||
408 | * @note The callback is invoked from ISR context and can | ||
409 | * only invoke I-Class functions. The callback is meant | ||
410 | * to wakeup the task that will handle the event by | ||
411 | * calling @p osalEventGetAndClearFlagsI(). | ||
412 | * @note This function is not part of the OSAL API and is provided | ||
413 | * exclusively as an example and for convenience. | ||
414 | * | ||
415 | * @param[in] esp pointer to the event flags object | ||
416 | * @param[in] cb pointer to the callback function | ||
417 | * @param[in] param parameter to be passed to the callback function | ||
418 | * | ||
419 | * @api | ||
420 | */ | ||
421 | void osalEventSetCallback(event_source_t *esp, | ||
422 | eventcallback_t cb, | ||
423 | void *param) { | ||
424 | |||
425 | osalDbgCheck(esp != NULL); | ||
426 | |||
427 | esp->cb = cb; | ||
428 | esp->param = param; | ||
429 | } | ||
430 | |||
431 | /** | ||
432 | * @brief Locks the specified mutex. | ||
433 | * @post The mutex is locked and inserted in the per-thread stack of owned | ||
434 | * mutexes. | ||
435 | * | ||
436 | * @param[in,out] mp pointer to the @p mutex_t object | ||
437 | * | ||
438 | * @api | ||
439 | */ | ||
440 | void osalMutexLock(mutex_t *mp) { | ||
441 | |||
442 | osalDbgCheck(mp != NULL); | ||
443 | |||
444 | *mp = 1; | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * @brief Unlocks the specified mutex. | ||
449 | * @note The HAL guarantees to release mutex in reverse lock order. The | ||
450 | * mutex being unlocked is guaranteed to be the last locked mutex | ||
451 | * by the invoking thread. | ||
452 | * The implementation can rely on this behavior and eventually | ||
453 | * ignore the @p mp parameter which is supplied in order to support | ||
454 | * those OSes not supporting a stack of the owned mutexes. | ||
455 | * | ||
456 | * @param[in,out] mp pointer to the @p mutex_t object | ||
457 | * | ||
458 | * @api | ||
459 | */ | ||
460 | void osalMutexUnlock(mutex_t *mp) { | ||
461 | |||
462 | osalDbgCheck(mp != NULL); | ||
463 | |||
464 | *mp = 0; | ||
465 | } | ||
466 | |||
467 | /** @} */ | ||