]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/rtos/rtx/TARGET_CORTEX_M/rt_CMSIS.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / rtos / rtx / TARGET_CORTEX_M / rt_CMSIS.c
1 /*----------------------------------------------------------------------------
2  *      RL-ARM - RTX
3  *----------------------------------------------------------------------------
4  *      Name:    rt_CMSIS.c
5  *      Purpose: CMSIS RTOS API
6  *      Rev.:    V4.60
7  *----------------------------------------------------------------------------
8  *
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.
21  *
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  *---------------------------------------------------------------------------*/
34
35 #define __CMSIS_GENERIC
36
37 #if defined (__CORTEX_M4) || defined (__CORTEX_M4F)
38   #include "core_cm4.h"
39 #elif defined (__CORTEX_M3)
40   #include "core_cm3.h"
41 #elif defined (__CORTEX_M0)
42   #include "core_cm0.h"
43 #elif defined (__CORTEX_M0PLUS)
44   #include "core_cm0plus.h"
45 #else
46   #error "Missing __CORTEX_Mx definition"
47 #endif
48
49 #include "rt_TypeDef.h"
50 #include "RTX_Conf.h"
51 #include "rt_System.h"
52 #include "rt_Task.h"
53 #include "rt_Event.h"
54 #include "rt_List.h"
55 #include "rt_Time.h"
56 #include "rt_Mutex.h"
57 #include "rt_Semaphore.h"
58 #include "rt_Mailbox.h"
59 #include "rt_MemBox.h"
60 #include "rt_HAL_CM.h"
61
62 #define os_thread_cb OS_TCB
63
64 #include "cmsis_os.h"
65
66 #if (osFeature_Signals != 16)
67 #error Invalid "osFeature_Signals" value!
68 #endif
69 #if (osFeature_Semaphore > 65535)
70 #error Invalid "osFeature_Semaphore" value!
71 #endif
72 #if (osFeature_Wait != 0)
73 #error osWait not supported!
74 #endif
75
76
77 // ==== Enumeration, structures, defines ====
78
79 // Service Calls defines
80
81 #if defined (__CC_ARM)          /* ARM Compiler */
82
83 #define __NO_RETURN __declspec(noreturn)
84
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
90
91 #define osCallback_type    osCallback
92 #define osCallback_ret     ret
93
94 #define SVC_0_1(f,t,...)                                                       \
95 __svc_indirect(0) t  _##f (t(*)());                                            \
96                   t     f (void);                                              \
97 __attribute__((always_inline))                                                 \
98 static __inline   t __##f (void) {                                             \
99   return _##f(f);                                                              \
100 }
101
102 #define SVC_1_1(f,t,t1,...)                                                    \
103 __svc_indirect(0) t  _##f (t(*)(t1),t1);                                       \
104                   t     f (t1 a1);                                             \
105 __attribute__((always_inline))                                                 \
106 static __inline   t __##f (t1 a1) {                                            \
107   return _##f(f,a1);                                                           \
108 }
109
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);                                                        \
116 }
117
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);                                                     \
124 }
125
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);                                                  \
132 }
133
134 #define SVC_1_2 SVC_1_1
135 #define SVC_1_3 SVC_1_1
136 #define SVC_2_3 SVC_2_1
137
138 #elif defined (__GNUC__)        /* GNU Compiler */
139
140 #define __NO_RETURN __attribute__((noreturn))
141
142 typedef uint32_t __attribute__((vector_size(8)))  ret64;
143 typedef uint32_t __attribute__((vector_size(16))) ret128;
144
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}
151
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}
157
158 #define osCallback_type     ret64
159 #define osCallback_ret     (ret64) {(uint32_t)ret.fp, (uint32_t)ret.arg}
160
161 #define SVC_ArgN(n) \
162   register int __r##n __asm("r"#n);
163
164 #define SVC_ArgR(n,t,a) \
165   register t   __r##n __asm("r"#n) = a;
166
167 #define SVC_Arg0()                                                             \
168   SVC_ArgN(0)                                                                  \
169   SVC_ArgN(1)                                                                  \
170   SVC_ArgN(2)                                                                  \
171   SVC_ArgN(3)
172
173 #define SVC_Arg1(t1)                                                           \
174   SVC_ArgR(0,t1,a1)                                                            \
175   SVC_ArgN(1)                                                                  \
176   SVC_ArgN(2)                                                                  \
177   SVC_ArgN(3)
178
179 #define SVC_Arg2(t1,t2)                                                        \
180   SVC_ArgR(0,t1,a1)                                                            \
181   SVC_ArgR(1,t2,a2)                                                            \
182   SVC_ArgN(2)                                                                  \
183   SVC_ArgN(3)
184
185 #define SVC_Arg3(t1,t2,t3)                                                     \
186   SVC_ArgR(0,t1,a1)                                                            \
187   SVC_ArgR(1,t2,a2)                                                            \
188   SVC_ArgR(2,t3,a3)                                                            \
189   SVC_ArgN(3)
190
191 #define SVC_Arg4(t1,t2,t3,t4)                                                  \
192   SVC_ArgR(0,t1,a1)                                                            \
193   SVC_ArgR(1,t2,a2)                                                            \
194   SVC_ArgR(2,t3,a3)                                                            \
195   SVC_ArgR(3,t4,a4)
196
197 #if (defined (__CORTEX_M0)) || defined (__CORTEX_M0PLUS)
198 #define SVC_Call(f)                                                            \
199   __asm volatile                                                                 \
200   (                                                                            \
201     "ldr r7,="#f"\n\t"                                                         \
202     "mov r12,r7\n\t"                                                           \
203     "svc 0"                                                                    \
204     :               "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3)         \
205     :                "r" (__r0),  "r" (__r1),  "r" (__r2),  "r" (__r3)         \
206     : "r7", "r12", "lr", "cc"                                                  \
207   );
208 #else
209 #define SVC_Call(f)                                                            \
210   __asm volatile                                                                 \
211   (                                                                            \
212     "ldr r12,="#f"\n\t"                                                        \
213     "svc 0"                                                                    \
214     :               "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3)         \
215     :                "r" (__r0),  "r" (__r1),  "r" (__r2),  "r" (__r3)         \
216     : "r12", "lr", "cc"                                                        \
217   );
218 #endif
219
220 #define SVC_0_1(f,t,rv)                                                        \
221 __attribute__((always_inline))                                                 \
222 static inline  t __##f (void) {                                                \
223   SVC_Arg0();                                                                  \
224   SVC_Call(f);                                                                 \
225   return (t) rv;                                                               \
226 }
227
228 #define SVC_1_1(f,t,t1,rv)                                                     \
229 __attribute__((always_inline))                                                 \
230 static inline  t __##f (t1 a1) {                                               \
231   SVC_Arg1(t1);                                                                \
232   SVC_Call(f);                                                                 \
233   return (t) rv;                                                               \
234 }
235
236 #define SVC_2_1(f,t,t1,t2,rv)                                                  \
237 __attribute__((always_inline))                                                 \
238 static inline  t __##f (t1 a1, t2 a2) {                                        \
239   SVC_Arg2(t1,t2);                                                             \
240   SVC_Call(f);                                                                 \
241   return (t) rv;                                                               \
242 }
243
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);                                                          \
248   SVC_Call(f);                                                                 \
249   return (t) rv;                                                               \
250 }
251
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);                                                       \
256   SVC_Call(f);                                                                 \
257   return (t) rv;                                                               \
258 }
259
260 #define SVC_1_2 SVC_1_1
261 #define SVC_1_3 SVC_1_1
262 #define SVC_2_3 SVC_2_1
263
264 #elif defined (__ICCARM__)      /* IAR Compiler */
265
266 #define __NO_RETURN __noreturn
267
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
273
274 #define osCallback_type    osCallback
275 #define osCallback_ret     ret
276
277 #define RET_osEvent     osEvent
278 #define RET_osCallback  osCallback
279
280 #define SVC_Setup(f)                                                           \
281   __asm(                                                                       \
282     "mov r12,%0\n"                                                             \
283     :: "r"(&f): "r12"                                                          \
284   );
285
286
287 #define SVC_0_1(f,t,...)                                                       \
288 t f (void);                                                                    \
289 _Pragma("swi_number=0") __swi t _##f (void);                                   \
290 static inline t __##f (void) {                                                 \
291   SVC_Setup(f);                                                                \
292   return _##f();                                                               \
293 }
294
295 #define SVC_1_1(f,t,t1,...)                                                    \
296 t f (t1 a1);                                                                   \
297 _Pragma("swi_number=0") __swi t _##f (t1 a1);                                  \
298 static inline t __##f (t1 a1) {                                                \
299   SVC_Setup(f);                                                                \
300   return _##f(a1);                                                             \
301 }
302
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) {                                         \
307   SVC_Setup(f);                                                                \
308   return _##f(a1,a2);                                                          \
309 }
310
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) {                                  \
315   SVC_Setup(f);                                                                \
316   return _##f(a1,a2,a3);                                                       \
317 }
318
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) {                           \
323   SVC_Setup(f);                                                                \
324   return _##f(a1,a2,a3,a4);                                                    \
325 }
326
327 #define SVC_1_2 SVC_1_1
328 #define SVC_1_3 SVC_1_1
329 #define SVC_2_3 SVC_2_1
330
331 #endif
332
333
334 // Callback structure
335 typedef struct {
336   void *fp;             // Function pointer
337   void *arg;            // Function argument
338 } osCallback;
339
340
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;
345 #endif
346
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;
352
353
354 // ==== Helper Functions ====
355
356 /// Convert timeout in millisec to system ticks
357 static uint32_t rt_ms2tick (uint32_t millisec) {
358   uint32_t tick;
359
360   if (millisec == osWaitForever) return 0xFFFF; // Indefinite timeout
361   if (millisec > 4000000) return 0xFFFE;        // Max ticks supported
362
363   tick = ((1000 * millisec) + os_clockrate - 1)  / os_clockrate;
364   if (tick > 0xFFFE) return 0xFFFE;
365
366   return tick;
367 }
368
369 /// Convert Thread ID to TCB pointer
370 static P_TCB rt_tid2ptcb (osThreadId thread_id) {
371   P_TCB ptcb;
372
373   if (thread_id == NULL) return NULL;
374
375   if ((uint32_t)thread_id & 3) return NULL;
376
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;
381   }
382 #endif
383
384   ptcb = thread_id;
385
386   if (ptcb->cb_type != TCB) return NULL;
387
388   return ptcb;
389 }
390
391 /// Convert ID pointer to Object pointer
392 static void *rt_id2obj (void *id) {
393
394   if ((uint32_t)id & 3) return NULL;
395
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;
400   }
401 #endif
402
403   return id;
404 }
405
406
407 // ==== Kernel Control ====
408
409 uint8_t os_initialized;                         // Kernel Initialized flag
410 uint8_t os_running;                             // Kernel Running flag
411
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)
416
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);
420
421 // Kernel Control Service Calls
422
423 /// Initialize the RTOS Kernel for creating objects
424 osStatus svcKernelInitialize (void) {
425   if (os_initialized) return osOK;
426
427   rt_sys_init();                                // RTX System Initialization
428   os_tsk.run->prio = 255;                       // Highest priority
429
430   sysThreadError(osOK);
431
432   os_initialized = 1;
433
434   return osOK;
435 }
436
437 /// Start the RTOS Kernel
438 osStatus svcKernelStart (void) {
439
440   if (os_running) return osOK;
441
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);
445
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
449
450   rt_sys_start();
451
452   os_running = 1;
453
454   return osOK;
455 }
456
457 /// Check if the RTOS kernel is already started
458 int32_t svcKernelRunning(void) {
459   return os_running;
460 }
461
462 // Kernel Control Public API
463
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();
469   } else {
470     return __svcKernelInitialize();
471   }
472 }
473
474 /// Start the RTOS Kernel
475 osStatus osKernelStart (void) {
476   uint32_t stack[8];
477
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
482       if (os_flags & 1) {
483         __set_CONTROL(0x02);                    // Set Privileged Thread mode & PSP
484       } else {
485         __set_CONTROL(0x03);                    // Set Unprivileged Thread mode & PSP
486       }
487       __DSB();
488       __ISB();
489       break;
490     case 0x01:                                  // Unprivileged Thread mode & MSP
491       return osErrorOS;
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
495         __DSB();
496         __ISB();
497       }
498       break;
499     case 0x03:                                  // Unprivileged Thread mode & PSP
500       if  (os_flags & 1) return osErrorOS;      // Privileged Thread mode requested
501       break;
502   }
503   return __svcKernelStart();
504 }
505
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
510     return os_running;
511   } else {
512     return __svcKernelRunning();
513   }
514 }
515
516
517 // ==== Thread Management ====
518
519 __NO_RETURN void osThreadExit (void);
520
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)
528
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);
532
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) {
535   P_TCB  ptcb;
536
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);
544     return NULL;
545   }
546
547   U8 priority = thread_def->tpriority - osPriorityIdle + 1;
548   P_TCB task_context = &thread_def->tcb;
549
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);
561
562   /* Dispatch this task to the scheduler for execution. */
563   DBG_TASK_NOTIFY(task_context, __TRUE);
564   rt_dispatch (task_context);
565
566   ptcb = (P_TCB)os_active_TCB[tsk - 1];         // TCB pointer
567
568   *((uint32_t *)ptcb->tsk_stack + 13) = (uint32_t)osThreadExit;
569
570   return ptcb;
571 }
572
573 /// Return the thread ID of the current running thread
574 osThreadId svcThreadGetId (void) {
575   OS_TID tsk;
576
577   tsk = rt_tsk_self();
578   if (tsk == 0) return NULL;
579   return (P_TCB)os_active_TCB[tsk - 1];
580 }
581
582 /// Terminate execution of a thread and remove it from ActiveThreads
583 osStatus svcThreadTerminate (osThreadId thread_id) {
584   OS_RESULT res;
585   P_TCB     ptcb;
586
587   ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
588   if (ptcb == NULL) return osErrorParameter;
589
590   res = rt_tsk_delete(ptcb->task_id);           // Delete task
591
592   if (res == OS_R_NOK) return osErrorResource;  // Delete task failed
593
594   return osOK;
595 }
596
597 /// Pass control to next thread that is in state READY
598 osStatus svcThreadYield (void) {
599   rt_tsk_pass();                                // Pass control to next task
600   return osOK;
601 }
602
603 /// Change priority of an active thread
604 osStatus svcThreadSetPriority (osThreadId thread_id, osPriority priority) {
605   OS_RESULT res;
606   P_TCB     ptcb;
607
608   ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
609   if (ptcb == NULL) return osErrorParameter;
610
611   if ((priority < osPriorityIdle) || (priority > osPriorityRealtime)) {
612     return osErrorValue;
613   }
614
615   res = rt_tsk_prio(                            // Change task priority
616     ptcb->task_id,                              // Task ID
617     priority - osPriorityIdle + 1               // New task priority
618   );
619
620   if (res == OS_R_NOK) return osErrorResource;  // Change task priority failed
621
622   return osOK;
623 }
624
625 /// Get current priority of an active thread
626 osPriority svcThreadGetPriority (osThreadId thread_id) {
627   P_TCB ptcb;
628
629   ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
630   if (ptcb == NULL) return osPriorityError;
631
632   return (osPriority)(ptcb->prio - 1 + osPriorityIdle);
633 }
634
635
636 // Thread Public API
637
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);
644   } else {
645     return __svcThreadCreate(thread_def, argument);
646   }
647 }
648
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();
653 }
654
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);
659 }
660
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();
665 }
666
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);
671 }
672
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);
677 }
678
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
684 }
685
686
687 // ==== Generic Wait Functions ====
688
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)
693 #endif
694
695 // Generic Wait Service Calls
696
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;
702 }
703
704 /// Wait for Signal, Message, Mail, or Timeout
705 #if osFeature_Wait != 0
706 os_InRegs osEvent_type svcWait (uint32_t millisec) {
707   osEvent ret;
708
709   if (millisec == 0) {
710     ret.status = osOK;
711     return osEvent_ret_status;
712   }
713
714   /* To Do: osEventSignal, osEventMessage, osEventMail */
715   rt_dly_wait(rt_ms2tick(millisec));
716   ret.status = osEventTimeout;
717
718   return osEvent_ret_status;
719 }
720 #endif
721
722
723 // Generic Wait API
724
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);
729 }
730
731 /// Wait for Signal, Message, Mail, or Timeout
732 os_InRegs osEvent osWait (uint32_t millisec) {
733   osEvent ret;
734
735 #if osFeature_Wait == 0
736   ret.status = osErrorOS;
737   return ret;
738 #else
739   if (__get_IPSR() != 0) {                      // Not allowed in ISR
740     ret.status = osErrorISR;
741     return ret;
742   }
743   return __svcWait(millisec);
744 #endif
745 }
746
747
748 // ==== Timer Management ====
749
750 // Timer definitions
751 #define osTimerInvalid  0
752 #define osTimerStopped  1
753 #define osTimerRunning  2
754
755 // Timer structures
756
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
766 } os_timer_cb;
767
768 // Timer variables
769 os_timer_cb *os_timer_head;                     // Pointer to first active Timer
770
771
772 // Timer Helper Functions
773
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;
777
778   prev = NULL;
779   p = os_timer_head;
780   while (p != NULL) {
781     if (tcnt < p->tcnt) break;
782     tcnt -= p->tcnt;
783     prev = p;
784     p = p->next;
785   }
786   pt->next = p;
787   pt->tcnt = (uint16_t)tcnt;
788   if (p != NULL) {
789     p->tcnt -= pt->tcnt;
790   }
791   if (prev != NULL) {
792     prev->next = pt;
793   } else {
794     os_timer_head = pt;
795   }
796 }
797
798 // Remove Timer from the list
799 static int rt_timer_remove (os_timer_cb *pt) {
800   os_timer_cb *p, *prev;
801
802   prev = NULL;
803   p = os_timer_head;
804   while (p != NULL) {
805     if (p == pt) break;
806     prev = p;
807     p = p->next;
808   }
809   if (p == NULL) return -1;
810   if (prev != NULL) {
811     prev->next = pt->next;
812   } else {
813     os_timer_head = pt->next;
814   }
815   if (pt->next != NULL) {
816     pt->next->tcnt += pt->tcnt;
817   }
818
819   return 0;
820 }
821
822
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)
829
830 // Timer Management Service Calls
831
832 /// Create timer
833 osTimerId svcTimerCreate (osTimerDef_t *timer_def, os_timer_type type, void *argument) {
834   os_timer_cb *pt;
835
836   if ((timer_def == NULL) || (timer_def->ptimer == NULL)) {
837     sysThreadError(osErrorParameter);
838     return NULL;
839   }
840
841   pt = timer_def->timer;
842   if (pt == NULL) {
843     sysThreadError(osErrorParameter);
844     return NULL;
845   }
846
847   if ((type != osTimerOnce) && (type != osTimerPeriodic)) {
848     sysThreadError(osErrorValue);
849     return NULL;
850   }
851
852   if (osThreadId_osTimerThread == NULL) {
853     sysThreadError(osErrorResource);
854     return NULL;
855   }
856
857   if (pt->state != osTimerInvalid){
858     sysThreadError(osErrorResource);
859     return NULL;
860   }
861
862   pt->state = osTimerStopped;
863   pt->type  =  (uint8_t)type;
864   pt->arg   = argument;
865   pt->timer = timer_def;
866
867   return (osTimerId)pt;
868 }
869
870 /// Start or restart timer
871 osStatus svcTimerStart (osTimerId timer_id, uint32_t millisec) {
872   os_timer_cb *pt;
873   uint32_t     tcnt;
874
875   pt = rt_id2obj(timer_id);
876   if (pt == NULL) return osErrorParameter;
877
878   tcnt = rt_ms2tick(millisec);
879   if (tcnt == 0) return osErrorValue;
880
881   switch (pt->state) {
882     case osTimerRunning:
883       if (rt_timer_remove(pt) != 0) {
884         return osErrorResource;
885       }
886       break;
887     case osTimerStopped:
888       pt->state = osTimerRunning;
889       pt->icnt  = (uint16_t)tcnt;
890       break;
891     default:
892       return osErrorResource;
893   }
894
895   rt_timer_insert(pt, tcnt);
896
897   return osOK;
898 }
899
900 /// Stop timer
901 osStatus svcTimerStop (osTimerId timer_id) {
902   os_timer_cb *pt;
903
904   pt = rt_id2obj(timer_id);
905   if (pt == NULL) return osErrorParameter;
906
907   if (pt->state != osTimerRunning) return osErrorResource;
908
909   pt->state = osTimerStopped;
910
911   if (rt_timer_remove(pt) != 0) {
912     return osErrorResource;
913   }
914
915   return osOK;
916 }
917
918 /// Delete timer
919 osStatus svcTimerDelete (osTimerId timer_id) {
920   os_timer_cb *pt;
921
922   pt = rt_id2obj(timer_id);
923   if (pt == NULL) return osErrorParameter;
924
925   switch (pt->state) {
926     case osTimerRunning:
927       rt_timer_remove(pt);
928       break;
929     case osTimerStopped:
930       break;
931     default:
932       return osErrorResource;
933   }
934
935   pt->state = osTimerInvalid;
936
937   return osOK;
938 }
939
940 /// Get timer callback parameters
941 os_InRegs osCallback_type svcTimerCall (osTimerId timer_id) {
942   os_timer_cb *pt;
943   osCallback   ret;
944
945   pt = rt_id2obj(timer_id);
946   if (pt == NULL) {
947     ret.fp  = NULL;
948     ret.arg = NULL;
949     return osCallback_ret;
950   }
951
952   ret.fp  = (void *)pt->timer->ptimer;
953   ret.arg = pt->arg;
954
955   return osCallback_ret;
956 }
957
958 static __INLINE osStatus isrMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec);
959
960 /// Timer Tick (called each SysTick)
961 void sysTimerTick (void) {
962   os_timer_cb *pt, *p;
963
964   p = os_timer_head;
965   if (p == NULL) return;
966
967   p->tcnt--;
968   while ((p != NULL) && (p->tcnt == 0)) {
969     pt = p;
970     p = p->next;
971     os_timer_head = p;
972     isrMessagePut(osMessageQId_osTimerMessageQ, (uint32_t)pt, 0);
973     if (pt->type == osTimerPeriodic) {
974       rt_timer_insert(pt, pt->icnt);
975     } else {
976       pt->state = osTimerStopped;
977     }
978   }
979 }
980
981
982 // Timer Management Public API
983
984 /// Create timer
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);
990   } else {
991     return __svcTimerCreate(timer_def, type, argument);
992   }
993 }
994
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);
999 }
1000
1001 /// Stop timer
1002 osStatus osTimerStop (osTimerId timer_id) {
1003   if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
1004   return __svcTimerStop(timer_id);
1005 }
1006
1007 /// Delete timer
1008 osStatus osTimerDelete (osTimerId timer_id) {
1009   if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
1010   return __svcTimerDelete(timer_id);
1011 }
1012
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);
1017 }
1018
1019
1020 // Timer Thread
1021 __NO_RETURN void osTimerThread (void const *argument) {
1022   osCallback cb;
1023   osEvent    evt;
1024
1025   for (;;) {
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);
1031       }
1032     }
1033   }
1034 }
1035
1036
1037 // ==== Signal Management ====
1038
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)
1044
1045 // Signal Service Calls
1046
1047 /// Set the specified Signal Flags of an active thread
1048 int32_t svcSignalSet (osThreadId thread_id, int32_t signals) {
1049   P_TCB   ptcb;
1050   int32_t sig;
1051
1052   ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
1053   if (ptcb == NULL) return 0x80000000;
1054
1055   if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000;
1056
1057   sig = ptcb->events;                           // Previous signal flags
1058
1059   rt_evt_set(signals, ptcb->task_id);           // Set event flags
1060
1061   return sig;
1062 }
1063
1064 /// Clear the specified Signal Flags of an active thread
1065 int32_t svcSignalClear (osThreadId thread_id, int32_t signals) {
1066   P_TCB   ptcb;
1067   int32_t sig;
1068
1069   ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
1070   if (ptcb == NULL) return 0x80000000;
1071
1072   if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000;
1073
1074   sig = ptcb->events;                           // Previous signal flags
1075
1076   rt_evt_clr(signals, ptcb->task_id);           // Clear event flags
1077
1078   return sig;
1079 }
1080
1081 /// Get Signal Flags status of an active thread
1082 int32_t svcSignalGet (osThreadId thread_id) {
1083   P_TCB ptcb;
1084
1085   ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
1086   if (ptcb == NULL) return 0x80000000;
1087
1088   return ptcb->events;                          // Return event flags
1089 }
1090
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) {
1093   OS_RESULT res;
1094   osEvent   ret;
1095
1096   if (signals & (0xFFFFFFFF << osFeature_Signals)) {
1097     ret.status = osErrorValue;
1098     return osEvent_ret_status;
1099   }
1100
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);
1105   }
1106
1107   if (res == OS_R_EVT) {
1108     ret.status = osEventSignal;
1109     ret.value.signals = signals ? signals : os_tsk.run->waits;
1110   } else {
1111     ret.status = millisec ? osEventTimeout : osOK;
1112     ret.value.signals = 0;
1113   }
1114
1115   return osEvent_ret_value;
1116 }
1117
1118
1119 // Signal ISR Calls
1120
1121 /// Set the specified Signal Flags of an active thread
1122 static __INLINE int32_t isrSignalSet (osThreadId thread_id, int32_t signals) {
1123   P_TCB   ptcb;
1124   int32_t sig;
1125
1126   ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
1127   if (ptcb == NULL) return 0x80000000;
1128
1129   if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000;
1130
1131   sig = ptcb->events;                           // Previous signal flags
1132
1133   isr_evt_set(signals, ptcb->task_id);          // Set event flags
1134
1135   return sig;
1136 }
1137
1138
1139 // Signal Public API
1140
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);
1147   }
1148 }
1149
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);
1154 }
1155
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);
1160 }
1161
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) {
1164   osEvent ret;
1165
1166   if (__get_IPSR() != 0) {                      // Not allowed in ISR
1167     ret.status = osErrorISR;
1168     return ret;
1169   }
1170   return __svcSignalWait(signals, millisec);
1171 }
1172
1173
1174 // ==== Mutex Management ====
1175
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)
1181
1182 // Mutex Service Calls
1183
1184 /// Create and Initialize a Mutex object
1185 osMutexId svcMutexCreate (osMutexDef_t *mutex_def) {
1186   OS_ID mut;
1187
1188   if (mutex_def == NULL) {
1189     sysThreadError(osErrorParameter);
1190     return NULL;
1191   }
1192
1193   mut = mutex_def->mutex;
1194   if (mut == NULL) {
1195     sysThreadError(osErrorParameter);
1196     return NULL;
1197   }
1198
1199   if (((P_MUCB)mut)->cb_type != 0) {
1200     sysThreadError(osErrorParameter);
1201     return NULL;
1202   }
1203
1204   rt_mut_init(mut);                             // Initialize Mutex
1205
1206   return mut;
1207 }
1208
1209 /// Wait until a Mutex becomes available
1210 osStatus svcMutexWait (osMutexId mutex_id, uint32_t millisec) {
1211   OS_ID     mut;
1212   OS_RESULT res;
1213
1214   mut = rt_id2obj(mutex_id);
1215   if (mut == NULL) return osErrorParameter;
1216
1217   if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter;
1218
1219   res = rt_mut_wait(mut, rt_ms2tick(millisec)); // Wait for Mutex
1220
1221   if (res == OS_R_TMO) {
1222     return (millisec ? osErrorTimeoutResource : osErrorResource);
1223   }
1224
1225   return osOK;
1226 }
1227
1228 /// Release a Mutex that was obtained with osMutexWait
1229 osStatus svcMutexRelease (osMutexId mutex_id) {
1230   OS_ID     mut;
1231   OS_RESULT res;
1232
1233   mut = rt_id2obj(mutex_id);
1234   if (mut == NULL) return osErrorParameter;
1235
1236   if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter;
1237
1238   res = rt_mut_release(mut);                    // Release Mutex
1239
1240   if (res == OS_R_NOK) return osErrorResource;  // Thread not owner or Zero Counter
1241
1242   return osOK;
1243 }
1244
1245 /// Delete a Mutex that was created by osMutexCreate
1246 osStatus svcMutexDelete (osMutexId mutex_id) {
1247   OS_ID mut;
1248
1249   mut = rt_id2obj(mutex_id);
1250   if (mut == NULL) return osErrorParameter;
1251
1252   if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter;
1253
1254   rt_mut_delete(mut);                           // Release Mutex
1255
1256   return osOK;
1257 }
1258
1259
1260 // Mutex Public API
1261
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);
1268   } else {
1269     return __svcMutexCreate(mutex_def);
1270   }
1271 }
1272
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);
1277 }
1278
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);
1283 }
1284
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);
1289 }
1290
1291
1292 // ==== Semaphore Management ====
1293
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)
1299
1300 // Semaphore Service Calls
1301
1302 /// Create and Initialize a Semaphore object
1303 osSemaphoreId svcSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count) {
1304   OS_ID sem;
1305
1306   if (semaphore_def == NULL) {
1307     sysThreadError(osErrorParameter);
1308     return NULL;
1309   }
1310
1311   sem = semaphore_def->semaphore;
1312   if (sem == NULL) {
1313     sysThreadError(osErrorParameter);
1314     return NULL;
1315   }
1316
1317   if (((P_SCB)sem)->cb_type != 0) {
1318     sysThreadError(osErrorParameter);
1319     return NULL;
1320   }
1321
1322   if (count > osFeature_Semaphore) {
1323     sysThreadError(osErrorValue);
1324     return NULL;
1325   }
1326
1327   rt_sem_init(sem, count);                      // Initialize Semaphore
1328
1329   return sem;
1330 }
1331
1332 /// Wait until a Semaphore becomes available
1333 int32_t svcSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec) {
1334   OS_ID     sem;
1335   OS_RESULT res;
1336
1337   sem = rt_id2obj(semaphore_id);
1338   if (sem == NULL) return -1;
1339
1340   if (((P_SCB)sem)->cb_type != SCB) return -1;
1341
1342   res = rt_sem_wait(sem, rt_ms2tick(millisec)); // Wait for Semaphore
1343
1344   if (res == OS_R_TMO) return 0;                // Timeout
1345
1346   return (((P_SCB)sem)->tokens + 1);
1347 }
1348
1349 /// Release a Semaphore
1350 osStatus svcSemaphoreRelease (osSemaphoreId semaphore_id) {
1351   OS_ID sem;
1352
1353   sem = rt_id2obj(semaphore_id);
1354   if (sem == NULL) return osErrorParameter;
1355
1356   if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter;
1357
1358   if (((P_SCB)sem)->tokens == osFeature_Semaphore) return osErrorResource;
1359
1360   rt_sem_send(sem);                             // Release Semaphore
1361
1362   return osOK;
1363 }
1364
1365 /// Delete a Semaphore that was created by osSemaphoreCreate
1366 osStatus svcSemaphoreDelete (osSemaphoreId semaphore_id) {
1367   OS_ID sem;
1368
1369   sem = rt_id2obj(semaphore_id);
1370   if (sem == NULL) return osErrorParameter;
1371
1372   if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter;
1373
1374   rt_sem_delete(sem);                           // Delete Semaphore
1375
1376   return osOK;
1377 }
1378
1379
1380 // Semaphore ISR Calls
1381
1382 /// Release a Semaphore
1383 static __INLINE osStatus isrSemaphoreRelease (osSemaphoreId semaphore_id) {
1384   OS_ID sem;
1385
1386   sem = rt_id2obj(semaphore_id);
1387   if (sem == NULL) return osErrorParameter;
1388
1389   if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter;
1390
1391   if (((P_SCB)sem)->tokens == osFeature_Semaphore) return osErrorResource;
1392
1393   isr_sem_send(sem);                            // Release Semaphore
1394
1395   return osOK;
1396 }
1397
1398
1399 // Semaphore Public API
1400
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);
1407   } else {
1408     return __svcSemaphoreCreate(semaphore_def, count);
1409   }
1410 }
1411
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);
1416 }
1417
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);
1424   }
1425 }
1426
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);
1431 }
1432
1433
1434 // ==== Memory Management Functions ====
1435
1436 // Memory Management Helper Functions
1437
1438 // Clear Memory Box (Zero init)
1439 static void rt_clr_box (void *box_mem, void *box) {
1440   uint32_t *p, n;
1441
1442   if (box) {
1443     p = box;
1444     for (n = ((P_BM)box_mem)->blk_size; n; n -= 4) {
1445       *p++ = 0;
1446     }
1447   }
1448 }
1449
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)
1454
1455 // Memory Management Service & ISR Calls
1456
1457 /// Create and Initialize memory pool
1458 osPoolId svcPoolCreate (const osPoolDef_t *pool_def) {
1459   uint32_t blk_sz;
1460
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);
1466     return NULL;
1467   }
1468
1469   blk_sz = (pool_def->item_sz + 3) & ~3;
1470
1471   _init_box(pool_def->pool, sizeof(struct OS_BM) + pool_def->pool_sz * blk_sz, blk_sz);
1472
1473   return pool_def->pool;
1474 }
1475
1476 /// Allocate a memory block from a memory pool
1477 void *sysPoolAlloc (osPoolId pool_id, uint32_t clr) {
1478   void *ptr;
1479
1480   if (pool_id == NULL) return NULL;
1481
1482   ptr = rt_alloc_box(pool_id);
1483   if (clr) {
1484     rt_clr_box(pool_id, ptr);
1485   }
1486
1487   return ptr;
1488 }
1489
1490 /// Return an allocated memory block back to a specific memory pool
1491 osStatus sysPoolFree (osPoolId pool_id, void *block) {
1492   int32_t res;
1493
1494   if (pool_id == NULL) return osErrorParameter;
1495
1496   res = rt_free_box(pool_id, block);
1497   if (res != 0) return osErrorValue;
1498
1499   return osOK;
1500 }
1501
1502
1503 // Memory Management Public API
1504
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);
1511   } else {
1512     return __svcPoolCreate(pool_def);
1513   }
1514 }
1515
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);
1522   }
1523 }
1524
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);
1531   }
1532 }
1533
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);
1540   }
1541 }
1542
1543
1544 // ==== Message Queue Management Functions ====
1545
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)
1550
1551 // Message Queue Service Calls
1552
1553 /// Create and Initialize Message Queue
1554 osMessageQId svcMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id) {
1555
1556   if ((queue_def == NULL) ||
1557       (queue_def->queue_sz == 0) ||
1558       (queue_def->pool == NULL)) {
1559     sysThreadError(osErrorParameter);
1560     return NULL;
1561   }
1562
1563   if (((P_MCB)queue_def->pool)->cb_type != 0) {
1564     sysThreadError(osErrorParameter);
1565     return NULL;
1566   }
1567
1568   rt_mbx_init(queue_def->pool, 4*(queue_def->queue_sz + 4));
1569
1570   return queue_def->pool;
1571 }
1572
1573 /// Put a Message to a Queue
1574 osStatus svcMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) {
1575   OS_RESULT res;
1576
1577   if (queue_id == NULL) return osErrorParameter;
1578
1579   if (((P_MCB)queue_id)->cb_type != MCB) return osErrorParameter;
1580
1581   res = rt_mbx_send(queue_id, (void *)info, rt_ms2tick(millisec));
1582
1583   if (res == OS_R_TMO) {
1584     return (millisec ? osErrorTimeoutResource : osErrorResource);
1585   }
1586
1587   return osOK;
1588 }
1589
1590 /// Get a Message or Wait for a Message from a Queue
1591 os_InRegs osEvent_type svcMessageGet (osMessageQId queue_id, uint32_t millisec) {
1592   OS_RESULT res;
1593   osEvent   ret;
1594
1595   if (queue_id == NULL) {
1596     ret.status = osErrorParameter;
1597     return osEvent_ret_status;
1598   }
1599
1600   if (((P_MCB)queue_id)->cb_type != MCB) {
1601     ret.status = osErrorParameter;
1602     return osEvent_ret_status;
1603   }
1604
1605   res = rt_mbx_wait(queue_id, &ret.value.p, rt_ms2tick(millisec));
1606
1607   if (res == OS_R_TMO) {
1608     ret.status = millisec ? osEventTimeout : osOK;
1609     return osEvent_ret_value;
1610   }
1611
1612   ret.status = osEventMessage;
1613
1614   return osEvent_ret_value;
1615 }
1616
1617
1618 // Message Queue ISR Calls
1619
1620 /// Put a Message to a Queue
1621 static __INLINE osStatus isrMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) {
1622
1623   if ((queue_id == NULL) || (millisec != 0)) {
1624     return osErrorParameter;
1625   }
1626
1627   if (((P_MCB)queue_id)->cb_type != MCB) return osErrorParameter;
1628
1629   if (rt_mbx_check(queue_id) == 0) {            // Check if Queue is full
1630     return osErrorResource;
1631   }
1632
1633   isr_mbx_send(queue_id, (void *)info);
1634
1635   return osOK;
1636 }
1637
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) {
1640   OS_RESULT res;
1641   osEvent   ret;
1642
1643   if ((queue_id == NULL) || (millisec != 0)) {
1644     ret.status = osErrorParameter;
1645     return ret;
1646   }
1647
1648   if (((P_MCB)queue_id)->cb_type != MCB) {
1649     ret.status = osErrorParameter;
1650     return ret;
1651   }
1652
1653   res = isr_mbx_receive(queue_id, &ret.value.p);
1654
1655   if (res != OS_R_MBX) {
1656     ret.status = osOK;
1657     return ret;
1658   }
1659
1660   ret.status = osEventMessage;
1661
1662   return ret;
1663 }
1664
1665
1666 // Message Queue Management Public API
1667
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);
1674   } else {
1675     return __svcMessageCreate(queue_def, thread_id);
1676   }
1677 }
1678
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);
1685   }
1686 }
1687
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);
1694   }
1695 }
1696
1697
1698 // ==== Mail Queue Management Functions ====
1699
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)
1704
1705 // Mail Queue Management Service & ISR Calls
1706
1707 /// Create and Initialize mail queue
1708 osMailQId svcMailCreate (osMailQDef_t *queue_def, osThreadId thread_id) {
1709   uint32_t blk_sz;
1710   P_MCB    pmcb;
1711   void    *pool;
1712
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);
1718     return NULL;
1719   }
1720
1721   pmcb = *(((void **)queue_def->pool) + 0);
1722   pool = *(((void **)queue_def->pool) + 1);
1723
1724   if ((pool == NULL) || (pmcb == NULL) || (pmcb->cb_type != 0)) {
1725     sysThreadError(osErrorParameter);
1726     return NULL;
1727   }
1728
1729   blk_sz = (queue_def->item_sz + 3) & ~3;
1730
1731   _init_box(pool, sizeof(struct OS_BM) + queue_def->queue_sz * blk_sz, blk_sz);
1732
1733   rt_mbx_init(pmcb, 4*(queue_def->queue_sz + 4));
1734
1735
1736   return queue_def->pool;
1737 }
1738
1739 /// Allocate a memory block from a mail
1740 void *sysMailAlloc (osMailQId queue_id, uint32_t millisec, uint32_t isr, uint32_t clr) {
1741   P_MCB pmcb;
1742   void *pool;
1743   void *mem;
1744
1745   if (queue_id == NULL) return NULL;
1746
1747   pmcb = *(((void **)queue_id) + 0);
1748   pool = *(((void **)queue_id) + 1);
1749
1750   if ((pool == NULL) || (pmcb == NULL)) return NULL;
1751
1752   if (isr && (millisec != 0)) return NULL;
1753
1754   mem = rt_alloc_box(pool);
1755   if (clr) {
1756     rt_clr_box(pool, mem);
1757   }
1758
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);
1763     } else {
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
1768       pmcb->state = 3;
1769     }
1770     rt_block(rt_ms2tick(millisec), WAIT_MBX);
1771   }
1772
1773   return mem;
1774 }
1775
1776 /// Free a memory block from a mail
1777 osStatus sysMailFree (osMailQId queue_id, void *mail, uint32_t isr) {
1778   P_MCB   pmcb;
1779   P_TCB   ptcb;
1780   void   *pool;
1781   void   *mem;
1782   int32_t res;
1783
1784   if (queue_id == NULL) return osErrorParameter;
1785
1786   pmcb = *(((void **)queue_id) + 0);
1787   pool = *(((void **)queue_id) + 1);
1788
1789   if ((pmcb == NULL) || (pool == NULL)) return osErrorParameter;
1790
1791   res = rt_free_box(pool, mail);
1792
1793   if (res != 0) return osErrorValue;
1794
1795   if (pmcb->state == 3) {
1796     // Task is waiting to allocate a message
1797     if (isr) {
1798       rt_psq_enq (pmcb, (U32)pool);
1799       rt_psh_req ();
1800     } else {
1801       mem = rt_alloc_box(pool);
1802       if (mem != NULL) {
1803         ptcb = rt_get_first((P_XCB)pmcb);
1804         if (pmcb->p_lnk == NULL) {
1805           pmcb->state = 0;
1806         }
1807         rt_ret_val(ptcb, (U32)mem);
1808         rt_rmv_dly(ptcb);
1809         rt_dispatch(ptcb);
1810       }
1811     }
1812   }
1813
1814   return osOK;
1815 }
1816
1817
1818 // Mail Queue Management Public API
1819
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);
1826   } else {
1827     return __svcMailCreate(queue_def, thread_id);
1828   }
1829 }
1830
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);
1837   }
1838 }
1839
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);
1846   }
1847 }
1848
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);
1855   }
1856 }
1857
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);
1863 }
1864
1865 #ifdef __CC_ARM
1866 #pragma push
1867 #pragma Ospace
1868 #endif // __arm__
1869 /// Get a mail from a queue
1870 os_InRegs osEvent osMailGet (osMailQId queue_id, uint32_t millisec) {
1871   osEvent ret;
1872
1873   if (queue_id == NULL) {
1874     ret.status = osErrorParameter;
1875     return ret;
1876   }
1877
1878   ret = osMessageGet(*((void **)queue_id), millisec);
1879   if (ret.status == osEventMessage) ret.status = osEventMail;
1880
1881   return ret;
1882 }
1883 #ifdef __CC_ARM
1884 #pragma pop
1885 #endif // __arm__