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