I messed up the merge, so pushing it over to another repo so I don't lose it. Will tidy up and remove later
Dependencies: BufferedSerial FatFileSystemCpp mbed
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 Thu Dec 15 2022 06:07:05 by 1.7.2