📄 os_alarm.c
字号:
}
/* alarm is present in alarm active list */
else
{
/* remove from active list */
pred->OSAlarmNext = alarm->OSAlarmNext;
}
}
/* mark as idle */
alarm->OSAlarmType = OS_ALARM_TYPE_IDLE;
alarm->OSAlarmTime = 0;
/* remember that this timer is periodic */
if (alarm->OSAlarmPeriod > 0) alarm->OSAlarmPeriod = 1;
/* and remove successor */
alarm->OSAlarmNext = (OS_ALARM *)0;
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
}
/**
* Set an idle alarm
*
* @param alarm The (idle) alarm to be set. This alarm is activated and will trigger
* after the specified number of ticks.
* @param ticks The number of ticks (from now) after which the alarm will trigger. If this is
* a periodic timer, this defines the period time in ticks.
* @param err Pointer to error variable
*
* @return Errors are returned in the err_ptr
* - OS_ERR_ALARM_TYPE The alarm was not idle
*
* @note The alarm must be idle.
* @see OSAlarmClear()
*/
void OSAlarmSet(OS_ALARM *alarm, INT16U ticks, INT8U *err_ptr)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
OS_ENTER_CRITICAL();
#if (OS_ARG_CHK_EN > 0)
/* alarm is not idle? */
if (alarm->OSAlarmType != OS_ALARM_TYPE_IDLE)
{
OS_EXIT_CRITICAL();
/* failure, cannot set a non-idle alarm */
*err_ptr = OS_ERR_ALARM_TYPE;
return;
}
#endif
#if (OS_ALARM_PERIODIC_EN > 0)
/* is this a periodic alarm? */
if (alarm->OSAlarmPeriod > 0)
{
/* remember period ticks */
alarm->OSAlarmPeriod = ticks;
}
#endif
/* set alarm trigger time */
OSAlarmTime(alarm, OSTimeGet() + ticks, err_ptr);
OS_EXIT_CRITICAL();
return;
}
/**
* Activate an alarm with an absolute alarm time. This function is internal
* and is called from OSAlarmSet() and OSAlarmTrigger() within a critical
* section.
*
* @param alarm The (idle) alarm to be setup.
* @param time The (absolute) time at which the alarm will trigger.
* @param err Pointer to error variable
*
* @return Errors are returned in the err_ptr
* - OS_ERR_ALARM_TYPE The alarm was not idle
*
* @note The alarm must be idle.
* @note No concurrent access to OSAlarm* may occur, i.e. the caller must wrap the call
* to OSAlarmTime() with OS_ENTER_CRITICAL(), OS_EXIT_CRITICAL().
* @see OSAlarmClear()
*/
static void OSAlarmTime(OS_ALARM *alarm, INT32U time, INT8U *err)
{
#if (OS_ARG_CHK_EN > 0)
/* alarm is not idle? */
if (alarm->OSAlarmType != OS_ALARM_TYPE_IDLE)
{
/* failure, cannot set a non-idle alarm */
*err = OS_ERR_ALARM_TYPE;
return;
}
#endif
/* remember absolute tick time at which this alarm triggers */
alarm->OSAlarmTime = time;
/* add alarm to OSAlarmActiveList */
/* no active timers yet? */
if (OSAlarmActiveList == (OS_ALARM *)0)
{
debug_printf("adding single alarm (%lu) in list", (unsigned long)alarm->OSAlarmTime);
/* add alarm to OSAlarmActiveList */
OSAlarmActiveList = alarm;
alarm->OSAlarmNext = (OS_ALARM *)0;
}
/* active timers present */
/* this is the alarm that will trigger as first in time */
else if (alarm->OSAlarmTime < OSAlarmActiveList->OSAlarmTime)
{
/* add alarm as first of OSAlarmActiveList */
alarm->OSAlarmNext = OSAlarmActiveList;
debug_printf("adding earliest alarm (%lu) in list before (%lu)", alarm->OSAlarmTime,
OSAlarmActiveList->OSAlarmTime);
OSAlarmActiveList = alarm;
}
/* active timers present */
/* this alarm will not trigger as first in time */
else
{
OS_ALARM *pred = OSAlarmActiveList;
/* search predecessing alarm */
while ((pred != (OS_ALARM *)0) &&
(pred->OSAlarmNext != (OS_ALARM *)0) &&
(((OS_ALARM *)pred->OSAlarmNext)->OSAlarmTime <= alarm->OSAlarmTime))
{
pred = pred->OSAlarmNext;
}
/* insert in active list */
if (pred->OSAlarmNext == 0)
{
debug_printf("inserting alarm (%lu) in list after (%lu)", alarm->OSAlarmTime, pred->OSAlarmTime);
} else {
debug_printf("inserting alarm (%lu) in list after (%lu) before (%lu)", alarm->OSAlarmTime,
pred->OSAlarmTime, ((OS_ALARM *)pred->OSAlarmNext)->OSAlarmTime);
}
alarm->OSAlarmNext = pred->OSAlarmNext;
pred->OSAlarmNext = alarm;
}
*err = OS_NO_ERR;
return;
}
/**
* For any alarm that triggers, set its event flags and reset the alarm.
*
* Any triggered one-shot alarm becomes idle. Any periodic alarm is restarted.
*
* @note Periodic timers behave real-time correct with respect to their period. There
* is no clock skew as long as OSAlarmTrigger() is called within the smallest alarm
* period in the system.
*
*/
void OSAlarmTrigger()
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
INT8U err;
INT32U time = OSTimeGet();
OS_ALARM *alarm;
/* enter our critical section protecting the alarms list */
OS_ENTER_CRITICAL();
/* iterate through all alarms that should trigger now */
while ((OSAlarmActiveList != (OS_ALARM *)0) && (OSAlarmActiveList->OSAlarmTime <= time))
{
/* pick first active alarm */
alarm = OSAlarmActiveList;
/* remove alarm from head of active list */
OSAlarmActiveList = OSAlarmActiveList->OSAlarmNext;
alarm->OSAlarmNext = (OS_ALARM *)0;
/* idle this alarm */
alarm->OSAlarmType = OS_ALARM_TYPE_IDLE;
debug_printf("removing alarm (%lu) from list", alarm->OSAlarmTime);
#if (OS_ALARM_PERIODIC_EN > 0)
/* periodic alarm? */
if (alarm->OSAlarmPeriod > 0)
{
/* reset alarm to trigger on next period */
OSAlarmTime(alarm, alarm->OSAlarmTime + alarm->OSAlarmPeriod, &err);
}
/* one-shot alarm */
else
#endif
{
/* not necessary, but maybe helpful in debugging */
alarm->OSAlarmTime = 0;
}
/* set the event flags (i.e. trigger) */
/* note that we are already in a critical section when entering OSFlagPost().
* OSFlagPost() enters and leaves a critical section AS WELL. For critical
* section implementation method 1 this will LEAVE our critical section as well,
* as that method does not respect nesting critical sections.
* We deal with this correctly for all cases after this call returns */
OSFlagPost(alarm->OSAlarmFlagGrp, alarm->OSAlarmFlags, OS_FLAG_SET, &err);
/* effectively does nothing for method 1.
* leaves our critical section for other methods */
OS_EXIT_CRITICAL();
/* re-enter our critical section protecting the alarms list */
OS_ENTER_CRITICAL();
}
/* leave our critical section */
OS_EXIT_CRITICAL();
}
/**
* Checks if the earliest alarm time is reached.
*
* This function is to be called in OSTimeTickHook() which runs in interrupt context. The
* function is minimal with O(1) execution time.
*
* If it returns >0, a subsequent call to OSAlarmTrigger() is needed to actually trigger
* any alarms. This may be done from outside OSTimeTickHook() to minimize interrupt time.
*
* @return >0 if the earliest alarm time is reached. A subsequent call to OSAlarmTrigger() is
* needed to trigger this alarm, and possibly other simultaneously triggered alarms.
*
*/
INT8U OSAlarmCheck()
{
/* any alarms active AND earliest alarm time reached? */
return ((OSAlarmActiveList != (OS_ALARM *)0) && (OSAlarmActiveList->OSAlarmTime <= OSTimeGet()));
}
#if 0
#include "page.h"
void OSAlarmDebug()
page_printf("\f");
OS_ALARM *blaat = OSAlarmActiveList;
while (blaat)
{
page_printf("%u->", blaat->OSAlarmTime);
blaat = blaat->OSAlarmNext;
}
page_printf("NULL\n");
}
#endif
#endif /* #if (OS_VERSION >= 251) && (OS_ALARM_EN > 0) && (OS_MAX_ALARMS > 0) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -