Alarm library for use with mbed.

Committer:
charlesgt
Date:
Mon Nov 15 23:22:07 2010 +0000
Revision:
2:23e65cacea5a
Parent:
1:f4c7f13e5553
can now set within within expiry function

Who changed what in which revision?

UserRevisionLine numberNew contents of line
charlesgt 0:33dddd0644c5 1 #include "mbed.h"
charlesgt 0:33dddd0644c5 2 #include "AlarmTimeDate.h"
charlesgt 0:33dddd0644c5 3
charlesgt 2:23e65cacea5a 4 volatile uint8_t AlarmTimeDate::iRTCIsSet = 0u;
charlesgt 2:23e65cacea5a 5 volatile uint8_t AlarmTimeDate::iIsrCount = 0u;
charlesgt 2:23e65cacea5a 6 volatile uint8_t AlarmTimeDate::iPad0 = 0u;
charlesgt 2:23e65cacea5a 7 volatile uint8_t AlarmTimeDate::iPad1 = 0u;
charlesgt 2:23e65cacea5a 8
charlesgt 0:33dddd0644c5 9 static AlarmTimeDate* list = NULL;
charlesgt 0:33dddd0644c5 10
charlesgt 0:33dddd0644c5 11 void AlarmTimeDate::PrintAlarm() {
charlesgt 0:33dddd0644c5 12 if (!iTime) printf("Alarm %x is not set\n",this);
charlesgt 0:33dddd0644c5 13 else printf("Alarm %x will expire next at %s\n",this,ctime(&iTime));
charlesgt 0:33dddd0644c5 14 }
charlesgt 0:33dddd0644c5 15
charlesgt 0:33dddd0644c5 16 void AlarmTimeDate::PrintAlarms() {
charlesgt 0:33dddd0644c5 17 AlarmTimeDate* p = list;
charlesgt 0:33dddd0644c5 18 while (p) {
charlesgt 0:33dddd0644c5 19 p->PrintAlarm();
charlesgt 0:33dddd0644c5 20 p = p->iNext;
charlesgt 0:33dddd0644c5 21 }
charlesgt 0:33dddd0644c5 22 }
charlesgt 0:33dddd0644c5 23
charlesgt 0:33dddd0644c5 24 AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr)
charlesgt 0:33dddd0644c5 25 :iTime(0),iFn(aFn),iPtr(aPtr) {
charlesgt 0:33dddd0644c5 26 Queue();
charlesgt 0:33dddd0644c5 27 }
charlesgt 0:33dddd0644c5 28
charlesgt 0:33dddd0644c5 29 AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, int aHours,
charlesgt 0:33dddd0644c5 30 int aMins, int aSecs, int aDayM, int aMon, int aYear)
charlesgt 0:33dddd0644c5 31 :iFn(aFn),iPtr(aPtr) {
charlesgt 0:33dddd0644c5 32 struct tm sectm;
charlesgt 0:33dddd0644c5 33 sectm.tm_sec = aSecs;
charlesgt 0:33dddd0644c5 34 sectm.tm_min = aMins;
charlesgt 0:33dddd0644c5 35 sectm.tm_hour = aHours;
charlesgt 0:33dddd0644c5 36 sectm.tm_mday = aDayM;
charlesgt 0:33dddd0644c5 37 sectm.tm_mon = aMon-1;
charlesgt 0:33dddd0644c5 38 sectm.tm_year = aYear-1970;
charlesgt 0:33dddd0644c5 39 iTime = mktime(&sectm);
charlesgt 0:33dddd0644c5 40 Queue();
charlesgt 0:33dddd0644c5 41 }
charlesgt 0:33dddd0644c5 42
charlesgt 0:33dddd0644c5 43 AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, int aHours, int aMins,
charlesgt 0:33dddd0644c5 44 int aSecs, bool aSkipWeekends)
charlesgt 0:33dddd0644c5 45 :iFn(aFn),iPtr(aPtr) {
charlesgt 0:33dddd0644c5 46 // current time
charlesgt 0:33dddd0644c5 47 time_t seconds = time(NULL);
charlesgt 0:33dddd0644c5 48 struct tm * sectm = localtime(&seconds);
charlesgt 0:33dddd0644c5 49 sectm->tm_sec = aSecs;
charlesgt 0:33dddd0644c5 50 sectm->tm_min = aMins;
charlesgt 0:33dddd0644c5 51 sectm->tm_hour = aHours;
charlesgt 0:33dddd0644c5 52 time_t secs2 = mktime(sectm);
charlesgt 0:33dddd0644c5 53 if (secs2<=seconds) {
charlesgt 0:33dddd0644c5 54 secs2+=24*3600; // move forward one day if alarm is set for hours:mins:secs before current time
charlesgt 0:33dddd0644c5 55 sectm = localtime(&secs2);
charlesgt 0:33dddd0644c5 56 }
charlesgt 0:33dddd0644c5 57 if (aSkipWeekends && !sectm->tm_wday) { // set on a Sunday but skipping weekends move to Monday
charlesgt 0:33dddd0644c5 58 secs2+=24*3600; // move forward one day if alarm is set for hours:mins:secs before current time
charlesgt 0:33dddd0644c5 59 sectm = localtime(&secs2);
charlesgt 0:33dddd0644c5 60 }
charlesgt 0:33dddd0644c5 61 if (aSkipWeekends && sectm->tm_wday==6) { // set on a Saturday but skipping weekends move to Monday
charlesgt 0:33dddd0644c5 62 secs2+=2*24*3600; // move forward one day if alarm is set for hours:mins:secs before current time
charlesgt 0:33dddd0644c5 63 sectm = localtime(&secs2);
charlesgt 0:33dddd0644c5 64 }
charlesgt 0:33dddd0644c5 65 iTime = mktime(sectm);
charlesgt 0:33dddd0644c5 66 if (aSkipWeekends) SetRepeat(EDailyNoWeeked);
charlesgt 0:33dddd0644c5 67 else SetRepeat(EDaily);
charlesgt 0:33dddd0644c5 68 Queue();
charlesgt 0:33dddd0644c5 69 }
charlesgt 0:33dddd0644c5 70
charlesgt 0:33dddd0644c5 71 AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, int aHours, int aMins,
charlesgt 0:33dddd0644c5 72 int aSecs, int aDayW, bool aFortNightly)
charlesgt 0:33dddd0644c5 73 :iFn(aFn),iPtr(aPtr) {
charlesgt 0:33dddd0644c5 74 // current time
charlesgt 0:33dddd0644c5 75 time_t seconds = time(NULL);
charlesgt 0:33dddd0644c5 76 struct tm * sectm = localtime(&seconds);
charlesgt 0:33dddd0644c5 77 sectm->tm_sec = aSecs;
charlesgt 0:33dddd0644c5 78 sectm->tm_min = aMins;
charlesgt 0:33dddd0644c5 79 sectm->tm_hour = aHours;
charlesgt 0:33dddd0644c5 80 sectm->tm_wday = aDayW;
charlesgt 0:33dddd0644c5 81 time_t secs2 = mktime(sectm);
charlesgt 0:33dddd0644c5 82 if (secs2<=seconds && !aFortNightly) {
charlesgt 0:33dddd0644c5 83 secs2+=7*24*3600; // move forward one week if alarm is set for hours:mins:secs:week day before current time
charlesgt 0:33dddd0644c5 84 sectm = localtime(&secs2);
charlesgt 0:33dddd0644c5 85 }
charlesgt 0:33dddd0644c5 86 if (secs2<=seconds && !aFortNightly) {
charlesgt 0:33dddd0644c5 87 secs2+=14*24*3600; // move forward one fornight if alarm is set for hours:mins:secs:week day before current time
charlesgt 0:33dddd0644c5 88 sectm = localtime(&secs2);
charlesgt 0:33dddd0644c5 89 }
charlesgt 0:33dddd0644c5 90 iTime = mktime(sectm);
charlesgt 0:33dddd0644c5 91 if (aFortNightly) SetRepeat(EFortNightly);
charlesgt 0:33dddd0644c5 92 else SetRepeat(EWeekly);
charlesgt 0:33dddd0644c5 93 Queue();
charlesgt 0:33dddd0644c5 94 }
charlesgt 0:33dddd0644c5 95
charlesgt 0:33dddd0644c5 96 AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, int aHours, int aMins,
charlesgt 0:33dddd0644c5 97 int aSecs, int aDayM)
charlesgt 0:33dddd0644c5 98 :iFn(aFn),iPtr(aPtr) {
charlesgt 0:33dddd0644c5 99 // current time
charlesgt 0:33dddd0644c5 100 time_t seconds = time(NULL);
charlesgt 0:33dddd0644c5 101 struct tm * sectm = localtime(&seconds);
charlesgt 0:33dddd0644c5 102 sectm->tm_sec = aSecs;
charlesgt 0:33dddd0644c5 103 sectm->tm_min = aMins;
charlesgt 0:33dddd0644c5 104 sectm->tm_hour = aHours;
charlesgt 0:33dddd0644c5 105 sectm->tm_mday = aDayM;
charlesgt 0:33dddd0644c5 106 time_t secs2 = mktime(sectm);
charlesgt 0:33dddd0644c5 107 if (secs2<=seconds) {
charlesgt 0:33dddd0644c5 108 if (sectm->tm_mon==11) {
charlesgt 0:33dddd0644c5 109 sectm->tm_mon = 0;
charlesgt 0:33dddd0644c5 110 sectm->tm_year++;
charlesgt 0:33dddd0644c5 111 } else {
charlesgt 0:33dddd0644c5 112 sectm->tm_mon++;
charlesgt 0:33dddd0644c5 113 }
charlesgt 0:33dddd0644c5 114 }
charlesgt 0:33dddd0644c5 115 iTime = mktime(sectm);
charlesgt 0:33dddd0644c5 116 SetRepeat(EMonthly);
charlesgt 0:33dddd0644c5 117 Queue();
charlesgt 0:33dddd0644c5 118 }
charlesgt 0:33dddd0644c5 119
charlesgt 0:33dddd0644c5 120 AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, int aHours, int aMins,
charlesgt 0:33dddd0644c5 121 int aSecs, int aDayM, int aMon)
charlesgt 0:33dddd0644c5 122 :iFn(aFn),iPtr(aPtr) {
charlesgt 0:33dddd0644c5 123 // current time
charlesgt 0:33dddd0644c5 124 time_t seconds = time(NULL);
charlesgt 0:33dddd0644c5 125 struct tm * sectm = localtime(&seconds);
charlesgt 0:33dddd0644c5 126 sectm->tm_sec = aSecs;
charlesgt 0:33dddd0644c5 127 sectm->tm_min = aMins;
charlesgt 0:33dddd0644c5 128 sectm->tm_hour = aHours;
charlesgt 0:33dddd0644c5 129 sectm->tm_mday = aDayM;
charlesgt 0:33dddd0644c5 130 sectm->tm_mon = aMon-1;
charlesgt 0:33dddd0644c5 131 time_t secs2 = mktime(sectm);
charlesgt 0:33dddd0644c5 132 if (secs2<=seconds) { // if programmed late in the year
charlesgt 0:33dddd0644c5 133 sectm->tm_year++;
charlesgt 0:33dddd0644c5 134 }
charlesgt 0:33dddd0644c5 135 iTime = mktime(sectm);
charlesgt 0:33dddd0644c5 136 SetRepeat(EYearly);
charlesgt 0:33dddd0644c5 137 Queue();
charlesgt 0:33dddd0644c5 138 }
charlesgt 0:33dddd0644c5 139
charlesgt 0:33dddd0644c5 140 AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, struct tm* aTm )
charlesgt 0:33dddd0644c5 141 :iFn(aFn),iPtr(aPtr) {
charlesgt 0:33dddd0644c5 142 iTime = mktime(aTm);
charlesgt 0:33dddd0644c5 143 Queue();
charlesgt 0:33dddd0644c5 144 }
charlesgt 0:33dddd0644c5 145
charlesgt 0:33dddd0644c5 146 AlarmTimeDate::AlarmTimeDate(AlarmCbFn aFn, void* aPtr, time_t aSec )
charlesgt 0:33dddd0644c5 147 :iTime(aSec),iFn(aFn),iPtr(aPtr) {
charlesgt 0:33dddd0644c5 148 Queue();
charlesgt 0:33dddd0644c5 149 }
charlesgt 0:33dddd0644c5 150
charlesgt 0:33dddd0644c5 151 AlarmTimeDate::~AlarmTimeDate() {
charlesgt 0:33dddd0644c5 152 DeQueue();
charlesgt 0:33dddd0644c5 153 Tick(NULL,NULL);
charlesgt 0:33dddd0644c5 154 }
charlesgt 0:33dddd0644c5 155
charlesgt 0:33dddd0644c5 156 void AlarmTimeDate::Queue() {
charlesgt 0:33dddd0644c5 157 iNext = list;
charlesgt 0:33dddd0644c5 158 list = this;
charlesgt 0:33dddd0644c5 159 Tick(NULL,NULL);
charlesgt 0:33dddd0644c5 160 }
charlesgt 0:33dddd0644c5 161
charlesgt 0:33dddd0644c5 162 void AlarmTimeDate::DeQueue() {
charlesgt 0:33dddd0644c5 163 AlarmTimeDate* p = list;
charlesgt 0:33dddd0644c5 164 AlarmTimeDate* prev = NULL;
charlesgt 0:33dddd0644c5 165 while (p) {
charlesgt 0:33dddd0644c5 166 if (p==this) {
charlesgt 0:33dddd0644c5 167 if (!prev) list = iNext;
charlesgt 0:33dddd0644c5 168 else {
charlesgt 0:33dddd0644c5 169 prev->iNext = iNext;
charlesgt 0:33dddd0644c5 170 }
charlesgt 0:33dddd0644c5 171 break;
charlesgt 0:33dddd0644c5 172 }
charlesgt 0:33dddd0644c5 173 prev = p;
charlesgt 0:33dddd0644c5 174 p = p->iNext;
charlesgt 0:33dddd0644c5 175 }
charlesgt 0:33dddd0644c5 176 }
charlesgt 0:33dddd0644c5 177
charlesgt 0:33dddd0644c5 178 void AlarmTimeDate::Set() {
charlesgt 2:23e65cacea5a 179 time_t seconds = time(NULL);
charlesgt 2:23e65cacea5a 180 if (iTime <= seconds) seconds++;
charlesgt 2:23e65cacea5a 181 else seconds = iTime;
charlesgt 2:23e65cacea5a 182 struct tm* localt = localtime(&seconds);
charlesgt 2:23e65cacea5a 183 __disable_irq();
charlesgt 2:23e65cacea5a 184 iRTCIsSet = 1;
charlesgt 0:33dddd0644c5 185 LPC_RTC->ALSEC = localt->tm_sec;
charlesgt 0:33dddd0644c5 186 LPC_RTC->ALMIN = localt->tm_min;
charlesgt 0:33dddd0644c5 187 LPC_RTC->ALHOUR = localt->tm_hour;
charlesgt 0:33dddd0644c5 188 LPC_RTC->ALDOM = localt->tm_mday;
charlesgt 0:33dddd0644c5 189 LPC_RTC->ALMON = localt->tm_mon+1;
charlesgt 0:33dddd0644c5 190 LPC_RTC->ALYEAR = localt->tm_year+1900;
charlesgt 0:33dddd0644c5 191 LPC_RTC->AMR = (uint8_t)~0xcfu; // match those above
charlesgt 2:23e65cacea5a 192 __enable_irq();
charlesgt 0:33dddd0644c5 193 }
charlesgt 0:33dddd0644c5 194
charlesgt 0:33dddd0644c5 195 void AlarmTimeDate::Expire() {
charlesgt 2:23e65cacea5a 196 time_t expiry = time(NULL);
charlesgt 1:f4c7f13e5553 197 iFn(iPtr);
charlesgt 0:33dddd0644c5 198 struct tm * sectm;
charlesgt 0:33dddd0644c5 199 switch (Repeat()) {
charlesgt 0:33dddd0644c5 200 case EDaily:
charlesgt 0:33dddd0644c5 201 iTime+=24*3600;
charlesgt 0:33dddd0644c5 202 break;
charlesgt 0:33dddd0644c5 203 case EDailyNoWeeked:
charlesgt 0:33dddd0644c5 204 sectm = localtime(&iTime);
charlesgt 0:33dddd0644c5 205 if (sectm->tm_wday==6)
charlesgt 2:23e65cacea5a 206 iTime+=2*24*3600; // its friday, skip it to sunday
charlesgt 0:33dddd0644c5 207 iTime+=24*3600;
charlesgt 2:23e65cacea5a 208 break;
charlesgt 0:33dddd0644c5 209 case EWeekly:
charlesgt 0:33dddd0644c5 210 iTime+=7*24*3600;
charlesgt 0:33dddd0644c5 211 break;
charlesgt 0:33dddd0644c5 212 case EFortNightly:
charlesgt 0:33dddd0644c5 213 iTime+=14*24*3600;
charlesgt 0:33dddd0644c5 214 break;
charlesgt 0:33dddd0644c5 215 case EMonthly:
charlesgt 0:33dddd0644c5 216 sectm = localtime(&iTime);
charlesgt 2:23e65cacea5a 217 if (++sectm->tm_mon==12) {
charlesgt 2:23e65cacea5a 218 sectm->tm_mon=0;
charlesgt 0:33dddd0644c5 219 sectm->tm_year++;
charlesgt 0:33dddd0644c5 220 }
charlesgt 0:33dddd0644c5 221 iTime = mktime(sectm);
charlesgt 0:33dddd0644c5 222 break;
charlesgt 0:33dddd0644c5 223 case EYearly:
charlesgt 0:33dddd0644c5 224 sectm = localtime(&iTime);
charlesgt 0:33dddd0644c5 225 sectm->tm_year++;
charlesgt 0:33dddd0644c5 226 iTime = mktime(sectm);
charlesgt 0:33dddd0644c5 227 break;
charlesgt 0:33dddd0644c5 228 default:
charlesgt 2:23e65cacea5a 229 // could have been reset
charlesgt 2:23e65cacea5a 230 if ( expiry >= iTime ) iTime = 0;
charlesgt 0:33dddd0644c5 231 }
charlesgt 0:33dddd0644c5 232 }
charlesgt 0:33dddd0644c5 233
charlesgt 0:33dddd0644c5 234 void AlarmTimeDate::Init() {
charlesgt 0:33dddd0644c5 235 LPC_RTC->CIIR = 0;
charlesgt 0:33dddd0644c5 236 LPC_RTC->ILR = 0x3;
charlesgt 0:33dddd0644c5 237 LPC_RTC->AMR = 0xffu;
charlesgt 0:33dddd0644c5 238 NVIC_SetVector(RTC_IRQn, (uint32_t)&RTCISR);
charlesgt 0:33dddd0644c5 239 NVIC_EnableIRQ(RTC_IRQn);
charlesgt 0:33dddd0644c5 240 }
charlesgt 0:33dddd0644c5 241
charlesgt 0:33dddd0644c5 242 void AlarmTimeDate::RTCISR() {
charlesgt 0:33dddd0644c5 243 LPC_RTC->ILR = 0x3;
charlesgt 2:23e65cacea5a 244 iRTCIsSet = 0;
charlesgt 2:23e65cacea5a 245 iIsrCount++;
charlesgt 2:23e65cacea5a 246 printf("I:%d\n",iIsrCount);
charlesgt 0:33dddd0644c5 247 }
charlesgt 0:33dddd0644c5 248
charlesgt 0:33dddd0644c5 249 void AlarmTimeDate::Tick(SleepFn aFn,void* aParam) {
charlesgt 2:23e65cacea5a 250 redo:
charlesgt 2:23e65cacea5a 251 printf("ticking %d\n",++iPad0);
charlesgt 2:23e65cacea5a 252 if (aFn) printf("Sleeping at %x\n",time(NULL));
charlesgt 2:23e65cacea5a 253 if (aFn && iRTCIsSet) {
charlesgt 2:23e65cacea5a 254 aFn(aParam);
charlesgt 2:23e65cacea5a 255 }
charlesgt 2:23e65cacea5a 256 __disable_irq();
charlesgt 2:23e65cacea5a 257 if (iIsrCount) iIsrCount--;
charlesgt 2:23e65cacea5a 258 __enable_irq();
charlesgt 2:23e65cacea5a 259 if (aFn ) printf("waking at %x\n",time(NULL));
charlesgt 0:33dddd0644c5 260 AlarmTimeDate* p = list;
charlesgt 0:33dddd0644c5 261 AlarmTimeDate* toSet = NULL;
charlesgt 0:33dddd0644c5 262 time_t seconds = time(NULL);
charlesgt 0:33dddd0644c5 263 time_t toSetTime = 0;
charlesgt 0:33dddd0644c5 264 while (p) {
charlesgt 0:33dddd0644c5 265 if (p->iTime && p->iTime <= seconds) p->Expire();
charlesgt 0:33dddd0644c5 266 p = p->iNext;
charlesgt 0:33dddd0644c5 267 }
charlesgt 0:33dddd0644c5 268 p = list;
charlesgt 0:33dddd0644c5 269 while (p) {
charlesgt 0:33dddd0644c5 270 if (p->iTime) {
charlesgt 0:33dddd0644c5 271 if (!toSet) {
charlesgt 0:33dddd0644c5 272 toSet = p;
charlesgt 0:33dddd0644c5 273 toSetTime = p->iTime;
charlesgt 0:33dddd0644c5 274 } else {
charlesgt 0:33dddd0644c5 275 if (p->iTime < toSetTime) {
charlesgt 0:33dddd0644c5 276 toSet = p;
charlesgt 0:33dddd0644c5 277 toSetTime = p->iTime;
charlesgt 0:33dddd0644c5 278 }
charlesgt 0:33dddd0644c5 279 }
charlesgt 0:33dddd0644c5 280 };
charlesgt 0:33dddd0644c5 281 p = p->iNext;
charlesgt 0:33dddd0644c5 282 }
charlesgt 0:33dddd0644c5 283 if (toSet) {
charlesgt 2:23e65cacea5a 284 printf("found something to set %x\n",toSet->iTime);
charlesgt 0:33dddd0644c5 285 toSet->Set();
charlesgt 0:33dddd0644c5 286 }
charlesgt 2:23e65cacea5a 287
charlesgt 2:23e65cacea5a 288 printf("ticking done %d:%d\n",--iPad0,iIsrCount);
charlesgt 2:23e65cacea5a 289 if (iIsrCount) goto redo;
charlesgt 2:23e65cacea5a 290 }