-
Notifications
You must be signed in to change notification settings - Fork 71
/
StateMachine.h
204 lines (178 loc) · 6.6 KB
/
StateMachine.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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//- -----------------------------------------------------------------------------------------------------------------------
// AskSin++
// 2017-12-23 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
//- -----------------------------------------------------------------------------------------------------------------------
#ifndef __STATE_MACHINE_H__
#define __STATE_MACHINE_H__
#include "Alarm.h"
namespace as {
template <class PeerList>
class StateMachine : public Alarm {
class ChangedAlarm : public Alarm {
enum { CHANGED=0x04 };
public:
ChangedAlarm () : Alarm(0) {}
virtual ~ChangedAlarm () {}
void set (uint32_t t,AlarmClock& clock) {
clock.cancel(*this);
Alarm::set(t);
clock.add(*this);
}
virtual void trigger (__attribute__((unused)) AlarmClock& clock) {
setflag(CHANGED);
}
bool changed () const { return hasflag(CHANGED); }
void changed (bool c) { setflag(c,CHANGED); }
};
protected:
enum { DELAY_NO=0x00, DELAY_INFINITE=0xffffffff };
uint8_t state;
ChangedAlarm calarm;
PeerList actlst;
StateMachine () : Alarm(0), state(AS_CM_JT_NONE), calarm(), actlst(0) {}
virtual ~StateMachine () {}
virtual void trigger (__attribute__((unused)) AlarmClock& clock) {
uint8_t next = getNextState(state);
uint32_t dly = getDelayForState(next,actlst);
setState(next,dly,actlst);
}
bool changed () const { return calarm.changed(); }
void changed (bool c) { calarm.changed(c); }
void setState (uint8_t next,uint32_t delay,const PeerList& lst=PeerList(0)) {
actlst = lst;
if( next != AS_CM_JT_NONE ) {
// first cancel possible running alarm
sysclock.cancel(*this);
// if state is different
while (state != next) {
switchState(state, next, delay);
state = next;
if (delay == DELAY_NO) {
// go immediately to the next state
next = getNextState(state);
delay = getDelayForState(next,lst);
}
}
if (delay != DELAY_INFINITE) {
set(delay);
sysclock.add(*this);
}
}
}
virtual void switchState(__attribute__((unused)) uint8_t oldstate,__attribute__((unused)) uint8_t newstate, __attribute__((unused)) uint32_t) {}
void jumpToTarget(const PeerList& lst) {
uint8_t next = getJumpTarget(state,lst);
if( next != AS_CM_JT_NONE ) {
// get delay for the next state
uint32_t dly = getDelayForState(next,lst);
// on/off time mode / absolute / minimal
if( next == state && (next == AS_CM_JT_ON || next == AS_CM_JT_OFF) && dly < DELAY_INFINITE) {
bool minimal = next == AS_CM_JT_ON ? lst.onTimeMode() : lst.offTimeMode();
// if minimal is set - we jump out if the new delay is shorter
if( minimal == true ) {
// DPRINT("Minimal");DDECLN(dly);
uint32_t curdly = sysclock.get(*this); // 0 means DELAY_INFINITE
if( curdly == 0 || curdly > dly ) {
// DPRINTLN(F("Skip short Delay"));
return;
}
}
}
// switch to next
setState(next,dly,lst);
}
}
virtual uint8_t getNextState (uint8_t stat) {
switch( stat ) {
case AS_CM_JT_ONDELAY: return AS_CM_JT_REFON;
case AS_CM_JT_REFON: return AS_CM_JT_RAMPON;
case AS_CM_JT_RAMPON: return AS_CM_JT_ON;
case AS_CM_JT_ON: return AS_CM_JT_OFFDELAY;
case AS_CM_JT_OFFDELAY: return AS_CM_JT_REFOFF;
case AS_CM_JT_REFOFF: return AS_CM_JT_RAMPOFF;
case AS_CM_JT_RAMPOFF: return AS_CM_JT_OFF;
case AS_CM_JT_OFF: return AS_CM_JT_ONDELAY;
}
return AS_CM_JT_NONE;
}
virtual uint32_t getDelayForState(uint8_t stat,const PeerList& lst) {
uint32_t delay = getDefaultDelay(stat);
if( lst.valid() == true ) {
uint8_t value = 0;
switch( stat ) {
case AS_CM_JT_ONDELAY: value = lst.onDly(); break;
case AS_CM_JT_ON: value = lst.onTime(); break;
case AS_CM_JT_OFFDELAY: value = lst.offDly(); break;
case AS_CM_JT_OFF: value = lst.offTime(); break;
default: return delay; break;
}
delay = AskSinBase::byteTimeCvt(value);
}
return delay;
}
virtual uint32_t getDefaultDelay(uint8_t stat) const {
switch( stat ) {
case AS_CM_JT_ON:
case AS_CM_JT_OFF:
return DELAY_INFINITE;
}
return DELAY_NO;
}
bool delayActive () const { return sysclock.get(*this) > 0; }
void triggerChanged (uint32_t delay) {
calarm.set(delay,sysclock);
}
uint8_t getJumpTarget(uint8_t stat,const PeerList& lst) const {
switch( stat ) {
case AS_CM_JT_ONDELAY: return lst.jtDlyOn();
case AS_CM_JT_REFON: return lst.jtRefOn();
case AS_CM_JT_RAMPON: return lst.jtRampOn();
case AS_CM_JT_ON: return lst.jtOn();
case AS_CM_JT_OFFDELAY: return lst.jtDlyOff();
case AS_CM_JT_REFOFF: return lst.jtRefOff();
case AS_CM_JT_RAMPOFF: return lst.jtRampOff();
case AS_CM_JT_OFF: return lst.jtOff();
}
return AS_CM_JT_NONE;
}
uint8_t getConditionForState(uint8_t stat,const PeerList& lst) const {
switch( stat ) {
case AS_CM_JT_ONDELAY: return lst.ctDlyOn();
case AS_CM_JT_REFON: return lst.ctRepOn();
case AS_CM_JT_RAMPON: return lst.ctRampOn();
case AS_CM_JT_ON: return lst.ctOn();
case AS_CM_JT_OFFDELAY: return lst.ctDlyOff();
case AS_CM_JT_REFOFF: return lst.ctRepOff();
case AS_CM_JT_RAMPOFF: return lst.ctRampOff();
case AS_CM_JT_OFF: return lst.ctOff();
}
return AS_CM_CT_X_GE_COND_VALUE_LO;
}
bool checkCondition (uint8_t stat,const PeerList& lst,uint8_t value) {
uint8_t cond = getConditionForState(stat,lst);
bool doit = false;
switch( cond ) {
case AS_CM_CT_X_GE_COND_VALUE_LO:
doit = (value >= lst.ctValLo());
break;
case AS_CM_CT_X_GE_COND_VALUE_HI:
doit = (value >= lst.ctValHi());
break;
case AS_CM_CT_X_LT_COND_VALUE_LO:
doit = (value < lst.ctValLo());
break;
case AS_CM_CT_X_LT_COND_VALUE_HI:
doit = (value < lst.ctValHi());
break;
case AS_CM_CT_COND_VALUE_LO_LE_X_LT_COND_VALUE_HI:
doit = ((lst.ctValLo() <= value) && (value < lst.ctValHi()));
break;
case AS_CM_CT_X_LT_COND_VALUE_LO_OR_X_GE_COND_VALUE_HI:
doit = ((value < lst.ctValLo()) || (value >= lst.ctValHi()));
break;
}
return doit;
}
};
}
#endif