AskSin++
StateMachine.h
1 //- -----------------------------------------------------------------------------------------------------------------------
2 // AskSin++
3 // 2017-12-23 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
4 //- -----------------------------------------------------------------------------------------------------------------------
5 
6 #ifndef __STATE_MACHINE_H__
7 #define __STATE_MACHINE_H__
8 
9 #include "Alarm.h"
10 
11 namespace as {
12 
13 template <class PeerList>
14 class StateMachine : public Alarm {
15 
16  class ChangedAlarm : public Alarm {
18  public:
19  ChangedAlarm (StateMachine<PeerList>& s) : Alarm(0), sm(s) {}
20  virtual ~ChangedAlarm () {}
21  void set (uint32_t t,AlarmClock& clock) {
22  clock.cancel(*this);
23  Alarm::set(t);
24  clock.add(*this);
25  }
26  virtual void trigger (__attribute__((unused)) AlarmClock& clock) {
27  sm.changed(true);
28  }
29  };
30 
31 protected:
32  enum { DELAY_NO=0x00, DELAY_INFINITE=0xffffffff };
33 
34  uint8_t state : 4;
35  bool change : 1;
36  ChangedAlarm calarm;
37  PeerList actlst;
38 
39  StateMachine () : Alarm(0), state(AS_CM_JT_NONE), change(false), calarm(*this), actlst(0) {}
40  virtual ~StateMachine () {}
41 
42  virtual void trigger (__attribute__((unused)) AlarmClock& clock) {
43  uint8_t next = getNextState(state);
44  uint32_t dly = getDelayForState(next,actlst);
45  setState(next,dly,actlst);
46  }
47 
48  bool changed () const { return change; }
49  void changed (bool c) { change=c; }
50 
51  void setState (uint8_t next,uint32_t delay,const PeerList& lst=PeerList(0)) {
52  actlst = lst;
53 
54  if( next != AS_CM_JT_NONE ) {
55  // first cancel possible running alarm
56  sysclock.cancel(*this);
57  // if state is different
58  while (state != next) {
59  switchState(state, next, delay);
60  state = next;
61 
62  if (delay == DELAY_NO) {
63  // go immediately to the next state
64  next = getNextState(state);
65  delay = getDelayForState(next,lst);
66  }
67  }
68  if (delay != DELAY_INFINITE) {
69  set(delay);
70  sysclock.add(*this);
71  }
72  }
73  }
74 
75  virtual void switchState(__attribute__((unused)) uint8_t oldstate,__attribute__((unused)) uint8_t newstate, __attribute__((unused)) uint32_t) {}
76 
77  void jumpToTarget(const PeerList& lst) {
78  uint8_t next = getJumpTarget(state,lst);
79  if( next != AS_CM_JT_NONE ) {
80  // get delay for the next state
81  uint32_t dly = getDelayForState(next,lst);
82  // on/off time mode / absolute / minimal
83  if( next == state && (next == AS_CM_JT_ON || next == AS_CM_JT_OFF) && dly < DELAY_INFINITE) {
84  bool minimal = next == AS_CM_JT_ON ? lst.onTimeMode() : lst.offTimeMode();
85  // if minimal is set - we jump out if the new delay is shorter
86  if( minimal == true ) {
87  // DPRINT("Minimal");DDECLN(dly);
88  uint32_t curdly = sysclock.get(*this); // 0 means DELAY_INFINITE
89  if( curdly == 0 || curdly > dly ) {
90  // DPRINTLN(F("Skip short Delay"));
91  return;
92  }
93  }
94  }
95  // switch to next
96  setState(next,dly,lst);
97  }
98  }
99 
100  virtual uint8_t getNextState (uint8_t stat) {
101  switch( stat ) {
102  case AS_CM_JT_ONDELAY: return AS_CM_JT_REFON;
103  case AS_CM_JT_REFON: return AS_CM_JT_RAMPON;
104  case AS_CM_JT_RAMPON: return AS_CM_JT_ON;
105  case AS_CM_JT_ON: return AS_CM_JT_OFFDELAY;
106  case AS_CM_JT_OFFDELAY: return AS_CM_JT_REFOFF;
107  case AS_CM_JT_REFOFF: return AS_CM_JT_RAMPOFF;
108  case AS_CM_JT_RAMPOFF: return AS_CM_JT_OFF;
109  case AS_CM_JT_OFF: return AS_CM_JT_ONDELAY;
110  }
111  return AS_CM_JT_NONE;
112  }
113 
114  virtual uint32_t getDelayForState(uint8_t stat,const PeerList& lst) {
115  uint32_t delay = getDefaultDelay(stat);
116  if( lst.valid() == true ) {
117  uint8_t value = 0;
118  switch( stat ) {
119  case AS_CM_JT_ONDELAY: value = lst.onDly(); break;
120  case AS_CM_JT_ON: value = lst.onTime(); break;
121  case AS_CM_JT_OFFDELAY: value = lst.offDly(); break;
122  case AS_CM_JT_OFF: value = lst.offTime(); break;
123  default: return delay; break;
124  }
125  delay = AskSinBase::byteTimeCvt(value);
126  }
127  return delay;
128  }
129 
130  virtual uint32_t getDefaultDelay(uint8_t stat) const {
131  switch( stat ) {
132  case AS_CM_JT_ON:
133  case AS_CM_JT_OFF:
134  return DELAY_INFINITE;
135  }
136  return DELAY_NO;
137  }
138 
139  bool delayActive () const { return sysclock.get(*this) > 0; }
140 
141  void triggerChanged (uint32_t delay) {
142  calarm.set(delay,sysclock);
143  }
144 
145  uint8_t getJumpTarget(uint8_t stat,const PeerList& lst) const {
146  switch( stat ) {
147  case AS_CM_JT_ONDELAY: return lst.jtDlyOn();
148  case AS_CM_JT_REFON: return lst.jtRefOn();
149  case AS_CM_JT_RAMPON: return lst.jtRampOn();
150  case AS_CM_JT_ON: return lst.jtOn();
151  case AS_CM_JT_OFFDELAY: return lst.jtDlyOff();
152  case AS_CM_JT_REFOFF: return lst.jtRefOff();
153  case AS_CM_JT_RAMPOFF: return lst.jtRampOff();
154  case AS_CM_JT_OFF: return lst.jtOff();
155  }
156  return AS_CM_JT_NONE;
157  }
158 
159  uint8_t getConditionForState(uint8_t stat,const PeerList& lst) const {
160  switch( stat ) {
161  case AS_CM_JT_ONDELAY: return lst.ctDlyOn();
162  case AS_CM_JT_REFON: return lst.ctRepOn();
163  case AS_CM_JT_RAMPON: return lst.ctRampOn();
164  case AS_CM_JT_ON: return lst.ctOn();
165  case AS_CM_JT_OFFDELAY: return lst.ctDlyOff();
166  case AS_CM_JT_REFOFF: return lst.ctRepOff();
167  case AS_CM_JT_RAMPOFF: return lst.ctRampOff();
168  case AS_CM_JT_OFF: return lst.ctOff();
169  }
170  return AS_CM_CT_X_GE_COND_VALUE_LO;
171  }
172 
173  bool checkCondition (uint8_t stat,const PeerList& lst,uint8_t value) {
174  uint8_t cond = getConditionForState(stat,lst);
175  bool doit = false;
176  switch( cond ) {
177  case AS_CM_CT_X_GE_COND_VALUE_LO:
178  doit = (value >= lst.ctValLo());
179  break;
180  case AS_CM_CT_X_GE_COND_VALUE_HI:
181  doit = (value >= lst.ctValHi());
182  break;
183  case AS_CM_CT_X_LT_COND_VALUE_LO:
184  doit = (value < lst.ctValLo());
185  break;
186  case AS_CM_CT_X_LT_COND_VALUE_HI:
187  doit = (value < lst.ctValHi());
188  break;
189  case AS_CM_CT_COND_VALUE_LO_LE_X_LT_COND_VALUE_HI:
190  doit = ((lst.ctValLo() <= value) && (value < lst.ctValHi()));
191  break;
192  case AS_CM_CT_X_LT_COND_VALUE_LO_OR_X_GE_COND_VALUE_HI:
193  doit = ((value < lst.ctValLo()) || (value >= lst.ctValHi()));
194  break;
195  }
196  return doit;
197  }
198 
199 };
200 
201 }
202 
203 #endif
as::Alarm
Definition: Alarm.h:15
as::AlarmClock
Definition: AlarmClock.h:32
as::StateMachine
Definition: StateMachine.h:14