AskSin++
Blind.h
1 //- -----------------------------------------------------------------------------------------------------------------------
2 // AskSin++
3 // 2017-12-03 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
4 //- -----------------------------------------------------------------------------------------------------------------------
5 
6 #ifndef __BLIND_H__
7 #define __BLIND_H__
8 
9 #include "MultiChannelDevice.h"
10 #include "Register.h"
11 #include "StateMachine.h"
12 
13 namespace as {
14 
15 DEFREGISTER(BlindReg1,CREG_AES_ACTIVE,
16  CREG_REFERENCE_RUNNING_TIME_TOP_BOTTOM,CREG_REFERENCE_RUNNING_TIME_BOTTOM_TOP,
17  CREG_CHANGE_OVER_DELAY,CREG_REFERENCE_RUN_COUNTER,CREG_TRANSMITTRYMAX,
18  CREG_STATUSINFO)
19 
20 class BlindList1 : public RegList1<BlindReg1> {
21 public:
22  BlindList1 (uint16_t addr) : RegList1<BlindReg1>(addr) {}
23  void defaults () {
24  clear();
25  // aesActive(false);
26  transmitTryMax(6);
27  // powerUpAction(false);
28  statusInfoMinDly(4);
29  statusInfoRandom(1);
30 
31  refRunningTimeTopBottom(500);
32  refRunningTimeBottomTop(500);
33  changeOverDelay(5);
34  //refRunCounter(0);
35  }
36 };
37 
38 DEFREGISTER(BlindReg3,PREG_CTRAMPONOFF,PREG_CTDELAYONOFF,PREG_CTONOFF,
39  PREG_CTREPONOFF,PREG_CONDVALUELOW,PREG_CONDVALUEHIGH,PREG_ONDELAYTIME,
40  PREG_ONTIME,PREG_OFFDELAYTIME,PREG_OFFTIME,PREG_ACTIONTYPE,PREG_JTONOFF,
41  PREG_JTDELAYONOFF,PREG_JTRAMPONOFF,PREG_JTREFONOFF,PREG_OFFLEVEL,
42  PREG_ONLEVEL,PREG_MAXTIMEFIRSTDIR,PREG_DRIVINGMODE)
43 
44 typedef RegList3<BlindReg3> BlindPeerList;
45 
46 class BlindList3 : public ShortLongList<BlindPeerList> {
47 public:
48  BlindList3 (uint16_t addr) : ShortLongList<BlindPeerList>(addr) {}
49  void defaults() {
50  BlindPeerList ssl = sh();
51  ssl.clear();
52 // ssl.ctRampOn(0);
53 // ssl.ctRampOff(0);
54 // ssl.ctDlyOn(0);
55 // ssl.ctDlyOff(0);
56 // ssl.ctOn(0);
57 // ssl.ctOff(0);
58 // ssl.ctRefOn(0);
59 // ssl.ctRefOff(0);
60  ssl.ctValLo(0x32);
61  ssl.ctValHi(0x64);
62 // ssl.onDly(0);
63  ssl.onTime(0xff);
64 // ssl.offDly(0);
65  ssl.offTime(0xff);
66  ssl.actionType(AS_CM_ACTIONTYPE_JUMP_TO_TARGET);
67 // ssl.offLevel(0);
68  ssl.onLevel(200); // 201 ???
69  ssl.maxTimeFirstDir(255);
70  //ssl.drivingMode(0);
71 
72  ssl = lg();
73  ssl.clear();
74 // ssl.ctRampOn(0);
75 // ssl.ctRampOff(0);
76 // ssl.ctDlyOn(0);
77 // ssl.ctDlyOff(0);
78 // ssl.ctOn(0);
79 // ssl.ctOff(0);
80 // ssl.ctRefOn(0);
81 // ssl.ctRefOff(0);
82  ssl.ctValLo(0x32);
83  ssl.ctValHi(0x64);
84 // ssl.onDly(0);
85  ssl.onTime(0xff);
86 // ssl.offDly(0);
87  ssl.offTime(0xff);
88  ssl.actionType(AS_CM_ACTIONTYPE_JUMP_TO_TARGET);
89  ssl.multiExec(true);
90 // ssl.offLevel(0);
91  ssl.onLevel(200); // 201 ???
92  ssl.maxTimeFirstDir(5);
93  //ssl.drivingMode(0);
94  }
95 
96  void odd() { // B
97  defaults();
98  BlindPeerList ssl = sh();
99  ssl.jtOff(AS_CM_JT_OFFDELAY);
100  ssl.jtDlyOff(AS_CM_JT_REFOFF);
101  ssl.jtOn(AS_CM_JT_OFFDELAY);
102  ssl.jtDlyOn(AS_CM_JT_OFFDELAY);
103  ssl.jtRampOff(AS_CM_JT_RAMPOFF);
104  ssl.jtRampOn(AS_CM_JT_ON);
105  ssl.jtRefOff(AS_CM_JT_RAMPOFF);
106  ssl.jtRefOn(AS_CM_JT_ON);
107  ssl = lg();
108  ssl.jtOff(AS_CM_JT_OFFDELAY);
109  ssl.jtDlyOff(AS_CM_JT_REFOFF);
110  ssl.jtOn(AS_CM_JT_OFFDELAY);
111  ssl.jtDlyOn(AS_CM_JT_OFFDELAY);
112  ssl.jtRampOff(AS_CM_JT_RAMPOFF);
113  ssl.jtRampOn(AS_CM_JT_ON);
114  ssl.jtRefOff(AS_CM_JT_RAMPOFF);
115  ssl.jtRefOn(AS_CM_JT_ON);
116  }
117 
118  void even() { // A
119  defaults();
120  BlindPeerList ssl = sh();
121  ssl.jtOff(AS_CM_JT_ONDELAY);
122  ssl.jtDlyOff(AS_CM_JT_ONDELAY);
123  ssl.jtOn(AS_CM_JT_ONDELAY);
124  ssl.jtDlyOn(AS_CM_JT_REFON);
125  ssl.jtRampOff(AS_CM_JT_OFF);
126  ssl.jtRampOn(AS_CM_JT_RAMPON);
127  ssl.jtRefOff(AS_CM_JT_OFF);
128  ssl.jtRefOn(AS_CM_JT_RAMPON);
129  ssl = lg();
130  ssl.jtOff(AS_CM_JT_ONDELAY);
131  ssl.jtDlyOff(AS_CM_JT_ONDELAY);
132  ssl.jtOn(AS_CM_JT_ONDELAY);
133  ssl.jtDlyOn(AS_CM_JT_REFON);
134  ssl.jtRampOff(AS_CM_JT_OFF);
135  ssl.jtRampOn(AS_CM_JT_RAMPON);
136  ssl.jtRefOff(AS_CM_JT_OFF);
137  ssl.jtRefOn(AS_CM_JT_RAMPON);
138  }
139 
140  void single() { //AB
141  defaults();
142  BlindPeerList ssl = sh();
143  ssl.jtOff(AS_CM_JT_ONDELAY);
144  ssl.jtDlyOff(AS_CM_JT_REFOFF);
145  ssl.jtOn(AS_CM_JT_OFFDELAY);
146  ssl.jtDlyOn(AS_CM_JT_REFON);
147  ssl.jtRampOn(AS_CM_JT_ON);
148  ssl.jtRefOn(AS_CM_JT_ON);
149  ssl.jtRampOff(AS_CM_JT_OFF);
150  ssl.jtRefOff(AS_CM_JT_ON);
151  ssl = lg();
152  ssl.jtOff(AS_CM_JT_ONDELAY);
153  ssl.jtDlyOff(AS_CM_JT_REFOFF);
154  ssl.jtOn(AS_CM_JT_OFFDELAY);
155  ssl.jtDlyOn(AS_CM_JT_REFON);
156  ssl.jtRampOn(AS_CM_JT_ON);
157  ssl.jtRefOn(AS_CM_JT_ON);
158  ssl.jtRampOff(AS_CM_JT_OFF);
159  ssl.jtRefOff(AS_CM_JT_OFF);
160  }
161 
162 };
163 
164 
165 class BlindStateMachine : public StateMachine<BlindPeerList> {
166 
167  class LevelUpdate : public Alarm {
168  BlindStateMachine& sm;
169  uint16_t done;
170  uint16_t fulltime;
171  uint8_t startlevel;
172  public:
173  LevelUpdate (BlindStateMachine& m) : Alarm(0), sm(m), done(0), fulltime(0), startlevel(0) {
174  async(true);
175  }
176  ~LevelUpdate () {}
177  void start (AlarmClock& clock,uint16_t ft) {
178  startlevel = sm.status();
179  fulltime = ft;
180  done = 0;
181  set(millis2ticks(100));
182  clock.add(*this);
183  sm.triggerChanged();
184  }
185  void stop (AlarmClock& clock) {
186  clock.cancel(*this);
187  if( done > fulltime ) done = fulltime;
188  uint8_t dx = (done * 200UL) / fulltime;
189  if( sm.state == AS_CM_JT_RAMPON ) {
190  if( dx > (200-startlevel) ) dx = 200-startlevel;
191  sm.updateLevel(startlevel + dx);
192  }
193  else if( sm.state == AS_CM_JT_RAMPOFF ) {
194  if( dx > startlevel ) dx = startlevel;
195  sm.updateLevel(startlevel - dx);
196  }
197  sm.triggerChanged();
198  }
199  virtual void trigger (AlarmClock& clock) {
200  // add 0.1s
201  ++done;
202  set(millis2ticks(100));
203  clock.add(*this);
204  }
205  };
206 
207 public:
208  void updateLevel (uint8_t l) {
209  if( l != level ) {
210  level = l;
211  DPRINT(F("New Level: "));DDECLN(level);
212  triggerChanged();
213  }
214  }
215 
216 protected:
217  uint8_t level, destlevel;
218  LevelUpdate update;
219  BlindList1 list1;
220 
221  virtual void trigger (AlarmClock& clock) {
222  uint8_t trigstate = state;
223  uint8_t trigdest = destlevel;
225  if( trigstate == AS_CM_JT_RAMPON || trigstate == AS_CM_JT_RAMPOFF ) {
226  if( trigdest != 0xff ) {
227  // update level to destlevel
228  updateLevel(trigdest);
229  }
230  }
231  }
232 
233  void triggerChanged () {
234  StateMachine<BlindPeerList>::triggerChanged(decis2ticks(list1.statusInfoMinDly()*5));
235  }
236 
237 public:
238  BlindStateMachine () : StateMachine<BlindPeerList>(), level(0xff), destlevel(0), /*alarm(*this),*/ update(*this), list1(0) {}
239  virtual ~BlindStateMachine () {}
240 
241  virtual void switchState(uint8_t oldstate,uint8_t newstate,__attribute__ ((unused)) uint32_t statedelay) {
242  DPRINT(F("Switch from "));DHEX(oldstate);DPRINT(F(" to "));DHEX(newstate);DPRINT(F(" delay: "));DHEXLN(statedelay);
243  switch( newstate ) {
244  case AS_CM_JT_RAMPON:
245  update.start(sysclock, list1.refRunningTimeBottomTop());
246  break;
247  case AS_CM_JT_RAMPOFF:
248  update.start(sysclock, list1.refRunningTimeTopBottom());
249  break;
250  }
251 
252  switch (oldstate) {
253  case AS_CM_JT_RAMPON:
254  case AS_CM_JT_RAMPOFF:
255  update.stop(sysclock);
256  break;
257  }
258  }
259 
260  void setup(BlindList1 l1) {
261  list1 = l1;
262  }
263 
264  void init () {
265  setState(AS_CM_JT_OFF, BlindStateMachine::DELAY_INFINITE);
266  updateLevel(0);
267  }
268 
269  void jumpToTarget(const BlindPeerList& lst) {
270  uint8_t next = getJumpTarget(state,lst);
271  DPRINT(F("jumpToTarget: "));DDEC(state);DPRINT(F(" "));DDECLN(next);
272  if( next != AS_CM_JT_NONE ) {
273  switch( next ) {
274  case AS_CM_JT_ONDELAY:
275  case AS_CM_JT_REFON:
276  case AS_CM_JT_RAMPON:
277  setDestLevel(lst.onLevel());
278  break;
279  case AS_CM_JT_OFFDELAY:
280  case AS_CM_JT_REFOFF:
281  case AS_CM_JT_RAMPOFF:
282  setDestLevel(lst.offLevel());
283  break;
284  }
285 
286  // get delay for the next state
287  uint32_t dly = getDelayForState(next,lst);
288  // on/off time mode / absolute / minimal
289  if( next == state && (next == AS_CM_JT_ON || next == AS_CM_JT_OFF) && dly < DELAY_INFINITE) {
290  bool minimal = next == AS_CM_JT_ON ? lst.onTimeMode() : lst.offTimeMode();
291  // if minimal is set - we jump out if the new delay is shorter
292  if( minimal == true ) {
293  // DPRINT("Minimal");DDECLN(dly);
294  uint32_t curdly = sysclock.get(*this); // 0 means DELAY_INFINITE
295  if( curdly == 0 || curdly > dly ) {
296  // DPRINTLN(F("Skip short Delay"));
297  return;
298  }
299  }
300  }
301  // switch to next
302  setState(next,dly,lst);
303  }
304  }
305 
306  virtual uint8_t getNextState (uint8_t stat) {
307  //DPRINT("getNextState: ");DDECLN(stat);
308  switch( stat ) {
309  case AS_CM_JT_ONDELAY: return AS_CM_JT_REFON;
310  case AS_CM_JT_REFON: return AS_CM_JT_RAMPON;
311  case AS_CM_JT_RAMPON:
312  if(actlst.valid() && destlevel == actlst.offLevel())
313  return AS_CM_JT_OFF;
314  return AS_CM_JT_ON;
315  case AS_CM_JT_ON: return AS_CM_JT_OFFDELAY;
316  case AS_CM_JT_OFFDELAY: return AS_CM_JT_REFOFF;
317  case AS_CM_JT_REFOFF: return AS_CM_JT_RAMPOFF;
318  case AS_CM_JT_RAMPOFF:
319  if(actlst.valid() && destlevel == actlst.onLevel())
320  return AS_CM_JT_ON;
321  return AS_CM_JT_OFF;
322  case AS_CM_JT_OFF: return AS_CM_JT_ONDELAY;
323  }
324  return AS_CM_JT_NONE;
325  }
326 
327  virtual uint32_t getDelayForState(uint8_t stat,const BlindPeerList& lst) {
328  if( lst.valid () == true ) {
329  if( stat == AS_CM_JT_RAMPON || stat == AS_CM_JT_RAMPOFF ) {
330  uint8_t first = lst.maxTimeFirstDir();
331  if( first != 0xff && first != 0x00 ) {
332  destlevel = 0xff;
333  return decis2ticks(first);
334  }
335  //destlevel = stat == AS_CM_JT_RAMPON ? lst.onLevel() : lst.offLevel();
336  }
337  }
339  }
340 
341  virtual uint32_t getDefaultDelay(uint8_t stat) const {
342  switch( stat ) {
343  case AS_CM_JT_ON:
344  case AS_CM_JT_OFF:
345  return DELAY_INFINITE;
346 
347  case AS_CM_JT_REFON:
348  case AS_CM_JT_REFOFF:
349  return decis2ticks(list1.changeOverDelay());
350 
351  case AS_CM_JT_RAMPON:
352  return calcDriveTime(destlevel-level,list1.refRunningTimeBottomTop(),destlevel==200);
353 
354  case AS_CM_JT_RAMPOFF:
355  return calcDriveTime(level-destlevel,list1.refRunningTimeTopBottom(),destlevel==0);
356 
357  }
358  return DELAY_NO;
359  }
360 
361  uint32_t calcDriveTime(uint8_t dx,uint32_t fulltime,bool extratime) const {
362  uint32_t dt = (fulltime * dx) / 200;
363  if( extratime == true ) dt += 20; // we add 2 additional seconds
364  DPRINT(F("calcDriveTime: "));DDEC(fulltime);DPRINT(F(" - "));DDEC(dx);DPRINT(F(" - "));DDECLN(dt);
365  return decis2ticks(dt);
366  }
367 
368  bool set (uint8_t value,__attribute__ ((unused)) uint16_t ramp,__attribute__ ((unused)) uint16_t delay) {
369  setDestLevel(value);
370  if( destlevel > level || destlevel == 200 ) {
371  setState(AS_CM_JT_ONDELAY, 0);
372  }
373  else if ( destlevel < level || destlevel == 0 ) {
374  setState(AS_CM_JT_OFFDELAY, 0);
375  }
376  return true;
377  }
378 
379  void remote (const BlindPeerList& lst,uint8_t counter) {
380  // perform action as defined in the list
381  switch (lst.actionType()) {
382  case AS_CM_ACTIONTYPE_JUMP_TO_TARGET:
383  jumpToTarget(lst);
384  break;
385  case AS_CM_ACTIONTYPE_TOGGLE_TO_COUNTER:
386  setDestLevel((counter & 0x01) == 0x01 ? lst.onLevel() : lst.offLevel());
387  break;
388  case AS_CM_ACTIONTYPE_TOGGLE_INVERSE_TO_COUNTER:
389  setDestLevel((counter & 0x01) == 0x00 ? lst.onLevel() : lst.offLevel());
390  break;
391  }
392  }
393 
394  void sensor (const BlindPeerList& lst,uint8_t counter,uint8_t value) {
395  if( checkCondition(state,lst,value) == true ) {
396  remote(lst,counter);
397  }
398  }
399 
400 // void toggleState () {
401 // if( state == AS_CM_JT_OFF ) {
402 // setDestLevel(200);
403 // }
404 // else {
405 // setDestLevel(0);
406 // }
407 // }
408 
409  bool setDestLevel (uint8_t value) {
410  DPRINT(F("setDestLevel: "));DDECLN(value);
411  destlevel = value;
412 // if( destlevel > level || destlevel == 200 ) {
413 // setState(AS_CM_JT_ONDELAY, 0);
414 // return true;
415 // }
416 // else if ( destlevel < level || destlevel == 0 ) {
417 // setState(AS_CM_JT_OFFDELAY, 0);
418 // return true;
419 // }
420  return false;
421  }
422 
423  void stop () {
424  if( state == AS_CM_JT_RAMPON || state == AS_CM_JT_RAMPOFF ) {
425  setState(getNextState(state),DELAY_INFINITE);
426  }
427  }
428 
429  uint8_t status () const {
430  return level;
431  }
432 
433  uint8_t flags () const {
434  uint8_t f = (state == AS_CM_JT_ON || state == AS_CM_JT_OFF) ? 0x00 : AS_CM_EXTSTATE_RUNNING;
435  if( state == AS_CM_JT_RAMPON ) {
436  f |= AS_CM_EXTSTATE_UP; // UP flag
437  }
438  else if( state == AS_CM_JT_RAMPOFF ) {
439  f |= AS_CM_EXTSTATE_DOWN; // DOWN flag
440  }
441  return f;
442  }
443 };
444 
445 }
446 
447 #endif
as::Alarm
Definition: Alarm.h:15
as::AlarmClock
Definition: AlarmClock.h:32
as::StateMachine
Definition: StateMachine.h:14
as::ShortLongList
Definition: Register.h:827
as::BlindStateMachine
Definition: Blind.h:165
as::BlindList3
Definition: Blind.h:46