Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1702 | - | 1 | /* Copyright (C) 2010-2011 Circuits At Home, LTD. All rights reserved. |
2 | |||
3 | This software may be distributed and modified under the terms of the GNU |
||
4 | General Public License version 2 (GPL2) as published by the Free Software |
||
5 | Foundation and appearing in the file GPL2.TXT included in the packaging of |
||
6 | this file. Please note that GPL2 Section 2[b] requires that all works based |
||
7 | on this software must also be made publicly available under the terms of |
||
8 | the GPL2 ("Copyleft"). |
||
9 | |||
10 | Contact information |
||
11 | ------------------- |
||
12 | |||
13 | Circuits At Home, LTD |
||
14 | Web : http://www.circuitsathome.com |
||
15 | e-mail : support@circuitsathome.com |
||
16 | */ |
||
17 | #ifndef __SCHEDULER_H__ |
||
18 | #define __SCHEDULER_H__ |
||
19 | |||
20 | #include <inttypes.h> |
||
21 | #include <avr/pgmspace.h> |
||
22 | #include <../Time/Time.h> |
||
23 | #include "WProgram.h" |
||
24 | |||
25 | #define DO_IT_FOREVER 0xFF |
||
26 | #define INVALID_TASK_ID 0xFF |
||
27 | #define IS_LEAP_YEAR(Y) ( ((Y)>0) && !((Y)%4) && ( ((Y)%100) || !((Y)%400) ) ) |
||
28 | #define DAYS_PER_YEAR(Y) ( ((IS_LEAP_YEAR((Y))) ? 366 : 365) ) |
||
29 | |||
30 | typedef void (*TaskCallback)(); |
||
31 | |||
32 | uint8_t DaysPerMonth(time_t t); |
||
33 | |||
34 | class SimpleClock |
||
35 | { |
||
36 | time_t unixTime; |
||
37 | |||
38 | public: |
||
39 | SimpleClock() : unixTime(0) {}; |
||
40 | SimpleClock(time_t time) : unixTime(time) {}; |
||
41 | bool SetTime(time_t time) { if (!time) return false; unixTime = time; return true; }; |
||
42 | time_t GetTime() { return unixTime; }; |
||
43 | void IncrementTime() { ++unixTime; }; |
||
44 | }; |
||
45 | |||
46 | class SchedulerTask |
||
47 | { |
||
48 | public: |
||
49 | enum PeriodTypes { enOnce, enHourly, enDaily, enWeekly, enMonthly, enYearly }; |
||
50 | |||
51 | struct TaskAttributes |
||
52 | { |
||
53 | uint8_t bmAllocated : 1; |
||
54 | uint8_t bmTaskSet : 1; |
||
55 | uint8_t bmEnabled : 1; |
||
56 | uint8_t bmPeriodType : 3; |
||
57 | }; |
||
58 | |||
59 | TaskAttributes taskAttribs; |
||
60 | |||
61 | uint8_t countDown; |
||
62 | time_t timeToFire; |
||
63 | TaskCallback pCallback; |
||
64 | |||
65 | bool IsAllocated() { return (taskAttribs.bmAllocated == 1); }; |
||
66 | bool IsEnabled() { return (taskAttribs.bmEnabled == 1); }; |
||
67 | bool IsSet() { return (taskAttribs.bmTaskSet == 1); }; |
||
68 | |||
69 | protected: |
||
70 | virtual bool UpdateTime(); // updates time for the next extcution time |
||
71 | |||
72 | public: |
||
73 | SchedulerTask() : |
||
74 | countDown(0), |
||
75 | timeToFire(0), |
||
76 | pCallback(NULL) |
||
77 | { *((uint8_t*)&taskAttribs) = 0; }; |
||
78 | |||
79 | void SetAllocated(bool bAllocated) { taskAttribs.bmAllocated = (bAllocated) ? 1 : 0; }; |
||
80 | void SetEnabled(bool bEnabled) { taskAttribs.bmEnabled = (bEnabled) ? 1 : 0; }; |
||
81 | bool Set(TaskCallback pfunc, uint8_t pt, time_t time, uint8_t num = DO_IT_FOREVER); |
||
82 | bool Reset() { timeToFire = 0; *((uint8_t*)&taskAttribs) = 0; pCallback = NULL; countDown = 0; }; |
||
83 | virtual bool Run(time_t time); |
||
84 | }; |
||
85 | |||
86 | template <class TASK_TYPE, const uint8_t MAX_TASKS> |
||
87 | class Scheduler : public SimpleClock |
||
88 | { |
||
89 | TASK_TYPE taskList[MAX_TASKS]; |
||
90 | |||
91 | uint8_t AllocateTask(); |
||
92 | void DeallocateTask(uint8_t task_id); |
||
93 | uint8_t CreateTask(const TaskCallback task, uint8_t type, time_t time, uint8_t num); |
||
94 | |||
95 | public: |
||
96 | uint8_t DailyTask(TaskCallback task, uint8_t hours = 0, uint8_t mins = 0, uint8_t secs = 0, uint8_t num = DO_IT_FOREVER); |
||
97 | uint8_t WeeklyTask(TaskCallback task, uint8_t dow = 1, uint8_t hours = 0, uint8_t mins = 0, uint8_t secs = 0, uint8_t num = DO_IT_FOREVER); |
||
98 | uint8_t MonthlyTask(TaskCallback task, uint8_t day = 0, uint8_t hours = 0, uint8_t mins = 0, uint8_t secs = 0, uint8_t num = DO_IT_FOREVER); |
||
99 | uint8_t YearlyTask(TaskCallback task, uint8_t mon, uint8_t day = 1, uint8_t hours = 0, uint8_t mins = 0, uint8_t secs = 0, uint8_t num = DO_IT_FOREVER); |
||
100 | void KillTask(uint8_t task_id) { DeallocateTask(task_id); }; |
||
101 | bool Run(); |
||
102 | }; |
||
103 | |||
104 | template <class TASK_TYPE, const uint8_t MAX_TASKS> |
||
105 | uint8_t Scheduler<TASK_TYPE, MAX_TASKS>::AllocateTask() |
||
106 | { |
||
107 | for (uint8_t i=0; i<MAX_TASKS; i++) |
||
108 | if (!taskList[i].IsAllocated()) |
||
109 | { |
||
110 | taskList[i].SetAllocated(true); |
||
111 | return i; |
||
112 | } |
||
113 | return INVALID_TASK_ID; |
||
114 | } |
||
115 | |||
116 | template <class TASK_TYPE, const uint8_t MAX_TASKS> |
||
117 | void Scheduler<TASK_TYPE, MAX_TASKS>::DeallocateTask(uint8_t id) |
||
118 | { |
||
119 | taskList[id].Reset(); |
||
120 | taskList[id].SetAllocated(false); |
||
121 | } |
||
122 | |||
123 | template <class TASK_TYPE, const uint8_t MAX_TASKS> |
||
124 | uint8_t Scheduler<TASK_TYPE, MAX_TASKS>::CreateTask(const TaskCallback task, uint8_t type, time_t time, uint8_t num) |
||
125 | { |
||
126 | uint8_t id = AllocateTask(); |
||
127 | |||
128 | if (id == INVALID_TASK_ID) |
||
129 | return INVALID_TASK_ID; |
||
130 | |||
131 | if (taskList[id].Set(task, type, time, num)) |
||
132 | { |
||
133 | taskList[id].SetEnabled(true); |
||
134 | return id; |
||
135 | } |
||
136 | else |
||
137 | DeallocateTask(id); |
||
138 | |||
139 | return INVALID_TASK_ID; |
||
140 | } |
||
141 | |||
142 | template <class TASK_TYPE, const uint8_t MAX_TASKS> |
||
143 | uint8_t Scheduler<TASK_TYPE, MAX_TASKS>::DailyTask(TaskCallback task, uint8_t hours, uint8_t mins, uint8_t secs, uint8_t num) |
||
144 | { |
||
145 | if (hours > 23 || mins > 59 || secs > 59) |
||
146 | return INVALID_TASK_ID; |
||
147 | |||
148 | time_t time = GetTime(); |
||
149 | |||
150 | tmElements_t tm; |
||
151 | tm.Hour = hours; |
||
152 | tm.Minute = mins; |
||
153 | tm.Second = secs; |
||
154 | tm.Day = day(time); |
||
155 | tm.Month = month(time); |
||
156 | tm.Year = year(time); |
||
157 | time_t t = makeTime(tm); |
||
158 | |||
159 | if (t < time) |
||
160 | t += SECS_PER_DAY; |
||
161 | |||
162 | return CreateTask(task, SchedulerTask::enDaily, t, num); |
||
163 | } |
||
164 | |||
165 | template <class TASK_TYPE, const uint8_t MAX_TASKS> |
||
166 | uint8_t Scheduler<TASK_TYPE, MAX_TASKS>::WeeklyTask(TaskCallback task, uint8_t dow, uint8_t hours, uint8_t mins, uint8_t secs, uint8_t num) |
||
167 | { |
||
168 | if (hours > 23 || mins > 59 || secs > 59 || dow < 1 || dow > 7) |
||
169 | return INVALID_TASK_ID; |
||
170 | |||
171 | time_t time = GetTime(); |
||
172 | |||
173 | tmElements_t tm; |
||
174 | tm.Hour = hours; |
||
175 | tm.Minute = mins; |
||
176 | tm.Second = secs; |
||
177 | tm.Day = day(time); |
||
178 | tm.Month = month(time); |
||
179 | tm.Year = year(time); |
||
180 | time_t t = makeTime(tm); |
||
181 | |||
182 | uint8_t wd = weekday(time); |
||
183 | uint8_t days_to_add = (wd < dow) ? dow - wd : 7 - wd + dow; |
||
184 | |||
185 | if (days_to_add) |
||
186 | t += days_to_add * SECS_PER_DAY; |
||
187 | |||
188 | if (t < time) |
||
189 | t+= SECS_PER_WEEK; |
||
190 | |||
191 | return CreateTask(task, SchedulerTask::enWeekly, t, num); |
||
192 | } |
||
193 | |||
194 | template <class TASK_TYPE, const uint8_t MAX_TASKS> |
||
195 | uint8_t Scheduler<TASK_TYPE, MAX_TASKS>::MonthlyTask(TaskCallback task, uint8_t day, uint8_t hours, uint8_t mins, uint8_t secs, uint8_t num) |
||
196 | { |
||
197 | if (hours > 23 || mins > 59 || secs > 59 || day > 31) |
||
198 | return INVALID_TASK_ID; |
||
199 | |||
200 | time_t time = GetTime(); |
||
201 | |||
202 | tmElements_t tm; |
||
203 | tm.Hour = hours; |
||
204 | tm.Minute = mins; |
||
205 | tm.Second = secs; |
||
206 | tm.Day = day; |
||
207 | tm.Month = month(time); |
||
208 | tm.Year = year(time); |
||
209 | time_t t = makeTime(tm); |
||
210 | |||
211 | if (t < time) |
||
212 | t += DaysPerMonth(t) * SECS_PER_DAY; |
||
213 | |||
214 | return CreateTask((const TaskCallback)task, SchedulerTask::enMonthly, t, (uint8_t)num); |
||
215 | } |
||
216 | |||
217 | template <class TASK_TYPE, const uint8_t MAX_TASKS> |
||
218 | uint8_t Scheduler<TASK_TYPE, MAX_TASKS>::YearlyTask(TaskCallback task, uint8_t mon, uint8_t day, uint8_t hours, uint8_t mins, uint8_t secs, uint8_t num) |
||
219 | { |
||
220 | if (hours > 23 || mins > 59 || secs > 59 || day > 31 || mon > 12) |
||
221 | return INVALID_TASK_ID; |
||
222 | |||
223 | time_t time = GetTime(); |
||
224 | uint16_t y = year(time); |
||
225 | |||
226 | tmElements_t tm; |
||
227 | tm.Hour = hours; |
||
228 | tm.Minute = mins; |
||
229 | tm.Second = secs; |
||
230 | tm.Day = day; |
||
231 | tm.Month = mon; |
||
232 | tm.Year = y; |
||
233 | time_t t = makeTime(tm); |
||
234 | |||
235 | if (t < time) |
||
236 | t += DAYS_PER_YEAR(y) * SECS_PER_DAY; |
||
237 | |||
238 | return CreateTask(task, SchedulerTask::enYearly, t, num); |
||
239 | } |
||
240 | |||
241 | template <class TASK_TYPE, const uint8_t MAX_TASKS> |
||
242 | bool Scheduler<TASK_TYPE, MAX_TASKS>::Run() |
||
243 | { |
||
244 | IncrementTime(); |
||
245 | time_t time = GetTime(); |
||
246 | |||
247 | for (uint8_t i=0; i<MAX_TASKS; i++) |
||
248 | if (!taskList[i].Run(time)) |
||
249 | return false; |
||
250 | return true; |
||
251 | } |
||
252 | |||
253 | #endif // __SCHEDULER_H__ |