AskSin++
IButton.h
1 //- -----------------------------------------------------------------------------------------------------------------------
2 // AskSin++
3 // 2018-05-03 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
4 //- -----------------------------------------------------------------------------------------------------------------------
5 
6 #ifndef __IBUTTON_H__
7 #define __IBUTTON_H__
8 
9 #include "MultiChannelDevice.h"
10 #include "Register.h"
11 
12 namespace as {
13 
14 DEFREGISTER(IButtonReg1,CREG_AES_ACTIVE,0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7)
15 class IButtonList1 : public RegList1<IButtonReg1> {
16 public:
17  IButtonList1 (uint16_t addr) : RegList1<IButtonReg1>(addr) {}
18  void defaults () {
19  clear();
20  }
21 };
22 
23 template<class HALTYPE,int PEERCOUNT,class List0Type=List0>
24 class IButtonChannel : public Channel<HALTYPE,IButtonList1,EmptyList,DefList4,PEERCOUNT,List0Type>, Alarm {
25 
26  enum { none=0, released, longpressed, longreleased };
27 
28  uint8_t state, matches, repeatcnt;
29 
30 public:
32 
33  IButtonChannel () : BaseChannel(), Alarm(0), state(0), matches(0),repeatcnt(0) {}
34  virtual ~IButtonChannel () {}
35 
36  virtual void trigger (__attribute__((unused)) AlarmClock& clock) {
37  state = 0;
38  this->changed(true);
39  }
40 
41  uint8_t status () const {
42  return state;
43  }
44 
45  uint8_t flags () const {
46  return 0;
47  }
48 
49  void start () {
50  matches <<= 1;
51  }
52 
53  bool check (uint8_t* addr) {
54  if( free() == false && isID(addr) == true ) {
55  matches |= 0b00000001;
56  return true;
57  }
58  return false;
59  }
60 
61  void finish () {
62  // channel is in remote mode
63  if( this->device().getList0().buttonMode() == 0 ) {
64  uint8_t s = none;
65  // 3 or 6 matches are longpress and longlongpress
66  if( (matches & 0b00111111) == 0b00000111 || (matches & 0b00111111) == 0b00111111 ) {
67  s = longpressed;
68  DPRINTLN(F("longpressed"));
69  // clear longlong
70  matches &= 0b11000111;
71  }
72  // check for long release
73  else if( (matches & 0b00001111) == 0b00001110 ) {
74  s = longreleased;
75  DPRINTLN(F("longreleased"));
76  }
77  // check for release
78  else if( (matches & 0b00000011) == 0b00000010 ) {
79  s = released;
80  DPRINTLN(F("released"));
81  }
82  if( s != none ) {
83  RemoteEventMsg& msg = (RemoteEventMsg&)this->device().message();
84  msg.init(this->device().nextcount(),this->number(),repeatcnt,(s==longreleased || s==longpressed),this->device().battery().low());
85  if( s == released || s == longreleased) {
86  // send the message to every peer
87  this->device().sendPeerEvent(msg,*this);
88  repeatcnt++;
89  }
90  else if (s == longpressed) {
91  // broadcast the message
92  this->device().broadcastPeerEvent(msg,*this);
93  }
94  }
95  }
96  // channel is in state mode
97  else {
98  uint8_t newstate = state;
99  uint8_t mask = (matches & 0b00000111);
100  if( mask == 0b00000111) newstate = 100;
101  else if( mask == 0b00000000) newstate = 0;
102  if( state != newstate ) {
103  state = newstate;
104  SensorEventMsg& msg = (SensorEventMsg&)this->device().message();
105  msg.init(this->device().nextcount(),this->number(),repeatcnt++,state,this->device().battery().low());
106  this->device().sendPeerEvent(msg,*this);
107  }
108  }
109  }
110 
111  bool match (uint8_t* addr) {
112  start();
113  bool res = check(addr);
114  finish();
115  return res;
116  }
117 
118  bool isID (uint8_t* buf) {
119  IButtonList1 l = this->getList1();
120  for( uint8_t n=0; n<8; ++n ) {
121  if( l.readRegister(0xe0+n) != buf[n] ) {
122  return false;
123  }
124  }
125  return true;
126  }
127 
128  void storeID (uint8_t* buf) {
129  if( learn() == true ) {
130  for( uint8_t n=0; n<8; ++n ) {
131  this->getList1().writeRegister(0xe0+n,buf[n]);
132  }
133  state = 0;
134  this->changed(true);
135  sysclock.cancel(*this);
136  }
137  }
138 
139  bool free () {
140  return this->getList1().readRegister(0xe0) == 0;
141  }
142 
143  bool learn () const {
144  return state == 200;
145  }
146 
147  bool process (const ActionSetMsg& msg) {
148  state = msg.value();
149  this->changed(true);
150  if( state != 0 ) {
151  set(seconds2ticks(60));
152  sysclock.add(*this);
153  }
154  return true;
155  }
156 
157  bool process (__attribute__((unused)) const RemoteEventMsg& msg) { return false; }
158  bool process (__attribute__((unused)) const SensorEventMsg& msg) { return false; }
159  bool process (__attribute__((unused)) const ActionCommandMsg& msg) { return false; }
160 };
161 
162 
163 template <class IButtonDev,class IButtonChannel,int READER_PIN,int LED_GREEN,int LED_RED>
164 class IButtonScanner : public Alarm {
165  OneWire ow;
166  IButtonDev& dev;
168  uint8_t cnt;
169 public:
170  IButtonScanner (IButtonDev& d) : Alarm(millis2ticks(500)), ow(READER_PIN), dev(d), cnt(0) {
171  led.init();
172  }
173  virtual ~IButtonScanner () {}
174 
175  IButtonChannel* learning () {
176  for( uint8_t i=0; i<dev.ibuttonCount(); ++i ) {
177  IButtonChannel& bc = dev.ibuttonChannel(i);
178  if( bc.learn() == true ) {
179  return &bc;
180  }
181  }
182  return 0;
183  }
184 
185  IButtonChannel* matches (uint8_t* addr) {
186  for( uint8_t i=0; i<dev.ibuttonCount(); ++i ) {
187  IButtonChannel& bc = dev.ibuttonChannel(i);
188  if( bc.match(addr) == true ) {
189  return &bc;
190  }
191  }
192  return 0;
193  }
194 
195  IButtonChannel* find (uint8_t* addr) {
196  for( uint8_t i=0; i<dev.ibuttonCount(); ++i ) {
197  IButtonChannel& bc = dev.ibuttonChannel(i);
198  if( bc.isID(addr) == true ) {
199  return &bc;
200  }
201  }
202  return 0;
203  }
204 
205  bool scan (uint8_t* addr) {
206  ow.reset_search();
207  if ( ow.search(addr) == false || OneWire::crc8(addr, 7) != addr[7] ) {
208  memset(addr,0,8);
209  return false;
210  }
211  return true;
212  }
213 
214  void start () {
215  for( uint8_t i=0; i<dev.ibuttonCount(); ++i ) {
216  IButtonChannel& bc = dev.ibuttonChannel(i);
217  bc.start();
218  }
219  }
220 
221  void finish () {
222  for( uint8_t i=0; i<dev.ibuttonCount(); ++i ) {
223  IButtonChannel& bc = dev.ibuttonChannel(i);
224  bc.finish();
225  }
226  }
227 
228  bool check (uint8_t* addr) {
229  bool res = false;
230  for( uint8_t i=0; i<dev.ibuttonCount(); ++i ) {
231  IButtonChannel& bc = dev.ibuttonChannel(i);
232  res |= bc.check(addr);
233  }
234  return res;
235  }
236 
237  void scanMulti () {
238  uint8_t found=0;
239  uint8_t known=0;
240  uint8_t addr[8];
241  start();
242  ow.reset_search();
243  while( ow.search(addr) == 1 ) {
244  if( OneWire::crc8(addr,7) == addr[7] ) {
245  if( addr[0] == 0x01 ) { // family code DS2401/DS1990A
246  found++;
247  if( check(addr) == true ) {
248  known++;
249  }
250  }
251  }
252  }
253  finish();
254  // signal for remote mode
255  if( found > 0 && dev.getList0().buttonMode() == 0 ) {
256  if( found == known ) {
257  led.ledOn(millis2ticks(500),0);
258  }
259  else {
260  led.ledOn(0,millis2ticks(500));
261  }
262  }
263  }
264 
265  bool learn (IButtonChannel* lc) {
266  uint8_t addr[8];
267  ow.reset_search();
268  while( ow.search(addr) == 1 ) {
269  if( OneWire::crc8(addr,7) == addr[7] ) {
270  if( addr[0] == 0x01 ) { // family code DS2401/DS1990A
271  if( find(addr) == 0 ) {
272  lc->storeID(addr);
273  return true;
274  }
275  }
276  }
277  }
278  return false;
279  }
280 
281  void trigger (AlarmClock& clock) {
282  // reactivate
283  set(millis2ticks(250));
284  clock.add(*this);
285  ++cnt;
286  // check if we have a learning channel
287  IButtonChannel* lc = learning();
288  if( lc != 0 ) {
289  uint8_t cycle = cnt & 0x01;
290  led.ledOn(cycle == 0 ? tick : 0, cycle == 0 ? 0 : tick);
291  // if we have learned a new ID
292  if( learn(lc) == true ) {
293  clock.cancel(*this);
294  set(seconds2ticks(5));
295  led.ledOff();
296  led.ledOn(tick);
297  clock.add(*this);
298  }
299  }
300  else {
301  // scan the bus now
302  scanMulti();
303  }
304  }
305 };
306 
307 }
308 
309 #endif
as::Alarm
Definition: Alarm.h:15
as::Channel
Definition: Channel.h:21
as::ActionSetMsg
Definition: Message.h:505
as::AlarmClock
Definition: AlarmClock.h:32
as::RemoteEventMsg
Definition: Message.h:463
as::SensorEventMsg
Definition: Message.h:480
as::ActionCommandMsg
Definition: Message.h:528
as::IButtonScanner
Definition: IButton.h:164
as::DualStatusLed< LED_GREEN, LED_RED >
as::IButtonChannel
Definition: IButton.h:24