AskSin++
ContactState.h
1 //- -----------------------------------------------------------------------------------------------------------------------
2 // AskSin++
3 // 2017-10-19 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
4 //- -----------------------------------------------------------------------------------------------------------------------
5 
6 #ifndef __CONTACTSTATE_H__
7 #define __CONTACTSTATE_H__
8 
9 
10 #include "MultiChannelDevice.h"
11 #include "sensors/PinPosition.h"
12 
13 #ifndef SABOTAGE_ACTIVE_STATE
14 #define SABOTAGE_ACTIVE_STATE LOW
15 #endif
16 
17 namespace as {
18 
19 template <class Sensor,class HALTYPE,class List0Type,class List1Type,class List4Type,int PEERCOUNT>
20 class StateGenericChannel : public Channel<HALTYPE,List1Type,EmptyList,List4Type,PEERCOUNT,List0Type>, public Alarm {
21 
22  class EventSender : public Alarm {
23  public:
24  StateGenericChannel& channel;
25  uint8_t count, state;
26 
27  EventSender (StateGenericChannel& c) : Alarm(0), channel(c), count(0), state(255) {}
28  virtual ~EventSender () {}
29  virtual void trigger (__attribute__ ((unused)) AlarmClock& clock) {
30  SensorEventMsg& msg = (SensorEventMsg&)channel.device().message();
31  msg.init(channel.device().nextcount(),channel.number(),count++,state,channel.device().battery().low());
32 #ifdef CONTACT_STATE_WITH_BATTERY
33  msg.append(channel.device().battery().current());
34  // msg.append(__gb_BatCount);
35 #endif
36  channel.device().sendPeerEvent(msg,channel);
37  }
38  };
39 
40  EventSender sender;
41  uint8_t sabpin;
42  bool sabotage;
43 
44 protected:
45  Sensor possens;
46 
47 public:
49 
50  StateGenericChannel () : BaseChannel(), Alarm(0), sender(*this), sabpin(0), sabotage(false) {}
51  virtual ~StateGenericChannel () {}
52 
53  void setup(Device<HALTYPE,List0Type>* dev,uint8_t number,uint16_t addr) {
54  BaseChannel::setup(dev,number,addr);
55  }
56 
57  void init (uint8_t sab) {
58  sabpin = sab;
59  init();
60  }
61 
62  void init () {
63  // get the current state
64  trigger(sysclock);
65  }
66 
67  uint8_t status () const {
68  return sender.state;
69  }
70 
71  uint8_t flags () const {
72  uint8_t flags = sabotage ? 0x07 << 1 : 0x00;
73  flags |= this->device().battery().low() ? 0x80 : 0x00;
74  return flags;
75  }
76 
77  void trigger (__attribute__ ((unused)) AlarmClock& clock) {
78  // reactivate polling - if interval greater 0
79  if( possens.interval() > 0) {
80  set(possens.interval());
81  clock.add(*this);
82  }
83  uint8_t newstate = sender.state;
84  uint8_t msg = 0;
85  possens.measure();
86  switch( possens.position() ) {
87  case Sensor::State::PosA:
88  msg = this->getList1().msgForPosA();
89  break;
90  case Sensor::State::PosB:
91  msg = this->getList1().msgForPosB();
92  break;
93  case Sensor::State::PosC:
94  msg = this->getList1().msgForPosC();
95  break;
96  default:
97  break;
98  }
99 
100  if( msg == 1) newstate = 0;
101  else if( msg == 2) newstate = 200;
102  else if( msg == 3) newstate = 100;
103 
104  // lets the position sensor remap the new state
105  newstate = possens.remap(newstate);
106 
107  if( sender.state == 255 ) {
108  // we are in the init stage - store state only
109  sender.state = newstate;
110  }
111  else if( newstate != sender.state ) {
112  uint8_t delay = this->getList1().eventDelaytime();
113  sender.state = newstate;
114  sysclock.cancel(sender);
115  if( delay == 0 ) {
116  sender.trigger(sysclock);
117  }
118  else {
119  sender.set(AskSinBase::byteTimeCvtSeconds(delay));
120  sysclock.add(sender);
121  }
122  uint16_t ledtime = (uint16_t)this->getList1().ledOntime() * 5;
123  if( ledtime > 0 ) {
124  this->device().led().ledOn(millis2ticks(ledtime),0);
125  }
126  }
127  if( sabpin != 0 ) {
128  bool sabstate = (possens.interval()==0 ? digitalRead(sabpin) : AskSinBase::readPin(sabpin) == SABOTAGE_ACTIVE_STATE);
129  if( sabotage != sabstate && this->device().getList0().sabotageMsg() == true ) {
130  sabotage = sabstate;
131  this->changed(true); // trigger StatusInfoMessage to central
132  }
133  }
134  }
135 
136 #ifdef CONTACT_STATE_WITH_BATTERY
137  void patchStatus (Message& msg) {
138  // append current battery value to status message
139  msg.append(this->device().battery().current());
140  }
141 #endif
142 };
143 
144 // alias for old code
145 template <class Sensor,class HALTYPE,class List0Type,class List1Type,class List4Type,int PEERCOUNT>
147 
148 template <class HALTYPE,class List0Type,class List1Type,class List4Type,int PEERCOUNT>
149 class ThreeStateChannel : public StateGenericChannel<TwoPinPosition,HALTYPE,List0Type,List1Type,List4Type,PEERCOUNT> {
150 public:
152 
153  ThreeStateChannel () : BaseChannel() {};
154  ~ThreeStateChannel () {}
155 
156  void init (uint8_t pin1,uint8_t pin2, uint8_t sab,const uint8_t* pmap) {
157  BaseChannel::possens.init(pin1,pin2,pmap);
158  BaseChannel::init(sab);
159  }
160 
161  void init (uint8_t pin1,uint8_t pin2, const uint8_t* pmap) {
162  BaseChannel::possens.init(pin1,pin2,pmap);
163  BaseChannel::init();
164  }
165 
166  void init (uint8_t pin1,uint8_t pin2, uint8_t sab) {
167  BaseChannel::possens.init(pin1,pin2);
168  BaseChannel::init(sab);
169  }
170 
171  void init (uint8_t pin1,uint8_t pin2) {
172  BaseChannel::possens.init(pin1,pin2);
173  BaseChannel::init();
174  }
175 };
176 
177 template <class HALTYPE,class List0Type,class List1Type,class List4Type,int PEERCOUNT, uint16_t WAITMILLIS_AFTER_ENABLE=0>
178 class TwoStateChannel : public StateGenericChannel<OnePinPosition<WAITMILLIS_AFTER_ENABLE>,HALTYPE,List0Type,List1Type,List4Type,PEERCOUNT> {
179 public:
180  typedef StateGenericChannel<OnePinPosition<WAITMILLIS_AFTER_ENABLE>,HALTYPE,List0Type,List1Type,List4Type,PEERCOUNT> BaseChannel;
181 
182  TwoStateChannel () : BaseChannel() {};
183  ~TwoStateChannel () {}
184 
185  void init (uint8_t pin, uint8_t en, uint8_t sab) {
186  BaseChannel::init(sab);
187  BaseChannel::possens.init(pin, en);
188  }
189 
190  void init (uint8_t pin, uint8_t sab) {
191  BaseChannel::init(sab);
192  BaseChannel::possens.init(pin, 0);
193  }
194 
195  void init (uint8_t pin) {
196  BaseChannel::init();
197  BaseChannel::possens.init(pin, 0);
198  }
199 };
200 
201 #define DEFCYCLETIME seconds2ticks(60UL*60*20)
202 template<class HalType,class ChannelType,int ChannelCount,class List0Type,uint32_t CycleTime=DEFCYCLETIME> // at least one message per day
203 class StateDevice : public MultiChannelDevice<HalType,ChannelType,ChannelCount,List0Type> {
204  class CycleInfoAlarm : public Alarm {
205  StateDevice& dev;
206  public:
207  CycleInfoAlarm (StateDevice& d) : Alarm (CycleTime), dev(d) {}
208  virtual ~CycleInfoAlarm () {}
209 
210  void trigger (AlarmClock& clock) {
211  set(CycleTime);
212  clock.add(*this);
213  for( uint8_t idx=1; idx<=dev.channels(); ++idx) {
214  dev.channel(idx).changed(true); // force StatusInfoMessage to central
215  }
216  }
217  } cycle;
218 public:
220  StateDevice(const DeviceInfo& info,uint16_t addr) : DevType(info,addr), cycle(*this) {}
221  virtual ~StateDevice () {}
222 
223  virtual void configChanged () {
224  // activate cycle info message
225  if( this->getList0().cycleInfoMsg() == true ) {
226  DPRINTLN(F("Activate Cycle Msg"));
227  sysclock.cancel(cycle);
228  cycle.set(CycleTime);
229  sysclock.add(cycle);
230  }
231  else {
232  DPRINTLN(F("Deactivate Cycle Msg"));
233  sysclock.cancel(cycle);
234  }
235  }
236 };
237 
238 // alias for old code
239 template<class HalType,class ChannelType,int ChannelCount,class List0Type,uint32_t CycleTime=DEFCYCLETIME>
241 
242 
243 #define contactISR(pin,func) if( digitalPinToInterrupt(pin) == NOT_AN_INTERRUPT ) \
244  enableInterrupt(pin,func,CHANGE); \
245 else \
246  attachInterrupt(digitalPinToInterrupt(pin),func,CHANGE);
247 
248 }
249 
250 #endif
as::TwoStateChannel
Definition: ContactState.h:178
as::Alarm
Definition: Alarm.h:15
as::Channel
Definition: Channel.h:21
as::Message
Definition: Message.h:51
as::StateGenericChannel
Definition: ContactState.h:20
as::AlarmClock
Definition: AlarmClock.h:32
as::MultiChannelDevice
Definition: MultiChannelDevice.h:505
as::Device< HALTYPE, List0Type >
as::DeviceInfo
Definition: Device.h:70
as::AskSinBase::readPin
static uint8_t readPin(uint8_t pinnr, uint8_t enablenr=0, uint8_t ms=0)
Definition: AskSinPP.h:186
as::SensorEventMsg
Definition: Message.h:480
as::ThreeStateChannel
Definition: ContactState.h:149
as::Sensor
Definition: Sensors.h:11
as::StateDevice
Definition: ContactState.h:203