Alarm library for use with mbed.
AlarmTimeDate.cpp
- Committer:
- charlesgt
- Date:
- 2010-10-31
- Revision:
- 1:f4c7f13e5553
- Parent:
- 0:33dddd0644c5
- Child:
- 2:23e65cacea5a
File content as of revision 1:f4c7f13e5553:
#include "mbed.h" #include "AlarmTimeDate.h" static AlarmTimeDate* list = NULL; void AlarmTimeDate::PrintAlarm() { if (!iTime) printf("Alarm %x is not set\n",this); else printf("Alarm %x will expire next at %s\n",this,ctime(&iTime)); } void AlarmTimeDate::PrintAlarms() { AlarmTimeDate* p = list; while (p) { p->PrintAlarm(); p = p->iNext; } } AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr) :iTime(0),iFn(aFn),iPtr(aPtr) { Queue(); } AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, int aHours, int aMins, int aSecs, int aDayM, int aMon, int aYear) :iFn(aFn),iPtr(aPtr) { struct tm sectm; sectm.tm_sec = aSecs; sectm.tm_min = aMins; sectm.tm_hour = aHours; sectm.tm_mday = aDayM; sectm.tm_mon = aMon-1; sectm.tm_year = aYear-1970; iTime = mktime(§m); Queue(); } AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, int aHours, int aMins, int aSecs, bool aSkipWeekends) :iFn(aFn),iPtr(aPtr) { // current time time_t seconds = time(NULL); struct tm * sectm = localtime(&seconds); sectm->tm_sec = aSecs; sectm->tm_min = aMins; sectm->tm_hour = aHours; time_t secs2 = mktime(sectm); if (secs2<=seconds) { secs2+=24*3600; // move forward one day if alarm is set for hours:mins:secs before current time sectm = localtime(&secs2); } if (aSkipWeekends && !sectm->tm_wday) { // set on a Sunday but skipping weekends move to Monday secs2+=24*3600; // move forward one day if alarm is set for hours:mins:secs before current time sectm = localtime(&secs2); } if (aSkipWeekends && sectm->tm_wday==6) { // set on a Saturday but skipping weekends move to Monday secs2+=2*24*3600; // move forward one day if alarm is set for hours:mins:secs before current time sectm = localtime(&secs2); } iTime = mktime(sectm); if (aSkipWeekends) SetRepeat(EDailyNoWeeked); else SetRepeat(EDaily); Queue(); } AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, int aHours, int aMins, int aSecs, int aDayW, bool aFortNightly) :iFn(aFn),iPtr(aPtr) { // current time time_t seconds = time(NULL); struct tm * sectm = localtime(&seconds); sectm->tm_sec = aSecs; sectm->tm_min = aMins; sectm->tm_hour = aHours; sectm->tm_wday = aDayW; time_t secs2 = mktime(sectm); if (secs2<=seconds && !aFortNightly) { secs2+=7*24*3600; // move forward one week if alarm is set for hours:mins:secs:week day before current time sectm = localtime(&secs2); } if (secs2<=seconds && !aFortNightly) { secs2+=14*24*3600; // move forward one fornight if alarm is set for hours:mins:secs:week day before current time sectm = localtime(&secs2); } iTime = mktime(sectm); if (aFortNightly) SetRepeat(EFortNightly); else SetRepeat(EWeekly); Queue(); } AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, int aHours, int aMins, int aSecs, int aDayM) :iFn(aFn),iPtr(aPtr) { // current time time_t seconds = time(NULL); struct tm * sectm = localtime(&seconds); sectm->tm_sec = aSecs; sectm->tm_min = aMins; sectm->tm_hour = aHours; sectm->tm_mday = aDayM; time_t secs2 = mktime(sectm); if (secs2<=seconds) { if (sectm->tm_mon==11) { sectm->tm_mon = 0; sectm->tm_year++; } else { sectm->tm_mon++; } } iTime = mktime(sectm); SetRepeat(EMonthly); Queue(); } AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, int aHours, int aMins, int aSecs, int aDayM, int aMon) :iFn(aFn),iPtr(aPtr) { // current time time_t seconds = time(NULL); struct tm * sectm = localtime(&seconds); sectm->tm_sec = aSecs; sectm->tm_min = aMins; sectm->tm_hour = aHours; sectm->tm_mday = aDayM; sectm->tm_mon = aMon-1; time_t secs2 = mktime(sectm); if (secs2<=seconds) { // if programmed late in the year sectm->tm_year++; } iTime = mktime(sectm); SetRepeat(EYearly); Queue(); } AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, struct tm* aTm ) :iFn(aFn),iPtr(aPtr) { iTime = mktime(aTm); Queue(); } AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, time_t aSec ) :iTime(aSec),iFn(aFn),iPtr(aPtr) { Queue(); } AlarmTimeDate::~AlarmTimeDate() { DeQueue(); Tick(NULL,NULL); } void AlarmTimeDate::Queue() { iNext = list; list = this; Tick(NULL,NULL); } void AlarmTimeDate::DeQueue() { AlarmTimeDate* p = list; AlarmTimeDate* prev = NULL; while (p) { if (p==this) { if (!prev) list = iNext; else { prev->iNext = iNext; } break; } prev = p; p = p->iNext; } } void AlarmTimeDate::Set() { struct tm* localt = localtime(&iTime); LPC_RTC->ALSEC = localt->tm_sec; LPC_RTC->ALMIN = localt->tm_min; LPC_RTC->ALHOUR = localt->tm_hour; LPC_RTC->ALDOM = localt->tm_mday; LPC_RTC->ALMON = localt->tm_mon+1; LPC_RTC->ALYEAR = localt->tm_year+1900; LPC_RTC->AMR = (uint8_t)~0xcfu; // match those above } void AlarmTimeDate::Expire() { iFn(iPtr); struct tm * sectm; switch (Repeat()) { case EDaily: iTime+=24*3600; break; case EDailyNoWeeked: sectm = localtime(&iTime); if (sectm->tm_wday==6) iTime+=7*24*3600; // its friday, skip it to sunday iTime+=24*3600; case EWeekly: iTime+=7*24*3600; break; case EFortNightly: iTime+=14*24*3600; break; case EMonthly: sectm = localtime(&iTime); if (++sectm->tm_mon==32) { sectm->tm_mon=1; sectm->tm_year++; } iTime = mktime(sectm); break; case EYearly: sectm = localtime(&iTime); sectm->tm_year++; iTime = mktime(sectm); break; default: iTime = 0; } } void AlarmTimeDate::Init() { LPC_RTC->CIIR = 0; LPC_RTC->ILR = 0x3; LPC_RTC->AMR = 0xffu; NVIC_SetVector(RTC_IRQn, (uint32_t)&RTCISR); NVIC_EnableIRQ(RTC_IRQn); } void AlarmTimeDate::RTCISR() { LPC_RTC->ILR = 0x3; } void AlarmTimeDate::Tick(SleepFn aFn,void* aParam) { if (aFn) aFn(aParam); // sleep first AlarmTimeDate* p = list; AlarmTimeDate* toSet = NULL; time_t seconds = time(NULL); time_t toSetTime = 0; while (p) { if (p->iTime && p->iTime <= seconds) p->Expire(); p = p->iNext; } seconds = time(NULL); p = list; while (p) { if (p->iTime) { if (!toSet) { toSet = p; toSetTime = p->iTime; } else { if (p->iTime < toSetTime) { toSet = p; toSetTime = p->iTime; } } }; p = p->iNext; } if (toSet) { toSet->Set(); } }