-
Notifications
You must be signed in to change notification settings - Fork 105
/
TimeAlarms.h
187 lines (156 loc) · 7.06 KB
/
TimeAlarms.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// TimeAlarms.h - Arduino Time alarms header for use with Time library
#ifndef TimeAlarms_h
#define TimeAlarms_h
#include <Arduino.h>
#include "TimeLib.h"
#if !defined(dtNBR_ALARMS )
#if defined(__AVR__)
#define dtNBR_ALARMS 6 // max is 255
#elif defined(ESP8266)
#define dtNBR_ALARMS 20 // for esp8266 chip - max is 255
#else
#define dtNBR_ALARMS 12 // assume non-AVR has more memory
#endif
#endif
#define USE_SPECIALIST_METHODS // define this for testing
typedef enum {
dtMillisecond,
dtSecond,
dtMinute,
dtHour,
dtDay
} dtUnits_t;
typedef struct {
uint8_t alarmType :4 ; // enumeration of daily/weekly (in future:
// biweekly/semimonthly/monthly/annual)
// note that the current API only supports daily
// or weekly alarm periods
uint8_t isEnabled :1 ; // the timer is only actioned if isEnabled is true
uint8_t isOneShot :1 ; // the timer will be de-allocated after trigger is processed
} AlarmMode_t;
// new time based alarms should be added just before dtLastAlarmType
typedef enum {
dtNotAllocated,
dtTimer,
dtExplicitAlarm,
dtDailyAlarm,
dtWeeklyAlarm,
dtLastAlarmType
} dtAlarmPeriod_t ; // in future: dtBiweekly, dtMonthly, dtAnnual
// macro to return true if the given type is a time based alarm, false if timer or not allocated
#define dtIsAlarm(_type_) (_type_ >= dtExplicitAlarm && _type_ < dtLastAlarmType)
#define dtUseAbsoluteValue(_type_) (_type_ == dtTimer || _type_ == dtExplicitAlarm)
typedef uint8_t AlarmID_t;
typedef AlarmID_t AlarmId; // Arduino friendly name
#define dtINVALID_ALARM_ID 255
#define dtINVALID_TIME (time_t)(-1)
#define AlarmHMS(_hr_, _min_, _sec_) (_hr_ * SECS_PER_HOUR + _min_ * SECS_PER_MIN + _sec_)
typedef void (*OnTick_t)(); // alarm callback function typedef
// class defining an alarm instance, only used by dtAlarmsClass
class AlarmClass
{
public:
AlarmClass();
OnTick_t onTickHandler;
void updateNextTrigger();
time_t value;
time_t nextTrigger;
AlarmMode_t Mode;
};
// class containing the collection of alarms
class TimeAlarmsClass
{
private:
AlarmClass Alarm[dtNBR_ALARMS];
void serviceAlarms();
uint8_t isServicing;
uint8_t servicedAlarmId; // the alarm currently being serviced
AlarmID_t create(time_t value, OnTick_t onTickHandler, uint8_t isOneShot, dtAlarmPeriod_t alarmType);
public:
TimeAlarmsClass();
// functions to create alarms and timers
// trigger once at the given time in the future
AlarmID_t triggerOnce(time_t value, OnTick_t onTickHandler) {
if (value <= 0) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, true, dtExplicitAlarm);
}
// trigger once at given time of day
AlarmID_t alarmOnce(time_t value, OnTick_t onTickHandler) {
if (value <= 0 || value > SECS_PER_DAY) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, true, dtDailyAlarm);
}
AlarmID_t alarmOnce(const int H, const int M, const int S, OnTick_t onTickHandler) {
return alarmOnce(AlarmHMS(H,M,S), onTickHandler);
}
// trigger once on a given day and time
AlarmID_t alarmOnce(const timeDayOfWeek_t DOW, const int H, const int M, const int S, OnTick_t onTickHandler) {
time_t value = (DOW-1) * SECS_PER_DAY + AlarmHMS(H,M,S);
if (value <= 0) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, true, dtWeeklyAlarm);
}
// trigger daily at given time of day
AlarmID_t alarmRepeat(time_t value, OnTick_t onTickHandler) {
if (value > SECS_PER_DAY) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, false, dtDailyAlarm);
}
AlarmID_t alarmRepeat(const int H, const int M, const int S, OnTick_t onTickHandler) {
return alarmRepeat(AlarmHMS(H,M,S), onTickHandler);
}
// trigger weekly at a specific day and time
AlarmID_t alarmRepeat(const timeDayOfWeek_t DOW, const int H, const int M, const int S, OnTick_t onTickHandler) {
time_t value = (DOW-1) * SECS_PER_DAY + AlarmHMS(H,M,S);
if (value <= 0) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, false, dtWeeklyAlarm);
}
// trigger once after the given number of seconds
AlarmID_t timerOnce(time_t value, OnTick_t onTickHandler) {
if (value <= 0) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, true, dtTimer);
}
AlarmID_t timerOnce(const int H, const int M, const int S, OnTick_t onTickHandler) {
return timerOnce(AlarmHMS(H,M,S), onTickHandler);
}
// trigger at a regular interval
AlarmID_t timerRepeat(time_t value, OnTick_t onTickHandler) {
if (value <= 0) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, false, dtTimer);
}
AlarmID_t timerRepeat(const int H, const int M, const int S, OnTick_t onTickHandler) {
return timerRepeat(AlarmHMS(H,M,S), onTickHandler);
}
void delay(unsigned long ms);
// utility methods
uint8_t getDigitsNow( dtUnits_t Units) const; // returns the current digit value for the given time unit
void waitForDigits( uint8_t Digits, dtUnits_t Units);
void waitForRollover(dtUnits_t Units);
// low level methods
void enable(AlarmID_t ID); // enable the alarm to trigger
void disable(AlarmID_t ID); // prevent the alarm from triggering
AlarmID_t getTriggeredAlarmId() const; // returns the currently triggered alarm id
bool getIsServicing() const; // returns isServicing
void write(AlarmID_t ID, time_t value); // write the value (and enable) the alarm with the given ID
time_t read(AlarmID_t ID) const; // return the value for the given timer
dtAlarmPeriod_t readType(AlarmID_t ID) const; // return the alarm type for the given alarm ID
void free(AlarmID_t ID); // free the id to allow its reuse
#ifndef USE_SPECIALIST_METHODS
private: // the following methods are for testing and are not documented as part of the standard library
#endif
uint8_t count() const; // returns the number of allocated timers
time_t getNextTrigger() const; // returns the time of the next scheduled alarm
time_t getNextTrigger(AlarmID_t ID) const; // returns the time of scheduled alarm
bool isAllocated(AlarmID_t ID) const; // returns true if this id is allocated
bool isAlarm(AlarmID_t ID) const; // returns true if id is for a time based alarm, false if its a timer or not allocated
};
extern TimeAlarmsClass Alarm; // make an instance for the user
/*==============================================================================
* MACROS
*============================================================================*/
/* public */
#define waitUntilThisSecond(_val_) waitForDigits( _val_, dtSecond)
#define waitUntilThisMinute(_val_) waitForDigits( _val_, dtMinute)
#define waitUntilThisHour(_val_) waitForDigits( _val_, dtHour)
#define waitUntilThisDay(_val_) waitForDigits( _val_, dtDay)
#define waitMinuteRollover() waitForRollover(dtSecond)
#define waitHourRollover() waitForRollover(dtMinute)
#define waitDayRollover() waitForRollover(dtHour)
#endif /* TimeAlarms_h */