/* * FreeRTOS Platform V1.1.2 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * http://aws.amazon.com/freertos * http://www.FreeRTOS.org */ /** * @file iot_clock_freertos.c * @brief Implementation of the functions in iot_clock.h for FreeRTOS systems. */ /* The config header is always included first. */ #include "iot_config.h" /* Standard includes. */ #include /* Platform clock include. */ #include "platform/iot_platform_types_freertos.h" #include "platform/iot_clock.h" #include "task.h" /* Configure logs for the functions in this file. */ #ifdef IOT_LOG_LEVEL_PLATFORM #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_PLATFORM #else #ifdef IOT_LOG_LEVEL_GLOBAL #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_GLOBAL #else #define LIBRARY_LOG_LEVEL IOT_LOG_NONE #endif #endif #define LIBRARY_LOG_NAME ( "CLOCK" ) #include "iot_logging_setup.h" /*-----------------------------------------------------------*/ /* * Time conversion constants. */ #define _MILLISECONDS_PER_SECOND ( 1000 ) /**< @brief Milliseconds per second. */ #define _MILLISECONDS_PER_TICK ( _MILLISECONDS_PER_SECOND / configTICK_RATE_HZ ) /**< Milliseconds per FreeRTOS tick. */ /*-----------------------------------------------------------*/ /* Private Callback function for timer expiry, delegate work to a Task to free * up the timer task for managing other timers */ static void prvTimerCallback( TimerHandle_t xTimerHandle ) { _IotSystemTimer_t * pxTimer = ( _IotSystemTimer_t * ) pvTimerGetTimerID( xTimerHandle ); /* The value of the timer ID, set in timer_create, should not be NULL. */ configASSERT( pxTimer != NULL ); /* Restart the timer if it is periodic. */ if( pxTimer->xTimerPeriod > 0 ) { xTimerChangePeriod( xTimerHandle, pxTimer->xTimerPeriod, 0 ); } /* Call timer Callback from this task */ pxTimer->threadRoutine( ( void * ) pxTimer->pArgument ); } /*-----------------------------------------------------------*/ bool IotClock_GetTimestring( char * pBuffer, size_t bufferSize, size_t * pTimestringLength ) { uint64_t milliSeconds = IotClock_GetTimeMs(); int timestringLength = 0; configASSERT( pBuffer != NULL ); configASSERT( pTimestringLength != NULL ); /* Convert the localTime struct to a string. */ timestringLength = snprintf( pBuffer, bufferSize, "%llu", milliSeconds ); /* Check for error from no string */ if( timestringLength == 0 ) { return false; } /* Set the output parameter. */ *pTimestringLength = timestringLength; return true; } /*-----------------------------------------------------------*/ uint64_t IotClock_GetTimeMs( void ) { TimeOut_t xCurrentTime = { 0 }; /* This must be unsigned because the behavior of signed integer overflow is undefined. */ uint64_t ullTickCount = 0ULL; /* Get the current tick count and overflow count. vTaskSetTimeOutState() * is used to get these values because they are both static in tasks.c. */ vTaskSetTimeOutState( &xCurrentTime ); /* Adjust the tick count for the number of times a TickType_t has overflowed. */ ullTickCount = ( uint64_t ) ( xCurrentTime.xOverflowCount ) << ( sizeof( TickType_t ) * 8 ); /* Add the current tick count. */ ullTickCount += xCurrentTime.xTimeOnEntering; /* Return the ticks converted to Milliseconds */ return ullTickCount * _MILLISECONDS_PER_TICK; } /*-----------------------------------------------------------*/ void IotClock_SleepMs( uint32_t sleepTimeMs ) { vTaskDelay( pdMS_TO_TICKS( sleepTimeMs ) ); } /*-----------------------------------------------------------*/ bool IotClock_TimerCreate( IotTimer_t * pNewTimer, IotThreadRoutine_t expirationRoutine, void * pArgument ) { _IotSystemTimer_t * pxTimer = ( _IotSystemTimer_t * ) pNewTimer; configASSERT( pNewTimer != NULL ); configASSERT( expirationRoutine != NULL ); IotLogDebug( "Creating new timer %p.", pNewTimer ); /* Set the timer expiration routine, argument and period */ pxTimer->threadRoutine = expirationRoutine; pxTimer->pArgument = pArgument; pxTimer->xTimerPeriod = 0; /* Create a new FreeRTOS timer. This call will not fail because the * memory for it has already been allocated, so the output parameter is * also set. */ pxTimer->timer = ( TimerHandle_t ) xTimerCreateStatic( "timer", /* Timer name. */ portMAX_DELAY, /* Initial timer period. Timers are created disarmed. */ pdFALSE, /* Don't auto-reload timer. */ ( void * ) pxTimer, /* Timer id. */ prvTimerCallback, /* Timer expiration callback. */ &pxTimer->xTimerBuffer ); /* Pre-allocated memory for timer. */ return true; } /*-----------------------------------------------------------*/ void IotClock_TimerDestroy( IotTimer_t * pTimer ) { _IotSystemTimer_t * pTimerInfo = ( _IotSystemTimer_t * ) pTimer; configASSERT( pTimerInfo != NULL ); configASSERT( pTimerInfo->timer != NULL ); IotLogDebug( "Destroying timer %p.", pTimer ); if( xTimerIsTimerActive( pTimerInfo->timer ) == pdTRUE ) { /* Stop the FreeRTOS timer. Because the timer is statically allocated, no call * to xTimerDelete is necessary. The timer is stopped so that it's not referenced * anywhere. xTimerStop will not fail when it has unlimited block time. */ ( void ) xTimerStop( pTimerInfo->timer, portMAX_DELAY ); /* Wait until the timer stop command is processed. */ while( xTimerIsTimerActive( pTimerInfo->timer ) == pdTRUE ) { vTaskDelay( 1 ); } } } /*-----------------------------------------------------------*/ bool IotClock_TimerArm( IotTimer_t * pTimer, uint32_t relativeTimeoutMs, uint32_t periodMs ) { _IotSystemTimer_t * pTimerInfo = ( _IotSystemTimer_t * ) pTimer; configASSERT( pTimerInfo != NULL ); TimerHandle_t xTimerHandle = pTimerInfo->timer; IotLogDebug( "Arming timer %p with timeout %llu and period %llu.", pTimer, relativeTimeoutMs, periodMs ); /* Set the timer period in ticks */ pTimerInfo->xTimerPeriod = pdMS_TO_TICKS( periodMs ); /* Set the timer to expire after relativeTimeoutMs, and restart it. */ ( void ) xTimerChangePeriod( xTimerHandle, pdMS_TO_TICKS( relativeTimeoutMs ), portMAX_DELAY ); return true; } /*-----------------------------------------------------------*/