Simulated product dispenser
Fork of mbed-cloud-workshop-connect-HTS221 by
pal_plat_rtos.c
00001 /******************************************************************************* 00002 * Copyright 2016, 2017 ARM Ltd. 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 *******************************************************************************/ 00016 #define _GNU_SOURCE // This is for ppoll found in poll.h 00017 #include <stdlib.h> 00018 #include <stdio.h> 00019 #include <time.h> 00020 #include <pthread.h> 00021 #include <semaphore.h> 00022 #include <signal.h> 00023 #include <mqueue.h> 00024 #include <errno.h> 00025 #include <string.h> 00026 #include <unistd.h> 00027 #include <fcntl.h> 00028 #include <sys/reboot.h> 00029 #include <sys/types.h> 00030 #include <sys/wait.h> 00031 #include <sys/utsname.h> 00032 00033 #include "pal.h" 00034 #include "pal_plat_rtos.h" 00035 00036 /* 00037 * The realtime clock is in nano seconds resolution. This is too much for us, so we use "longer" ticks. 00038 * Below are relevant defines. 00039 * make sure they all coherent. Can use one at the other, but will add some unneeded calculations. 00040 */ 00041 #define NANOS_PER_TICK 100 00042 #define TICKS_PER_MICRO 10L 00043 #define TICKS_PER_MILLI TICKS_PER_MICRO * 1000 00044 #define TICKS_PER_SECOND TICKS_PER_MILLI * 1000 00045 00046 // priorities must be positive, so shift all by this margin. we might want to do smarter convert. 00047 #define LINUX_THREAD_PRIORITY_BASE 10 00048 00049 // message Queues names related staff: 00050 #define MQ_FILENAME_LEN 10 00051 00052 #ifndef CLOCK_MONOTONIC_RAW //a workaround for the operWRT port that missing this include 00053 #define CLOCK_MONOTONIC_RAW 4 //http://elixir.free-electrons.com/linux/latest/source/include/uapi/linux/time.h 00054 #endif 00055 00056 #define PAL_THREAD_PRIORITY_TRANSLATE(x) ((int16_t)(x + 7)) 00057 00058 typedef struct palThreadData 00059 { 00060 palThreadFuncPtr userFunction; 00061 void* userFunctionArgument; 00062 } palThreadData_t; 00063 00064 /* 00065 * Internal struct to handle timers. 00066 */ 00067 struct palTimerInfo 00068 { 00069 struct palTimerInfo *next; 00070 timer_t handle; 00071 palTimerFuncPtr function; 00072 void *funcArgs; 00073 palTimerType_t timerType; 00074 }; 00075 00076 00077 PAL_PRIVATE char g_mqName[MQ_FILENAME_LEN]; 00078 PAL_PRIVATE int g_mqNextNameNum = 0; 00079 00080 // Mutex to prevent simultaneus modification of the linked list of the timers in g_timerList. 00081 PAL_PRIVATE palMutexID_t g_timerListMutex = 0; 00082 00083 // A singly linked list of the timers, access may be done only if holding the g_timerListMutex. 00084 // The list is needed as the timers use async signals and when the signal is finally delivered, the 00085 // palTimerInfo timer struct may be already deleted. The signals themselves carry pointer to timer, 00086 // so whenever a signal is received, the thread will look if the palTimerInfo is still on the list, 00087 // and if it is, uses the struct to find the callback pointer and arguments. 00088 PAL_PRIVATE volatile struct palTimerInfo *g_timerList = NULL; 00089 00090 extern palStatus_t pal_plat_getRandomBufferFromHW(uint8_t *randomBuf, size_t bufSizeBytes, size_t* actualRandomSizeBytes); 00091 00092 PAL_PRIVATE palStatus_t startTimerThread(); 00093 PAL_PRIVATE palStatus_t stopTimerThread(); 00094 PAL_PRIVATE void palTimerThread(void const *args); 00095 00096 inline PAL_PRIVATE void nextMessageQName() 00097 { 00098 g_mqNextNameNum++; 00099 for (int j = 4, divider = 10000; j < 9; j++, divider /= 10) 00100 { 00101 g_mqName[j] = '0' + (g_mqNextNameNum / divider) %10 ; //just to make sure we don't write more then 1 digit. 00102 } 00103 g_mqName[9] = '\0'; 00104 } 00105 00106 00107 /*! Initiate a system reboot. 00108 */ 00109 void pal_plat_osReboot (void) 00110 { 00111 // Syncronize cached files to persistant storage. 00112 sync(); 00113 // Reboot the device 00114 reboot(RB_AUTOBOOT); 00115 } 00116 00117 /*! Initialize all data structures (semaphores, mutexs, memory pools, message queues) at system initialization. 00118 * In case of a failure in any of the initializations, the function returns with an error and stops the rest of the initializations. 00119 * @param[in] opaqueContext The context passed to the initialization (not required for generic CMSIS, pass NULL in this case). 00120 * \return PAL_SUCCESS(0) in case of success, PAL_ERR_CREATION_FAILED in case of failure. 00121 */ 00122 palStatus_t pal_plat_RTOSInitialize (void* opaqueContext) 00123 { 00124 palStatus_t status = PAL_SUCCESS; 00125 (void)opaqueContext; 00126 strncpy(g_mqName, "/pal00001", MQ_FILENAME_LEN); 00127 g_mqNextNameNum = 1; // used for the next name 00128 #if (PAL_USE_HW_RTC) 00129 status = pal_plat_rtcInit(); 00130 #endif 00131 00132 // Setup the signal handler thread which will be shared with all the timers 00133 00134 status = pal_osMutexCreate(&g_timerListMutex); 00135 00136 if (status == PAL_SUCCESS) { 00137 00138 sigset_t blocked; 00139 00140 sigemptyset(&blocked); 00141 sigaddset(&blocked, PAL_TIMER_SIGNAL); 00142 00143 // Make PAL_TIMER_SIGNAL blocked from this thread and the others 00144 // created onwards. Note: there is no handler for that on purpose, as 00145 // the signal is handled by the timer thread itself by sigwaitinfo(). 00146 int err = pthread_sigmask(SIG_BLOCK, &blocked, NULL); 00147 00148 if (err != 0) { 00149 00150 status = PAL_ERR_SYSCALL_FAILED ; 00151 } 00152 } 00153 00154 if (status == PAL_SUCCESS) { 00155 00156 status = startTimerThread(); 00157 } 00158 00159 return status; 00160 } 00161 00162 /*! De-Initialize thread objects. 00163 */ 00164 palStatus_t pal_plat_RTOSDestroy (void) 00165 { 00166 palStatus_t ret = PAL_SUCCESS; 00167 00168 #if PAL_USE_HW_RTC 00169 ret = pal_plat_rtcDeInit(); 00170 #endif 00171 00172 // Is there really a point to check these, as if the shutdown fails, what can we do? 00173 // Nobody is going to call the shutdown again. 00174 if (ret == PAL_SUCCESS) { 00175 ret = stopTimerThread(); 00176 } 00177 00178 if (ret == PAL_SUCCESS) { 00179 ret = pal_osMutexDelete(&g_timerListMutex); 00180 } 00181 00182 return ret; 00183 } 00184 00185 /*return The RTOS kernel system timer counter, in microseconds 00186 */ 00187 00188 uint64_t pal_plat_osKernelSysTick (void) // optional API - not part of original CMSIS API. 00189 { 00190 /*Using clock_gettime is more accurate, but then we have to convert it to ticks. we are using a tick every 100 nanoseconds*/ 00191 struct timespec ts; 00192 uint64_t ticks; 00193 //TODO: error handling 00194 clock_gettime(CLOCK_MONOTONIC_RAW, &ts); 00195 00196 ticks = (uint64_t) (ts.tv_sec * (uint64_t)TICKS_PER_SECOND 00197 + (ts.tv_nsec / NANOS_PER_TICK)); 00198 return ticks; 00199 } 00200 00201 /* Convert the value from microseconds to kernel sys ticks. 00202 * This is the same as CMSIS macro osKernelSysTickMicroSec. 00203 * since we return microsecods as ticks, just return the value 00204 */ 00205 uint64_t pal_plat_osKernelSysTickMicroSec (uint64_t microseconds) 00206 { 00207 00208 //convert to nanoseconds 00209 return microseconds * TICKS_PER_MICRO; 00210 } 00211 00212 /*! Get the system tick frequency. 00213 * \return The system tick frequency. 00214 */ 00215 inline uint64_t pal_plat_osKernelSysTickFrequency (void) 00216 { 00217 /* since we use clock_gettime, with resolution of 100 nanosecond per tick*/ 00218 return TICKS_PER_SECOND; 00219 } 00220 00221 PAL_PRIVATE void threadCleanupHandler(void* arg) 00222 { 00223 free(arg); 00224 } 00225 00226 PAL_PRIVATE void* threadFunction(void* arg) 00227 { 00228 /* 00229 * note: even if a thread is only scheduled but has not started running, it will be cancelled only once it starts running and once it reaches a cancellation point, 00230 * hence the clean up handler will always be executed thus avoiding a memory leak. 00231 * see section 2.9.5 @ http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html 00232 */ 00233 pthread_cleanup_push(threadCleanupHandler, arg); // register a cleanup handler to be executed once the thread is finished/terminated (threads can terminate only when reaching a cancellation point) 00234 palThreadData_t* threadData = (palThreadData_t*)arg; 00235 threadData->userFunction(threadData->userFunctionArgument); 00236 pthread_cleanup_pop(1); // in case the thread has not terminated execute the cleanup handler (passing a non zero value to pthread_cleanup_pop) 00237 return NULL; 00238 } 00239 00240 palStatus_t pal_plat_osThreadCreate (palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, palThreadID_t* threadID) 00241 { 00242 palStatus_t status = PAL_ERR_GENERIC_FAILURE; 00243 pthread_t sysThreadID = (pthread_t)NULL; 00244 struct sched_param schedParam; 00245 pthread_attr_t attr; 00246 pthread_attr_t* ptrAttr = NULL; 00247 palThreadData_t* threadData; 00248 int err = pthread_attr_init(&attr); 00249 if (0 != err) 00250 { 00251 goto finish; 00252 } 00253 ptrAttr = &attr; 00254 00255 err = pthread_attr_setstacksize(ptrAttr, stackSize); 00256 if (0 != err) 00257 { 00258 goto finish; 00259 } 00260 00261 err = pthread_attr_setschedpolicy(ptrAttr, SCHED_RR); 00262 if (0 != err) 00263 { 00264 goto finish; 00265 } 00266 00267 #if (PAL_SIMULATOR_TEST_ENABLE == 0) // disable ONLY for Linux PC simulator 00268 err = pthread_attr_setinheritsched(ptrAttr, PTHREAD_EXPLICIT_SCHED); 00269 if (0 != err) 00270 { 00271 goto finish; 00272 } 00273 #endif 00274 00275 err = pthread_attr_setdetachstate(ptrAttr, PTHREAD_CREATE_DETACHED); 00276 if (0 != err) 00277 { 00278 goto finish; 00279 } 00280 00281 schedParam.sched_priority = PAL_THREAD_PRIORITY_TRANSLATE(priority); 00282 err = pthread_attr_setschedparam(ptrAttr, &schedParam); 00283 if (0 != err) 00284 { 00285 goto finish; 00286 } 00287 00288 threadData = (palThreadData_t*)malloc(sizeof(palThreadData_t)); 00289 if (NULL == threadData) 00290 { 00291 status = PAL_ERR_RTOS_RESOURCE ; 00292 goto finish; 00293 } 00294 threadData->userFunction = function; 00295 threadData->userFunctionArgument = funcArgument; 00296 00297 err = pthread_create(&sysThreadID, ptrAttr, threadFunction, (void*)threadData); 00298 if (0 != err) 00299 { 00300 free(threadData); 00301 status = (EPERM == err) ? PAL_ERR_RTOS_PRIORITY : PAL_ERR_RTOS_RESOURCE ; 00302 goto finish; 00303 } 00304 00305 *threadID = (palThreadID_t)sysThreadID; 00306 status = PAL_SUCCESS; 00307 00308 finish: 00309 if (NULL != ptrAttr) 00310 { 00311 err = pthread_attr_destroy(ptrAttr); 00312 if (0 != err) 00313 { 00314 PAL_LOG(ERR, "pal_plat_osThreadCreate failed to destroy pthread_attr_t\n"); 00315 } 00316 } 00317 return status; 00318 } 00319 00320 palThreadID_t pal_plat_osThreadGetId (void) 00321 { 00322 palThreadID_t threadID = (palThreadID_t)pthread_self(); 00323 return threadID; 00324 } 00325 00326 palStatus_t pal_plat_osThreadTerminate (palThreadID_t* threadID) 00327 { 00328 palStatus_t status = PAL_ERR_RTOS_TASK ; 00329 int err; 00330 pthread_t sysThreadID = (pthread_t)*threadID; 00331 if (!pthread_equal(pthread_self(), sysThreadID)) // self termination not allowed 00332 { 00333 err = pthread_cancel(sysThreadID); 00334 if ((0 == err) || (ESRCH == err)) 00335 { 00336 status = PAL_SUCCESS; 00337 } 00338 else 00339 { 00340 status = PAL_ERR_RTOS_RESOURCE ; 00341 } 00342 } 00343 return status; 00344 } 00345 00346 /*! Wait for a specified period of time in milliseconds. 00347 * 00348 * @param[in] milliseconds The number of milliseconds to wait before proceeding. 00349 * 00350 * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. 00351 */ 00352 palStatus_t pal_plat_osDelay (uint32_t milliseconds) 00353 { 00354 struct timespec sTime; 00355 struct timespec rTime; // this will return how much sleep time still left in case of interrupted sleep 00356 int stat; 00357 //init rTime, as we will copy it over to stime inside the do-while loop. 00358 rTime.tv_sec = milliseconds / 1000; 00359 rTime.tv_nsec = PAL_MILLI_TO_NANO(milliseconds); 00360 00361 do 00362 { 00363 sTime.tv_sec = rTime.tv_sec; 00364 sTime.tv_nsec = rTime.tv_nsec; 00365 stat = nanosleep(&sTime, &rTime); 00366 } while ((-1 == stat) && (EINTR ==errno)) ; 00367 return (stat == 0) ? PAL_SUCCESS : PAL_ERR_GENERIC_FAILURE; 00368 } 00369 00370 00371 /* 00372 * Internal struct to handle timers. 00373 */ 00374 00375 typedef struct palTimerThreadContext 00376 { 00377 // semaphore used for signaling both the thread startup and thread closure 00378 palSemaphoreID_t startStopSemaphore; 00379 00380 // If set, the timer thread will stop its loop, signal the startStopSemaphore 00381 // and run out of thread function. This is set and accessed while holding the 00382 // g_timerListMutex. 00383 volatile bool threadStopRequested; 00384 00385 } palTimerThreadContext_t; 00386 00387 00388 static palThreadID_t s_palHighResTimerThreadID = NULLPTR; 00389 static palTimerThreadContext_t s_palTimerThreadContext = {0}; 00390 00391 /* 00392 * Thread for handling the signals from all timers by calling the attached callback 00393 */ 00394 00395 PAL_PRIVATE void palTimerThread(void const *args) 00396 { 00397 palTimerThreadContext_t* context = (palTimerThreadContext_t*)args; 00398 00399 int err = 0; 00400 00401 sigset_t signal_set_to_wait; 00402 00403 sigemptyset(&signal_set_to_wait); 00404 sigaddset(&signal_set_to_wait, PAL_TIMER_SIGNAL); 00405 00406 // signal the caller that thread has started 00407 pal_osSemaphoreRelease(context->startStopSemaphore); 00408 00409 // loop until signaled with threadStopRequested 00410 while (1) { 00411 00412 siginfo_t info; 00413 00414 // wait for signal from a timer 00415 err = sigwaitinfo(&signal_set_to_wait, &info); 00416 00417 // A positive return value is the signal number, negative value is a sign of some 00418 // signal handler interrupting the OS call and errno should be then EINTR. 00419 // The other two documented errors, EAGAIN or EINVAL should not happen as we're 00420 // not using the timeout, but have them logged just in case. 00421 if (err <= 0) { 00422 if (errno != EINTR) { 00423 PAL_LOG(ERR, "palTimerThread: sigwaitinfo failed with %d\n", errno); 00424 } 00425 } else { 00426 00427 // before using the timer list or threadStopRequested flag, we need to claim the mutex 00428 pal_osMutexWait(g_timerListMutex, PAL_RTOS_WAIT_FOREVER); 00429 00430 if (context->threadStopRequested) { 00431 00432 // release mutex and bail out 00433 pal_osMutexRelease(g_timerListMutex); 00434 break; 00435 00436 } else { 00437 00438 // the sival_ptr contains the pointer of timer which caused it 00439 struct palTimerInfo* signal_timer = (struct palTimerInfo*)info.si_value.sival_ptr; 00440 00441 struct palTimerInfo *temp_timer = (struct palTimerInfo*)g_timerList; 00442 00443 palTimerFuncPtr found_function = NULL; 00444 void *found_funcArgs; 00445 00446 // Check, if the timer still is on the list. It may have been deleted, if the 00447 // signal delivery / client callback has taken some time. 00448 while (temp_timer != NULL) { 00449 00450 if (temp_timer == signal_timer) { 00451 00452 // Ok, found the timer from list, backup the parameters as we release 00453 // the mutex after this loop, before calling the callback and the 00454 // temp_timer may very well get deleted just after the mutex is released. 00455 00456 found_function = temp_timer->function; 00457 found_funcArgs = temp_timer->funcArgs; 00458 00459 break; 00460 } else { 00461 temp_timer = temp_timer->next; 00462 } 00463 } 00464 00465 // Release the list mutex before callback to avoid callback deadlocking other threads 00466 // if they try to create a timer. 00467 pal_osMutexRelease(g_timerListMutex); 00468 00469 // the function may be NULL here if the timer was already freed 00470 if (found_function) { 00471 // finally call the callback function 00472 found_function(found_funcArgs); 00473 } 00474 } 00475 } 00476 } 00477 00478 // signal the caller that thread is now stopping and it can continue the pal_destroy() 00479 pal_osSemaphoreRelease(context->startStopSemaphore); 00480 } 00481 00482 PAL_PRIVATE palStatus_t startTimerThread() 00483 { 00484 palStatus_t status; 00485 00486 status = pal_osSemaphoreCreate(0, &s_palTimerThreadContext.startStopSemaphore); 00487 00488 if (status == PAL_SUCCESS) { 00489 00490 s_palTimerThreadContext.threadStopRequested = false; 00491 00492 status = pal_osThreadCreateWithAlloc(palTimerThread, &s_palTimerThreadContext, PAL_osPriorityReservedHighResTimer, 00493 PAL_RTOS_HIGH_RES_TIMER_THREAD_STACK_SIZE, NULL, &s_palHighResTimerThreadID); 00494 00495 if (status == PAL_SUCCESS) { 00496 00497 // the timer thread will signal on semaphore when it has started 00498 pal_osSemaphoreWait(s_palTimerThreadContext.startStopSemaphore, PAL_RTOS_WAIT_FOREVER, NULL); 00499 00500 } else { 00501 // cleanup the semaphore 00502 pal_osSemaphoreDelete(&s_palTimerThreadContext.startStopSemaphore); 00503 } 00504 } 00505 00506 return status; 00507 } 00508 00509 PAL_PRIVATE palStatus_t stopTimerThread() 00510 { 00511 palStatus_t status; 00512 00513 union sigval value; 00514 value.sival_ptr = NULL; 00515 00516 status = pal_osMutexWait(g_timerListMutex, PAL_RTOS_WAIT_FOREVER); 00517 00518 if (status == PAL_SUCCESS) { 00519 00520 // set the flag to end the thread 00521 s_palTimerThreadContext.threadStopRequested = true; 00522 00523 // ping the timer thread that it should start shutdown 00524 pthread_t sysThreadID = (pthread_t)s_palHighResTimerThreadID; 00525 int err; 00526 00527 do { 00528 00529 err = pthread_sigqueue(sysThreadID, PAL_TIMER_SIGNAL, value); 00530 00531 } while (err == EAGAIN); // retry (spin, yuck!) if the signal queue is full 00532 00533 pal_osMutexRelease(g_timerListMutex); 00534 00535 // pthread_sigqueue() failed, which is a sign of thread being dead, so a wait 00536 // on semaphore would cause a deadlock. 00537 if (err == 0) { 00538 00539 // wait for for acknowledgement that timer thread is going down 00540 pal_osSemaphoreWait(s_palTimerThreadContext.startStopSemaphore, PAL_RTOS_WAIT_FOREVER, NULL); 00541 } 00542 00543 pal_osSemaphoreDelete(&s_palTimerThreadContext.startStopSemaphore); 00544 00545 // and clean up the thread 00546 status = pal_osThreadTerminate(&s_palHighResTimerThreadID); 00547 } 00548 return status; 00549 } 00550 00551 00552 /*! Create a timer. 00553 * 00554 * @param[in] function A function pointer to the timer callback function. 00555 * @param[in] funcArgument An argument for the timer callback function. 00556 * @param[in] timerType The timer type to be created, periodic or oneShot. 00557 * @param[out] timerID The ID of the created timer, zero value indicates an error. 00558 * 00559 * \return PAL_SUCCESS when the timer was created successfully. A specific error in case of failure. 00560 */ 00561 palStatus_t pal_plat_osTimerCreate (palTimerFuncPtr function, void* funcArgument, 00562 palTimerType_t timerType, palTimerID_t* timerID) 00563 { 00564 00565 palStatus_t status = PAL_SUCCESS; 00566 struct palTimerInfo* timerInfo = NULL; 00567 { 00568 struct sigevent sig; 00569 timer_t localTimer; 00570 00571 if ((NULL == timerID) || (NULL == (void*) function)) 00572 { 00573 return PAL_ERR_INVALID_ARGUMENT ; 00574 } 00575 00576 timerInfo = (struct palTimerInfo*) malloc(sizeof(struct palTimerInfo)); 00577 if (NULL == timerInfo) 00578 { 00579 status = PAL_ERR_NO_MEMORY ; 00580 goto finish; 00581 } 00582 00583 timerInfo->function = function; 00584 timerInfo->funcArgs = funcArgument; 00585 timerInfo->timerType = timerType; 00586 00587 memset(&sig, 0, sizeof(sig)); 00588 00589 sig.sigev_notify = SIGEV_SIGNAL; 00590 sig.sigev_signo = PAL_TIMER_SIGNAL; 00591 00592 // the signal handler uses this to find the correct timer context 00593 sig.sigev_value.sival_ptr = timerInfo; 00594 00595 int ret = timer_create(CLOCK_MONOTONIC, &sig, &localTimer); 00596 if (-1 == ret) 00597 { 00598 if (EINVAL == errno) 00599 { 00600 status = PAL_ERR_INVALID_ARGUMENT ; 00601 goto finish; 00602 } 00603 if (ENOMEM == errno) 00604 { 00605 status = PAL_ERR_NO_MEMORY ; 00606 goto finish; 00607 } 00608 PAL_LOG(ERR, "Rtos timer create error %d", ret); 00609 status = PAL_ERR_GENERIC_FAILURE; 00610 goto finish; 00611 } 00612 00613 // managed to create the timer - finish up 00614 timerInfo->handle = localTimer; 00615 *timerID = (palTimerID_t) timerInfo; 00616 00617 pal_osMutexWait(g_timerListMutex, PAL_RTOS_WAIT_FOREVER); 00618 00619 // add the new timer to head of the singly linked list 00620 timerInfo->next = (struct palTimerInfo *)g_timerList; 00621 00622 g_timerList = timerInfo; 00623 00624 pal_osMutexRelease(g_timerListMutex); 00625 } 00626 finish: if (PAL_SUCCESS != status) 00627 { 00628 if (NULL != timerInfo) 00629 { 00630 free(timerInfo); 00631 *timerID = (palTimerID_t) NULL; 00632 } 00633 } 00634 return status; 00635 } 00636 00637 /* Convert milliseconds into seconds and nanoseconds inside a timespec struct 00638 */ 00639 PAL_PRIVATE void convertMilli2Timespec(uint32_t millisec, struct timespec* ts) 00640 { 00641 ts->tv_sec = millisec / 1000; 00642 ts->tv_nsec = PAL_MILLI_TO_NANO(millisec); 00643 } 00644 00645 /*! Start or restart a timer. 00646 * 00647 * @param[in] timerID The handle for the timer to start. 00648 * @param[in] millisec The time in milliseconds to set the timer to. 00649 * 00650 * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. 00651 */ 00652 palStatus_t pal_plat_osTimerStart (palTimerID_t timerID, uint32_t millisec) 00653 { 00654 palStatus_t status = PAL_SUCCESS; 00655 if (NULL == (struct palTimerInfo *) timerID) 00656 { 00657 return PAL_ERR_INVALID_ARGUMENT ; 00658 } 00659 00660 struct palTimerInfo* timerInfo = (struct palTimerInfo *) timerID; 00661 struct itimerspec its; 00662 00663 convertMilli2Timespec(millisec, &(its.it_value)); 00664 00665 if (palOsTimerPeriodic == timerInfo->timerType) 00666 { 00667 convertMilli2Timespec(millisec, &(its.it_interval)); 00668 } 00669 else 00670 { // one time timer 00671 convertMilli2Timespec(0, &(its.it_interval)); 00672 } 00673 00674 if (-1 == timer_settime(timerInfo->handle, 0, &its, NULL)) 00675 { 00676 status = PAL_ERR_INVALID_ARGUMENT ; 00677 } 00678 00679 return status; 00680 } 00681 00682 /*! Stop a timer. 00683 * 00684 * @param[in] timerID The handle for the timer to stop. 00685 * 00686 * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. 00687 */ 00688 palStatus_t pal_plat_osTimerStop (palTimerID_t timerID) 00689 { 00690 palStatus_t status = PAL_SUCCESS; 00691 if (NULL == (struct palTimerInfo *) timerID) 00692 { 00693 return PAL_ERR_INVALID_ARGUMENT ; 00694 } 00695 00696 struct palTimerInfo* timerInfo = (struct palTimerInfo *) timerID; 00697 struct itimerspec its; 00698 00699 // set timer to 0 to disarm it. 00700 convertMilli2Timespec(0, &(its.it_value)); 00701 00702 convertMilli2Timespec(0, &(its.it_interval)); 00703 00704 if (-1 == timer_settime(timerInfo->handle, 0, &its, NULL)) 00705 { 00706 status = PAL_ERR_INVALID_ARGUMENT ; 00707 } 00708 00709 return status; 00710 } 00711 00712 /*! Delete the timer object 00713 * 00714 * @param[inout] timerID The handle for the timer to delete. In success, *timerID = NULL. 00715 * 00716 * \return PAL_SUCCESS when the timer was deleted successfully, PAL_ERR_RTOS_PARAMETER when the timerID is incorrect. 00717 */ 00718 palStatus_t pal_plat_osTimerDelete (palTimerID_t* timerID) 00719 { 00720 palStatus_t status = PAL_SUCCESS; 00721 if (NULL == timerID) 00722 { 00723 return PAL_ERR_INVALID_ARGUMENT ; 00724 } 00725 struct palTimerInfo* timerInfo = (struct palTimerInfo *) *timerID; 00726 00727 if (NULL == timerInfo) 00728 { 00729 status = PAL_ERR_RTOS_PARAMETER ; 00730 } 00731 00732 // the list of timers is protected by a mutex to avoid concurrency issues 00733 pal_osMutexWait(g_timerListMutex, PAL_RTOS_WAIT_FOREVER); 00734 00735 // remove the timer from the list before freeing it 00736 struct palTimerInfo *prev_timer = NULL; 00737 struct palTimerInfo *temp_timer = (struct palTimerInfo *)g_timerList; 00738 00739 while (temp_timer) { 00740 00741 if (temp_timer == timerInfo) { 00742 // found the timer from list, now it needs to be removed from there 00743 00744 if (prev_timer) { 00745 // there was a previous item, so update its next to this objects next 00746 prev_timer->next = temp_timer->next; 00747 } else { 00748 // the item was the first/only one, so update the list head instead 00749 g_timerList = temp_timer->next; 00750 } 00751 // all done now 00752 break; 00753 00754 } else { 00755 prev_timer = temp_timer; 00756 temp_timer = temp_timer->next; 00757 } 00758 } 00759 00760 timer_t lt = timerInfo->handle; 00761 if (-1 == timer_delete(lt)) 00762 { 00763 status = PAL_ERR_RTOS_RESOURCE ; 00764 } 00765 00766 pal_osMutexRelease(g_timerListMutex); 00767 00768 free(timerInfo); 00769 *timerID = (palTimerID_t) NULL; 00770 00771 return status; 00772 } 00773 00774 /*! Create and initialize a mutex object. 00775 * 00776 * @param[out] mutexID The created mutex ID handle, zero value indicates an error. 00777 * 00778 * \return PAL_SUCCESS when the mutex was created successfully, a specific error in case of failure. 00779 */ 00780 palStatus_t pal_plat_osMutexCreate (palMutexID_t* mutexID) 00781 { 00782 palStatus_t status = PAL_SUCCESS; 00783 pthread_mutex_t* mutex = NULL; 00784 { 00785 int ret; 00786 if (NULL == mutexID) 00787 { 00788 return PAL_ERR_INVALID_ARGUMENT ; 00789 } 00790 00791 mutex = malloc(sizeof(pthread_mutex_t)); 00792 if (NULL == mutex) 00793 { 00794 status = PAL_ERR_NO_MEMORY ; 00795 goto finish; 00796 } 00797 00798 pthread_mutexattr_t mutexAttr; 00799 pthread_mutexattr_init(&mutexAttr); 00800 pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE); 00801 ret = pthread_mutex_init(mutex, &mutexAttr); 00802 00803 if (0 != ret) 00804 { 00805 if (ENOMEM == ret) 00806 { 00807 status = PAL_ERR_NO_MEMORY ; 00808 } 00809 else 00810 { 00811 PAL_LOG(ERR, "Rtos mutex create status %d", ret); 00812 status = PAL_ERR_GENERIC_FAILURE; 00813 } 00814 goto finish; 00815 } 00816 *mutexID = (palMutexID_t) mutex; 00817 } 00818 finish: if (PAL_SUCCESS != status) 00819 { 00820 if (NULL != mutex) 00821 { 00822 free(mutex); 00823 } 00824 } 00825 return status; 00826 } 00827 00828 /* Wait until a mutex becomes available. 00829 * 00830 * @param[in] mutexID The handle for the mutex. 00831 * @param[in] millisec The timeout for the waiting operation if the timeout expires before the semaphore is released and an error is returned from the function. 00832 * 00833 * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, one of the following error codes in case of failure: 00834 * PAL_ERR_RTOS_RESOURCE - Mutex not available but no timeout set. 00835 * PAL_ERR_RTOS_TIMEOUT - Mutex was not available until timeout expired. 00836 * PAL_ERR_RTOS_PARAMETER - Mutex ID is invalid. 00837 * PAL_ERR_RTOS_ISR - Cannot be called from interrupt service routines. 00838 */ 00839 palStatus_t pal_plat_osMutexWait (palMutexID_t mutexID, uint32_t millisec) 00840 { 00841 palStatus_t status = PAL_SUCCESS; 00842 int err; 00843 if (NULL == ((pthread_mutex_t*) mutexID)) 00844 { 00845 return PAL_ERR_INVALID_ARGUMENT ; 00846 } 00847 pthread_mutex_t* mutex = (pthread_mutex_t*) mutexID; 00848 00849 if (PAL_RTOS_WAIT_FOREVER != millisec) 00850 { 00851 /* calculate the wait absolute time */ 00852 struct timespec ts; 00853 clock_gettime(CLOCK_REALTIME, &ts); 00854 00855 ts.tv_sec += (millisec / PAL_MILLI_PER_SECOND); 00856 ts.tv_nsec += PAL_MILLI_TO_NANO(millisec); 00857 ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND; // if there is some overflow in the addition of nanoseconds. 00858 ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND; 00859 00860 while ((err = pthread_mutex_timedlock(mutex, &ts)) != 0 && err == EINTR) 00861 { 00862 continue; /* Restart if interrupted by handler */ 00863 } 00864 } 00865 else 00866 { // wait for ever 00867 err = pthread_mutex_lock(mutex); 00868 } 00869 00870 if (0 != err) 00871 { 00872 if (err == ETIMEDOUT) 00873 { 00874 status = PAL_ERR_RTOS_TIMEOUT ; 00875 } 00876 else 00877 { 00878 PAL_LOG(ERR, "Rtos mutex wait status %d", err); 00879 status = PAL_ERR_GENERIC_FAILURE; 00880 } 00881 } 00882 00883 return status; 00884 } 00885 00886 /* Release a mutex that was obtained by osMutexWait. 00887 * 00888 * @param[in] mutexID The handle for the mutex. 00889 * 00890 * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. 00891 */ 00892 palStatus_t pal_plat_osMutexRelease (palMutexID_t mutexID) 00893 { 00894 palStatus_t status = PAL_SUCCESS; 00895 int result = 0; 00896 00897 pthread_mutex_t* mutex = (pthread_mutex_t*) mutexID; 00898 if (NULL == mutex) 00899 { 00900 return PAL_ERR_INVALID_ARGUMENT ; 00901 } 00902 00903 result = pthread_mutex_unlock(mutex); 00904 if (0 != result) 00905 { 00906 // only reason this might fail - process don't have permission for mutex. 00907 PAL_LOG(ERR, "Rtos mutex release failure - %d",result); 00908 status = PAL_ERR_GENERIC_FAILURE; 00909 } 00910 return status; 00911 } 00912 00913 /*Delete a mutex object. 00914 * 00915 * @param[inout] mutexID The ID of the mutex to delete. In success, *mutexID = NULL. 00916 * 00917 * \return PAL_SUCCESS when the mutex was deleted successfully, one of the following error codes in case of failure: 00918 * PAL_ERR_RTOS_RESOURCE - Mutex already released. 00919 * PAL_ERR_RTOS_PARAMETER - Mutex ID is invalid. 00920 * PAL_ERR_RTOS_ISR - Cannot be called from interrupt service routines. 00921 * \note After this call, mutex_id is no longer valid and cannot be used. 00922 */ 00923 palStatus_t pal_plat_osMutexDelete (palMutexID_t* mutexID) 00924 { 00925 palStatus_t status = PAL_SUCCESS; 00926 uint32_t ret; 00927 if (NULL == mutexID) 00928 { 00929 return PAL_ERR_INVALID_ARGUMENT ; 00930 } 00931 pthread_mutex_t* mutex = (pthread_mutex_t*) *mutexID; 00932 00933 if (NULL == mutex) 00934 { 00935 status = PAL_ERR_RTOS_RESOURCE ; 00936 } 00937 ret = pthread_mutex_destroy(mutex); 00938 if ((PAL_SUCCESS == status) && (0 != ret)) 00939 { 00940 PAL_LOG(ERR,"pal_plat_osMutexDelete 0x%x",ret); 00941 status = PAL_ERR_RTOS_RESOURCE ; 00942 } 00943 if (NULL != mutex) 00944 { 00945 free(mutex); 00946 } 00947 00948 *mutexID = (palMutexID_t) NULL; 00949 return status; 00950 } 00951 00952 /* Create and initialize a semaphore object. 00953 * 00954 * Semaphore is shared between threads, but not process. 00955 * 00956 * @param[in] count The number of available resources. 00957 * @param[out] semaphoreID The ID of the created semaphore, zero value indicates an error. 00958 * 00959 * \return PAL_SUCCESS when the semaphore was created successfully, a specific error in case of failure. 00960 */ 00961 palStatus_t pal_plat_osSemaphoreCreate (uint32_t count, 00962 palSemaphoreID_t* semaphoreID) 00963 { 00964 palStatus_t status = PAL_SUCCESS; 00965 sem_t* semaphore = NULL; 00966 00967 { 00968 if (NULL == semaphoreID) 00969 { 00970 return PAL_ERR_INVALID_ARGUMENT ; 00971 } 00972 semaphore = malloc(sizeof(sem_t)); 00973 if (NULL == semaphore) 00974 { 00975 status = PAL_ERR_NO_MEMORY ; 00976 goto finish; 00977 } 00978 /* create the semaphore as shared between threads */ 00979 int ret = sem_init(semaphore, 0, count); 00980 if (-1 == ret) 00981 { 00982 if (EINVAL == errno) 00983 { 00984 /* count is too big */ 00985 status = PAL_ERR_INVALID_ARGUMENT ; 00986 } 00987 else 00988 { 00989 PAL_LOG(ERR, "Rtos semaphore init error %d", ret); 00990 status = PAL_ERR_GENERIC_FAILURE; 00991 } 00992 goto finish; 00993 } 00994 00995 *semaphoreID = (palSemaphoreID_t) semaphore; 00996 } 00997 finish: if (PAL_SUCCESS != status) 00998 { 00999 if (NULL != semaphore) 01000 { 01001 free(semaphore); 01002 } 01003 *semaphoreID = (palSemaphoreID_t) NULL; 01004 } 01005 return status; 01006 } 01007 01008 /* Wait until a semaphore token becomes available. 01009 * 01010 * @param[in] semaphoreID The handle for the semaphore. 01011 * @param[in] millisec The timeout for the waiting operation if the timeout expires before the semaphore is released and an error is returned from the function. 01012 * @param[out] countersAvailable The number of semaphores available (before the wait), if semaphores are not available (timeout/error) zero is returned. 01013 * 01014 * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, one of the following error codes in case of failure: 01015 * PAL_ERR_RTOS_TIMEOUT - Semaphore was not available until timeout expired. 01016 * PAL_ERR_RTOS_PARAMETER - Semaphore ID is invalid. 01017 * PAL_ERR_INVALID_ARGUMENT - countersAvailable is NULL 01018 * 01019 * NOTES: 1. counterAvailable returns 0 in case there are no semaphores available or there are other threads waiting on it. 01020 * Value is not thread safe - it might be changed by the time it is read/returned. 01021 * 2. timed wait is using absolute time. 01022 */ 01023 palStatus_t pal_plat_osSemaphoreWait (palSemaphoreID_t semaphoreID, 01024 uint32_t millisec, int32_t* countersAvailable) 01025 { 01026 palStatus_t status = PAL_SUCCESS; 01027 int tmpCounters = 0; 01028 { 01029 int err; 01030 sem_t* sem = (sem_t*) semaphoreID; 01031 if ((NULL == sem)) 01032 { 01033 return PAL_ERR_INVALID_ARGUMENT ; 01034 } 01035 01036 if (PAL_RTOS_WAIT_FOREVER != millisec) 01037 { 01038 /* calculate the wait absolute time */ 01039 struct timespec ts; 01040 clock_gettime(CLOCK_REALTIME, &ts); 01041 ts.tv_sec += millisec / PAL_MILLI_PER_SECOND; 01042 ts.tv_nsec += PAL_MILLI_TO_NANO(millisec); 01043 ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND; // in case there is overflow in the nanoseconds. 01044 ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND; 01045 01046 while ((err = sem_timedwait(sem, &ts)) == -1 && errno == EINTR) 01047 continue; /* Restart if interrupted by handler */ 01048 } 01049 else 01050 { // wait for ever 01051 do 01052 { 01053 err = sem_wait(sem); 01054 01055 /* loop again if the wait was interrupted by a signal */ 01056 } while ((err == -1) && (errno == EINTR)); 01057 } 01058 01059 if (-1 == err) 01060 { 01061 tmpCounters = 0; 01062 if (errno == ETIMEDOUT) 01063 { 01064 status = PAL_ERR_RTOS_TIMEOUT ; 01065 } 01066 else 01067 { /* seems this is not a valid semaphore */ 01068 status = PAL_ERR_RTOS_PARAMETER ; 01069 } 01070 goto finish; 01071 } 01072 /* get the counter number, shouldn't fail, as we already know this is valid semaphore */ 01073 sem_getvalue(sem, &tmpCounters); 01074 } 01075 finish: 01076 if (NULL != countersAvailable) 01077 { 01078 *countersAvailable = tmpCounters; 01079 } 01080 return status; 01081 } 01082 01083 /*! Release a semaphore token. 01084 * 01085 * @param[in] semaphoreID The handle for the semaphore. 01086 * 01087 * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. 01088 */ 01089 palStatus_t pal_plat_osSemaphoreRelease (palSemaphoreID_t semaphoreID) 01090 { 01091 palStatus_t status = PAL_SUCCESS; 01092 sem_t* sem = (sem_t*) semaphoreID; 01093 01094 if (NULL == sem) 01095 { 01096 return PAL_ERR_INVALID_ARGUMENT ; 01097 } 01098 01099 if (-1 == sem_post(sem)) 01100 { 01101 if (EINVAL == errno) 01102 { 01103 status = PAL_ERR_RTOS_PARAMETER ; 01104 } 01105 else 01106 { /* max value of semaphore exeeded */ 01107 PAL_LOG(ERR, "Rtos semaphore release error %d", errno); 01108 status = PAL_ERR_GENERIC_FAILURE; 01109 } 01110 } 01111 01112 return status; 01113 } 01114 01115 /*! Delete a semaphore object. 01116 * 01117 * @param[inout] semaphoreID: The ID of the semaphore to delete. In success, *semaphoreID = NULL. 01118 * 01119 * \return PAL_SUCCESS when the semaphore was deleted successfully, one of the following error codes in case of failure: 01120 * PAL_ERR_RTOS_RESOURCE - Semaphore already released. 01121 * PAL_ERR_RTOS_PARAMETER - Semaphore ID is invalid. 01122 * \note After this call, the semaphore_id is no longer valid and cannot be used. 01123 */ 01124 palStatus_t pal_plat_osSemaphoreDelete (palSemaphoreID_t* semaphoreID) 01125 { 01126 palStatus_t status = PAL_SUCCESS; 01127 { 01128 if (NULL == semaphoreID) 01129 { 01130 return PAL_ERR_INVALID_ARGUMENT ; 01131 } 01132 01133 sem_t* sem = (sem_t*) (*semaphoreID); 01134 if (NULL == sem) 01135 { 01136 status = PAL_ERR_RTOS_RESOURCE ; 01137 goto finish; 01138 } 01139 if (-1 == sem_destroy(sem)) 01140 { 01141 status = PAL_ERR_RTOS_PARAMETER ; 01142 goto finish; 01143 } 01144 01145 if (NULL != sem) 01146 { 01147 free(sem); 01148 } 01149 *semaphoreID = (palSemaphoreID_t) NULL; 01150 } 01151 finish: return status; 01152 } 01153 01154 /*! Perform an atomic increment for a signed32 bit value. 01155 * 01156 * @param[in,out] valuePtr The address of the value to increment. 01157 * @param[in] increment The number by which to increment. 01158 * 01159 * \returns The value of the valuePtr after the increment operation. 01160 */ 01161 int32_t pal_plat_osAtomicIncrement (int32_t* valuePtr, int32_t increment) 01162 { 01163 int32_t res = __sync_add_and_fetch(valuePtr, increment); 01164 return res; 01165 } 01166 01167 01168 void *pal_plat_malloc (size_t len) 01169 { 01170 return malloc(len); 01171 } 01172 01173 01174 void pal_plat_free (void * buffer) 01175 { 01176 return free(buffer); 01177 } 01178 01179 palStatus_t pal_plat_osRandomBuffer (uint8_t *randomBuf, size_t bufSizeBytes, size_t* actualRandomSizeBytes) 01180 { 01181 palStatus_t status = PAL_SUCCESS; 01182 status = pal_plat_getRandomBufferFromHW(randomBuf, bufSizeBytes, actualRandomSizeBytes); 01183 return status; 01184 } 01185 01186 #if (PAL_USE_HW_RTC) 01187 #include <linux/rtc.h> 01188 #include <sys/ioctl.h> 01189 #include <time.h> 01190 palMutexID_t rtcMutex = NULLPTR; 01191 01192 #if RTC_PRIVILEGE 01193 static const char default_rtc[] = "/dev/rtc0"; 01194 01195 PAL_PRIVATE uint64_t pal_convertTimeStructToSeconds(const struct rtc_time *dateTime) 01196 { 01197 /* Number of days from begin of the non Leap-year*/ 01198 uint64_t monthDays[] = {0, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U}; 01199 uint64_t seconds, daysCount = 0; 01200 /* Compute number of days from 1970 till given year*/ 01201 daysCount = (dateTime->tm_year + 1900 - 1970) * PAL_DAYS_IN_A_YEAR; 01202 /* Add leap year days */ 01203 daysCount += (((dateTime->tm_year + 1900) / 4) - (1970U / 4)); 01204 /* Add number of days till given month*/ 01205 daysCount += monthDays[dateTime->tm_mon]; 01206 /* Add days in given month minus one */ 01207 daysCount += (dateTime->tm_mday - 1); 01208 if (!(((dateTime->tm_year + 1900) & 3U)) && (dateTime->tm_mon <= 2U)) 01209 { 01210 daysCount--; 01211 } 01212 01213 seconds = (daysCount * PAL_SECONDS_PER_DAY) + (dateTime->tm_hour * PAL_SECONDS_PER_HOUR) + 01214 (dateTime->tm_min * PAL_SECONDS_PER_MIN) + dateTime->tm_sec; 01215 01216 return seconds; 01217 } 01218 #endif 01219 01220 palStatus_t pal_plat_osGetRtcTime(uint64_t *rtcGetTime) 01221 { 01222 palStatus_t ret = PAL_SUCCESS; 01223 #if RTC_PRIVILEGE 01224 struct rtc_time GetTime ={0}; 01225 if(rtcGetTime != NULL) 01226 { 01227 int fd, retval = 0; 01228 fd = open(default_rtc, O_RDONLY); 01229 if (fd == -1) 01230 { 01231 ret = PAL_ERR_RTOS_RTC_OPEN_DEVICE_ERROR; 01232 } 01233 else 01234 { 01235 retval = ioctl(fd, RTC_RD_TIME , &GetTime); 01236 if (retval == -1) 01237 { 01238 ret = PAL_ERR_RTOS_RTC_OPEN_IOCTL_ERROR ; 01239 } 01240 else 01241 { 01242 *rtcGetTime = pal_convertTimeStructToSeconds(&GetTime); 01243 } 01244 close(fd); 01245 } 01246 } 01247 else 01248 { 01249 ret = PAL_ERR_NULL_POINTER ; 01250 } 01251 #else 01252 *rtcGetTime = time(NULL); 01253 #endif 01254 return ret; 01255 } 01256 01257 palStatus_t pal_plat_osSetRtcTime(uint64_t rtcSetTime) 01258 { 01259 palStatus_t ret = 0; 01260 int retval = 0; 01261 #if RTC_PRIVILEGE 01262 int fd = 0; 01263 int retval = 0; 01264 struct tm * convertedTime = gmtime((time_t*)&rtcSetTime); 01265 01266 fd = open (default_rtc, O_RDONLY); 01267 retval = ioctl(fd, RTC_SET_TIME, (struct rtc_time*)convertedTime); 01268 if (retval == -1) 01269 { 01270 ret = PAL_ERR_RTOS_RTC_OPEN_IOCTL_ERROR ; 01271 } 01272 close(fd); 01273 #else 01274 ret = pal_osMutexWait(rtcMutex, 5 * PAL_MILLI_PER_SECOND * PAL_ONE_SEC); 01275 if(ret == PAL_SUCCESS) 01276 { 01277 retval = stime((time_t*)&rtcSetTime); 01278 if (retval == -1) 01279 { 01280 ret = PAL_ERR_RTOS_NO_PRIVILEGED; //need to give privilege mode "sudo setcap -v cap_sys_time=+epi [filename]" 01281 } 01282 pal_osMutexRelease(rtcMutex); 01283 } 01284 #endif 01285 return ret; 01286 } 01287 01288 palStatus_t pal_plat_rtcInit(void) 01289 { 01290 palStatus_t ret = PAL_SUCCESS; 01291 if(NULLPTR == rtcMutex) 01292 { 01293 ret = pal_osMutexCreate(&rtcMutex); 01294 } 01295 return ret; 01296 } 01297 01298 palStatus_t pal_plat_rtcDeInit(void) 01299 { 01300 palStatus_t ret = PAL_SUCCESS; 01301 if(NULLPTR != rtcMutex) 01302 { 01303 ret = pal_osMutexDelete(&rtcMutex); 01304 rtcMutex = NULLPTR; 01305 } 01306 return ret; 01307 } 01308 01309 #endif //#if (PAL_USE_HW_RTC) 01310
Generated on Tue Jul 12 2022 19:12:14 by 1.7.2