Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-rtos by
rt_CMSIS.c
00001 /*---------------------------------------------------------------------------- 00002 * RL-ARM - RTX 00003 *---------------------------------------------------------------------------- 00004 * Name: rt_CMSIS.c 00005 * Purpose: CMSIS RTOS API 00006 * Rev.: V4.60 00007 *---------------------------------------------------------------------------- 00008 * 00009 * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH 00010 * All rights reserved. 00011 * Redistribution and use in source and binary forms, with or without 00012 * modification, are permitted provided that the following conditions are met: 00013 * - Redistributions of source code must retain the above copyright 00014 * notice, this list of conditions and the following disclaimer. 00015 * - Redistributions in binary form must reproduce the above copyright 00016 * notice, this list of conditions and the following disclaimer in the 00017 * documentation and/or other materials provided with the distribution. 00018 * - Neither the name of ARM nor the names of its contributors may be used 00019 * to endorse or promote products derived from this software without 00020 * specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00023 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00024 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00025 * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE 00026 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00027 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00028 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00029 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00030 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00031 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 *---------------------------------------------------------------------------*/ 00034 00035 #define __CMSIS_GENERIC 00036 00037 #if defined (__CORTEX_M4) || defined (__CORTEX_M4F) 00038 #include "core_cm4.h" 00039 #elif defined (__CORTEX_M3) 00040 #include "core_cm3.h" 00041 #elif defined (__CORTEX_M0) 00042 #include "core_cm0.h" 00043 #elif defined (__CORTEX_M0PLUS) 00044 #include "core_cm0plus.h" 00045 #else 00046 #error "Missing __CORTEX_Mx definition" 00047 #endif 00048 00049 #include "rt_TypeDef.h" 00050 #include "RTX_Conf.h" 00051 #include "rt_System.h" 00052 #include "rt_Task.h" 00053 #include "rt_Event.h" 00054 #include "rt_List.h" 00055 #include "rt_Time.h" 00056 #include "rt_Mutex.h" 00057 #include "rt_Semaphore.h" 00058 #include "rt_Mailbox.h" 00059 #include "rt_MemBox.h" 00060 #include "rt_HAL_CM.h" 00061 00062 #define os_thread_cb OS_TCB 00063 00064 #include "cmsis_os.h" 00065 00066 #if (osFeature_Signals != 16) 00067 #error Invalid "osFeature_Signals" value! 00068 #endif 00069 #if (osFeature_Semaphore > 65535) 00070 #error Invalid "osFeature_Semaphore" value! 00071 #endif 00072 #if (osFeature_Wait != 0) 00073 #error osWait not supported! 00074 #endif 00075 00076 00077 // ==== Enumeration, structures, defines ==== 00078 00079 // Service Calls defines 00080 00081 #if defined (__CC_ARM) /* ARM Compiler */ 00082 00083 #define __NO_RETURN __declspec(noreturn) 00084 00085 #define osEvent_type osEvent 00086 #define osEvent_ret_status ret 00087 #define osEvent_ret_value ret 00088 #define osEvent_ret_msg ret 00089 #define osEvent_ret_mail ret 00090 00091 #define osCallback_type osCallback 00092 #define osCallback_ret ret 00093 00094 #define SVC_0_1(f,t,...) \ 00095 __svc_indirect(0) t _##f (t(*)()); \ 00096 t f (void); \ 00097 __attribute__((always_inline)) \ 00098 static __inline t __##f (void) { \ 00099 return _##f(f); \ 00100 } 00101 00102 #define SVC_1_1(f,t,t1,...) \ 00103 __svc_indirect(0) t _##f (t(*)(t1),t1); \ 00104 t f (t1 a1); \ 00105 __attribute__((always_inline)) \ 00106 static __inline t __##f (t1 a1) { \ 00107 return _##f(f,a1); \ 00108 } 00109 00110 #define SVC_2_1(f,t,t1,t2,...) \ 00111 __svc_indirect(0) t _##f (t(*)(t1,t2),t1,t2); \ 00112 t f (t1 a1, t2 a2); \ 00113 __attribute__((always_inline)) \ 00114 static __inline t __##f (t1 a1, t2 a2) { \ 00115 return _##f(f,a1,a2); \ 00116 } 00117 00118 #define SVC_3_1(f,t,t1,t2,t3,...) \ 00119 __svc_indirect(0) t _##f (t(*)(t1,t2,t3),t1,t2,t3); \ 00120 t f (t1 a1, t2 a2, t3 a3); \ 00121 __attribute__((always_inline)) \ 00122 static __inline t __##f (t1 a1, t2 a2, t3 a3) { \ 00123 return _##f(f,a1,a2,a3); \ 00124 } 00125 00126 #define SVC_4_1(f,t,t1,t2,t3,t4,...) \ 00127 __svc_indirect(0) t _##f (t(*)(t1,t2,t3,t4),t1,t2,t3,t4); \ 00128 t f (t1 a1, t2 a2, t3 a3, t4 a4); \ 00129 __attribute__((always_inline)) \ 00130 static __inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) { \ 00131 return _##f(f,a1,a2,a3,a4); \ 00132 } 00133 00134 #define SVC_1_2 SVC_1_1 00135 #define SVC_1_3 SVC_1_1 00136 #define SVC_2_3 SVC_2_1 00137 00138 #elif defined (__GNUC__) /* GNU Compiler */ 00139 00140 #define __NO_RETURN __attribute__((noreturn)) 00141 00142 typedef uint32_t __attribute__((vector_size(8))) ret64; 00143 typedef uint32_t __attribute__((vector_size(16))) ret128; 00144 00145 #define RET_pointer __r0 00146 #define RET_int32_t __r0 00147 #define RET_osStatus __r0 00148 #define RET_osPriority __r0 00149 #define RET_osEvent {(osStatus)__r0, {(uint32_t)__r1}, {(void *)__r2}} 00150 #define RET_osCallback {(void *)__r0, (void *)__r1} 00151 00152 #define osEvent_type ret128 00153 #define osEvent_ret_status (ret128){ret.status} 00154 #define osEvent_ret_value (ret128){ret.status, ret.value.v} 00155 #define osEvent_ret_msg (ret128){ret.status, ret.value.v, (uint32_t)ret.def.message_id} 00156 #define osEvent_ret_mail (ret128){ret.status, ret.value.v, (uint32_t)ret.def.mail_id} 00157 00158 #define osCallback_type ret64 00159 #define osCallback_ret (ret64) {(uint32_t)ret.fp, (uint32_t)ret.arg} 00160 00161 #define SVC_ArgN(n) \ 00162 register int __r##n __asm("r"#n); 00163 00164 #define SVC_ArgR(n,t,a) \ 00165 register t __r##n __asm("r"#n) = a; 00166 00167 #define SVC_Arg0() \ 00168 SVC_ArgN(0) \ 00169 SVC_ArgN(1) \ 00170 SVC_ArgN(2) \ 00171 SVC_ArgN(3) 00172 00173 #define SVC_Arg1(t1) \ 00174 SVC_ArgR(0,t1,a1) \ 00175 SVC_ArgN(1) \ 00176 SVC_ArgN(2) \ 00177 SVC_ArgN(3) 00178 00179 #define SVC_Arg2(t1,t2) \ 00180 SVC_ArgR(0,t1,a1) \ 00181 SVC_ArgR(1,t2,a2) \ 00182 SVC_ArgN(2) \ 00183 SVC_ArgN(3) 00184 00185 #define SVC_Arg3(t1,t2,t3) \ 00186 SVC_ArgR(0,t1,a1) \ 00187 SVC_ArgR(1,t2,a2) \ 00188 SVC_ArgR(2,t3,a3) \ 00189 SVC_ArgN(3) 00190 00191 #define SVC_Arg4(t1,t2,t3,t4) \ 00192 SVC_ArgR(0,t1,a1) \ 00193 SVC_ArgR(1,t2,a2) \ 00194 SVC_ArgR(2,t3,a3) \ 00195 SVC_ArgR(3,t4,a4) 00196 00197 #if (defined (__CORTEX_M0)) || defined (__CORTEX_M0PLUS) 00198 #define SVC_Call(f) \ 00199 __asm volatile \ 00200 ( \ 00201 "ldr r7,="#f"\n\t" \ 00202 "mov r12,r7\n\t" \ 00203 "svc 0" \ 00204 : "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3) \ 00205 : "r" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) \ 00206 : "r7", "r12", "lr", "cc" \ 00207 ); 00208 #else 00209 #define SVC_Call(f) \ 00210 __asm volatile \ 00211 ( \ 00212 "ldr r12,="#f"\n\t" \ 00213 "svc 0" \ 00214 : "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3) \ 00215 : "r" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) \ 00216 : "r12", "lr", "cc" \ 00217 ); 00218 #endif 00219 00220 #define SVC_0_1(f,t,rv) \ 00221 __attribute__((always_inline)) \ 00222 static inline t __##f (void) { \ 00223 SVC_Arg0(); \ 00224 SVC_Call(f); \ 00225 return (t) rv; \ 00226 } 00227 00228 #define SVC_1_1(f,t,t1,rv) \ 00229 __attribute__((always_inline)) \ 00230 static inline t __##f (t1 a1) { \ 00231 SVC_Arg1(t1); \ 00232 SVC_Call(f); \ 00233 return (t) rv; \ 00234 } 00235 00236 #define SVC_2_1(f,t,t1,t2,rv) \ 00237 __attribute__((always_inline)) \ 00238 static inline t __##f (t1 a1, t2 a2) { \ 00239 SVC_Arg2(t1,t2); \ 00240 SVC_Call(f); \ 00241 return (t) rv; \ 00242 } 00243 00244 #define SVC_3_1(f,t,t1,t2,t3,rv) \ 00245 __attribute__((always_inline)) \ 00246 static inline t __##f (t1 a1, t2 a2, t3 a3) { \ 00247 SVC_Arg3(t1,t2,t3); \ 00248 SVC_Call(f); \ 00249 return (t) rv; \ 00250 } 00251 00252 #define SVC_4_1(f,t,t1,t2,t3,t4,rv) \ 00253 __attribute__((always_inline)) \ 00254 static inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) { \ 00255 SVC_Arg4(t1,t2,t3,t4); \ 00256 SVC_Call(f); \ 00257 return (t) rv; \ 00258 } 00259 00260 #define SVC_1_2 SVC_1_1 00261 #define SVC_1_3 SVC_1_1 00262 #define SVC_2_3 SVC_2_1 00263 00264 #elif defined (__ICCARM__) /* IAR Compiler */ 00265 00266 #define __NO_RETURN __noreturn 00267 00268 #define RET_osEvent "=r"(ret.status), "=r"(ret.value), "=r"(ret.def) 00269 #define RET_osCallback "=r"(ret.fp), "=r"(ret.arg) 00270 00271 #define osEvent_type osEvent 00272 #define osEvent_ret_status ret 00273 #define osEvent_ret_value ret 00274 #define osEvent_ret_msg ret 00275 #define osEvent_ret_mail ret 00276 00277 #define osCallback_type uint64_t 00278 #define osCallback_ret ((uint64_t)ret.fp | ((uint64_t)ret.arg)<<32) 00279 00280 #define SVC_Setup(f) \ 00281 __asm( \ 00282 "mov r12,%0\n" \ 00283 :: "r"(&f): "r12" \ 00284 ); 00285 00286 #define SVC_Ret3() \ 00287 __asm( \ 00288 "ldr r0,[sp,#0]\n" \ 00289 "ldr r1,[sp,#4]\n" \ 00290 "ldr r2,[sp,#8]\n" \ 00291 ); 00292 00293 #define SVC_0_1(f,t,...) \ 00294 t f (void); \ 00295 _Pragma("swi_number=0") __swi t _##f (void); \ 00296 static inline t __##f (void) { \ 00297 SVC_Setup(f); \ 00298 return _##f(); \ 00299 } 00300 00301 #define SVC_1_1(f,t,t1,...) \ 00302 t f (t1 a1); \ 00303 _Pragma("swi_number=0") __swi t _##f (t1 a1); \ 00304 static inline t __##f (t1 a1) { \ 00305 SVC_Setup(f); \ 00306 return _##f(a1); \ 00307 } 00308 00309 #define SVC_2_1(f,t,t1,t2,...) \ 00310 t f (t1 a1, t2 a2); \ 00311 _Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2); \ 00312 static inline t __##f (t1 a1, t2 a2) { \ 00313 SVC_Setup(f); \ 00314 return _##f(a1,a2); \ 00315 } 00316 00317 #define SVC_3_1(f,t,t1,t2,t3,...) \ 00318 t f (t1 a1, t2 a2, t3 a3); \ 00319 _Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2, t3 a3); \ 00320 static inline t __##f (t1 a1, t2 a2, t3 a3) { \ 00321 SVC_Setup(f); \ 00322 return _##f(a1,a2,a3); \ 00323 } 00324 00325 #define SVC_4_1(f,t,t1,t2,t3,t4,...) \ 00326 t f (t1 a1, t2 a2, t3 a3, t4 a4); \ 00327 _Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2, t3 a3, t4 a4); \ 00328 static inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) { \ 00329 SVC_Setup(f); \ 00330 return _##f(a1,a2,a3,a4); \ 00331 } 00332 00333 #define SVC_1_2(f,t,t1,rr) \ 00334 uint64_t f (t1 a1); \ 00335 _Pragma("swi_number=0") __swi uint64_t _##f (t1 a1); \ 00336 static inline t __##f (t1 a1) { \ 00337 t ret; \ 00338 SVC_Setup(f); \ 00339 _##f(a1); \ 00340 __asm("" : rr : :); \ 00341 return ret; \ 00342 } 00343 00344 #define SVC_1_3(f,t,t1,rr) \ 00345 t f (t1 a1); \ 00346 void f##_ (t1 a1) { \ 00347 f(a1); \ 00348 SVC_Ret3(); \ 00349 } \ 00350 _Pragma("swi_number=0") __swi void _##f (t1 a1); \ 00351 static inline t __##f (t1 a1) { \ 00352 t ret; \ 00353 SVC_Setup(f##_); \ 00354 _##f(a1); \ 00355 __asm("" : rr : :); \ 00356 return ret; \ 00357 } 00358 00359 #define SVC_2_3(f,t,t1,t2,rr) \ 00360 t f (t1 a1, t2 a2); \ 00361 void f##_ (t1 a1, t2 a2) { \ 00362 f(a1,a2); \ 00363 SVC_Ret3(); \ 00364 } \ 00365 _Pragma("swi_number=0") __swi void _##f (t1 a1, t2 a2); \ 00366 static inline t __##f (t1 a1, t2 a2) { \ 00367 t ret; \ 00368 SVC_Setup(f##_); \ 00369 _##f(a1,a2); \ 00370 __asm("" : rr : :); \ 00371 return ret; \ 00372 } 00373 00374 #endif 00375 00376 00377 // Callback structure 00378 typedef struct { 00379 void *fp; // Function pointer 00380 void *arg; // Function argument 00381 } osCallback; 00382 00383 00384 // OS Section definitions 00385 #ifdef OS_SECTIONS_LINK_INFO 00386 extern const uint32_t os_section_id$$Base; 00387 extern const uint32_t os_section_id$$Limit; 00388 #endif 00389 00390 // OS Timers external resources 00391 extern osThreadDef_t os_thread_def_osTimerThread; 00392 extern osThreadId osThreadId_osTimerThread; 00393 extern osMessageQDef_t os_messageQ_def_osTimerMessageQ; 00394 extern osMessageQId osMessageQId_osTimerMessageQ; 00395 00396 00397 // ==== Helper Functions ==== 00398 00399 /// Convert timeout in millisec to system ticks 00400 static uint32_t rt_ms2tick (uint32_t millisec) { 00401 uint32_t tick; 00402 00403 if (millisec == osWaitForever) return 0xFFFF; // Indefinite timeout 00404 if (millisec > 4000000) return 0xFFFE; // Max ticks supported 00405 00406 tick = ((1000 * millisec) + os_clockrate - 1) / os_clockrate; 00407 if (tick > 0xFFFE) return 0xFFFE; 00408 00409 return tick; 00410 } 00411 00412 /// Convert Thread ID to TCB pointer 00413 static P_TCB rt_tid2ptcb (osThreadId thread_id) { 00414 P_TCB ptcb; 00415 00416 if (thread_id == NULL) return NULL; 00417 00418 if ((uint32_t)thread_id & 3) return NULL; 00419 00420 #ifdef OS_SECTIONS_LINK_INFO 00421 if ((os_section_id$$Base != 0) && (os_section_id$$Limit != 0)) { 00422 if (thread_id < (osThreadId)os_section_id$$Base) return NULL; 00423 if (thread_id >= (osThreadId)os_section_id$$Limit) return NULL; 00424 } 00425 #endif 00426 00427 ptcb = thread_id; 00428 00429 if (ptcb->cb_type != TCB) return NULL; 00430 00431 return ptcb; 00432 } 00433 00434 /// Convert ID pointer to Object pointer 00435 static void *rt_id2obj (void *id) { 00436 00437 if ((uint32_t)id & 3) return NULL; 00438 00439 #ifdef OS_SECTIONS_LINK_INFO 00440 if ((os_section_id$$Base != 0) && (os_section_id$$Limit != 0)) { 00441 if (id < (void *)os_section_id$$Base) return NULL; 00442 if (id >= (void *)os_section_id$$Limit) return NULL; 00443 } 00444 #endif 00445 00446 return id; 00447 } 00448 00449 00450 // ==== Kernel Control ==== 00451 00452 uint8_t os_initialized; // Kernel Initialized flag 00453 uint8_t os_running; // Kernel Running flag 00454 00455 // Kernel Control Service Calls declarations 00456 SVC_0_1(svcKernelInitialize, osStatus, RET_osStatus) 00457 SVC_0_1(svcKernelStart, osStatus, RET_osStatus) 00458 SVC_0_1(svcKernelRunning, int32_t, RET_int32_t) 00459 00460 extern void sysThreadError (osStatus status); 00461 osThreadId svcThreadCreate (osThreadDef_t *thread_def, void *argument); 00462 osMessageQId svcMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id); 00463 00464 // Kernel Control Service Calls 00465 00466 /// Initialize the RTOS Kernel for creating objects 00467 osStatus svcKernelInitialize (void) { 00468 if (os_initialized) return osOK; 00469 00470 rt_sys_init(); // RTX System Initialization 00471 os_tsk.run->prio = 255; // Highest priority 00472 00473 sysThreadError(osOK); 00474 00475 os_initialized = 1; 00476 00477 return osOK; 00478 } 00479 00480 /// Start the RTOS Kernel 00481 osStatus svcKernelStart (void) { 00482 00483 if (os_running) return osOK; 00484 00485 // Create OS Timers resources (Message Queue & Thread) 00486 osMessageQId_osTimerMessageQ = svcMessageCreate (&os_messageQ_def_osTimerMessageQ, NULL); 00487 osThreadId_osTimerThread = svcThreadCreate(&os_thread_def_osTimerThread, NULL); 00488 00489 rt_tsk_prio(0, 0); // Lowest priority 00490 __set_PSP(os_tsk.run->tsk_stack + 8*4); // New context 00491 os_tsk.run = NULL; // Force context switch 00492 00493 rt_sys_start(); 00494 00495 os_running = 1; 00496 00497 return osOK; 00498 } 00499 00500 /// Check if the RTOS kernel is already started 00501 int32_t svcKernelRunning(void) { 00502 return os_running; 00503 } 00504 00505 // Kernel Control Public API 00506 00507 /// Initialize the RTOS Kernel for creating objects 00508 osStatus osKernelInitialize (void) { 00509 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 00510 if ((__get_CONTROL() & 1) == 0) { // Privileged mode 00511 return svcKernelInitialize(); 00512 } else { 00513 return __svcKernelInitialize(); 00514 } 00515 } 00516 00517 /// Start the RTOS Kernel 00518 osStatus osKernelStart (void) { 00519 uint32_t stack[8]; 00520 00521 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 00522 switch (__get_CONTROL() & 0x03) { 00523 case 0x00: // Privileged Thread mode & MSP 00524 __set_PSP((uint32_t)(stack + 8)); // Initial PSP 00525 if (os_flags & 1) { 00526 __set_CONTROL(0x02); // Set Privileged Thread mode & PSP 00527 } else { 00528 __set_CONTROL(0x03); // Set Unprivileged Thread mode & PSP 00529 } 00530 __DSB(); 00531 __ISB(); 00532 break; 00533 case 0x01: // Unprivileged Thread mode & MSP 00534 return osErrorOS; 00535 case 0x02: // Privileged Thread mode & PSP 00536 if ((os_flags & 1) == 0) { // Unprivileged Thread mode requested 00537 __set_CONTROL(0x03); // Set Unprivileged Thread mode & PSP 00538 __DSB(); 00539 __ISB(); 00540 } 00541 break; 00542 case 0x03: // Unprivileged Thread mode & PSP 00543 if (os_flags & 1) return osErrorOS; // Privileged Thread mode requested 00544 break; 00545 } 00546 return __svcKernelStart(); 00547 } 00548 00549 /// Check if the RTOS kernel is already started 00550 int32_t osKernelRunning(void) { 00551 if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { 00552 // in ISR or Privileged 00553 return os_running; 00554 } else { 00555 return __svcKernelRunning(); 00556 } 00557 } 00558 00559 00560 // ==== Thread Management ==== 00561 00562 __NO_RETURN void osThreadExit (void); 00563 00564 // Thread Service Calls declarations 00565 SVC_2_1(svcThreadCreate, osThreadId, osThreadDef_t *, void *, RET_pointer) 00566 SVC_0_1(svcThreadGetId, osThreadId, RET_pointer) 00567 SVC_1_1(svcThreadTerminate, osStatus, osThreadId, RET_osStatus) 00568 SVC_0_1(svcThreadYield, osStatus, RET_osStatus) 00569 SVC_2_1(svcThreadSetPriority, osStatus, osThreadId, osPriority, RET_osStatus) 00570 SVC_1_1(svcThreadGetPriority, osPriority, osThreadId, RET_osPriority) 00571 00572 // Thread Service Calls 00573 extern OS_TID rt_get_TID (void); 00574 extern void rt_init_context (P_TCB p_TCB, U8 priority, FUNCP task_body); 00575 00576 /// Create a thread and add it to Active Threads and set it to state READY 00577 osThreadId svcThreadCreate (osThreadDef_t *thread_def, void *argument) { 00578 P_TCB ptcb; 00579 00580 if ((thread_def == NULL) || 00581 (thread_def->pthread == NULL) || 00582 (thread_def->tpriority < osPriorityIdle) || 00583 (thread_def->tpriority > osPriorityRealtime) || 00584 (thread_def->stacksize == 0) || 00585 (thread_def->stack_pointer == NULL) ) { 00586 sysThreadError(osErrorParameter); 00587 return NULL; 00588 } 00589 00590 U8 priority = thread_def->tpriority - osPriorityIdle + 1; 00591 P_TCB task_context = &thread_def->tcb; 00592 00593 /* If "size != 0" use a private user provided stack. */ 00594 task_context->stack = (U32*)thread_def->stack_pointer; 00595 task_context->priv_stack = thread_def->stacksize; 00596 /* Pass parameter 'argv' to 'rt_init_context' */ 00597 task_context->msg = argument; 00598 /* For 'size == 0' system allocates the user stack from the memory pool. */ 00599 rt_init_context (task_context, priority, (FUNCP)thread_def->pthread); 00600 00601 /* Find a free entry in 'os_active_TCB' table. */ 00602 OS_TID tsk = rt_get_TID (); 00603 os_active_TCB[tsk-1] = task_context; 00604 task_context->task_id = tsk; 00605 DBG_TASK_NOTIFY(task_context, __TRUE); 00606 rt_dispatch (task_context); 00607 00608 ptcb = (P_TCB)os_active_TCB[tsk - 1]; // TCB pointer 00609 00610 *((uint32_t *)ptcb->tsk_stack + 13) = (uint32_t)osThreadExit; 00611 00612 return ptcb; 00613 } 00614 00615 /// Return the thread ID of the current running thread 00616 osThreadId svcThreadGetId (void) { 00617 OS_TID tsk; 00618 00619 tsk = rt_tsk_self(); 00620 if (tsk == 0) return NULL; 00621 return (P_TCB)os_active_TCB[tsk - 1]; 00622 } 00623 00624 /// Terminate execution of a thread and remove it from ActiveThreads 00625 osStatus svcThreadTerminate (osThreadId thread_id) { 00626 OS_RESULT res; 00627 P_TCB ptcb; 00628 00629 ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer 00630 if (ptcb == NULL) return osErrorParameter; 00631 00632 res = rt_tsk_delete(ptcb->task_id); // Delete task 00633 00634 if (res == OS_R_NOK) return osErrorResource; // Delete task failed 00635 00636 return osOK; 00637 } 00638 00639 /// Pass control to next thread that is in state READY 00640 osStatus svcThreadYield (void) { 00641 rt_tsk_pass(); // Pass control to next task 00642 return osOK; 00643 } 00644 00645 /// Change priority of an active thread 00646 osStatus svcThreadSetPriority (osThreadId thread_id, osPriority priority) { 00647 OS_RESULT res; 00648 P_TCB ptcb; 00649 00650 ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer 00651 if (ptcb == NULL) return osErrorParameter; 00652 00653 if ((priority < osPriorityIdle) || (priority > osPriorityRealtime)) { 00654 return osErrorValue; 00655 } 00656 00657 res = rt_tsk_prio( // Change task priority 00658 ptcb->task_id, // Task ID 00659 priority - osPriorityIdle + 1 // New task priority 00660 ); 00661 00662 if (res == OS_R_NOK) return osErrorResource; // Change task priority failed 00663 00664 return osOK; 00665 } 00666 00667 /// Get current priority of an active thread 00668 osPriority svcThreadGetPriority (osThreadId thread_id) { 00669 P_TCB ptcb; 00670 00671 ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer 00672 if (ptcb == NULL) return osPriorityError; 00673 00674 return (osPriority)(ptcb->prio - 1 + osPriorityIdle); 00675 } 00676 00677 00678 // Thread Public API 00679 00680 /// Create a thread and add it to Active Threads and set it to state READY 00681 osThreadId osThreadCreate (osThreadDef_t *thread_def, void *argument) { 00682 if (__get_IPSR() != 0) return NULL; // Not allowed in ISR 00683 if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { 00684 // Privileged and not running 00685 return svcThreadCreate(thread_def, argument); 00686 } else { 00687 return __svcThreadCreate(thread_def, argument); 00688 } 00689 } 00690 00691 /// Return the thread ID of the current running thread 00692 osThreadId osThreadGetId (void) { 00693 if (__get_IPSR() != 0) return NULL; // Not allowed in ISR 00694 return __svcThreadGetId(); 00695 } 00696 00697 /// Terminate execution of a thread and remove it from ActiveThreads 00698 osStatus osThreadTerminate (osThreadId thread_id) { 00699 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 00700 return __svcThreadTerminate(thread_id); 00701 } 00702 00703 /// Pass control to next thread that is in state READY 00704 osStatus osThreadYield (void) { 00705 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 00706 return __svcThreadYield(); 00707 } 00708 00709 /// Change priority of an active thread 00710 osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority) { 00711 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 00712 return __svcThreadSetPriority(thread_id, priority); 00713 } 00714 00715 /// Get current priority of an active thread 00716 osPriority osThreadGetPriority (osThreadId thread_id) { 00717 if (__get_IPSR() != 0) return osPriorityError;// Not allowed in ISR 00718 return __svcThreadGetPriority(thread_id); 00719 } 00720 00721 /// INTERNAL - Not Public 00722 /// Auto Terminate Thread on exit (used implicitly when thread exists) 00723 __NO_RETURN void osThreadExit (void) { 00724 __svcThreadTerminate(__svcThreadGetId()); 00725 for (;;); // Should never come here 00726 } 00727 00728 00729 // ==== Generic Wait Functions ==== 00730 00731 // Generic Wait Service Calls declarations 00732 SVC_1_1(svcDelay, osStatus, uint32_t, RET_osStatus) 00733 #if osFeature_Wait != 0 00734 SVC_1_3(svcWait, os_InRegs osEvent, uint32_t, RET_osEvent) 00735 #endif 00736 00737 // Generic Wait Service Calls 00738 00739 /// Wait for Timeout (Time Delay) 00740 osStatus svcDelay (uint32_t millisec) { 00741 if (millisec == 0) return osOK; 00742 rt_dly_wait(rt_ms2tick(millisec)); 00743 return osEventTimeout; 00744 } 00745 00746 /// Wait for Signal, Message, Mail, or Timeout 00747 #if osFeature_Wait != 0 00748 os_InRegs osEvent_type svcWait (uint32_t millisec) { 00749 osEvent ret; 00750 00751 if (millisec == 0) { 00752 ret.status = osOK; 00753 return osEvent_ret_status; 00754 } 00755 00756 /* To Do: osEventSignal, osEventMessage, osEventMail */ 00757 rt_dly_wait(rt_ms2tick(millisec)); 00758 ret.status = osEventTimeout; 00759 00760 return osEvent_ret_status; 00761 } 00762 #endif 00763 00764 00765 // Generic Wait API 00766 00767 /// Wait for Timeout (Time Delay) 00768 osStatus osDelay (uint32_t millisec) { 00769 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 00770 return __svcDelay(millisec); 00771 } 00772 00773 /// Wait for Signal, Message, Mail, or Timeout 00774 os_InRegs osEvent osWait (uint32_t millisec) { 00775 osEvent ret; 00776 00777 #if osFeature_Wait == 0 00778 ret.status = osErrorOS; 00779 return ret; 00780 #else 00781 if (__get_IPSR() != 0) { // Not allowed in ISR 00782 ret.status = osErrorISR; 00783 return ret; 00784 } 00785 return __svcWait(millisec); 00786 #endif 00787 } 00788 00789 00790 // ==== Timer Management ==== 00791 00792 // Timer definitions 00793 #define osTimerInvalid 0 00794 #define osTimerStopped 1 00795 #define osTimerRunning 2 00796 00797 // Timer structures 00798 00799 typedef struct os_timer_cb_ { // Timer Control Block 00800 struct os_timer_cb_ *next; // Pointer to next active Timer 00801 uint8_t state; // Timer State 00802 uint8_t type; // Timer Type (Periodic/One-shot) 00803 uint16_t reserved; // Reserved 00804 uint16_t tcnt; // Timer Delay Count 00805 uint16_t icnt; // Timer Initial Count 00806 void *arg; // Timer Function Argument 00807 osTimerDef_t *timer; // Pointer to Timer definition 00808 } os_timer_cb; 00809 00810 // Timer variables 00811 os_timer_cb *os_timer_head; // Pointer to first active Timer 00812 00813 00814 // Timer Helper Functions 00815 00816 // Insert Timer into the list sorted by time 00817 static void rt_timer_insert (os_timer_cb *pt, uint32_t tcnt) { 00818 os_timer_cb *p, *prev; 00819 00820 prev = NULL; 00821 p = os_timer_head; 00822 while (p != NULL) { 00823 if (tcnt < p->tcnt) break; 00824 tcnt -= p->tcnt; 00825 prev = p; 00826 p = p->next; 00827 } 00828 pt->next = p; 00829 pt->tcnt = (uint16_t)tcnt; 00830 if (p != NULL) { 00831 p->tcnt -= pt->tcnt; 00832 } 00833 if (prev != NULL) { 00834 prev->next = pt; 00835 } else { 00836 os_timer_head = pt; 00837 } 00838 } 00839 00840 // Remove Timer from the list 00841 static int rt_timer_remove (os_timer_cb *pt) { 00842 os_timer_cb *p, *prev; 00843 00844 prev = NULL; 00845 p = os_timer_head; 00846 while (p != NULL) { 00847 if (p == pt) break; 00848 prev = p; 00849 p = p->next; 00850 } 00851 if (p == NULL) return -1; 00852 if (prev != NULL) { 00853 prev->next = pt->next; 00854 } else { 00855 os_timer_head = pt->next; 00856 } 00857 if (pt->next != NULL) { 00858 pt->next->tcnt += pt->tcnt; 00859 } 00860 00861 return 0; 00862 } 00863 00864 00865 // Timer Service Calls declarations 00866 SVC_3_1(svcTimerCreate, osTimerId, osTimerDef_t *, os_timer_type, void *, RET_pointer) 00867 SVC_2_1(svcTimerStart, osStatus, osTimerId, uint32_t, RET_osStatus) 00868 SVC_1_1(svcTimerStop, osStatus, osTimerId, RET_osStatus) 00869 SVC_1_1(svcTimerDelete, osStatus, osTimerId, RET_osStatus) 00870 SVC_1_2(svcTimerCall, os_InRegs osCallback, osTimerId, RET_osCallback) 00871 00872 // Timer Management Service Calls 00873 00874 /// Create timer 00875 osTimerId svcTimerCreate (osTimerDef_t *timer_def, os_timer_type type, void *argument) { 00876 os_timer_cb *pt; 00877 00878 if ((timer_def == NULL) || (timer_def->ptimer == NULL)) { 00879 sysThreadError(osErrorParameter); 00880 return NULL; 00881 } 00882 00883 pt = timer_def->timer; 00884 if (pt == NULL) { 00885 sysThreadError(osErrorParameter); 00886 return NULL; 00887 } 00888 00889 if ((type != osTimerOnce) && (type != osTimerPeriodic)) { 00890 sysThreadError(osErrorValue); 00891 return NULL; 00892 } 00893 00894 if (osThreadId_osTimerThread == NULL) { 00895 sysThreadError(osErrorResource); 00896 return NULL; 00897 } 00898 00899 if (pt->state != osTimerInvalid){ 00900 sysThreadError(osErrorResource); 00901 return NULL; 00902 } 00903 00904 pt->state = osTimerStopped; 00905 pt->type = (uint8_t)type; 00906 pt->arg = argument; 00907 pt->timer = timer_def; 00908 00909 return (osTimerId)pt; 00910 } 00911 00912 /// Start or restart timer 00913 osStatus svcTimerStart (osTimerId timer_id, uint32_t millisec) { 00914 os_timer_cb *pt; 00915 uint32_t tcnt; 00916 00917 pt = rt_id2obj(timer_id); 00918 if (pt == NULL) return osErrorParameter; 00919 00920 tcnt = rt_ms2tick(millisec); 00921 if (tcnt == 0) return osErrorValue; 00922 00923 switch (pt->state) { 00924 case osTimerRunning: 00925 if (rt_timer_remove(pt) != 0) { 00926 return osErrorResource; 00927 } 00928 break; 00929 case osTimerStopped: 00930 pt->state = osTimerRunning; 00931 pt->icnt = (uint16_t)tcnt; 00932 break; 00933 default: 00934 return osErrorResource; 00935 } 00936 00937 rt_timer_insert(pt, tcnt); 00938 00939 return osOK; 00940 } 00941 00942 /// Stop timer 00943 osStatus svcTimerStop (osTimerId timer_id) { 00944 os_timer_cb *pt; 00945 00946 pt = rt_id2obj(timer_id); 00947 if (pt == NULL) return osErrorParameter; 00948 00949 if (pt->state != osTimerRunning) return osErrorResource; 00950 00951 pt->state = osTimerStopped; 00952 00953 if (rt_timer_remove(pt) != 0) { 00954 return osErrorResource; 00955 } 00956 00957 return osOK; 00958 } 00959 00960 /// Delete timer 00961 osStatus svcTimerDelete (osTimerId timer_id) { 00962 os_timer_cb *pt; 00963 00964 pt = rt_id2obj(timer_id); 00965 if (pt == NULL) return osErrorParameter; 00966 00967 switch (pt->state) { 00968 case osTimerRunning: 00969 rt_timer_remove(pt); 00970 break; 00971 case osTimerStopped: 00972 break; 00973 default: 00974 return osErrorResource; 00975 } 00976 00977 pt->state = osTimerInvalid; 00978 00979 return osOK; 00980 } 00981 00982 /// Get timer callback parameters 00983 os_InRegs osCallback_type svcTimerCall (osTimerId timer_id) { 00984 os_timer_cb *pt; 00985 osCallback ret; 00986 00987 pt = rt_id2obj(timer_id); 00988 if (pt == NULL) { 00989 ret.fp = NULL; 00990 ret.arg = NULL; 00991 return osCallback_ret; 00992 } 00993 00994 ret.fp = (void *)pt->timer->ptimer; 00995 ret.arg = pt->arg; 00996 00997 return osCallback_ret; 00998 } 00999 01000 static __INLINE osStatus isrMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec); 01001 01002 /// Timer Tick (called each SysTick) 01003 void sysTimerTick (void) { 01004 os_timer_cb *pt, *p; 01005 01006 p = os_timer_head; 01007 if (p == NULL) return; 01008 01009 p->tcnt--; 01010 while ((p != NULL) && (p->tcnt == 0)) { 01011 pt = p; 01012 p = p->next; 01013 os_timer_head = p; 01014 isrMessagePut(osMessageQId_osTimerMessageQ, (uint32_t)pt, 0); 01015 if (pt->type == osTimerPeriodic) { 01016 rt_timer_insert(pt, pt->icnt); 01017 } else { 01018 pt->state = osTimerStopped; 01019 } 01020 } 01021 } 01022 01023 01024 // Timer Management Public API 01025 01026 /// Create timer 01027 osTimerId osTimerCreate (osTimerDef_t *timer_def, os_timer_type type, void *argument) { 01028 if (__get_IPSR() != 0) return NULL; // Not allowed in ISR 01029 if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { 01030 // Privileged and not running 01031 return svcTimerCreate(timer_def, type, argument); 01032 } else { 01033 return __svcTimerCreate(timer_def, type, argument); 01034 } 01035 } 01036 01037 /// Start or restart timer 01038 osStatus osTimerStart (osTimerId timer_id, uint32_t millisec) { 01039 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 01040 return __svcTimerStart(timer_id, millisec); 01041 } 01042 01043 /// Stop timer 01044 osStatus osTimerStop (osTimerId timer_id) { 01045 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 01046 return __svcTimerStop(timer_id); 01047 } 01048 01049 /// Delete timer 01050 osStatus osTimerDelete (osTimerId timer_id) { 01051 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 01052 return __svcTimerDelete(timer_id); 01053 } 01054 01055 /// INTERNAL - Not Public 01056 /// Get timer callback parameters (used by OS Timer Thread) 01057 os_InRegs osCallback osTimerCall (osTimerId timer_id) { 01058 return __svcTimerCall(timer_id); 01059 } 01060 01061 01062 // Timer Thread 01063 __NO_RETURN void osTimerThread (void const *argument) { 01064 osCallback cb; 01065 osEvent evt; 01066 01067 for (;;) { 01068 evt = osMessageGet(osMessageQId_osTimerMessageQ, osWaitForever); 01069 if (evt.status == osEventMessage) { 01070 cb = osTimerCall(evt.value.p); 01071 if (cb.fp != NULL) { 01072 (*(os_ptimer)cb.fp)(cb.arg); 01073 } 01074 } 01075 } 01076 } 01077 01078 01079 // ==== Signal Management ==== 01080 01081 // Signal Service Calls declarations 01082 SVC_2_1(svcSignalSet, int32_t, osThreadId, int32_t, RET_int32_t) 01083 SVC_2_1(svcSignalClear, int32_t, osThreadId, int32_t, RET_int32_t) 01084 SVC_1_1(svcSignalGet, int32_t, osThreadId, RET_int32_t) 01085 SVC_2_3(svcSignalWait, os_InRegs osEvent, int32_t, uint32_t, RET_osEvent) 01086 01087 // Signal Service Calls 01088 01089 /// Set the specified Signal Flags of an active thread 01090 int32_t svcSignalSet (osThreadId thread_id, int32_t signals) { 01091 P_TCB ptcb; 01092 int32_t sig; 01093 01094 ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer 01095 if (ptcb == NULL) return 0x80000000; 01096 01097 if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000; 01098 01099 sig = ptcb->events; // Previous signal flags 01100 01101 rt_evt_set(signals, ptcb->task_id); // Set event flags 01102 01103 return sig; 01104 } 01105 01106 /// Clear the specified Signal Flags of an active thread 01107 int32_t svcSignalClear (osThreadId thread_id, int32_t signals) { 01108 P_TCB ptcb; 01109 int32_t sig; 01110 01111 ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer 01112 if (ptcb == NULL) return 0x80000000; 01113 01114 if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000; 01115 01116 sig = ptcb->events; // Previous signal flags 01117 01118 rt_evt_clr(signals, ptcb->task_id); // Clear event flags 01119 01120 return sig; 01121 } 01122 01123 /// Get Signal Flags status of an active thread 01124 int32_t svcSignalGet (osThreadId thread_id) { 01125 P_TCB ptcb; 01126 01127 ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer 01128 if (ptcb == NULL) return 0x80000000; 01129 01130 return ptcb->events; // Return event flags 01131 } 01132 01133 /// Wait for one or more Signal Flags to become signaled for the current RUNNING thread 01134 os_InRegs osEvent_type svcSignalWait (int32_t signals, uint32_t millisec) { 01135 OS_RESULT res; 01136 osEvent ret; 01137 01138 if (signals & (0xFFFFFFFF << osFeature_Signals)) { 01139 ret.status = osErrorValue; 01140 return osEvent_ret_status; 01141 } 01142 01143 if (signals != 0) { // Wait for all specified signals 01144 res = rt_evt_wait(signals, rt_ms2tick(millisec), __TRUE); 01145 } else { // Wait for any signal 01146 res = rt_evt_wait(0xFFFF, rt_ms2tick(millisec), __FALSE); 01147 } 01148 01149 if (res == OS_R_EVT) { 01150 ret.status = osEventSignal; 01151 ret.value.signals = signals ? signals : os_tsk.run->waits; 01152 } else { 01153 ret.status = millisec ? osEventTimeout : osOK; 01154 ret.value.signals = 0; 01155 } 01156 01157 return osEvent_ret_value; 01158 } 01159 01160 01161 // Signal ISR Calls 01162 01163 /// Set the specified Signal Flags of an active thread 01164 static __INLINE int32_t isrSignalSet (osThreadId thread_id, int32_t signals) { 01165 P_TCB ptcb; 01166 int32_t sig; 01167 01168 ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer 01169 if (ptcb == NULL) return 0x80000000; 01170 01171 if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000; 01172 01173 sig = ptcb->events; // Previous signal flags 01174 01175 isr_evt_set(signals, ptcb->task_id); // Set event flags 01176 01177 return sig; 01178 } 01179 01180 01181 // Signal Public API 01182 01183 /// Set the specified Signal Flags of an active thread 01184 int32_t osSignalSet (osThreadId thread_id, int32_t signals) { 01185 if (__get_IPSR() != 0) { // in ISR 01186 return isrSignalSet(thread_id, signals); 01187 } else { // in Thread 01188 return __svcSignalSet(thread_id, signals); 01189 } 01190 } 01191 01192 /// Clear the specified Signal Flags of an active thread 01193 int32_t osSignalClear (osThreadId thread_id, int32_t signals) { 01194 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 01195 return __svcSignalClear(thread_id, signals); 01196 } 01197 01198 /// Get Signal Flags status of an active thread 01199 int32_t osSignalGet (osThreadId thread_id) { 01200 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 01201 return __svcSignalGet(thread_id); 01202 } 01203 01204 /// Wait for one or more Signal Flags to become signaled for the current RUNNING thread 01205 os_InRegs osEvent osSignalWait (int32_t signals, uint32_t millisec) { 01206 osEvent ret; 01207 01208 if (__get_IPSR() != 0) { // Not allowed in ISR 01209 ret.status = osErrorISR; 01210 return ret; 01211 } 01212 return __svcSignalWait(signals, millisec); 01213 } 01214 01215 01216 // ==== Mutex Management ==== 01217 01218 // Mutex Service Calls declarations 01219 SVC_1_1(svcMutexCreate, osMutexId, osMutexDef_t *, RET_pointer) 01220 SVC_2_1(svcMutexWait, osStatus, osMutexId, uint32_t, RET_osStatus) 01221 SVC_1_1(svcMutexRelease, osStatus, osMutexId, RET_osStatus) 01222 SVC_1_1(svcMutexDelete, osStatus, osMutexId, RET_osStatus) 01223 01224 // Mutex Service Calls 01225 01226 /// Create and Initialize a Mutex object 01227 osMutexId svcMutexCreate (osMutexDef_t *mutex_def) { 01228 OS_ID mut; 01229 01230 if (mutex_def == NULL) { 01231 sysThreadError(osErrorParameter); 01232 return NULL; 01233 } 01234 01235 mut = mutex_def->mutex; 01236 if (mut == NULL) { 01237 sysThreadError(osErrorParameter); 01238 return NULL; 01239 } 01240 01241 if (((P_MUCB)mut)->cb_type != 0) { 01242 sysThreadError(osErrorParameter); 01243 return NULL; 01244 } 01245 01246 rt_mut_init(mut); // Initialize Mutex 01247 01248 return mut; 01249 } 01250 01251 /// Wait until a Mutex becomes available 01252 osStatus svcMutexWait (osMutexId mutex_id, uint32_t millisec) { 01253 OS_ID mut; 01254 OS_RESULT res; 01255 01256 mut = rt_id2obj(mutex_id); 01257 if (mut == NULL) return osErrorParameter; 01258 01259 if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter; 01260 01261 res = rt_mut_wait(mut, rt_ms2tick(millisec)); // Wait for Mutex 01262 01263 if (res == OS_R_TMO) { 01264 return (millisec ? osErrorTimeoutResource : osErrorResource); 01265 } 01266 01267 return osOK; 01268 } 01269 01270 /// Release a Mutex that was obtained with osMutexWait 01271 osStatus svcMutexRelease (osMutexId mutex_id) { 01272 OS_ID mut; 01273 OS_RESULT res; 01274 01275 mut = rt_id2obj(mutex_id); 01276 if (mut == NULL) return osErrorParameter; 01277 01278 if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter; 01279 01280 res = rt_mut_release(mut); // Release Mutex 01281 01282 if (res == OS_R_NOK) return osErrorResource; // Thread not owner or Zero Counter 01283 01284 return osOK; 01285 } 01286 01287 /// Delete a Mutex that was created by osMutexCreate 01288 osStatus svcMutexDelete (osMutexId mutex_id) { 01289 OS_ID mut; 01290 01291 mut = rt_id2obj(mutex_id); 01292 if (mut == NULL) return osErrorParameter; 01293 01294 if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter; 01295 01296 rt_mut_delete(mut); // Release Mutex 01297 01298 return osOK; 01299 } 01300 01301 01302 // Mutex Public API 01303 01304 /// Create and Initialize a Mutex object 01305 osMutexId osMutexCreate (osMutexDef_t *mutex_def) { 01306 if (__get_IPSR() != 0) return NULL; // Not allowed in ISR 01307 if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { 01308 // Privileged and not running 01309 return svcMutexCreate(mutex_def); 01310 } else { 01311 return __svcMutexCreate(mutex_def); 01312 } 01313 } 01314 01315 /// Wait until a Mutex becomes available 01316 osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec) { 01317 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 01318 return __svcMutexWait(mutex_id, millisec); 01319 } 01320 01321 /// Release a Mutex that was obtained with osMutexWait 01322 osStatus osMutexRelease (osMutexId mutex_id) { 01323 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 01324 return __svcMutexRelease(mutex_id); 01325 } 01326 01327 /// Delete a Mutex that was created by osMutexCreate 01328 osStatus osMutexDelete (osMutexId mutex_id) { 01329 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 01330 return __svcMutexDelete(mutex_id); 01331 } 01332 01333 01334 // ==== Semaphore Management ==== 01335 01336 // Semaphore Service Calls declarations 01337 SVC_2_1(svcSemaphoreCreate, osSemaphoreId, const osSemaphoreDef_t *, int32_t, RET_pointer) 01338 SVC_2_1(svcSemaphoreWait, int32_t, osSemaphoreId, uint32_t, RET_int32_t) 01339 SVC_1_1(svcSemaphoreRelease, osStatus, osSemaphoreId, RET_osStatus) 01340 SVC_1_1(svcSemaphoreDelete, osStatus, osSemaphoreId, RET_osStatus) 01341 01342 // Semaphore Service Calls 01343 01344 /// Create and Initialize a Semaphore object 01345 osSemaphoreId svcSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count) { 01346 OS_ID sem; 01347 01348 if (semaphore_def == NULL) { 01349 sysThreadError(osErrorParameter); 01350 return NULL; 01351 } 01352 01353 sem = semaphore_def->semaphore; 01354 if (sem == NULL) { 01355 sysThreadError(osErrorParameter); 01356 return NULL; 01357 } 01358 01359 if (((P_SCB)sem)->cb_type != 0) { 01360 sysThreadError(osErrorParameter); 01361 return NULL; 01362 } 01363 01364 if (count > osFeature_Semaphore) { 01365 sysThreadError(osErrorValue); 01366 return NULL; 01367 } 01368 01369 rt_sem_init(sem, count); // Initialize Semaphore 01370 01371 return sem; 01372 } 01373 01374 /// Wait until a Semaphore becomes available 01375 int32_t svcSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec) { 01376 OS_ID sem; 01377 OS_RESULT res; 01378 01379 sem = rt_id2obj(semaphore_id); 01380 if (sem == NULL) return -1; 01381 01382 if (((P_SCB)sem)->cb_type != SCB) return -1; 01383 01384 res = rt_sem_wait(sem, rt_ms2tick(millisec)); // Wait for Semaphore 01385 01386 if (res == OS_R_TMO) return 0; // Timeout 01387 01388 return (((P_SCB)sem)->tokens + 1); 01389 } 01390 01391 /// Release a Semaphore 01392 osStatus svcSemaphoreRelease (osSemaphoreId semaphore_id) { 01393 OS_ID sem; 01394 01395 sem = rt_id2obj(semaphore_id); 01396 if (sem == NULL) return osErrorParameter; 01397 01398 if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter; 01399 01400 if (((P_SCB)sem)->tokens == osFeature_Semaphore) return osErrorResource; 01401 01402 rt_sem_send(sem); // Release Semaphore 01403 01404 return osOK; 01405 } 01406 01407 /// Delete a Semaphore that was created by osSemaphoreCreate 01408 osStatus svcSemaphoreDelete (osSemaphoreId semaphore_id) { 01409 OS_ID sem; 01410 01411 sem = rt_id2obj(semaphore_id); 01412 if (sem == NULL) return osErrorParameter; 01413 01414 if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter; 01415 01416 rt_sem_delete(sem); // Delete Semaphore 01417 01418 return osOK; 01419 } 01420 01421 01422 // Semaphore ISR Calls 01423 01424 /// Release a Semaphore 01425 static __INLINE osStatus isrSemaphoreRelease (osSemaphoreId semaphore_id) { 01426 OS_ID sem; 01427 01428 sem = rt_id2obj(semaphore_id); 01429 if (sem == NULL) return osErrorParameter; 01430 01431 if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter; 01432 01433 if (((P_SCB)sem)->tokens == osFeature_Semaphore) return osErrorResource; 01434 01435 isr_sem_send(sem); // Release Semaphore 01436 01437 return osOK; 01438 } 01439 01440 01441 // Semaphore Public API 01442 01443 /// Create and Initialize a Semaphore object 01444 osSemaphoreId osSemaphoreCreate (osSemaphoreDef_t *semaphore_def, int32_t count) { 01445 if (__get_IPSR() != 0) return NULL; // Not allowed in ISR 01446 if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { 01447 // Privileged and not running 01448 return svcSemaphoreCreate(semaphore_def, count); 01449 } else { 01450 return __svcSemaphoreCreate(semaphore_def, count); 01451 } 01452 } 01453 01454 /// Wait until a Semaphore becomes available 01455 int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec) { 01456 if (__get_IPSR() != 0) return -1; // Not allowed in ISR 01457 return __svcSemaphoreWait(semaphore_id, millisec); 01458 } 01459 01460 /// Release a Semaphore 01461 osStatus osSemaphoreRelease (osSemaphoreId semaphore_id) { 01462 if (__get_IPSR() != 0) { // in ISR 01463 return isrSemaphoreRelease(semaphore_id); 01464 } else { // in Thread 01465 return __svcSemaphoreRelease(semaphore_id); 01466 } 01467 } 01468 01469 /// Delete a Semaphore that was created by osSemaphoreCreate 01470 osStatus osSemaphoreDelete (osSemaphoreId semaphore_id) { 01471 if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR 01472 return __svcSemaphoreDelete(semaphore_id); 01473 } 01474 01475 01476 // ==== Memory Management Functions ==== 01477 01478 // Memory Management Helper Functions 01479 01480 // Clear Memory Box (Zero init) 01481 static void rt_clr_box (void *box_mem, void *box) { 01482 uint32_t *p, n; 01483 01484 if (box) { 01485 p = box; 01486 for (n = ((P_BM)box_mem)->blk_size; n; n -= 4) { 01487 *p++ = 0; 01488 } 01489 } 01490 } 01491 01492 // Memory Management Service Calls declarations 01493 SVC_1_1(svcPoolCreate, osPoolId, const osPoolDef_t *, RET_pointer) 01494 SVC_2_1(sysPoolAlloc, void *, osPoolId, uint32_t, RET_pointer) 01495 SVC_2_1(sysPoolFree, osStatus, osPoolId, void *, RET_osStatus) 01496 01497 // Memory Management Service & ISR Calls 01498 01499 /// Create and Initialize memory pool 01500 osPoolId svcPoolCreate (const osPoolDef_t *pool_def) { 01501 uint32_t blk_sz; 01502 01503 if ((pool_def == NULL) || 01504 (pool_def->pool_sz == 0) || 01505 (pool_def->item_sz == 0) || 01506 (pool_def->pool == NULL)) { 01507 sysThreadError(osErrorParameter); 01508 return NULL; 01509 } 01510 01511 blk_sz = (pool_def->item_sz + 3) & ~3; 01512 01513 _init_box(pool_def->pool, sizeof(struct OS_BM) + pool_def->pool_sz * blk_sz, blk_sz); 01514 01515 return pool_def->pool; 01516 } 01517 01518 /// Allocate a memory block from a memory pool 01519 void *sysPoolAlloc (osPoolId pool_id, uint32_t clr) { 01520 void *ptr; 01521 01522 if (pool_id == NULL) return NULL; 01523 01524 ptr = rt_alloc_box(pool_id); 01525 if (clr) { 01526 rt_clr_box(pool_id, ptr); 01527 } 01528 01529 return ptr; 01530 } 01531 01532 /// Return an allocated memory block back to a specific memory pool 01533 osStatus sysPoolFree (osPoolId pool_id, void *block) { 01534 int32_t res; 01535 01536 if (pool_id == NULL) return osErrorParameter; 01537 01538 res = rt_free_box(pool_id, block); 01539 if (res != 0) return osErrorValue; 01540 01541 return osOK; 01542 } 01543 01544 01545 // Memory Management Public API 01546 01547 /// Create and Initialize memory pool 01548 osPoolId osPoolCreate (osPoolDef_t *pool_def) { 01549 if (__get_IPSR() != 0) return NULL; // Not allowed in ISR 01550 if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { 01551 // Privileged and not running 01552 return svcPoolCreate(pool_def); 01553 } else { 01554 return __svcPoolCreate(pool_def); 01555 } 01556 } 01557 01558 /// Allocate a memory block from a memory pool 01559 void *osPoolAlloc (osPoolId pool_id) { 01560 if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { // in ISR or Privileged 01561 return sysPoolAlloc(pool_id, 0); 01562 } else { // in Thread 01563 return __sysPoolAlloc(pool_id, 0); 01564 } 01565 } 01566 01567 /// Allocate a memory block from a memory pool and set memory block to zero 01568 void *osPoolCAlloc (osPoolId pool_id) { 01569 if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { // in ISR or Privileged 01570 return sysPoolAlloc(pool_id, 1); 01571 } else { // in Thread 01572 return __sysPoolAlloc(pool_id, 1); 01573 } 01574 } 01575 01576 /// Return an allocated memory block back to a specific memory pool 01577 osStatus osPoolFree (osPoolId pool_id, void *block) { 01578 if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { // in ISR or Privileged 01579 return sysPoolFree(pool_id, block); 01580 } else { // in Thread 01581 return __sysPoolFree(pool_id, block); 01582 } 01583 } 01584 01585 01586 // ==== Message Queue Management Functions ==== 01587 01588 // Message Queue Management Service Calls declarations 01589 SVC_2_1(svcMessageCreate, osMessageQId, osMessageQDef_t *, osThreadId, RET_pointer) 01590 SVC_3_1(svcMessagePut, osStatus, osMessageQId, uint32_t, uint32_t, RET_osStatus) 01591 SVC_2_3(svcMessageGet, os_InRegs osEvent, osMessageQId, uint32_t, RET_osEvent) 01592 01593 // Message Queue Service Calls 01594 01595 /// Create and Initialize Message Queue 01596 osMessageQId svcMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id) { 01597 01598 if ((queue_def == NULL) || 01599 (queue_def->queue_sz == 0) || 01600 (queue_def->pool == NULL)) { 01601 sysThreadError(osErrorParameter); 01602 return NULL; 01603 } 01604 01605 if (((P_MCB)queue_def->pool)->cb_type != 0) { 01606 sysThreadError(osErrorParameter); 01607 return NULL; 01608 } 01609 01610 rt_mbx_init(queue_def->pool, 4*(queue_def->queue_sz + 4)); 01611 01612 return queue_def->pool; 01613 } 01614 01615 /// Put a Message to a Queue 01616 osStatus svcMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) { 01617 OS_RESULT res; 01618 01619 if (queue_id == NULL) return osErrorParameter; 01620 01621 if (((P_MCB)queue_id)->cb_type != MCB) return osErrorParameter; 01622 01623 res = rt_mbx_send(queue_id, (void *)info, rt_ms2tick(millisec)); 01624 01625 if (res == OS_R_TMO) { 01626 return (millisec ? osErrorTimeoutResource : osErrorResource); 01627 } 01628 01629 return osOK; 01630 } 01631 01632 /// Get a Message or Wait for a Message from a Queue 01633 os_InRegs osEvent_type svcMessageGet (osMessageQId queue_id, uint32_t millisec) { 01634 OS_RESULT res; 01635 osEvent ret; 01636 01637 if (queue_id == NULL) { 01638 ret.status = osErrorParameter; 01639 return osEvent_ret_status; 01640 } 01641 01642 if (((P_MCB)queue_id)->cb_type != MCB) { 01643 ret.status = osErrorParameter; 01644 return osEvent_ret_status; 01645 } 01646 01647 res = rt_mbx_wait(queue_id, &ret.value.p, rt_ms2tick(millisec)); 01648 01649 if (res == OS_R_TMO) { 01650 ret.status = millisec ? osEventTimeout : osOK; 01651 return osEvent_ret_value; 01652 } 01653 01654 ret.status = osEventMessage; 01655 01656 return osEvent_ret_value; 01657 } 01658 01659 01660 // Message Queue ISR Calls 01661 01662 /// Put a Message to a Queue 01663 static __INLINE osStatus isrMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) { 01664 01665 if ((queue_id == NULL) || (millisec != 0)) { 01666 return osErrorParameter; 01667 } 01668 01669 if (((P_MCB)queue_id)->cb_type != MCB) return osErrorParameter; 01670 01671 if (rt_mbx_check(queue_id) == 0) { // Check if Queue is full 01672 return osErrorResource; 01673 } 01674 01675 isr_mbx_send(queue_id, (void *)info); 01676 01677 return osOK; 01678 } 01679 01680 /// Get a Message or Wait for a Message from a Queue 01681 static __INLINE os_InRegs osEvent isrMessageGet (osMessageQId queue_id, uint32_t millisec) { 01682 OS_RESULT res; 01683 osEvent ret; 01684 01685 if ((queue_id == NULL) || (millisec != 0)) { 01686 ret.status = osErrorParameter; 01687 return ret; 01688 } 01689 01690 if (((P_MCB)queue_id)->cb_type != MCB) { 01691 ret.status = osErrorParameter; 01692 return ret; 01693 } 01694 01695 res = isr_mbx_receive(queue_id, &ret.value.p); 01696 01697 if (res != OS_R_MBX) { 01698 ret.status = osOK; 01699 return ret; 01700 } 01701 01702 ret.status = osEventMessage; 01703 01704 return ret; 01705 } 01706 01707 01708 // Message Queue Management Public API 01709 01710 /// Create and Initialize Message Queue 01711 osMessageQId osMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id) { 01712 if (__get_IPSR() != 0) return NULL; // Not allowed in ISR 01713 if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { 01714 // Privileged and not running 01715 return svcMessageCreate(queue_def, thread_id); 01716 } else { 01717 return __svcMessageCreate(queue_def, thread_id); 01718 } 01719 } 01720 01721 /// Put a Message to a Queue 01722 osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) { 01723 if (__get_IPSR() != 0) { // in ISR 01724 return isrMessagePut(queue_id, info, millisec); 01725 } else { // in Thread 01726 return __svcMessagePut(queue_id, info, millisec); 01727 } 01728 } 01729 01730 /// Get a Message or Wait for a Message from a Queue 01731 os_InRegs osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec) { 01732 if (__get_IPSR() != 0) { // in ISR 01733 return isrMessageGet(queue_id, millisec); 01734 } else { // in Thread 01735 return __svcMessageGet(queue_id, millisec); 01736 } 01737 } 01738 01739 01740 // ==== Mail Queue Management Functions ==== 01741 01742 // Mail Queue Management Service Calls declarations 01743 SVC_2_1(svcMailCreate, osMailQId, osMailQDef_t *, osThreadId, RET_pointer) 01744 SVC_4_1(sysMailAlloc, void *, osMailQId, uint32_t, uint32_t, uint32_t, RET_pointer) 01745 SVC_3_1(sysMailFree, osStatus, osMailQId, void *, uint32_t, RET_osStatus) 01746 01747 // Mail Queue Management Service & ISR Calls 01748 01749 /// Create and Initialize mail queue 01750 osMailQId svcMailCreate (osMailQDef_t *queue_def, osThreadId thread_id) { 01751 uint32_t blk_sz; 01752 P_MCB pmcb; 01753 void *pool; 01754 01755 if ((queue_def == NULL) || 01756 (queue_def->queue_sz == 0) || 01757 (queue_def->item_sz == 0) || 01758 (queue_def->pool == NULL)) { 01759 sysThreadError(osErrorParameter); 01760 return NULL; 01761 } 01762 01763 pmcb = *(((void **)queue_def->pool) + 0); 01764 pool = *(((void **)queue_def->pool) + 1); 01765 01766 if ((pool == NULL) || (pmcb == NULL) || (pmcb->cb_type != 0)) { 01767 sysThreadError(osErrorParameter); 01768 return NULL; 01769 } 01770 01771 blk_sz = (queue_def->item_sz + 3) & ~3; 01772 01773 _init_box(pool, sizeof(struct OS_BM) + queue_def->queue_sz * blk_sz, blk_sz); 01774 01775 rt_mbx_init(pmcb, 4*(queue_def->queue_sz + 4)); 01776 01777 01778 return queue_def->pool; 01779 } 01780 01781 /// Allocate a memory block from a mail 01782 void *sysMailAlloc (osMailQId queue_id, uint32_t millisec, uint32_t isr, uint32_t clr) { 01783 P_MCB pmcb; 01784 void *pool; 01785 void *mem; 01786 01787 if (queue_id == NULL) return NULL; 01788 01789 pmcb = *(((void **)queue_id) + 0); 01790 pool = *(((void **)queue_id) + 1); 01791 01792 if ((pool == NULL) || (pmcb == NULL)) return NULL; 01793 01794 if (isr && (millisec != 0)) return NULL; 01795 01796 mem = rt_alloc_box(pool); 01797 if (clr) { 01798 rt_clr_box(pool, mem); 01799 } 01800 01801 if ((mem == NULL) && (millisec != 0)) { 01802 // Put Task to sleep when Memory not available 01803 if (pmcb->p_lnk != NULL) { 01804 rt_put_prio((P_XCB)pmcb, os_tsk.run); 01805 } else { 01806 pmcb->p_lnk = os_tsk.run; 01807 os_tsk.run->p_lnk = NULL; 01808 os_tsk.run->p_rlnk = (P_TCB)pmcb; 01809 // Task is waiting to allocate a message 01810 pmcb->state = 3; 01811 } 01812 rt_block(rt_ms2tick(millisec), WAIT_MBX); 01813 } 01814 01815 return mem; 01816 } 01817 01818 /// Free a memory block from a mail 01819 osStatus sysMailFree (osMailQId queue_id, void *mail, uint32_t isr) { 01820 P_MCB pmcb; 01821 P_TCB ptcb; 01822 void *pool; 01823 void *mem; 01824 int32_t res; 01825 01826 if (queue_id == NULL) return osErrorParameter; 01827 01828 pmcb = *(((void **)queue_id) + 0); 01829 pool = *(((void **)queue_id) + 1); 01830 01831 if ((pmcb == NULL) || (pool == NULL)) return osErrorParameter; 01832 01833 res = rt_free_box(pool, mail); 01834 01835 if (res != 0) return osErrorValue; 01836 01837 if (pmcb->state == 3) { 01838 // Task is waiting to allocate a message 01839 if (isr) { 01840 rt_psq_enq (pmcb, (U32)pool); 01841 rt_psh_req (); 01842 } else { 01843 mem = rt_alloc_box(pool); 01844 if (mem != NULL) { 01845 ptcb = rt_get_first((P_XCB)pmcb); 01846 if (pmcb->p_lnk == NULL) { 01847 pmcb->state = 0; 01848 } 01849 rt_ret_val(ptcb, (U32)mem); 01850 rt_rmv_dly(ptcb); 01851 rt_dispatch(ptcb); 01852 } 01853 } 01854 } 01855 01856 return osOK; 01857 } 01858 01859 01860 // Mail Queue Management Public API 01861 01862 /// Create and Initialize mail queue 01863 osMailQId osMailCreate (osMailQDef_t *queue_def, osThreadId thread_id) { 01864 if (__get_IPSR() != 0) return NULL; // Not allowed in ISR 01865 if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { 01866 // Privileged and not running 01867 return svcMailCreate(queue_def, thread_id); 01868 } else { 01869 return __svcMailCreate(queue_def, thread_id); 01870 } 01871 } 01872 01873 /// Allocate a memory block from a mail 01874 void *osMailAlloc (osMailQId queue_id, uint32_t millisec) { 01875 if (__get_IPSR() != 0) { // in ISR 01876 return sysMailAlloc(queue_id, millisec, 1, 0); 01877 } else { // in Thread 01878 return __sysMailAlloc(queue_id, millisec, 0, 0); 01879 } 01880 } 01881 01882 /// Allocate a memory block from a mail and set memory block to zero 01883 void *osMailCAlloc (osMailQId queue_id, uint32_t millisec) { 01884 if (__get_IPSR() != 0) { // in ISR 01885 return sysMailAlloc(queue_id, millisec, 1, 1); 01886 } else { // in Thread 01887 return __sysMailAlloc(queue_id, millisec, 0, 1); 01888 } 01889 } 01890 01891 /// Free a memory block from a mail 01892 osStatus osMailFree (osMailQId queue_id, void *mail) { 01893 if (__get_IPSR() != 0) { // in ISR 01894 return sysMailFree(queue_id, mail, 1); 01895 } else { // in Thread 01896 return __sysMailFree(queue_id, mail, 0); 01897 } 01898 } 01899 01900 /// Put a mail to a queue 01901 osStatus osMailPut (osMailQId queue_id, void *mail) { 01902 if (queue_id == NULL) return osErrorParameter; 01903 if (mail == NULL) return osErrorValue; 01904 return osMessagePut(*((void **)queue_id), (uint32_t)mail, 0); 01905 } 01906 01907 /// Get a mail from a queue 01908 os_InRegs osEvent osMailGet (osMailQId queue_id, uint32_t millisec) { 01909 osEvent ret; 01910 01911 if (queue_id == NULL) { 01912 ret.status = osErrorParameter; 01913 return ret; 01914 } 01915 01916 ret = osMessageGet(*((void **)queue_id), millisec); 01917 if (ret.status == osEventMessage) ret.status = osEventMail; 01918 01919 return ret; 01920 }
Generated on Wed Jul 13 2022 18:32:39 by
