Слияние кода завершено, страница обновится автоматически
/*!
* \file timer.c
*
* \brief Timer objects and scheduling management implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2017 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*/
#include "utilities.h"
#include "board.h"
#include "rtc-board.h"
#include "timer.h"
/*!
* Safely execute call back
*/
#define ExecuteCallBack( _callback_, context ) \
do \
{ \
if( _callback_ == NULL ) \
{ \
while( 1 ); \
} \
else \
{ \
_callback_( context ); \
} \
}while( 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 );
/*!
* \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 );
/*!
* \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 );
void TimerInit( TimerEvent_t *obj, void ( *callback )( void *context ) )
{
obj->Timestamp = 0;
obj->ReloadValue = 0;
obj->IsStarted = false;
obj->IsNext2Expire = false;
obj->Callback = callback;
obj->Context = NULL;
obj->Next = NULL;
}
void TimerSetContext( TimerEvent_t *obj, void* context )
{
obj->Context = context;
}
void TimerStart( TimerEvent_t *obj )
{
uint32_t elapsedTime = 0;
CRITICAL_SECTION_BEGIN( );
if( ( obj == NULL ) || ( TimerExists( obj ) == true ) )
{
CRITICAL_SECTION_END( );
return;
}
obj->Timestamp = obj->ReloadValue;
obj->IsStarted = true;
obj->IsNext2Expire = false;
if( TimerListHead == NULL )
{
RtcSetTimerContext( );
// Inserts a timer at time now + obj->Timestamp
TimerInsertNewHeadTimer( obj );
}
else
{
elapsedTime = RtcGetTimerElapsedTime( );
obj->Timestamp += elapsedTime;
if( obj->Timestamp < TimerListHead->Timestamp )
{
TimerInsertNewHeadTimer( obj );
}
else
{
TimerInsertTimer( obj );
}
}
CRITICAL_SECTION_END( );
}
static void TimerInsertTimer( TimerEvent_t *obj )
{
TimerEvent_t* cur = TimerListHead;
TimerEvent_t* next = TimerListHead->Next;
while( cur->Next != NULL )
{
if( obj->Timestamp > next->Timestamp )
{
cur = next;
next = next->Next;
}
else
{
cur->Next = obj;
obj->Next = next;
return;
}
}
cur->Next = obj;
obj->Next = NULL;
}
static void TimerInsertNewHeadTimer( TimerEvent_t *obj )
{
TimerEvent_t* cur = TimerListHead;
if( cur != NULL )
{
cur->IsNext2Expire = false;
}
obj->Next = cur;
TimerListHead = obj;
TimerSetTimeout( TimerListHead );
}
bool TimerIsStarted( TimerEvent_t *obj )
{
return obj->IsStarted;
}
void TimerIrqHandler( void )
{
TimerEvent_t* cur;
TimerEvent_t* next;
uint32_t old = RtcGetTimerContext( );
uint32_t now = RtcSetTimerContext( );
uint32_t deltaContext = now - old; // intentional wrap around
// Update timeStamp based upon new Time Reference
// because delta context should never exceed 2^32
if( TimerListHead != NULL )
{
for( cur = TimerListHead; cur->Next != NULL; cur = cur->Next )
{
next = cur->Next;
if( next->Timestamp > deltaContext )
{
next->Timestamp -= deltaContext;
}
else
{
next->Timestamp = 0;
}
}
}
// Execute immediately the alarm callback
if ( TimerListHead != NULL )
{
cur = TimerListHead;
TimerListHead = TimerListHead->Next;
cur->IsStarted = false;
ExecuteCallBack( cur->Callback, cur->Context );
}
// Remove all the expired object from the list
while( ( TimerListHead != NULL ) && ( TimerListHead->Timestamp < RtcGetTimerElapsedTime( ) ) )
{
cur = TimerListHead;
TimerListHead = TimerListHead->Next;
cur->IsStarted = false;
ExecuteCallBack( cur->Callback, cur->Context );
}
// Start the next TimerListHead if it exists AND NOT running
if( ( TimerListHead != NULL ) && ( TimerListHead->IsNext2Expire == false ) )
{
TimerSetTimeout( TimerListHead );
}
}
void TimerStop( TimerEvent_t *obj )
{
CRITICAL_SECTION_BEGIN( );
TimerEvent_t* prev = TimerListHead;
TimerEvent_t* cur = TimerListHead;
// List is empty or the obj to stop does not exist
if( ( TimerListHead == NULL ) || ( obj == NULL ) )
{
CRITICAL_SECTION_END( );
return;
}
obj->IsStarted = false;
if( TimerListHead == obj ) // Stop the Head
{
if( TimerListHead->IsNext2Expire == true ) // The head is already running
{
TimerListHead->IsNext2Expire = false;
if( TimerListHead->Next != NULL )
{
TimerListHead = TimerListHead->Next;
TimerSetTimeout( TimerListHead );
}
else
{
RtcStopAlarm( );
TimerListHead = NULL;
}
}
else // Stop the head before it is started
{
if( TimerListHead->Next != NULL )
{
TimerListHead = TimerListHead->Next;
}
else
{
TimerListHead = NULL;
}
}
}
else // Stop an object within the list
{
while( cur != NULL )
{
if( cur == obj )
{
if( cur->Next != NULL )
{
cur = cur->Next;
prev->Next = cur;
}
else
{
cur = NULL;
prev->Next = cur;
}
break;
}
else
{
prev = cur;
cur = cur->Next;
}
}
}
CRITICAL_SECTION_END( );
}
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;
uint32_t ticks = RtcMs2Tick( value );
TimerStop( obj );
minValue = RtcGetMinimumTimeout( );
if( ticks < minValue )
{
ticks = minValue;
}
obj->Timestamp = ticks;
obj->ReloadValue = ticks;
}
TimerTime_t TimerGetCurrentTime( void )
{
uint32_t now = RtcGetTimerValue( );
return RtcTick2Ms( now );
}
TimerTime_t TimerGetElapsedTime( TimerTime_t past )
{
if ( past == 0 )
{
return 0;
}
uint32_t nowInTicks = RtcGetTimerValue( );
uint32_t pastInTicks = RtcMs2Tick( past );
// Intentional wrap around. Works Ok if tick duration below 1ms
return RtcTick2Ms( nowInTicks - pastInTicks );
}
static void TimerSetTimeout( TimerEvent_t *obj )
{
int32_t minTicks= RtcGetMinimumTimeout( );
obj->IsNext2Expire = true;
// In case deadline too soon
if( obj->Timestamp < ( RtcGetTimerElapsedTime( ) + minTicks ) )
{
obj->Timestamp = RtcGetTimerElapsedTime( ) + minTicks;
}
RtcSetAlarm( obj->Timestamp );
}
TimerTime_t TimerTempCompensation( TimerTime_t period, float temperature )
{
return RtcTempCompensation( period, temperature );
}
void TimerProcess( void )
{
RtcProcess( );
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарий ( 0 )