AskSin++
Switch.h
1 //- -----------------------------------------------------------------------------------------------------------------------
2 // AskSin++
3 // 2016-10-31 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
4 //- -----------------------------------------------------------------------------------------------------------------------
5 
6 #ifndef __SWITCH_H__
7 #define __SWITCH_H__
8 
9 #include "MultiChannelDevice.h"
10 #include "Register.h"
11 
12 
13 namespace as {
14 
15 DEFREGISTER(SwitchReg1,CREG_AES_ACTIVE,CREG_TRANSMITTRYMAX,CREG_POWERUPACTION,CREG_STATUSINFO)
16 
17 class SwitchList1 : public RegList1<SwitchReg1> {
18 public:
19  SwitchList1(uint16_t addr) : RegList1<SwitchReg1>(addr) {}
20  void defaults () {
21  clear ();
22  //aesActive(false);
23  transmitTryMax(6);
24  //powerUpAction(false);
25  statusInfoMinDly(4);
26  statusInfoRandom(1);
27  }
28 };
29 
30 #define SWITCH_LIST3_STANDARD_REGISTER PREG_CTDELAYONOFF,PREG_CTONOFF,PREG_CONDVALUELOW,PREG_CONDVALUEHIGH,\
31  PREG_ONDELAYTIME,PREG_ONTIME,PREG_OFFDELAYTIME,PREG_OFFTIME,PREG_ACTIONTYPE,PREG_JTONOFF,PREG_JTDELAYONOFF
32 
33 DEFREGISTER(SwitchReg3,SWITCH_LIST3_STANDARD_REGISTER)
34 
35 typedef RegList3<SwitchReg3> SwitchPeerList;
36 
37 template <class PeerRegisterListType>
38 class SwitchList3Tmpl : public ShortLongList<PeerRegisterListType> {
39 public:
40  SwitchList3Tmpl (uint16_t addr) : ShortLongList<PeerRegisterListType>(addr) {}
41  void defaults() {
42  PeerRegisterListType ssl = this->sh();
43  ssl.clear();
44 // ssl.ctDlyOn(0);
45 // ssl.ctDlyOff(0);
46 // ssl.ctOn(0);
47 // ssl.ctOff(0);
48  ssl.ctValLo(0x32);
49  ssl.ctValHi(0x64);
50 // ssl.onDly(0);
51  ssl.onTime(0xff);
52 // ssl.offDly(0);
53  ssl.offTime(0xff);
54  ssl.actionType(AS_CM_ACTIONTYPE_JUMP_TO_TARGET);
55 // ssl.offTimeMode(false);
56 // ssl.onTimeMode(false);
57 
58  ssl = this->lg();
59  ssl.clear();
60 // ssl.ctDlyOn(0);
61 // ssl.ctDlyOff(0);
62 // ssl.ctOn(0);
63 // ssl.ctOff(0);
64  ssl.ctValLo(0x32);
65  ssl.ctValHi(0x64);
66 // ssl.onDly(0);
67  ssl.onTime(0xff);
68 // ssl.offDly(0);
69  ssl.offTime(0xff);
70  ssl.actionType(AS_CM_ACTIONTYPE_JUMP_TO_TARGET);
71  ssl.multiExec(true);
72 // ssl.offTimeMode(false);
73 // ssl.onTimeMode(false);
74  }
75 
76  void odd() {
77  defaults();
78  PeerRegisterListType ssl = this->sh();
79  ssl.jtOn(AS_CM_JT_OFFDELAY);
80  ssl.jtOff(AS_CM_JT_OFF);
81  ssl.jtDlyOn(AS_CM_JT_OFF);
82  ssl.jtDlyOff(AS_CM_JT_OFF);
83  ssl = this->lg();
84  ssl.jtOn(AS_CM_JT_OFFDELAY);
85  ssl.jtOff(AS_CM_JT_OFF);
86  ssl.jtDlyOn(AS_CM_JT_OFF);
87  ssl.jtDlyOff(AS_CM_JT_OFF);
88  }
89 
90  void even() {
91  defaults();
92  PeerRegisterListType ssl = this->sh();
93  ssl.jtOn(AS_CM_JT_ON);
94  ssl.jtOff(AS_CM_JT_ONDELAY);
95  ssl.jtDlyOn(AS_CM_JT_ON);
96  ssl.jtDlyOff(AS_CM_JT_ON);
97  ssl = this->lg();
98  ssl.jtOn(AS_CM_JT_ON);
99  ssl.jtOff(AS_CM_JT_ONDELAY);
100  ssl.jtDlyOn(AS_CM_JT_ON);
101  ssl.jtDlyOff(AS_CM_JT_ON);
102  }
103 
104  void single() {
105  defaults();
106  PeerRegisterListType ssl = this->sh();
107  ssl.jtOn(AS_CM_JT_OFFDELAY);
108  ssl.jtOff(AS_CM_JT_ONDELAY);
109  ssl.jtDlyOn(AS_CM_JT_ON);
110  ssl.jtDlyOff(AS_CM_JT_OFF);
111  ssl = this->lg();
112  ssl.jtOn(AS_CM_JT_OFFDELAY);
113  ssl.jtOff(AS_CM_JT_ONDELAY);
114  ssl.jtDlyOn(AS_CM_JT_ON);
115  ssl.jtDlyOff(AS_CM_JT_OFF);
116  ssl.multiExec(false);
117  }
118 };
119 // define the standard list3 for switch devices
121 
123 
124 #define DELAY_NO 0x00
125 #define DELAY_INFINITE 0xffffffff
126 
127  class StateAlarm : public Alarm {
128  SwitchStateMachine& sm;
129  SwitchPeerList lst;
130  public:
131  StateAlarm(SwitchStateMachine& m) : Alarm(0), sm(m), lst(0) {}
132  void list(SwitchPeerList l) {lst=l;}
133  virtual void trigger (__attribute__((unused)) AlarmClock& clock) {
134  uint8_t next = sm.getNextState();
135  uint32_t dly = sm.getDelayForState(next,lst);
136  sm.setState(next,dly,lst);
137  }
138  };
139 
140  void setState (uint8_t next,uint32_t delay,const SwitchPeerList& lst=SwitchPeerList(0),uint8_t deep=0) {
141  // check deep to prevent infinite recursion
142  if( next != AS_CM_JT_NONE && deep < 4) {
143  // first cancel possible running alarm
144  sysclock.cancel(alarm);
145  // if state is different
146  if (state != next) {
147  switchState(state, next,delay);
148  state = next;
149  }
150  if (delay == DELAY_NO) {
151  // go immediately to the next state
152  next = getNextState();
153  delay = getDelayForState(next,lst);
154  setState(next, delay, lst, ++deep);
155  }
156  else if (delay != DELAY_INFINITE) {
157  alarm.list(lst);
158  alarm.set(delay);
159  sysclock.add(alarm);
160  }
161  }
162  }
163 
164 protected:
165  uint8_t state : 4;
166  bool change : 1;
167  StateAlarm alarm;
168 
169 public:
170  SwitchStateMachine() : state(AS_CM_JT_NONE), change(false), alarm(*this) {}
171  virtual ~SwitchStateMachine () {}
172 
173  bool changed () const { return change; }
174  void changed (bool c) { change=c; }
175 
176  void setup(__attribute__ ((unused)) BaseList l1) {}
177 
178  virtual void switchState(__attribute__((unused)) uint8_t oldstate,__attribute__((unused)) uint8_t newstate,__attribute__((unused)) uint32_t delay) {}
179 
180  void jumpToTarget(const SwitchPeerList& lst) {
181  uint8_t next = getJumpTarget(state,lst);
182  if( next != AS_CM_JT_NONE ) {
183  // get delay for the next state
184  uint32_t dly = getDelayForState(next,lst);
185  // on/off time mode / absolute / minimal
186  if( next == state && (next == AS_CM_JT_ON || next == AS_CM_JT_OFF) && dly < DELAY_INFINITE) {
187  bool minimal = next == AS_CM_JT_ON ? lst.onTimeMode() : lst.offTimeMode();
188  // if minimal is set - we jump out if the new delay is shorter
189  if( minimal == true ) {
190  // DPRINT("Minimal");DDECLN(dly);
191  uint32_t curdly = sysclock.get(alarm); // 0 means DELAY_INFINITE
192  if( curdly == 0 || curdly > dly ) {
193  // DPRINTLN(F("Skip short Delay"));
194  return;
195  }
196  }
197  }
198  // switch to next
199  setState(next,dly,lst);
200  }
201  }
202 
203  void toggleState () {
204  setState( state == AS_CM_JT_ON ? AS_CM_JT_OFF : AS_CM_JT_ON, DELAY_INFINITE);
205  }
206 
207  uint8_t getNextState () {
208  switch( state ) {
209  case AS_CM_JT_ONDELAY: return AS_CM_JT_ON;
210  case AS_CM_JT_ON: return AS_CM_JT_OFFDELAY;
211  case AS_CM_JT_OFFDELAY: return AS_CM_JT_OFF;
212  case AS_CM_JT_OFF: return AS_CM_JT_ONDELAY;
213  }
214  return AS_CM_JT_NONE;
215  }
216 
217  uint8_t getJumpTarget(uint8_t stat,const SwitchPeerList& lst) const {
218  switch( stat ) {
219  case AS_CM_JT_ONDELAY: return lst.jtDlyOn();
220  case AS_CM_JT_ON: return lst.jtOn();
221  case AS_CM_JT_OFFDELAY: return lst.jtDlyOff();
222  case AS_CM_JT_OFF: return lst.jtOff();
223  }
224  return AS_CM_JT_NONE;
225  }
226 
227  uint8_t getConditionForState(uint8_t stat,const SwitchPeerList& lst) const {
228  switch( stat ) {
229  case AS_CM_JT_ONDELAY: return lst.ctDlyOn();
230  case AS_CM_JT_ON: return lst.ctOn();
231  case AS_CM_JT_OFFDELAY: return lst.ctDlyOff();
232  case AS_CM_JT_OFF: return lst.ctOff();
233  }
234  return AS_CM_CT_X_GE_COND_VALUE_LO;
235  }
236 
237  uint32_t getDelayForState(uint8_t stat,const SwitchPeerList& lst) const {
238  if( lst.valid() == false ) {
239  return getDefaultDelay(stat);
240  }
241  uint8_t value = 0;
242  switch( stat ) {
243  case AS_CM_JT_ONDELAY: value = lst.onDly(); break;
244  case AS_CM_JT_ON: value = lst.onTime(); break;
245  case AS_CM_JT_OFFDELAY: value = lst.offDly(); break;
246  case AS_CM_JT_OFF: value = lst.offTime(); break;
247  }
248  return AskSinBase::byteTimeCvt(value);
249  }
250 
251  uint32_t getDefaultDelay(uint8_t stat) const {
252  switch( stat ) {
253  case AS_CM_JT_ON:
254  case AS_CM_JT_OFF:
255  return DELAY_INFINITE;
256  }
257  return DELAY_NO;
258  }
259 
260  bool delayActive () const { return sysclock.get(alarm) > 0; }
261 
262  bool set (uint8_t value,__attribute__ ((unused)) uint16_t ramp,uint16_t delay) {
263  status(value, delay);
264  return true;
265  }
266 
267  void remote (const SwitchPeerList& lst,uint8_t counter) {
268  // perform action as defined in the list
269  switch (lst.actionType()) {
270  case AS_CM_ACTIONTYPE_JUMP_TO_TARGET:
271  jumpToTarget(lst);
272  break;
273  case AS_CM_ACTIONTYPE_TOGGLE_TO_COUNTER:
274  setState((counter & 0x01) == 0x01 ? AS_CM_JT_ON : AS_CM_JT_OFF, DELAY_INFINITE);
275  break;
276  case AS_CM_ACTIONTYPE_TOGGLE_INVERSE_TO_COUNTER:
277  setState((counter & 0x01) == 0x00 ? AS_CM_JT_ON : AS_CM_JT_OFF, DELAY_INFINITE);
278  break;
279  }
280  }
281 
282  void sensor (const SwitchPeerList& lst,uint8_t counter,uint8_t value) {
283  uint8_t cond = getConditionForState(state,lst);
284  bool doit = false;
285  switch( cond ) {
286  case AS_CM_CT_X_GE_COND_VALUE_LO:
287  doit = (value >= lst.ctValLo());
288  break;
289  case AS_CM_CT_X_GE_COND_VALUE_HI:
290  doit = (value >= lst.ctValHi());
291  break;
292  case AS_CM_CT_X_LT_COND_VALUE_LO:
293  doit = (value < lst.ctValLo());
294  break;
295  case AS_CM_CT_X_LT_COND_VALUE_HI:
296  doit = (value < lst.ctValHi());
297  break;
298  case AS_CM_CT_COND_VALUE_LO_LE_X_LT_COND_VALUE_HI:
299  doit = ((lst.ctValLo() <= value) && (value < lst.ctValHi()));
300  break;
301  case AS_CM_CT_X_LT_COND_VALUE_LO_OR_X_GE_COND_VALUE_HI:
302  doit =((value < lst.ctValLo()) || (value >= lst.ctValHi()));
303  break;
304  }
305  if( doit == true ) {
306  remote(lst,counter);
307  }
308  }
309 
310  void stop () {}
311 
312  void status (uint8_t stat, uint16_t delay) {
313  setState( stat == 0 ? AS_CM_JT_OFF : AS_CM_JT_ON, AskSinBase::intTimeCvt(delay) );
314  }
315 
316  uint8_t status () const {
317  return state == AS_CM_JT_OFF ? 0 : 200;
318  }
319 
320  uint8_t flags () const {
321  return delayActive() ? 0x40 : 0x00;
322  }
323 };
324 
325 template <class HalType,int PeerCount,class List0Type,class IODriver=ArduinoPins>
326 class SwitchChannel : public ActorChannel<HalType,SwitchList1,SwitchList3,PeerCount,List0Type,SwitchStateMachine> {
327 
328 protected:
330  uint8_t lowact;
331  uint8_t pin;
332 
333 public:
334  SwitchChannel () : BaseChannel(), lowact(false), pin(0) {}
335  virtual ~SwitchChannel() {}
336 
337  void init (uint8_t p,bool value=false) {
338  pin=p;
339  IODriver::setOutput(pin);
340  lowact = value;
341  typename BaseChannel::List1 l1 = BaseChannel::getList1();
342  this->set(l1.powerUpAction() == true ? 200 : 0, 0, 0xffff );
343  this->changed(true);
344  }
345 
346  uint8_t flags () const {
347  uint8_t flags = BaseChannel::flags();
348  if( this->device().battery().low() == true ) {
349  flags |= 0x80;
350  }
351  return flags;
352  }
353 
354 
355  virtual void switchState(__attribute__((unused)) uint8_t oldstate,uint8_t newstate,__attribute__((unused)) uint32_t delay) {
356  if( newstate == AS_CM_JT_ON ) {
357  if( lowact == true ) IODriver::setLow(pin);
358  else IODriver::setHigh(pin);
359  }
360  else if ( newstate == AS_CM_JT_OFF ) {
361  if( lowact == true ) IODriver::setHigh(pin);
362  else IODriver::setLow(pin);
363  }
364  this->changed(true);
365  }
366 };
367 
368 }
369 
370 #endif
as::Alarm
Definition: Alarm.h:15
as::SwitchStateMachine
Definition: Switch.h:122
as::AlarmClock
Definition: AlarmClock.h:32
as::BaseList
Definition: ChannelList.h:14
as::SwitchList3Tmpl
Definition: Switch.h:38
as::ShortLongList
Definition: Register.h:827
as::SwitchChannel
Definition: Switch.h:326
as::ActorChannel
Definition: Channel.h:263