Subversion Repositories Projects

Rev

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__