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;