| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- /*
- / _____) _ | |
- ( (____ _____ ____ _| |_ _____ ____| |__
- \____ \| ___ | (_ _) ___ |/ ___) _ \
- _____) ) ____| | | || |_| ____( (___| | | |
- (______/|_____)_|_|_| \__)_____)\____)_| |_|
- (C)2013 Semtech
- Description: Timer objects and scheduling management
- License: Revised BSD License, see LICENSE.TXT file include in the project
- Maintainer: Miguel Luis and Gregory Cristian
- */
- #include "board.h"
- #include "rtc-board.h"
- #include "timer-board.h"
- static bool LowPowerModeEnable = true;
- /*!
- * This flag is used to make sure we have looped through the main several time to avoid race issues
- */
- volatile uint8_t HasLoopedThroughMain = 0;
- /*!
- * Timers list head pointer
- */
- static TimerEvent_t *TimerListHead = NULL;
- /*!
- * \brief Adds or replace the head timer of the list.
- *
- * \remark The list is automatically sorted. The list head always contains the
- * next timer to expire.
- *
- * \param [IN] obj Timer object to be become the new head
- * \param [IN] remainingTime Remaining time of the previous head to be replaced
- */
- static void TimerInsertNewHeadTimer( TimerEvent_t *obj, uint32_t remainingTime );
- /*!
- * \brief Adds a timer to the list.
- *
- * \remark The list is automatically sorted. The list head always contains the
- * next timer to expire.
- *
- * \param [IN] obj Timer object to be added to the list
- * \param [IN] remainingTime Remaining time of the running head after which the object may be added
- */
- static void TimerInsertTimer( TimerEvent_t *obj, uint32_t remainingTime );
- /*!
- * \brief Sets a timeout with the duration "timestamp"
- *
- * \param [IN] timestamp Delay duration
- */
- static void TimerSetTimeout( TimerEvent_t *obj );
- /*!
- * \brief Check if the Object to be added is not already in the list
- *
- * \param [IN] timestamp Delay duration
- * \retval true (the object is already in the list) or false
- */
- static bool TimerExists( TimerEvent_t *obj );
- /*!
- * \brief Read the timer value of the currently running timer
- *
- * \retval value current timer value
- */
- uint32_t TimerGetValue( void );
- void TimerSetLowPowerEnable( bool enable )
- {
- LowPowerModeEnable = enable;
- }
- bool TimerGetLowPowerEnable( void )
- {
- return LowPowerModeEnable;
- }
- void TimerInit( TimerEvent_t *obj, void ( *callback )( void ) )
- {
- obj->Timestamp = 0;
- obj->ReloadValue = 0;
- obj->IsRunning = false;
- obj->Callback = callback;
- obj->Next = NULL;
- }
- void TimerStart( TimerEvent_t *obj )
- {
- uint32_t elapsedTime = 0;
- uint32_t remainingTime = 0;
- __disable_irq( );
- if( ( obj == NULL ) || ( TimerExists( obj ) == true ) )
- {
- __enable_irq( );
- return;
- }
- obj->Timestamp = obj->ReloadValue;
- obj->IsRunning = false;
- if( TimerListHead == NULL )
- {
- TimerInsertNewHeadTimer( obj, obj->Timestamp );
- }
- else
- {
- if( TimerListHead->IsRunning == true )
- {
- elapsedTime = TimerGetValue( );
- if( elapsedTime > TimerListHead->Timestamp )
- {
- elapsedTime = TimerListHead->Timestamp; // security but should never occur
- }
- remainingTime = TimerListHead->Timestamp - elapsedTime;
- }
- else
- {
- remainingTime = TimerListHead->Timestamp;
- }
-
- if( obj->Timestamp < remainingTime )
- {
- TimerInsertNewHeadTimer( obj, remainingTime );
- }
- else
- {
- TimerInsertTimer( obj, remainingTime );
- }
- }
- __enable_irq( );
- }
- static void TimerInsertTimer( TimerEvent_t *obj, uint32_t remainingTime )
- {
- uint32_t aggregatedTimestamp = 0; // hold the sum of timestamps
- uint32_t aggregatedTimestampNext = 0; // hold the sum of timestamps up to the next event
- TimerEvent_t* prev = TimerListHead;
- TimerEvent_t* cur = TimerListHead->Next;
- if( cur == NULL )
- { // obj comes just after the head
- obj->Timestamp -= remainingTime;
- prev->Next = obj;
- obj->Next = NULL;
- }
- else
- {
- aggregatedTimestamp = remainingTime;
- aggregatedTimestampNext = remainingTime + cur->Timestamp;
- while( prev != NULL )
- {
- if( aggregatedTimestampNext > obj->Timestamp )
- {
- obj->Timestamp -= aggregatedTimestamp;
- if( cur != NULL )
- {
- cur->Timestamp -= obj->Timestamp;
- }
- prev->Next = obj;
- obj->Next = cur;
- break;
- }
- else
- {
- prev = cur;
- cur = cur->Next;
- if( cur == NULL )
- { // obj comes at the end of the list
- aggregatedTimestamp = aggregatedTimestampNext;
- obj->Timestamp -= aggregatedTimestamp;
- prev->Next = obj;
- obj->Next = NULL;
- break;
- }
- else
- {
- aggregatedTimestamp = aggregatedTimestampNext;
- aggregatedTimestampNext = aggregatedTimestampNext + cur->Timestamp;
- }
- }
- }
- }
- }
- static void TimerInsertNewHeadTimer( TimerEvent_t *obj, uint32_t remainingTime )
- {
- TimerEvent_t* cur = TimerListHead;
- if( cur != NULL )
- {
- cur->Timestamp = remainingTime - obj->Timestamp;
- cur->IsRunning = false;
- }
- obj->Next = cur;
- obj->IsRunning = true;
- TimerListHead = obj;
- TimerSetTimeout( TimerListHead );
- }
- void TimerIrqHandler( void )
- {
- uint32_t elapsedTime = 0;
-
- if( LowPowerModeEnable == false )
- {
- if( TimerListHead == NULL )
- {
- return; // Only necessary when the standard timer is used as a time base
- }
- }
- elapsedTime = TimerGetValue( );
- if( elapsedTime > TimerListHead->Timestamp )
- {
- TimerListHead->Timestamp = 0;
- }
- else
- {
- TimerListHead->Timestamp -= elapsedTime;
- }
- while( ( TimerListHead != NULL ) && ( TimerListHead->Timestamp == 0 ) )
- {
- TimerEvent_t* elapsedTimer = TimerListHead;
- TimerListHead = TimerListHead->Next;
- if( elapsedTimer->Callback != NULL )
- {
- elapsedTimer->Callback( );
- }
- }
- // start the next TimerListHead if it exists
- if( TimerListHead != NULL )
- {
- TimerListHead->IsRunning = true;
- TimerSetTimeout( TimerListHead );
- }
- }
- void TimerStop( TimerEvent_t *obj )
- {
- __disable_irq( );
- uint32_t elapsedTime = 0;
- uint32_t remainingTime = 0;
- TimerEvent_t* prev = TimerListHead;
- TimerEvent_t* cur = TimerListHead;
- // List is empty or the Obj to stop does not exist
- if( ( TimerListHead == NULL ) || ( obj == NULL ) )
- {
- __enable_irq( );
- return;
- }
- if( TimerListHead == obj ) // Stop the Head
- {
- if( TimerListHead->IsRunning == true ) // The head is already running
- {
- elapsedTime = TimerGetValue( );
- if( elapsedTime > obj->Timestamp )
- {
- elapsedTime = obj->Timestamp;
- }
-
- remainingTime = obj->Timestamp - elapsedTime;
-
- if( TimerListHead->Next != NULL )
- {
- TimerListHead->IsRunning = false;
- TimerListHead = TimerListHead->Next;
- TimerListHead->Timestamp += remainingTime;
- TimerListHead->IsRunning = true;
- TimerSetTimeout( TimerListHead );
- }
- else
- {
- TimerListHead = NULL;
- }
- }
- else // Stop the head before it is started
- {
- if( TimerListHead->Next != NULL )
- {
- remainingTime = obj->Timestamp;
- TimerListHead = TimerListHead->Next;
- TimerListHead->Timestamp += remainingTime;
- }
- else
- {
- TimerListHead = NULL;
- }
- }
- }
- else // Stop an object within the list
- {
- remainingTime = obj->Timestamp;
-
- while( cur != NULL )
- {
- if( cur == obj )
- {
- if( cur->Next != NULL )
- {
- cur = cur->Next;
- prev->Next = cur;
- cur->Timestamp += remainingTime;
- }
- else
- {
- cur = NULL;
- prev->Next = cur;
- }
- break;
- }
- else
- {
- prev = cur;
- cur = cur->Next;
- }
- }
- }
- __enable_irq( );
- }
-
- static bool TimerExists( TimerEvent_t *obj )
- {
- TimerEvent_t* cur = TimerListHead;
- while( cur != NULL )
- {
- if( cur == obj )
- {
- return true;
- }
- cur = cur->Next;
- }
- return false;
- }
- void TimerReset( TimerEvent_t *obj )
- {
- TimerStop( obj );
- TimerStart( obj );
- }
- void TimerSetValue( TimerEvent_t *obj, uint32_t value )
- {
- uint32_t minValue = 0;
- TimerStop( obj );
- if( LowPowerModeEnable == true )
- {
- minValue = RtcGetMinimumTimeout( );
- }
- else
- {
- minValue = TimerHwGetMinimumTimeout( );
- }
-
- if( value < minValue )
- {
- value = minValue;
- }
- obj->Timestamp = value;
- obj->ReloadValue = value;
- }
- uint32_t TimerGetValue( void )
- {
- if( LowPowerModeEnable == true )
- {
- return RtcGetTimerElapsedTime( );
- }
- else
- {
- return TimerHwGetElapsedTime( );
- }
- }
- TimerTime_t TimerGetCurrentTime( void )
- {
- if( LowPowerModeEnable == true )
- {
- return RtcGetTimerValue( );
- }
- else
- {
- return TimerHwGetTime( );
- }
- }
- static void TimerSetTimeout( TimerEvent_t *obj )
- {
- HasLoopedThroughMain = 0;
- if( LowPowerModeEnable == true )
- {
- RtcSetTimeout( obj->Timestamp );
- }
- else
- {
- TimerHwStart( obj->Timestamp );
- }
- }
- void TimerLowPowerHandler( void )
- {
- if( ( TimerListHead != NULL ) && ( TimerListHead->IsRunning == true ) )
- {
- if( HasLoopedThroughMain < 5 )
- {
- HasLoopedThroughMain++;
- }
- else
- {
- HasLoopedThroughMain = 0;
-
- if( LowPowerModeEnable == true )
- {
- RtcEnterLowPowerStopMode( );
- }
- else
- {
- TimerHwEnterLowPowerStopMode( );
- }
- }
- }
- }
|