leo hendrickson / Mbed OS example-Ethernet-mbed-Cloud-connect
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pal_plat_rtos.c Source File

pal_plat_rtos.c

00001 /*******************************************************************************
00002  * Copyright 2018 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 /* PAL-RTOS porting for SXOS SDK
00018 *  This is porting code for PAL RTOS APIS for
00019 *  SXOS SDK / RSX RTOS.
00020 */
00021 
00022 
00023 #include "pal.h"
00024 #include "pal_plat_rtos.h"
00025 
00026 #include <cos.h>
00027 #include <tm.h>
00028 #include <dm.h>
00029 
00030 #include <stdlib.h>
00031 #include <stdio.h> // snprintf
00032 
00033 #define TRACE_GROUP "PAL"
00034 
00035 extern palStatus_t pal_plat_getRandomBufferFromHW(uint8_t *randomBuf, size_t bufSizeBytes, size_t* actualRandomSizeBytes);
00036 
00037 PAL_PRIVATE void pal_plat_osTimerHelperThreadFunction(const void* param);
00038 
00039 //! Internal timer structure
00040 typedef struct palTimer {
00041     palTimerFuncPtr function;
00042     void*           functionArgs;
00043     palTimerType_t  timerType;
00044     uint32_t        periodMs;
00045 } palTimer_t;
00046 
00047 //! Internal mutex structure
00048 typedef struct palMutex {
00049     COS_MUTEX   osMutex;
00050 } palMutex_t;
00051 
00052 //! Internal semaphore structure
00053 typedef struct palSemaphore {
00054     COS_SEMA    osSemaphore;
00055 } palSemaphore_t;
00056 
00057 //! Internal semaphore structure
00058 typedef struct palThread
00059 {
00060     palThreadFuncPtr    userFunction;
00061     void*               userFunctionArgument;
00062     char*               name;
00063     HANDLE              osThread;
00064 } palThread_t;
00065 
00066 
00067 // XXX: this just has to have space for pal_0xffffffff\0
00068 #define PAL_THREAD_NAME_MAX_LEN 16 // max len for thread name which holds the pointer (as string) to dynamically allocated thread data
00069 
00070 // Max attempts to try setting RTC time
00071 #define PAL_MAX_RTC_SET_ATTEMPTS 5
00072 
00073 // This define controls if the timer uses the IRQ based timer or task one. In practice
00074 // this affects on the context where the timer callback is called on. Unless the ns-hal-pal and PAL
00075 // sides can implement a recursive critical section without mutexes, the code needs a thread
00076 // context. Note: the mutex code can not be called from IRQ.
00077 #ifndef PAL_SXOS_USE_TIMER_HELPER_THREAD
00078 #define PAL_SXOS_USE_TIMER_HELPER_THREAD 1
00079 #endif
00080 
00081 #if PAL_SXOS_USE_TIMER_HELPER_THREAD
00082 
00083 // The timer callback thread is having this much stack, which should be plenty as on other OS' even 1KB is
00084 // enough for the client code. But of course the OS itself affects also on the needed stack space
00085 #ifndef PAL_TIMER_THREAD_STACK_SIZE
00086 #define PAL_TIMER_THREAD_STACK_SIZE (4*1024)
00087 #endif
00088 
00089 PAL_PRIVATE palThreadID_t g_timer_helper_thread;
00090 #endif
00091 
00092 palStatus_t pal_plat_RTOSInitialize(void* opaqueContext)
00093 {
00094     palStatus_t status;
00095 
00096 #if PAL_SXOS_USE_TIMER_HELPER_THREAD
00097     status = pal_plat_osThreadCreate(pal_plat_osTimerHelperThreadFunction,
00098                                     NULL,
00099                                     PAL_osPriorityReservedHighResTimer ,
00100                                     PAL_TIMER_THREAD_STACK_SIZE,
00101                                     &g_timer_helper_thread);
00102 #else
00103     status = PAL_SUCCESS;
00104 #endif
00105 
00106 #if (PAL_USE_HW_RTC)
00107     if (status == PAL_SUCCESS)
00108     {
00109         status = pal_plat_rtcInit();
00110     }
00111 #endif
00112 
00113     return status;
00114 }
00115 
00116 palStatus_t pal_plat_RTOSDestroy(void)
00117 {
00118     palStatus_t status;
00119 
00120 #if PAL_SXOS_USE_TIMER_HELPER_THREAD
00121     status = pal_plat_osThreadTerminate(&g_timer_helper_thread);
00122 #else
00123     status = PAL_SUCCESS;
00124 #endif
00125 
00126 #if (PAL_USE_HW_RTC)
00127     if (status == PAL_SUCCESS)
00128     {
00129         status = pal_plat_rtcDeInit();
00130     }
00131 #endif
00132 
00133     return status;
00134 }
00135 
00136 palStatus_t pal_plat_osDelay(uint32_t milliseconds)
00137 {
00138     palStatus_t status = PAL_SUCCESS;
00139 
00140     if (COS_Sleep(milliseconds) == false) {
00141         // according to source, the COS_Sleep() returns unconditionally TRUE, but
00142         // let's be super cautious and pass the error to caller. OTOH, nobody checks
00143         // the return value anyway..
00144         status = PAL_ERR_RTOS_OS ;
00145     }
00146     return status;
00147 }
00148 
00149 
00150 uint64_t pal_plat_osKernelSysTick()
00151 {
00152 
00153     static uint32_t prevCountLo = 0;
00154     static uint64_t prevCount = 0;
00155 
00156     uint32_t osCount = (uint32_t)COS_GetTickCount();
00157 
00158     if (osCount < prevCountLo) {
00159         prevCount = (1LL << 32) + osCount;
00160     } else {
00161         prevCount = osCount;
00162     }
00163     prevCountLo = osCount;
00164 
00165     return prevCount;
00166 }
00167 
00168 uint64_t pal_plat_osKernelSysTickMicroSec(uint64_t microseconds)
00169 {
00170     uint64_t ticks = (uint64_t)COS_Msec2Tick(microseconds / 1000);
00171     return ticks;
00172 }
00173 
00174 uint64_t pal_plat_osKernelSysTickFrequency()
00175 {
00176     uint64_t ticksPerSecond = COS_Sec2Tick(1);
00177     return ticksPerSecond;
00178 }
00179 
00180 PAL_PRIVATE void pal_plat_osThreadWarpperFunction(void* param)
00181 {
00182     palThread_t* thread = param;
00183 
00184     thread->userFunction(thread->userFunctionArgument);
00185 
00186     // COS does not seem to support thread function to return (problems in deleting the thread).
00187     // Therefore if userFunction returns, we stay here waiting for task to be deleted.
00188     HANDLE task = COS_GetCurrentTaskHandle();
00189     COS_EVENT event;
00190     for (;;) {
00191         COS_WaitEvent(task, &event, COS_WAIT_FOREVER);
00192     }
00193 }
00194 
00195 
00196 palStatus_t pal_plat_osThreadCreate(palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, palThreadID_t* threadID)
00197 {
00198     palStatus_t status = PAL_SUCCESS;
00199 
00200     int bytesWritten;
00201     palThread_t* thread = malloc(sizeof(palThread_t));
00202     char* threadName = malloc((PAL_THREAD_NAME_MAX_LEN + 1)); // name will hold the address of the dynamically allocated palThread_t (as string)
00203     thread = malloc(sizeof(palThread_t));
00204     if ((NULL == thread) || (NULL == threadName))
00205     {
00206         status = PAL_ERR_RTOS_RESOURCE ;
00207         goto clean;
00208     }
00209 
00210     // XXX: the thread name really needs to come from the client side, as then we could use meaningful names
00211     bytesWritten = snprintf(threadName, (PAL_THREAD_NAME_MAX_LEN + 1), "pal_%p", thread);
00212     if ((bytesWritten <= 0) || ((PAL_THREAD_NAME_MAX_LEN + 1) <= bytesWritten))
00213     {
00214         status = PAL_ERR_RTOS_RESOURCE ;
00215         goto clean;
00216     }
00217 
00218     // Note: COS_CreateTask() has a pStackAddr -parameter but it actually does not use it and
00219     // it allocates the stack internally.
00220     thread->name = threadName;
00221     thread->userFunction = function;
00222     thread->userFunctionArgument = funcArgument;
00223 
00224     // XXX: the priorities need a mapping, so far just use a 0x80 (0 is highest, 0xff lowest priority)
00225 
00226     uint8_t taskPriority = 0x80;
00227 
00228     // Create and start a task. As the thread cleanup seems to require a COS_StopTask(),
00229     // we use a wrapper to call the user provided function and eventually do the cleanup.
00230     HANDLE threadOs = COS_CreateTask((PTASK_ENTRY)pal_plat_osThreadWarpperFunction,
00231                                     thread,
00232                                     NULL,
00233                                     stackSize,
00234                                     taskPriority,
00235                                     COS_CREATE_DEFAULT,
00236                                     0,
00237                                     threadName);
00238 
00239     if (threadOs == NULL)
00240     {
00241         status = PAL_ERR_NO_MEMORY ;
00242         goto clean;
00243     }
00244     else
00245     {
00246         thread->osThread = threadOs;
00247         *threadID = (palThreadID_t)thread;
00248     }
00249 
00250     return status;
00251 
00252 clean:
00253     free(thread);
00254     free(threadName);
00255 
00256     return status;
00257 }
00258 
00259 palThreadID_t pal_plat_osThreadGetId(void)
00260 {
00261     // XXX: the current thread ID is not really a useful value for anything but separating
00262     // threads in debug traces. The given value is NOT the same as returned by pal_osThreadCreate().
00263     HANDLE currTask = COS_GetCurrentTaskHandle();
00264 
00265     return (palThreadID_t)currTask;
00266 }
00267 
00268 palStatus_t pal_plat_osThreadTerminate(palThreadID_t* threadID)
00269 {
00270     palStatus_t status = PAL_SUCCESS;
00271 
00272     palThread_t* thread = (palThread_t*)*threadID;
00273 
00274     if (COS_GetCurrentTaskHandle() == thread->osThread) // self termination not allowed
00275     {
00276         status = PAL_ERR_RTOS_TASK ;
00277         goto end;
00278     }
00279 
00280     // deleting a running task is not supported by COS, so it needs to be stopped first.
00281     COS_StopTask((TASK_HANDLE *)thread->osThread);
00282 
00283     // this has a hardcoded "return FALSE", which may or may not be a bug, so pass the return check here
00284     COS_DeleteTask(thread->osThread);
00285 
00286     free(thread->name);
00287     free(thread);
00288 
00289 end:
00290 
00291     return status;
00292 }
00293 
00294 // This thread function will be used to serve the timer requests. It will not do
00295 // anything itself but call the COS_WaitEvent(), which internally will handle calling
00296 // the timer callbacks.
00297 PAL_PRIVATE void pal_plat_osTimerHelperThreadFunction(const void* param)
00298 {
00299     HANDLE current_task = COS_GetCurrentTaskHandle();
00300 
00301     while (true)
00302     {
00303         COS_EVENT event;
00304         COS_WaitEvent(current_task, &event, COS_WAIT_FOREVER);
00305     }
00306 }
00307 
00308 PAL_PRIVATE void pal_plat_osTimerWarpperFunction(void* param)
00309 {
00310     palTimer_t* timer = param;
00311 
00312     if (timer->timerType == palOsTimerPeriodic )
00313     {
00314         // XXX: by re-starting the periodic timer here we get relatively constant
00315         // interval. But of course this requires the callback to return before the
00316         // timeout or behavior gets bad. But this whole IRQ based timer code really
00317         // expects the timer callback to just behave.
00318         // Having the timer starting here is also convenient for the caller site also,
00319         // as it can stop the timer from callback and this wrapper will not overwrite
00320         // that will.
00321 #if PAL_SXOS_USE_TIMER_HELPER_THREAD
00322         const palThread_t* timer_thread = (palThread_t*)g_timer_helper_thread;
00323 
00324         HANDLE timer_thread_handle = timer_thread->osThread;
00325 
00326         COS_StartCallbackTimer(timer_thread_handle, timer->periodMs, pal_plat_osTimerWarpperFunction, param);
00327 #else
00328         COS_StartFunctionTimer(timer->periodMs, pal_plat_osTimerWarpperFunction, param);
00329 #endif
00330     }
00331 
00332     timer->function(timer->functionArgs);
00333 }
00334 
00335 palStatus_t pal_plat_osTimerCreate(palTimerFuncPtr function, void* funcArgument, palTimerType_t timerType, palTimerID_t* timerID)
00336 {
00337     palStatus_t status = PAL_SUCCESS;
00338 
00339     // the COS identifies the timer by callback+param tuple. As we pass the PAL timer callback
00340     // and its own timer struct as parameter to COS timer, the uniqueness is guaranteed and there is no
00341     // need to maintain a local timer ID scheme.
00342 
00343     palTimer_t* timer = malloc(sizeof(palTimer_t));
00344 
00345     if (NULL == timer)
00346     {
00347         status = PAL_ERR_NO_MEMORY ;
00348     }
00349 
00350     if (PAL_SUCCESS == status)
00351     {
00352         timer->function = function;
00353         timer->functionArgs = funcArgument;
00354         timer->timerType = timerType;
00355 
00356         *timerID = (palTimerID_t)timer;
00357     }
00358 
00359     return status;
00360 }
00361 
00362 palStatus_t pal_plat_osTimerStart(palTimerID_t timerID, uint32_t millisec)
00363 {
00364     palStatus_t status = PAL_SUCCESS;
00365 
00366     palTimer_t* timer = (palTimer_t*)timerID;
00367 
00368     // There is no periodic timer on COS as far as I know, so we need to emulate it
00369     // by storing the period to timer and re-issue the timer from the callback itself.
00370     timer->periodMs = millisec;
00371 
00372 #if PAL_SXOS_USE_TIMER_HELPER_THREAD
00373     const palThread_t* timer_thread = (palThread_t*)g_timer_helper_thread;
00374 
00375     HANDLE timer_thread_handle = timer_thread->osThread;
00376 
00377     COS_StartCallbackTimer(timer_thread_handle, millisec, pal_plat_osTimerWarpperFunction, timer);
00378 #else
00379     // XXX: there is a COS_StartFunctionTimerForcedly(), which will actually
00380     // do less-forced restart of timer than COS_StartFunctionTimer(), which will
00381     // stop existing timer and start another.
00382     COS_StartFunctionTimer(millisec, pal_plat_osTimerWarpperFunction, timer);
00383 #endif
00384 
00385     return status;
00386 }
00387 
00388 palStatus_t pal_plat_osTimerStop(palTimerID_t timerID)
00389 {
00390     palStatus_t status = PAL_SUCCESS;
00391 
00392     palTimer_t* timer = (palTimer_t*)timerID;
00393 
00394 #if PAL_SXOS_USE_TIMER_HELPER_THREAD
00395     const palThread_t* timer_thread = (palThread_t*)g_timer_helper_thread;
00396 
00397     HANDLE timer_thread_handle = timer_thread->osThread;
00398 
00399     COS_StopCallbackTimer(timer_thread_handle, (COS_CALLBACK_FUNC_T)pal_plat_osTimerWarpperFunction, timer);
00400 #else
00401     COS_StopFunctionTimer((COS_CALLBACK_FUNC_T)pal_plat_osTimerWarpperFunction, timer);
00402 #endif
00403 
00404     return status;
00405 }
00406 
00407 palStatus_t pal_plat_osTimerDelete(palTimerID_t* timerID)
00408 {
00409     palStatus_t status = PAL_SUCCESS;
00410 
00411     palTimer_t* timer = (palTimer_t*)*timerID;
00412 
00413     free(timer);
00414 
00415     *timerID = 0;
00416 
00417     return status;
00418 }
00419 
00420 
00421 palStatus_t pal_plat_osMutexCreate(palMutexID_t* mutexID)
00422 {
00423     // There is a COS_CreateMutex() & COS_DeleteMutex()using HANDLE's, but it is
00424     // marked as deprecated.
00425     // Let's then use the other API, COS_Mutex*, which takes in a COS_MUTEX
00426 
00427     palStatus_t status = PAL_SUCCESS;
00428     palMutex_t* mutex;
00429 
00430     // the COS_MutexInit() expects a zeroed struct, hence calloc()
00431     mutex = (palMutex_t*)calloc(1, sizeof(palMutex_t));
00432     if (NULL == mutex)
00433     {
00434         status = PAL_ERR_NO_MEMORY ;
00435     }
00436 
00437     if (PAL_SUCCESS == status)
00438     {
00439         // init can not fail
00440         COS_MutexInit(&mutex->osMutex);
00441 
00442         // Note: the PAL does not touch the given pointer unless success.
00443         *mutexID = (palMutexID_t)mutex;
00444     }
00445 
00446     return status;
00447 }
00448 
00449 
00450 palStatus_t pal_plat_osMutexWait(palMutexID_t mutexID, uint32_t millisec)
00451 {
00452     palStatus_t status = PAL_SUCCESS;
00453 
00454     palMutex_t* mutex = (palMutex_t*)mutexID;
00455 
00456     if (millisec == PAL_RTOS_WAIT_FOREVER) {
00457 
00458         COS_MutexLock(&mutex->osMutex);
00459     }
00460     else
00461     {
00462         if (COS_MutexTryLock(&mutex->osMutex, millisec) == false) {
00463 
00464             status = PAL_ERR_RTOS_TIMEOUT ;
00465         }
00466     }
00467 
00468     return status;
00469 }
00470 
00471 
00472 palStatus_t pal_plat_osMutexRelease(palMutexID_t mutexID)
00473 {
00474     palMutex_t* mutex = (palMutex_t*)mutexID;
00475 
00476     COS_MutexUnlock(&mutex->osMutex);
00477 
00478     return PAL_SUCCESS;
00479 }
00480 
00481 palStatus_t pal_plat_osMutexDelete(palMutexID_t* mutexID)
00482 {
00483     palMutex_t* mutex = (palMutex_t*)*mutexID;
00484     COS_MutexDestroy(&mutex->osMutex);
00485 
00486     free(mutex);
00487 
00488     *mutexID = NULL;
00489 
00490     return PAL_SUCCESS;
00491 }
00492 
00493 palStatus_t pal_plat_osSemaphoreCreate(uint32_t count, palSemaphoreID_t* semaphoreID)
00494 {
00495     // There is a COS_CreateSemaphore() & COS_DeleteSemaphore()using HANDLE's, but it is
00496     // marked as deprecated.
00497     // Let's then use the other API, COS_Sema*, which takes in a COS_SEMA
00498 
00499     palStatus_t status = PAL_SUCCESS;
00500     palSemaphore_t* semaphore;
00501 
00502     // the COS_SemaInit() expects a zeroed struct, hence calloc()
00503     semaphore = (palSemaphore_t*)calloc(1, sizeof(palSemaphore_t));
00504     if (NULL == semaphore)
00505     {
00506         status = PAL_ERR_NO_MEMORY ;
00507     }
00508 
00509     if (PAL_SUCCESS == status)
00510     {
00511         // init can not fail
00512         COS_SemaInit(&semaphore->osSemaphore, count);
00513 
00514         // Note: the PAL does not touch the given pointer unless success.
00515         *semaphoreID = (palSemaphoreID_t)semaphore;
00516     }
00517 
00518     return status;
00519 }
00520 
00521 palStatus_t pal_plat_osSemaphoreWait(palSemaphoreID_t semaphoreID, uint32_t millisec, int32_t* countersAvailable)
00522 {
00523     palStatus_t status = PAL_SUCCESS;
00524 
00525     palSemaphore_t* semaphore = (palSemaphore_t*)semaphoreID;
00526 
00527     if (millisec == PAL_RTOS_WAIT_FOREVER)
00528     {
00529         COS_SemaTake(&semaphore->osSemaphore);
00530     }
00531     else
00532     {
00533         if (COS_SemaTryTake(&semaphore->osSemaphore, millisec) == false)
00534         {
00535             status = PAL_ERR_RTOS_TIMEOUT ;
00536         }
00537     }
00538 
00539     if ((NULL != countersAvailable) && (PAL_SUCCESS == status))
00540     {
00541         // XXX: this is pointless, only the test code uses the counters value and
00542         // the whole countersAvailable needs to be removed from API. On other OS there are even
00543         // silly hacks to support this misfeature.
00544         *countersAvailable = semaphore->osSemaphore.count;
00545     }
00546 
00547     return status;
00548 }
00549 
00550 palStatus_t pal_plat_osSemaphoreRelease(palSemaphoreID_t semaphoreID)
00551 {
00552     palSemaphore_t* semaphore = (palSemaphore_t*)semaphoreID;
00553 
00554     COS_SemaRelease(&semaphore->osSemaphore);
00555 
00556     return PAL_SUCCESS;
00557 }
00558 
00559 palStatus_t pal_plat_osSemaphoreDelete(palSemaphoreID_t* semaphoreID)
00560 {
00561     palSemaphore_t* semaphore = (palSemaphore_t*)*semaphoreID;
00562 
00563     COS_SemaDestroy(&semaphore->osSemaphore);
00564 
00565     free(semaphore);
00566 
00567     *semaphoreID = NULL;
00568 
00569     return PAL_SUCCESS;
00570 }
00571 
00572 
00573 void *pal_plat_malloc(size_t len)
00574 {
00575     return malloc(len);
00576 }
00577 
00578 
00579 void pal_plat_free(void * buffer)
00580 {
00581     free(buffer);
00582 }
00583 
00584 int32_t pal_plat_osAtomicIncrement(int32_t* valuePtr, int32_t increment)
00585 {
00586     int32_t res;
00587 
00588     HANDLE section = COS_EnterCriticalSection();
00589 
00590     res = *valuePtr + increment;
00591     *valuePtr = res;
00592 
00593     COS_ExitCriticalSection(section);
00594 
00595     return res;
00596 }
00597 
00598 palStatus_t pal_plat_osRandomBuffer(uint8_t *randomBuf, size_t bufSizeBytes, size_t* actualRandomSizeBytes)
00599 {
00600     // XXX: this needs to return success until properly implemented to get the client side into network
00601     //palStatus_t status = PAL_ERR_NOT_IMPLEMENTED;
00602 
00603     palStatus_t status = PAL_SUCCESS;
00604     return status;
00605 }
00606 
00607 void pal_plat_osReboot(void)
00608 {
00609     DM_DeviceSwithOff(true);
00610     while (1)
00611     {
00612         COS_Sleep(1000); // Wait until reset
00613     }
00614 }
00615 
00616 #if defined(PAL_USE_HW_RTC)
00617 
00618 PAL_PRIVATE palMutexID_t rtcMutex = NULLPTR;
00619 
00620 /*
00621  * Unisoc TM_FILENAME's DateTime is not seconds since 1.1.1970 but
00622  * seconds since 1.1.2000
00623  */
00624 #define EPOCH_TIME_1_1_2000  (946684800)
00625 
00626 palStatus_t pal_plat_osSetRtcTime(uint64_t rtcSetTime)
00627 {
00628     palStatus_t ret = PAL_SUCCESS;
00629     if (rtcSetTime < (uint64_t)PAL_MIN_RTC_SET_TIME)
00630     {
00631         ret = PAL_ERR_INVALID_TIME ;
00632     }
00633     else
00634     {
00635         ret = pal_osMutexWait(rtcMutex, 5 * PAL_MILLI_PER_SECOND * PAL_ONE_SEC);
00636         if (ret == PAL_SUCCESS)
00637         {
00638             TM_FILETIME tm_filetime;
00639             TM_SYSTEMTIME tm_systemtime;
00640 
00641             tm_filetime.DateTime = (UINT32)rtcSetTime - EPOCH_TIME_1_1_2000;
00642             if (!TM_FileTimeToSystemTime(tm_filetime, &tm_systemtime))
00643             {
00644                 ret = PAL_ERR_TIME_TRANSLATE ;
00645             }
00646 
00647             if (ret == PAL_SUCCESS)
00648             {
00649                 // TM_SetSystemTime returns false if platform RTC handler is busy.
00650                 // Therefore try couple of times.
00651                 bool ret_rtc = false;
00652                 for (int attempt = PAL_MAX_RTC_SET_ATTEMPTS; attempt > 0 && !ret_rtc; attempt--)
00653                 {
00654                     ret_rtc = TM_SetSystemTime(&tm_systemtime);
00655 
00656                     // Wait a moment before trying again
00657                     if (!ret_rtc)
00658                     {
00659                         COS_Sleep(1);
00660                     }
00661                 }
00662 
00663                 if (!ret_rtc)
00664                 {
00665                     ret = PAL_ERR_RTOS_RTC_SET_TIME_ERROR;
00666                 }
00667             }
00668 
00669             pal_osMutexRelease(rtcMutex);
00670         }
00671     }
00672 
00673     return ret;
00674 }
00675 
00676 palStatus_t pal_plat_osGetRtcTime(uint64_t *rtcGetTime)
00677 {
00678     palStatus_t ret = PAL_SUCCESS;
00679     if (rtcGetTime != NULL)
00680     {
00681         TM_FILETIME tm_filetime;
00682         TM_SYSTEMTIME tm_systemtime;
00683 
00684         if (!TM_GetSystemTime(&tm_systemtime))
00685         {
00686             ret = PAL_ERR_RTOS_RTC_GET_TIME_ERROR;
00687         }
00688 
00689         if (ret == PAL_SUCCESS && !TM_SystemTimeToFileTime(&tm_systemtime, &tm_filetime))
00690         {
00691             ret = PAL_ERR_TIME_TRANSLATE ;
00692         }
00693         *rtcGetTime = (uint64_t)tm_filetime.DateTime + EPOCH_TIME_1_1_2000;
00694     }
00695     else
00696     {
00697         ret = PAL_ERR_NULL_POINTER ;
00698     }
00699 
00700     return ret;
00701 }
00702 
00703 palStatus_t pal_plat_rtcDeInit(void)
00704 {
00705     palStatus_t ret = PAL_SUCCESS;
00706     if (NULLPTR != rtcMutex)
00707     {
00708         ret = pal_osMutexDelete(&rtcMutex);
00709         rtcMutex = NULLPTR;
00710     }
00711     return ret;
00712 }
00713 
00714 palStatus_t pal_plat_rtcInit(void)
00715 {
00716     palStatus_t ret = PAL_SUCCESS;
00717     if (NULLPTR == rtcMutex)
00718     {
00719         ret = pal_osMutexCreate(&rtcMutex);
00720     }
00721     return ret;
00722 }
00723 #endif