Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pal_plat_rtos.c Source File

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