1 /*----------------------------------------------------------------------------
3 *----------------------------------------------------------------------------
5 * Purpose: CMSIS RTOS API
7 *----------------------------------------------------------------------------
9 * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
10 * All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * - Neither the name of ARM nor the names of its contributors may be used
19 * to endorse or promote products derived from this software without
20 * specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *---------------------------------------------------------------------------*/
35 #define __CMSIS_GENERIC
37 #if defined (__CORTEX_M4) || defined (__CORTEX_M4F)
39 #elif defined (__CORTEX_M3)
41 #elif defined (__CORTEX_M0)
43 #elif defined (__CORTEX_M0PLUS)
44 #include "core_cm0plus.h"
46 #error "Missing __CORTEX_Mx definition"
49 #include "rt_TypeDef.h"
51 #include "rt_System.h"
57 #include "rt_Semaphore.h"
58 #include "rt_Mailbox.h"
59 #include "rt_MemBox.h"
60 #include "rt_HAL_CM.h"
62 #define os_thread_cb OS_TCB
66 #if (osFeature_Signals != 16)
67 #error Invalid "osFeature_Signals" value!
69 #if (osFeature_Semaphore > 65535)
70 #error Invalid "osFeature_Semaphore" value!
72 #if (osFeature_Wait != 0)
73 #error osWait not supported!
77 // ==== Enumeration, structures, defines ====
79 // Service Calls defines
81 #if defined (__CC_ARM) /* ARM Compiler */
83 #define __NO_RETURN __declspec(noreturn)
85 #define osEvent_type osEvent
86 #define osEvent_ret_status ret
87 #define osEvent_ret_value ret
88 #define osEvent_ret_msg ret
89 #define osEvent_ret_mail ret
91 #define osCallback_type osCallback
92 #define osCallback_ret ret
94 #define SVC_0_1(f,t,...) \
95 __svc_indirect(0) t _##f (t(*)()); \
97 __attribute__((always_inline)) \
98 static __inline t __##f (void) { \
102 #define SVC_1_1(f,t,t1,...) \
103 __svc_indirect(0) t _##f (t(*)(t1),t1); \
105 __attribute__((always_inline)) \
106 static __inline t __##f (t1 a1) { \
110 #define SVC_2_1(f,t,t1,t2,...) \
111 __svc_indirect(0) t _##f (t(*)(t1,t2),t1,t2); \
112 t f (t1 a1, t2 a2); \
113 __attribute__((always_inline)) \
114 static __inline t __##f (t1 a1, t2 a2) { \
115 return _##f(f,a1,a2); \
118 #define SVC_3_1(f,t,t1,t2,t3,...) \
119 __svc_indirect(0) t _##f (t(*)(t1,t2,t3),t1,t2,t3); \
120 t f (t1 a1, t2 a2, t3 a3); \
121 __attribute__((always_inline)) \
122 static __inline t __##f (t1 a1, t2 a2, t3 a3) { \
123 return _##f(f,a1,a2,a3); \
126 #define SVC_4_1(f,t,t1,t2,t3,t4,...) \
127 __svc_indirect(0) t _##f (t(*)(t1,t2,t3,t4),t1,t2,t3,t4); \
128 t f (t1 a1, t2 a2, t3 a3, t4 a4); \
129 __attribute__((always_inline)) \
130 static __inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) { \
131 return _##f(f,a1,a2,a3,a4); \
134 #define SVC_1_2 SVC_1_1
135 #define SVC_1_3 SVC_1_1
136 #define SVC_2_3 SVC_2_1
138 #elif defined (__GNUC__) /* GNU Compiler */
140 #define __NO_RETURN __attribute__((noreturn))
142 typedef uint32_t __attribute__((vector_size(8))) ret64
;
143 typedef uint32_t __attribute__((vector_size(16))) ret128
;
145 #define RET_pointer __r0
146 #define RET_int32_t __r0
147 #define RET_osStatus __r0
148 #define RET_osPriority __r0
149 #define RET_osEvent {(osStatus)__r0, {(uint32_t)__r1}, {(void *)__r2}}
150 #define RET_osCallback {(void *)__r0, (void *)__r1}
152 #define osEvent_type ret128
153 #define osEvent_ret_status (ret128){ret.status}
154 #define osEvent_ret_value (ret128){ret.status, ret.value.v}
155 #define osEvent_ret_msg (ret128){ret.status, ret.value.v, (uint32_t)ret.def.message_id}
156 #define osEvent_ret_mail (ret128){ret.status, ret.value.v, (uint32_t)ret.def.mail_id}
158 #define osCallback_type ret64
159 #define osCallback_ret (ret64) {(uint32_t)ret.fp, (uint32_t)ret.arg}
161 #define SVC_ArgN(n) \
162 register int __r##n __asm("r"#n);
164 #define SVC_ArgR(n,t,a) \
165 register t __r##n __asm("r"#n) = a;
173 #define SVC_Arg1(t1) \
179 #define SVC_Arg2(t1,t2) \
185 #define SVC_Arg3(t1,t2,t3) \
191 #define SVC_Arg4(t1,t2,t3,t4) \
197 #if (defined (__CORTEX_M0)) || defined (__CORTEX_M0PLUS)
198 #define SVC_Call(f) \
204 : "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3) \
205 : "r" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) \
206 : "r7", "r12", "lr", "cc" \
209 #define SVC_Call(f) \
212 "ldr r12,="#f"\n\t" \
214 : "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3) \
215 : "r" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) \
216 : "r12", "lr", "cc" \
220 #define SVC_0_1(f,t,rv) \
221 __attribute__((always_inline)) \
222 static inline t __##f (void) { \
228 #define SVC_1_1(f,t,t1,rv) \
229 __attribute__((always_inline)) \
230 static inline t __##f (t1 a1) { \
236 #define SVC_2_1(f,t,t1,t2,rv) \
237 __attribute__((always_inline)) \
238 static inline t __##f (t1 a1, t2 a2) { \
244 #define SVC_3_1(f,t,t1,t2,t3,rv) \
245 __attribute__((always_inline)) \
246 static inline t __##f (t1 a1, t2 a2, t3 a3) { \
247 SVC_Arg3(t1,t2,t3); \
252 #define SVC_4_1(f,t,t1,t2,t3,t4,rv) \
253 __attribute__((always_inline)) \
254 static inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) { \
255 SVC_Arg4(t1,t2,t3,t4); \
260 #define SVC_1_2 SVC_1_1
261 #define SVC_1_3 SVC_1_1
262 #define SVC_2_3 SVC_2_1
264 #elif defined (__ICCARM__) /* IAR Compiler */
266 #define __NO_RETURN __noreturn
268 #define osEvent_type osEvent
269 #define osEvent_ret_status ret
270 #define osEvent_ret_value ret
271 #define osEvent_ret_msg ret
272 #define osEvent_ret_mail ret
274 #define osCallback_type osCallback
275 #define osCallback_ret ret
277 #define RET_osEvent osEvent
278 #define RET_osCallback osCallback
280 #define SVC_Setup(f) \
287 #define SVC_0_1(f,t,...) \
289 _Pragma("swi_number=0") __swi t _##f (void); \
290 static inline t __##f (void) { \
295 #define SVC_1_1(f,t,t1,...) \
297 _Pragma("swi_number=0") __swi t _##f (t1 a1); \
298 static inline t __##f (t1 a1) { \
303 #define SVC_2_1(f,t,t1,t2,...) \
304 t f (t1 a1, t2 a2); \
305 _Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2); \
306 static inline t __##f (t1 a1, t2 a2) { \
308 return _##f(a1,a2); \
311 #define SVC_3_1(f,t,t1,t2,t3,...) \
312 t f (t1 a1, t2 a2, t3 a3); \
313 _Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2, t3 a3); \
314 static inline t __##f (t1 a1, t2 a2, t3 a3) { \
316 return _##f(a1,a2,a3); \
319 #define SVC_4_1(f,t,t1,t2,t3,t4,...) \
320 t f (t1 a1, t2 a2, t3 a3, t4 a4); \
321 _Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2, t3 a3, t4 a4); \
322 static inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) { \
324 return _##f(a1,a2,a3,a4); \
327 #define SVC_1_2 SVC_1_1
328 #define SVC_1_3 SVC_1_1
329 #define SVC_2_3 SVC_2_1
334 // Callback structure
336 void *fp
; // Function pointer
337 void *arg
; // Function argument
341 // OS Section definitions
342 #ifdef OS_SECTIONS_LINK_INFO
343 extern const uint32_t os_section_id$$Base
;
344 extern const uint32_t os_section_id$$Limit
;
347 // OS Timers external resources
348 extern osThreadDef_t os_thread_def_osTimerThread
;
349 extern osThreadId osThreadId_osTimerThread
;
350 extern osMessageQDef_t os_messageQ_def_osTimerMessageQ
;
351 extern osMessageQId osMessageQId_osTimerMessageQ
;
354 // ==== Helper Functions ====
356 /// Convert timeout in millisec to system ticks
357 static uint32_t rt_ms2tick (uint32_t millisec
) {
360 if (millisec
== osWaitForever
) return 0xFFFF; // Indefinite timeout
361 if (millisec
> 4000000) return 0xFFFE; // Max ticks supported
363 tick
= ((1000 * millisec
) + os_clockrate
- 1) / os_clockrate
;
364 if (tick
> 0xFFFE) return 0xFFFE;
369 /// Convert Thread ID to TCB pointer
370 static P_TCB
rt_tid2ptcb (osThreadId thread_id
) {
373 if (thread_id
== NULL
) return NULL
;
375 if ((uint32_t)thread_id
& 3) return NULL
;
377 #ifdef OS_SECTIONS_LINK_INFO
378 if ((os_section_id$$Base
!= 0) && (os_section_id$$Limit
!= 0)) {
379 if (thread_id
< (osThreadId
)os_section_id$$Base
) return NULL
;
380 if (thread_id
>= (osThreadId
)os_section_id$$Limit
) return NULL
;
386 if (ptcb
->cb_type
!= TCB
) return NULL
;
391 /// Convert ID pointer to Object pointer
392 static void *rt_id2obj (void *id
) {
394 if ((uint32_t)id
& 3) return NULL
;
396 #ifdef OS_SECTIONS_LINK_INFO
397 if ((os_section_id$$Base
!= 0) && (os_section_id$$Limit
!= 0)) {
398 if (id
< (void *)os_section_id$$Base
) return NULL
;
399 if (id
>= (void *)os_section_id$$Limit
) return NULL
;
407 // ==== Kernel Control ====
409 uint8_t os_initialized
; // Kernel Initialized flag
410 uint8_t os_running
; // Kernel Running flag
412 // Kernel Control Service Calls declarations
413 SVC_0_1(svcKernelInitialize
, osStatus
, RET_osStatus
)
414 SVC_0_1(svcKernelStart
, osStatus
, RET_osStatus
)
415 SVC_0_1(svcKernelRunning
, int32_t, RET_int32_t
)
417 extern void sysThreadError (osStatus status
);
418 osThreadId
svcThreadCreate (osThreadDef_t
*thread_def
, void *argument
);
419 osMessageQId
svcMessageCreate (osMessageQDef_t
*queue_def
, osThreadId thread_id
);
421 // Kernel Control Service Calls
423 /// Initialize the RTOS Kernel for creating objects
424 osStatus
svcKernelInitialize (void) {
425 if (os_initialized
) return osOK
;
427 rt_sys_init(); // RTX System Initialization
428 os_tsk
.run
->prio
= 255; // Highest priority
430 sysThreadError(osOK
);
437 /// Start the RTOS Kernel
438 osStatus
svcKernelStart (void) {
440 if (os_running
) return osOK
;
442 // Create OS Timers resources (Message Queue & Thread)
443 osMessageQId_osTimerMessageQ
= svcMessageCreate (&os_messageQ_def_osTimerMessageQ
, NULL
);
444 osThreadId_osTimerThread
= svcThreadCreate(&os_thread_def_osTimerThread
, NULL
);
446 rt_tsk_prio(0, 0); // Lowest priority
447 __set_PSP(os_tsk
.run
->tsk_stack
+ 8*4); // New context
448 os_tsk
.run
= NULL
; // Force context switch
457 /// Check if the RTOS kernel is already started
458 int32_t svcKernelRunning(void) {
462 // Kernel Control Public API
464 /// Initialize the RTOS Kernel for creating objects
465 osStatus
osKernelInitialize (void) {
466 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
467 if ((__get_CONTROL() & 1) == 0) { // Privileged mode
468 return svcKernelInitialize();
470 return __svcKernelInitialize();
474 /// Start the RTOS Kernel
475 osStatus
osKernelStart (void) {
478 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
479 switch (__get_CONTROL() & 0x03) {
480 case 0x00: // Privileged Thread mode & MSP
481 __set_PSP((uint32_t)(stack
+ 8)); // Initial PSP
483 __set_CONTROL(0x02); // Set Privileged Thread mode & PSP
485 __set_CONTROL(0x03); // Set Unprivileged Thread mode & PSP
490 case 0x01: // Unprivileged Thread mode & MSP
492 case 0x02: // Privileged Thread mode & PSP
493 if ((os_flags
& 1) == 0) { // Unprivileged Thread mode requested
494 __set_CONTROL(0x03); // Set Unprivileged Thread mode & PSP
499 case 0x03: // Unprivileged Thread mode & PSP
500 if (os_flags
& 1) return osErrorOS
; // Privileged Thread mode requested
503 return __svcKernelStart();
506 /// Check if the RTOS kernel is already started
507 int32_t osKernelRunning(void) {
508 if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) {
509 // in ISR or Privileged
512 return __svcKernelRunning();
517 // ==== Thread Management ====
519 __NO_RETURN
void osThreadExit (void);
521 // Thread Service Calls declarations
522 SVC_2_1(svcThreadCreate
, osThreadId
, osThreadDef_t
*, void *, RET_pointer
)
523 SVC_0_1(svcThreadGetId
, osThreadId
, RET_pointer
)
524 SVC_1_1(svcThreadTerminate
, osStatus
, osThreadId
, RET_osStatus
)
525 SVC_0_1(svcThreadYield
, osStatus
, RET_osStatus
)
526 SVC_2_1(svcThreadSetPriority
, osStatus
, osThreadId
, osPriority
, RET_osStatus
)
527 SVC_1_1(svcThreadGetPriority
, osPriority
, osThreadId
, RET_osPriority
)
529 // Thread Service Calls
530 extern OS_TID
rt_get_TID (void);
531 extern void rt_init_context (P_TCB p_TCB
, U8 priority
, FUNCP task_body
);
533 /// Create a thread and add it to Active Threads and set it to state READY
534 osThreadId
svcThreadCreate (osThreadDef_t
*thread_def
, void *argument
) {
537 if ((thread_def
== NULL
) ||
538 (thread_def
->pthread
== NULL
) ||
539 (thread_def
->tpriority
< osPriorityIdle
) ||
540 (thread_def
->tpriority
> osPriorityRealtime
) ||
541 (thread_def
->stacksize
== 0) ||
542 (thread_def
->stack_pointer
== NULL
) ) {
543 sysThreadError(osErrorParameter
);
547 U8 priority
= thread_def
->tpriority
- osPriorityIdle
+ 1;
548 P_TCB task_context
= &thread_def
->tcb
;
550 /* Utilize the user provided stack. */
551 task_context
->stack
= (U32
*)thread_def
->stack_pointer
;
552 task_context
->priv_stack
= thread_def
->stacksize
;
553 /* Find a free entry in 'os_active_TCB' table. */
554 OS_TID tsk
= rt_get_TID ();
555 os_active_TCB
[tsk
-1] = task_context
;
556 task_context
->task_id
= tsk
;
557 /* Pass parameter 'argv' to 'rt_init_context' */
558 task_context
->msg
= argument
;
559 /* Initialize thread context structure, including the thread's stack. */
560 rt_init_context (task_context
, priority
, (FUNCP
)thread_def
->pthread
);
562 /* Dispatch this task to the scheduler for execution. */
563 DBG_TASK_NOTIFY(task_context
, __TRUE
);
564 rt_dispatch (task_context
);
566 ptcb
= (P_TCB
)os_active_TCB
[tsk
- 1]; // TCB pointer
568 *((uint32_t *)ptcb
->tsk_stack
+ 13) = (uint32_t)osThreadExit
;
573 /// Return the thread ID of the current running thread
574 osThreadId
svcThreadGetId (void) {
578 if (tsk
== 0) return NULL
;
579 return (P_TCB
)os_active_TCB
[tsk
- 1];
582 /// Terminate execution of a thread and remove it from ActiveThreads
583 osStatus
svcThreadTerminate (osThreadId thread_id
) {
587 ptcb
= rt_tid2ptcb(thread_id
); // Get TCB pointer
588 if (ptcb
== NULL
) return osErrorParameter
;
590 res
= rt_tsk_delete(ptcb
->task_id
); // Delete task
592 if (res
== OS_R_NOK
) return osErrorResource
; // Delete task failed
597 /// Pass control to next thread that is in state READY
598 osStatus
svcThreadYield (void) {
599 rt_tsk_pass(); // Pass control to next task
603 /// Change priority of an active thread
604 osStatus
svcThreadSetPriority (osThreadId thread_id
, osPriority priority
) {
608 ptcb
= rt_tid2ptcb(thread_id
); // Get TCB pointer
609 if (ptcb
== NULL
) return osErrorParameter
;
611 if ((priority
< osPriorityIdle
) || (priority
> osPriorityRealtime
)) {
615 res
= rt_tsk_prio( // Change task priority
616 ptcb
->task_id
, // Task ID
617 priority
- osPriorityIdle
+ 1 // New task priority
620 if (res
== OS_R_NOK
) return osErrorResource
; // Change task priority failed
625 /// Get current priority of an active thread
626 osPriority
svcThreadGetPriority (osThreadId thread_id
) {
629 ptcb
= rt_tid2ptcb(thread_id
); // Get TCB pointer
630 if (ptcb
== NULL
) return osPriorityError
;
632 return (osPriority
)(ptcb
->prio
- 1 + osPriorityIdle
);
638 /// Create a thread and add it to Active Threads and set it to state READY
639 osThreadId
osThreadCreate (osThreadDef_t
*thread_def
, void *argument
) {
640 if (__get_IPSR() != 0) return NULL
; // Not allowed in ISR
641 if (((__get_CONTROL() & 1) == 0) && (os_running
== 0)) {
642 // Privileged and not running
643 return svcThreadCreate(thread_def
, argument
);
645 return __svcThreadCreate(thread_def
, argument
);
649 /// Return the thread ID of the current running thread
650 osThreadId
osThreadGetId (void) {
651 if (__get_IPSR() != 0) return NULL
; // Not allowed in ISR
652 return __svcThreadGetId();
655 /// Terminate execution of a thread and remove it from ActiveThreads
656 osStatus
osThreadTerminate (osThreadId thread_id
) {
657 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
658 return __svcThreadTerminate(thread_id
);
661 /// Pass control to next thread that is in state READY
662 osStatus
osThreadYield (void) {
663 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
664 return __svcThreadYield();
667 /// Change priority of an active thread
668 osStatus
osThreadSetPriority (osThreadId thread_id
, osPriority priority
) {
669 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
670 return __svcThreadSetPriority(thread_id
, priority
);
673 /// Get current priority of an active thread
674 osPriority
osThreadGetPriority (osThreadId thread_id
) {
675 if (__get_IPSR() != 0) return osPriorityError
;// Not allowed in ISR
676 return __svcThreadGetPriority(thread_id
);
679 /// INTERNAL - Not Public
680 /// Auto Terminate Thread on exit (used implicitly when thread exists)
681 __NO_RETURN
void osThreadExit (void) {
682 __svcThreadTerminate(__svcThreadGetId());
683 for (;;); // Should never come here
687 // ==== Generic Wait Functions ====
689 // Generic Wait Service Calls declarations
690 SVC_1_1(svcDelay
, osStatus
, uint32_t, RET_osStatus
)
691 #if osFeature_Wait != 0
692 SVC_1_3(svcWait
, os_InRegs osEvent
, uint32_t, RET_osEvent
)
695 // Generic Wait Service Calls
697 /// Wait for Timeout (Time Delay)
698 osStatus
svcDelay (uint32_t millisec
) {
699 if (millisec
== 0) return osOK
;
700 rt_dly_wait(rt_ms2tick(millisec
));
701 return osEventTimeout
;
704 /// Wait for Signal, Message, Mail, or Timeout
705 #if osFeature_Wait != 0
706 os_InRegs osEvent_type
svcWait (uint32_t millisec
) {
711 return osEvent_ret_status
;
714 /* To Do: osEventSignal, osEventMessage, osEventMail */
715 rt_dly_wait(rt_ms2tick(millisec
));
716 ret
.status
= osEventTimeout
;
718 return osEvent_ret_status
;
725 /// Wait for Timeout (Time Delay)
726 osStatus
osDelay (uint32_t millisec
) {
727 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
728 return __svcDelay(millisec
);
731 /// Wait for Signal, Message, Mail, or Timeout
732 os_InRegs osEvent
osWait (uint32_t millisec
) {
735 #if osFeature_Wait == 0
736 ret
.status
= osErrorOS
;
739 if (__get_IPSR() != 0) { // Not allowed in ISR
740 ret
.status
= osErrorISR
;
743 return __svcWait(millisec
);
748 // ==== Timer Management ====
751 #define osTimerInvalid 0
752 #define osTimerStopped 1
753 #define osTimerRunning 2
757 typedef struct os_timer_cb_
{ // Timer Control Block
758 struct os_timer_cb_
*next
; // Pointer to next active Timer
759 uint8_t state
; // Timer State
760 uint8_t type
; // Timer Type (Periodic/One-shot)
761 uint16_t reserved
; // Reserved
762 uint16_t tcnt
; // Timer Delay Count
763 uint16_t icnt
; // Timer Initial Count
764 void *arg
; // Timer Function Argument
765 osTimerDef_t
*timer
; // Pointer to Timer definition
769 os_timer_cb
*os_timer_head
; // Pointer to first active Timer
772 // Timer Helper Functions
774 // Insert Timer into the list sorted by time
775 static void rt_timer_insert (os_timer_cb
*pt
, uint32_t tcnt
) {
776 os_timer_cb
*p
, *prev
;
781 if (tcnt
< p
->tcnt
) break;
787 pt
->tcnt
= (uint16_t)tcnt
;
798 // Remove Timer from the list
799 static int rt_timer_remove (os_timer_cb
*pt
) {
800 os_timer_cb
*p
, *prev
;
809 if (p
== NULL
) return -1;
811 prev
->next
= pt
->next
;
813 os_timer_head
= pt
->next
;
815 if (pt
->next
!= NULL
) {
816 pt
->next
->tcnt
+= pt
->tcnt
;
823 // Timer Service Calls declarations
824 SVC_3_1(svcTimerCreate
, osTimerId
, osTimerDef_t
*, os_timer_type
, void *, RET_pointer
)
825 SVC_2_1(svcTimerStart
, osStatus
, osTimerId
, uint32_t, RET_osStatus
)
826 SVC_1_1(svcTimerStop
, osStatus
, osTimerId
, RET_osStatus
)
827 SVC_1_1(svcTimerDelete
, osStatus
, osTimerId
, RET_osStatus
)
828 SVC_1_2(svcTimerCall
, os_InRegs osCallback
, osTimerId
, RET_osCallback
)
830 // Timer Management Service Calls
833 osTimerId
svcTimerCreate (osTimerDef_t
*timer_def
, os_timer_type type
, void *argument
) {
836 if ((timer_def
== NULL
) || (timer_def
->ptimer
== NULL
)) {
837 sysThreadError(osErrorParameter
);
841 pt
= timer_def
->timer
;
843 sysThreadError(osErrorParameter
);
847 if ((type
!= osTimerOnce
) && (type
!= osTimerPeriodic
)) {
848 sysThreadError(osErrorValue
);
852 if (osThreadId_osTimerThread
== NULL
) {
853 sysThreadError(osErrorResource
);
857 if (pt
->state
!= osTimerInvalid
){
858 sysThreadError(osErrorResource
);
862 pt
->state
= osTimerStopped
;
863 pt
->type
= (uint8_t)type
;
865 pt
->timer
= timer_def
;
867 return (osTimerId
)pt
;
870 /// Start or restart timer
871 osStatus
svcTimerStart (osTimerId timer_id
, uint32_t millisec
) {
875 pt
= rt_id2obj(timer_id
);
876 if (pt
== NULL
) return osErrorParameter
;
878 tcnt
= rt_ms2tick(millisec
);
879 if (tcnt
== 0) return osErrorValue
;
883 if (rt_timer_remove(pt
) != 0) {
884 return osErrorResource
;
888 pt
->state
= osTimerRunning
;
889 pt
->icnt
= (uint16_t)tcnt
;
892 return osErrorResource
;
895 rt_timer_insert(pt
, tcnt
);
901 osStatus
svcTimerStop (osTimerId timer_id
) {
904 pt
= rt_id2obj(timer_id
);
905 if (pt
== NULL
) return osErrorParameter
;
907 if (pt
->state
!= osTimerRunning
) return osErrorResource
;
909 pt
->state
= osTimerStopped
;
911 if (rt_timer_remove(pt
) != 0) {
912 return osErrorResource
;
919 osStatus
svcTimerDelete (osTimerId timer_id
) {
922 pt
= rt_id2obj(timer_id
);
923 if (pt
== NULL
) return osErrorParameter
;
932 return osErrorResource
;
935 pt
->state
= osTimerInvalid
;
940 /// Get timer callback parameters
941 os_InRegs osCallback_type
svcTimerCall (osTimerId timer_id
) {
945 pt
= rt_id2obj(timer_id
);
949 return osCallback_ret
;
952 ret
.fp
= (void *)pt
->timer
->ptimer
;
955 return osCallback_ret
;
958 static __INLINE osStatus
isrMessagePut (osMessageQId queue_id
, uint32_t info
, uint32_t millisec
);
960 /// Timer Tick (called each SysTick)
961 void sysTimerTick (void) {
965 if (p
== NULL
) return;
968 while ((p
!= NULL
) && (p
->tcnt
== 0)) {
972 isrMessagePut(osMessageQId_osTimerMessageQ
, (uint32_t)pt
, 0);
973 if (pt
->type
== osTimerPeriodic
) {
974 rt_timer_insert(pt
, pt
->icnt
);
976 pt
->state
= osTimerStopped
;
982 // Timer Management Public API
985 osTimerId
osTimerCreate (osTimerDef_t
*timer_def
, os_timer_type type
, void *argument
) {
986 if (__get_IPSR() != 0) return NULL
; // Not allowed in ISR
987 if (((__get_CONTROL() & 1) == 0) && (os_running
== 0)) {
988 // Privileged and not running
989 return svcTimerCreate(timer_def
, type
, argument
);
991 return __svcTimerCreate(timer_def
, type
, argument
);
995 /// Start or restart timer
996 osStatus
osTimerStart (osTimerId timer_id
, uint32_t millisec
) {
997 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
998 return __svcTimerStart(timer_id
, millisec
);
1002 osStatus
osTimerStop (osTimerId timer_id
) {
1003 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
1004 return __svcTimerStop(timer_id
);
1008 osStatus
osTimerDelete (osTimerId timer_id
) {
1009 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
1010 return __svcTimerDelete(timer_id
);
1013 /// INTERNAL - Not Public
1014 /// Get timer callback parameters (used by OS Timer Thread)
1015 os_InRegs osCallback
osTimerCall (osTimerId timer_id
) {
1016 return __svcTimerCall(timer_id
);
1021 __NO_RETURN
void osTimerThread (void const *argument
) {
1026 evt
= osMessageGet(osMessageQId_osTimerMessageQ
, osWaitForever
);
1027 if (evt
.status
== osEventMessage
) {
1028 cb
= osTimerCall(evt
.value
.p
);
1029 if (cb
.fp
!= NULL
) {
1030 (*(os_ptimer
)cb
.fp
)(cb
.arg
);
1037 // ==== Signal Management ====
1039 // Signal Service Calls declarations
1040 SVC_2_1(svcSignalSet
, int32_t, osThreadId
, int32_t, RET_int32_t
)
1041 SVC_2_1(svcSignalClear
, int32_t, osThreadId
, int32_t, RET_int32_t
)
1042 SVC_1_1(svcSignalGet
, int32_t, osThreadId
, RET_int32_t
)
1043 SVC_2_3(svcSignalWait
, os_InRegs osEvent
, int32_t, uint32_t, RET_osEvent
)
1045 // Signal Service Calls
1047 /// Set the specified Signal Flags of an active thread
1048 int32_t svcSignalSet (osThreadId thread_id
, int32_t signals
) {
1052 ptcb
= rt_tid2ptcb(thread_id
); // Get TCB pointer
1053 if (ptcb
== NULL
) return 0x80000000;
1055 if (signals
& (0xFFFFFFFF << osFeature_Signals
)) return 0x80000000;
1057 sig
= ptcb
->events
; // Previous signal flags
1059 rt_evt_set(signals
, ptcb
->task_id
); // Set event flags
1064 /// Clear the specified Signal Flags of an active thread
1065 int32_t svcSignalClear (osThreadId thread_id
, int32_t signals
) {
1069 ptcb
= rt_tid2ptcb(thread_id
); // Get TCB pointer
1070 if (ptcb
== NULL
) return 0x80000000;
1072 if (signals
& (0xFFFFFFFF << osFeature_Signals
)) return 0x80000000;
1074 sig
= ptcb
->events
; // Previous signal flags
1076 rt_evt_clr(signals
, ptcb
->task_id
); // Clear event flags
1081 /// Get Signal Flags status of an active thread
1082 int32_t svcSignalGet (osThreadId thread_id
) {
1085 ptcb
= rt_tid2ptcb(thread_id
); // Get TCB pointer
1086 if (ptcb
== NULL
) return 0x80000000;
1088 return ptcb
->events
; // Return event flags
1091 /// Wait for one or more Signal Flags to become signaled for the current RUNNING thread
1092 os_InRegs osEvent_type
svcSignalWait (int32_t signals
, uint32_t millisec
) {
1096 if (signals
& (0xFFFFFFFF << osFeature_Signals
)) {
1097 ret
.status
= osErrorValue
;
1098 return osEvent_ret_status
;
1101 if (signals
!= 0) { // Wait for all specified signals
1102 res
= rt_evt_wait(signals
, rt_ms2tick(millisec
), __TRUE
);
1103 } else { // Wait for any signal
1104 res
= rt_evt_wait(0xFFFF, rt_ms2tick(millisec
), __FALSE
);
1107 if (res
== OS_R_EVT
) {
1108 ret
.status
= osEventSignal
;
1109 ret
.value
.signals
= signals
? signals
: os_tsk
.run
->waits
;
1111 ret
.status
= millisec
? osEventTimeout
: osOK
;
1112 ret
.value
.signals
= 0;
1115 return osEvent_ret_value
;
1121 /// Set the specified Signal Flags of an active thread
1122 static __INLINE
int32_t isrSignalSet (osThreadId thread_id
, int32_t signals
) {
1126 ptcb
= rt_tid2ptcb(thread_id
); // Get TCB pointer
1127 if (ptcb
== NULL
) return 0x80000000;
1129 if (signals
& (0xFFFFFFFF << osFeature_Signals
)) return 0x80000000;
1131 sig
= ptcb
->events
; // Previous signal flags
1133 isr_evt_set(signals
, ptcb
->task_id
); // Set event flags
1139 // Signal Public API
1141 /// Set the specified Signal Flags of an active thread
1142 int32_t osSignalSet (osThreadId thread_id
, int32_t signals
) {
1143 if (__get_IPSR() != 0) { // in ISR
1144 return isrSignalSet(thread_id
, signals
);
1145 } else { // in Thread
1146 return __svcSignalSet(thread_id
, signals
);
1150 /// Clear the specified Signal Flags of an active thread
1151 int32_t osSignalClear (osThreadId thread_id
, int32_t signals
) {
1152 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
1153 return __svcSignalClear(thread_id
, signals
);
1156 /// Get Signal Flags status of an active thread
1157 int32_t osSignalGet (osThreadId thread_id
) {
1158 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
1159 return __svcSignalGet(thread_id
);
1162 /// Wait for one or more Signal Flags to become signaled for the current RUNNING thread
1163 os_InRegs osEvent
osSignalWait (int32_t signals
, uint32_t millisec
) {
1166 if (__get_IPSR() != 0) { // Not allowed in ISR
1167 ret
.status
= osErrorISR
;
1170 return __svcSignalWait(signals
, millisec
);
1174 // ==== Mutex Management ====
1176 // Mutex Service Calls declarations
1177 SVC_1_1(svcMutexCreate
, osMutexId
, osMutexDef_t
*, RET_pointer
)
1178 SVC_2_1(svcMutexWait
, osStatus
, osMutexId
, uint32_t, RET_osStatus
)
1179 SVC_1_1(svcMutexRelease
, osStatus
, osMutexId
, RET_osStatus
)
1180 SVC_1_1(svcMutexDelete
, osStatus
, osMutexId
, RET_osStatus
)
1182 // Mutex Service Calls
1184 /// Create and Initialize a Mutex object
1185 osMutexId
svcMutexCreate (osMutexDef_t
*mutex_def
) {
1188 if (mutex_def
== NULL
) {
1189 sysThreadError(osErrorParameter
);
1193 mut
= mutex_def
->mutex
;
1195 sysThreadError(osErrorParameter
);
1199 if (((P_MUCB
)mut
)->cb_type
!= 0) {
1200 sysThreadError(osErrorParameter
);
1204 rt_mut_init(mut
); // Initialize Mutex
1209 /// Wait until a Mutex becomes available
1210 osStatus
svcMutexWait (osMutexId mutex_id
, uint32_t millisec
) {
1214 mut
= rt_id2obj(mutex_id
);
1215 if (mut
== NULL
) return osErrorParameter
;
1217 if (((P_MUCB
)mut
)->cb_type
!= MUCB
) return osErrorParameter
;
1219 res
= rt_mut_wait(mut
, rt_ms2tick(millisec
)); // Wait for Mutex
1221 if (res
== OS_R_TMO
) {
1222 return (millisec
? osErrorTimeoutResource
: osErrorResource
);
1228 /// Release a Mutex that was obtained with osMutexWait
1229 osStatus
svcMutexRelease (osMutexId mutex_id
) {
1233 mut
= rt_id2obj(mutex_id
);
1234 if (mut
== NULL
) return osErrorParameter
;
1236 if (((P_MUCB
)mut
)->cb_type
!= MUCB
) return osErrorParameter
;
1238 res
= rt_mut_release(mut
); // Release Mutex
1240 if (res
== OS_R_NOK
) return osErrorResource
; // Thread not owner or Zero Counter
1245 /// Delete a Mutex that was created by osMutexCreate
1246 osStatus
svcMutexDelete (osMutexId mutex_id
) {
1249 mut
= rt_id2obj(mutex_id
);
1250 if (mut
== NULL
) return osErrorParameter
;
1252 if (((P_MUCB
)mut
)->cb_type
!= MUCB
) return osErrorParameter
;
1254 rt_mut_delete(mut
); // Release Mutex
1262 /// Create and Initialize a Mutex object
1263 osMutexId
osMutexCreate (osMutexDef_t
*mutex_def
) {
1264 if (__get_IPSR() != 0) return NULL
; // Not allowed in ISR
1265 if (((__get_CONTROL() & 1) == 0) && (os_running
== 0)) {
1266 // Privileged and not running
1267 return svcMutexCreate(mutex_def
);
1269 return __svcMutexCreate(mutex_def
);
1273 /// Wait until a Mutex becomes available
1274 osStatus
osMutexWait (osMutexId mutex_id
, uint32_t millisec
) {
1275 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
1276 return __svcMutexWait(mutex_id
, millisec
);
1279 /// Release a Mutex that was obtained with osMutexWait
1280 osStatus
osMutexRelease (osMutexId mutex_id
) {
1281 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
1282 return __svcMutexRelease(mutex_id
);
1285 /// Delete a Mutex that was created by osMutexCreate
1286 osStatus
osMutexDelete (osMutexId mutex_id
) {
1287 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
1288 return __svcMutexDelete(mutex_id
);
1292 // ==== Semaphore Management ====
1294 // Semaphore Service Calls declarations
1295 SVC_2_1(svcSemaphoreCreate
, osSemaphoreId
, const osSemaphoreDef_t
*, int32_t, RET_pointer
)
1296 SVC_2_1(svcSemaphoreWait
, int32_t, osSemaphoreId
, uint32_t, RET_int32_t
)
1297 SVC_1_1(svcSemaphoreRelease
, osStatus
, osSemaphoreId
, RET_osStatus
)
1298 SVC_1_1(svcSemaphoreDelete
, osStatus
, osSemaphoreId
, RET_osStatus
)
1300 // Semaphore Service Calls
1302 /// Create and Initialize a Semaphore object
1303 osSemaphoreId
svcSemaphoreCreate (const osSemaphoreDef_t
*semaphore_def
, int32_t count
) {
1306 if (semaphore_def
== NULL
) {
1307 sysThreadError(osErrorParameter
);
1311 sem
= semaphore_def
->semaphore
;
1313 sysThreadError(osErrorParameter
);
1317 if (((P_SCB
)sem
)->cb_type
!= 0) {
1318 sysThreadError(osErrorParameter
);
1322 if (count
> osFeature_Semaphore
) {
1323 sysThreadError(osErrorValue
);
1327 rt_sem_init(sem
, count
); // Initialize Semaphore
1332 /// Wait until a Semaphore becomes available
1333 int32_t svcSemaphoreWait (osSemaphoreId semaphore_id
, uint32_t millisec
) {
1337 sem
= rt_id2obj(semaphore_id
);
1338 if (sem
== NULL
) return -1;
1340 if (((P_SCB
)sem
)->cb_type
!= SCB
) return -1;
1342 res
= rt_sem_wait(sem
, rt_ms2tick(millisec
)); // Wait for Semaphore
1344 if (res
== OS_R_TMO
) return 0; // Timeout
1346 return (((P_SCB
)sem
)->tokens
+ 1);
1349 /// Release a Semaphore
1350 osStatus
svcSemaphoreRelease (osSemaphoreId semaphore_id
) {
1353 sem
= rt_id2obj(semaphore_id
);
1354 if (sem
== NULL
) return osErrorParameter
;
1356 if (((P_SCB
)sem
)->cb_type
!= SCB
) return osErrorParameter
;
1358 if (((P_SCB
)sem
)->tokens
== osFeature_Semaphore
) return osErrorResource
;
1360 rt_sem_send(sem
); // Release Semaphore
1365 /// Delete a Semaphore that was created by osSemaphoreCreate
1366 osStatus
svcSemaphoreDelete (osSemaphoreId semaphore_id
) {
1369 sem
= rt_id2obj(semaphore_id
);
1370 if (sem
== NULL
) return osErrorParameter
;
1372 if (((P_SCB
)sem
)->cb_type
!= SCB
) return osErrorParameter
;
1374 rt_sem_delete(sem
); // Delete Semaphore
1380 // Semaphore ISR Calls
1382 /// Release a Semaphore
1383 static __INLINE osStatus
isrSemaphoreRelease (osSemaphoreId semaphore_id
) {
1386 sem
= rt_id2obj(semaphore_id
);
1387 if (sem
== NULL
) return osErrorParameter
;
1389 if (((P_SCB
)sem
)->cb_type
!= SCB
) return osErrorParameter
;
1391 if (((P_SCB
)sem
)->tokens
== osFeature_Semaphore
) return osErrorResource
;
1393 isr_sem_send(sem
); // Release Semaphore
1399 // Semaphore Public API
1401 /// Create and Initialize a Semaphore object
1402 osSemaphoreId
osSemaphoreCreate (osSemaphoreDef_t
*semaphore_def
, int32_t count
) {
1403 if (__get_IPSR() != 0) return NULL
; // Not allowed in ISR
1404 if (((__get_CONTROL() & 1) == 0) && (os_running
== 0)) {
1405 // Privileged and not running
1406 return svcSemaphoreCreate(semaphore_def
, count
);
1408 return __svcSemaphoreCreate(semaphore_def
, count
);
1412 /// Wait until a Semaphore becomes available
1413 int32_t osSemaphoreWait (osSemaphoreId semaphore_id
, uint32_t millisec
) {
1414 if (__get_IPSR() != 0) return -1; // Not allowed in ISR
1415 return __svcSemaphoreWait(semaphore_id
, millisec
);
1418 /// Release a Semaphore
1419 osStatus
osSemaphoreRelease (osSemaphoreId semaphore_id
) {
1420 if (__get_IPSR() != 0) { // in ISR
1421 return isrSemaphoreRelease(semaphore_id
);
1422 } else { // in Thread
1423 return __svcSemaphoreRelease(semaphore_id
);
1427 /// Delete a Semaphore that was created by osSemaphoreCreate
1428 osStatus
osSemaphoreDelete (osSemaphoreId semaphore_id
) {
1429 if (__get_IPSR() != 0) return osErrorISR
; // Not allowed in ISR
1430 return __svcSemaphoreDelete(semaphore_id
);
1434 // ==== Memory Management Functions ====
1436 // Memory Management Helper Functions
1438 // Clear Memory Box (Zero init)
1439 static void rt_clr_box (void *box_mem
, void *box
) {
1444 for (n
= ((P_BM
)box_mem
)->blk_size
; n
; n
-= 4) {
1450 // Memory Management Service Calls declarations
1451 SVC_1_1(svcPoolCreate
, osPoolId
, const osPoolDef_t
*, RET_pointer
)
1452 SVC_2_1(sysPoolAlloc
, void *, osPoolId
, uint32_t, RET_pointer
)
1453 SVC_2_1(sysPoolFree
, osStatus
, osPoolId
, void *, RET_osStatus
)
1455 // Memory Management Service & ISR Calls
1457 /// Create and Initialize memory pool
1458 osPoolId
svcPoolCreate (const osPoolDef_t
*pool_def
) {
1461 if ((pool_def
== NULL
) ||
1462 (pool_def
->pool_sz
== 0) ||
1463 (pool_def
->item_sz
== 0) ||
1464 (pool_def
->pool
== NULL
)) {
1465 sysThreadError(osErrorParameter
);
1469 blk_sz
= (pool_def
->item_sz
+ 3) & ~3;
1471 _init_box(pool_def
->pool
, sizeof(struct OS_BM
) + pool_def
->pool_sz
* blk_sz
, blk_sz
);
1473 return pool_def
->pool
;
1476 /// Allocate a memory block from a memory pool
1477 void *sysPoolAlloc (osPoolId pool_id
, uint32_t clr
) {
1480 if (pool_id
== NULL
) return NULL
;
1482 ptr
= rt_alloc_box(pool_id
);
1484 rt_clr_box(pool_id
, ptr
);
1490 /// Return an allocated memory block back to a specific memory pool
1491 osStatus
sysPoolFree (osPoolId pool_id
, void *block
) {
1494 if (pool_id
== NULL
) return osErrorParameter
;
1496 res
= rt_free_box(pool_id
, block
);
1497 if (res
!= 0) return osErrorValue
;
1503 // Memory Management Public API
1505 /// Create and Initialize memory pool
1506 osPoolId
osPoolCreate (osPoolDef_t
*pool_def
) {
1507 if (__get_IPSR() != 0) return NULL
; // Not allowed in ISR
1508 if (((__get_CONTROL() & 1) == 0) && (os_running
== 0)) {
1509 // Privileged and not running
1510 return svcPoolCreate(pool_def
);
1512 return __svcPoolCreate(pool_def
);
1516 /// Allocate a memory block from a memory pool
1517 void *osPoolAlloc (osPoolId pool_id
) {
1518 if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { // in ISR or Privileged
1519 return sysPoolAlloc(pool_id
, 0);
1520 } else { // in Thread
1521 return __sysPoolAlloc(pool_id
, 0);
1525 /// Allocate a memory block from a memory pool and set memory block to zero
1526 void *osPoolCAlloc (osPoolId pool_id
) {
1527 if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { // in ISR or Privileged
1528 return sysPoolAlloc(pool_id
, 1);
1529 } else { // in Thread
1530 return __sysPoolAlloc(pool_id
, 1);
1534 /// Return an allocated memory block back to a specific memory pool
1535 osStatus
osPoolFree (osPoolId pool_id
, void *block
) {
1536 if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { // in ISR or Privileged
1537 return sysPoolFree(pool_id
, block
);
1538 } else { // in Thread
1539 return __sysPoolFree(pool_id
, block
);
1544 // ==== Message Queue Management Functions ====
1546 // Message Queue Management Service Calls declarations
1547 SVC_2_1(svcMessageCreate
, osMessageQId
, osMessageQDef_t
*, osThreadId
, RET_pointer
)
1548 SVC_3_1(svcMessagePut
, osStatus
, osMessageQId
, uint32_t, uint32_t, RET_osStatus
)
1549 SVC_2_3(svcMessageGet
, os_InRegs osEvent
, osMessageQId
, uint32_t, RET_osEvent
)
1551 // Message Queue Service Calls
1553 /// Create and Initialize Message Queue
1554 osMessageQId
svcMessageCreate (osMessageQDef_t
*queue_def
, osThreadId thread_id
) {
1556 if ((queue_def
== NULL
) ||
1557 (queue_def
->queue_sz
== 0) ||
1558 (queue_def
->pool
== NULL
)) {
1559 sysThreadError(osErrorParameter
);
1563 if (((P_MCB
)queue_def
->pool
)->cb_type
!= 0) {
1564 sysThreadError(osErrorParameter
);
1568 rt_mbx_init(queue_def
->pool
, 4*(queue_def
->queue_sz
+ 4));
1570 return queue_def
->pool
;
1573 /// Put a Message to a Queue
1574 osStatus
svcMessagePut (osMessageQId queue_id
, uint32_t info
, uint32_t millisec
) {
1577 if (queue_id
== NULL
) return osErrorParameter
;
1579 if (((P_MCB
)queue_id
)->cb_type
!= MCB
) return osErrorParameter
;
1581 res
= rt_mbx_send(queue_id
, (void *)info
, rt_ms2tick(millisec
));
1583 if (res
== OS_R_TMO
) {
1584 return (millisec
? osErrorTimeoutResource
: osErrorResource
);
1590 /// Get a Message or Wait for a Message from a Queue
1591 os_InRegs osEvent_type
svcMessageGet (osMessageQId queue_id
, uint32_t millisec
) {
1595 if (queue_id
== NULL
) {
1596 ret
.status
= osErrorParameter
;
1597 return osEvent_ret_status
;
1600 if (((P_MCB
)queue_id
)->cb_type
!= MCB
) {
1601 ret
.status
= osErrorParameter
;
1602 return osEvent_ret_status
;
1605 res
= rt_mbx_wait(queue_id
, &ret
.value
.p
, rt_ms2tick(millisec
));
1607 if (res
== OS_R_TMO
) {
1608 ret
.status
= millisec
? osEventTimeout
: osOK
;
1609 return osEvent_ret_value
;
1612 ret
.status
= osEventMessage
;
1614 return osEvent_ret_value
;
1618 // Message Queue ISR Calls
1620 /// Put a Message to a Queue
1621 static __INLINE osStatus
isrMessagePut (osMessageQId queue_id
, uint32_t info
, uint32_t millisec
) {
1623 if ((queue_id
== NULL
) || (millisec
!= 0)) {
1624 return osErrorParameter
;
1627 if (((P_MCB
)queue_id
)->cb_type
!= MCB
) return osErrorParameter
;
1629 if (rt_mbx_check(queue_id
) == 0) { // Check if Queue is full
1630 return osErrorResource
;
1633 isr_mbx_send(queue_id
, (void *)info
);
1638 /// Get a Message or Wait for a Message from a Queue
1639 static __INLINE os_InRegs osEvent
isrMessageGet (osMessageQId queue_id
, uint32_t millisec
) {
1643 if ((queue_id
== NULL
) || (millisec
!= 0)) {
1644 ret
.status
= osErrorParameter
;
1648 if (((P_MCB
)queue_id
)->cb_type
!= MCB
) {
1649 ret
.status
= osErrorParameter
;
1653 res
= isr_mbx_receive(queue_id
, &ret
.value
.p
);
1655 if (res
!= OS_R_MBX
) {
1660 ret
.status
= osEventMessage
;
1666 // Message Queue Management Public API
1668 /// Create and Initialize Message Queue
1669 osMessageQId
osMessageCreate (osMessageQDef_t
*queue_def
, osThreadId thread_id
) {
1670 if (__get_IPSR() != 0) return NULL
; // Not allowed in ISR
1671 if (((__get_CONTROL() & 1) == 0) && (os_running
== 0)) {
1672 // Privileged and not running
1673 return svcMessageCreate(queue_def
, thread_id
);
1675 return __svcMessageCreate(queue_def
, thread_id
);
1679 /// Put a Message to a Queue
1680 osStatus
osMessagePut (osMessageQId queue_id
, uint32_t info
, uint32_t millisec
) {
1681 if (__get_IPSR() != 0) { // in ISR
1682 return isrMessagePut(queue_id
, info
, millisec
);
1683 } else { // in Thread
1684 return __svcMessagePut(queue_id
, info
, millisec
);
1688 /// Get a Message or Wait for a Message from a Queue
1689 os_InRegs osEvent
osMessageGet (osMessageQId queue_id
, uint32_t millisec
) {
1690 if (__get_IPSR() != 0) { // in ISR
1691 return isrMessageGet(queue_id
, millisec
);
1692 } else { // in Thread
1693 return __svcMessageGet(queue_id
, millisec
);
1698 // ==== Mail Queue Management Functions ====
1700 // Mail Queue Management Service Calls declarations
1701 SVC_2_1(svcMailCreate
, osMailQId
, osMailQDef_t
*, osThreadId
, RET_pointer
)
1702 SVC_4_1(sysMailAlloc
, void *, osMailQId
, uint32_t, uint32_t, uint32_t, RET_pointer
)
1703 SVC_3_1(sysMailFree
, osStatus
, osMailQId
, void *, uint32_t, RET_osStatus
)
1705 // Mail Queue Management Service & ISR Calls
1707 /// Create and Initialize mail queue
1708 osMailQId
svcMailCreate (osMailQDef_t
*queue_def
, osThreadId thread_id
) {
1713 if ((queue_def
== NULL
) ||
1714 (queue_def
->queue_sz
== 0) ||
1715 (queue_def
->item_sz
== 0) ||
1716 (queue_def
->pool
== NULL
)) {
1717 sysThreadError(osErrorParameter
);
1721 pmcb
= *(((void **)queue_def
->pool
) + 0);
1722 pool
= *(((void **)queue_def
->pool
) + 1);
1724 if ((pool
== NULL
) || (pmcb
== NULL
) || (pmcb
->cb_type
!= 0)) {
1725 sysThreadError(osErrorParameter
);
1729 blk_sz
= (queue_def
->item_sz
+ 3) & ~3;
1731 _init_box(pool
, sizeof(struct OS_BM
) + queue_def
->queue_sz
* blk_sz
, blk_sz
);
1733 rt_mbx_init(pmcb
, 4*(queue_def
->queue_sz
+ 4));
1736 return queue_def
->pool
;
1739 /// Allocate a memory block from a mail
1740 void *sysMailAlloc (osMailQId queue_id
, uint32_t millisec
, uint32_t isr
, uint32_t clr
) {
1745 if (queue_id
== NULL
) return NULL
;
1747 pmcb
= *(((void **)queue_id
) + 0);
1748 pool
= *(((void **)queue_id
) + 1);
1750 if ((pool
== NULL
) || (pmcb
== NULL
)) return NULL
;
1752 if (isr
&& (millisec
!= 0)) return NULL
;
1754 mem
= rt_alloc_box(pool
);
1756 rt_clr_box(pool
, mem
);
1759 if ((mem
== NULL
) && (millisec
!= 0)) {
1760 // Put Task to sleep when Memory not available
1761 if (pmcb
->p_lnk
!= NULL
) {
1762 rt_put_prio((P_XCB
)pmcb
, os_tsk
.run
);
1764 pmcb
->p_lnk
= os_tsk
.run
;
1765 os_tsk
.run
->p_lnk
= NULL
;
1766 os_tsk
.run
->p_rlnk
= (P_TCB
)pmcb
;
1767 // Task is waiting to allocate a message
1770 rt_block(rt_ms2tick(millisec
), WAIT_MBX
);
1776 /// Free a memory block from a mail
1777 osStatus
sysMailFree (osMailQId queue_id
, void *mail
, uint32_t isr
) {
1784 if (queue_id
== NULL
) return osErrorParameter
;
1786 pmcb
= *(((void **)queue_id
) + 0);
1787 pool
= *(((void **)queue_id
) + 1);
1789 if ((pmcb
== NULL
) || (pool
== NULL
)) return osErrorParameter
;
1791 res
= rt_free_box(pool
, mail
);
1793 if (res
!= 0) return osErrorValue
;
1795 if (pmcb
->state
== 3) {
1796 // Task is waiting to allocate a message
1798 rt_psq_enq (pmcb
, (U32
)pool
);
1801 mem
= rt_alloc_box(pool
);
1803 ptcb
= rt_get_first((P_XCB
)pmcb
);
1804 if (pmcb
->p_lnk
== NULL
) {
1807 rt_ret_val(ptcb
, (U32
)mem
);
1818 // Mail Queue Management Public API
1820 /// Create and Initialize mail queue
1821 osMailQId
osMailCreate (osMailQDef_t
*queue_def
, osThreadId thread_id
) {
1822 if (__get_IPSR() != 0) return NULL
; // Not allowed in ISR
1823 if (((__get_CONTROL() & 1) == 0) && (os_running
== 0)) {
1824 // Privileged and not running
1825 return svcMailCreate(queue_def
, thread_id
);
1827 return __svcMailCreate(queue_def
, thread_id
);
1831 /// Allocate a memory block from a mail
1832 void *osMailAlloc (osMailQId queue_id
, uint32_t millisec
) {
1833 if (__get_IPSR() != 0) { // in ISR
1834 return sysMailAlloc(queue_id
, millisec
, 1, 0);
1835 } else { // in Thread
1836 return __sysMailAlloc(queue_id
, millisec
, 0, 0);
1840 /// Allocate a memory block from a mail and set memory block to zero
1841 void *osMailCAlloc (osMailQId queue_id
, uint32_t millisec
) {
1842 if (__get_IPSR() != 0) { // in ISR
1843 return sysMailAlloc(queue_id
, millisec
, 1, 1);
1844 } else { // in Thread
1845 return __sysMailAlloc(queue_id
, millisec
, 0, 1);
1849 /// Free a memory block from a mail
1850 osStatus
osMailFree (osMailQId queue_id
, void *mail
) {
1851 if (__get_IPSR() != 0) { // in ISR
1852 return sysMailFree(queue_id
, mail
, 1);
1853 } else { // in Thread
1854 return __sysMailFree(queue_id
, mail
, 0);
1858 /// Put a mail to a queue
1859 osStatus
osMailPut (osMailQId queue_id
, void *mail
) {
1860 if (queue_id
== NULL
) return osErrorParameter
;
1861 if (mail
== NULL
) return osErrorValue
;
1862 return osMessagePut(*((void **)queue_id
), (uint32_t)mail
, 0);
1869 /// Get a mail from a queue
1870 os_InRegs osEvent
osMailGet (osMailQId queue_id
, uint32_t millisec
) {
1873 if (queue_id
== NULL
) {
1874 ret
.status
= osErrorParameter
;
1878 ret
= osMessageGet(*((void **)queue_id
), millisec
);
1879 if (ret
.status
== osEventMessage
) ret
.status
= osEventMail
;