Alarm library for use with mbed.
Diff: AlarmTimeDate.cpp
- Revision:
- 0:33dddd0644c5
- Child:
- 1:f4c7f13e5553
diff -r 000000000000 -r 33dddd0644c5 AlarmTimeDate.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AlarmTimeDate.cpp Sat Oct 30 23:41:22 2010 +0000 @@ -0,0 +1,262 @@ +#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() { + 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; + } + printf( "Calling %x\n",iFn); + iFn(iPtr); +} + +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) { + 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(); + } + if (aFn) aFn(aParam); +}