AskSin++
Remote.h
1 //- -----------------------------------------------------------------------------------------------------------------------
2 // AskSin++
3 // 2017-04-12 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
4 //- -----------------------------------------------------------------------------------------------------------------------
5 
6 #ifndef __REMOTE_H__
7 #define __REMOTE_H__
8 
9 #include "Channel.h"
10 #include "ChannelList.h"
11 #include "Button.h"
12 #include "Message.h"
13 #include "Register.h"
14 
15 namespace as {
16 
17 DEFREGISTER(RemoteReg1,CREG_LONGPRESSTIME,CREG_AES_ACTIVE,CREG_DOUBLEPRESSTIME)
18 class RemoteList1 : public RegList1<RemoteReg1> {
19 public:
20  RemoteList1 (uint16_t addr) : RegList1<RemoteReg1>(addr) {}
21  void defaults () {
22  clear();
23  longPressTime(1);
24  // aesActive(false);
25  // doublePressTime(0);
26  }
27 };
28 
29 template<class HALTYPE,int PEERCOUNT,class List0Type=List0,class List1Type=RemoteList1>
30 class RemoteChannel : public Channel<HALTYPE,List1Type,EmptyList,DefList4,PEERCOUNT,List0Type>, public Button {
31 
32 private:
33  uint8_t repeatcnt;
34  volatile bool isr;
35 
36 public:
37 
39 
40  RemoteChannel () : BaseChannel(), repeatcnt(0), isr(false) {}
41  virtual ~RemoteChannel () {}
42 
43  Button& button () { return *(Button*)this; }
44 
45  uint8_t status () const {
46  return 0;
47  }
48 
49  uint8_t flags () const {
50  return 0;
51  }
52 
53  virtual void state(uint8_t s) {
54  DHEX(BaseChannel::number());
55  Button::state(s);
56  RemoteEventMsg& msg = (RemoteEventMsg&)this->device().message();
57  msg.init(this->device().nextcount(),this->number(),repeatcnt,(s==longreleased || s==longpressed),this->device().battery().low());
58  if( s == released || s == longreleased) {
59  // send the message to every peer
60  this->device().sendPeerEvent(msg,*this);
61  repeatcnt++;
62  }
63  else if (s == longpressed) {
64  // broadcast the message
65  this->device().broadcastPeerEvent(msg,*this);
66  }
67  }
68 
69  uint8_t state() const {
70  return Button::state();
71  }
72 
73  bool pressed () const {
74  uint8_t s = state();
75  return s == Button::pressed || s == Button::debounce || s == Button::longpressed;
76  }
77 
78  bool configChanged() {
79  //we have to add 300ms to the value set in CCU!
80  uint16_t _longpressTime = 300 + (this->getList1().longPressTime() * 100);
81  //DPRINT("longpressTime = ");DDECLN(_longpressTime);
82  setLongPressTime(millis2ticks(_longpressTime));
83  return true;
84  }
85 };
86 
87 template<class DeviceType,int DownChannel,int UpChannel>
88 class RemoteEncoder : public BaseEncoder, public Alarm {
89  int8_t last;
90  DeviceType& sdev;
91 public:
92  RemoteEncoder(DeviceType& d) : BaseEncoder(), Alarm(0), last(0), sdev(d) {}
93  virtual ~RemoteEncoder() {}
94 
95  void process () {
96  int8_t dir = read();
97  if( dir != 0 ) {
98  if( dir < 0 ) dir = -1;
99  else dir = 1;
100  sysclock.cancel(*this);
101  if( last != 0 && last != dir ) {
102  trigger(sysclock);
103  }
104  sdev.channel(dir < 0 ? DownChannel : UpChannel).state(StateButton<>::longpressed);
105  set(millis2ticks(400));
106  last = dir;
107  sysclock.add(*this);
108  }
109  }
110 
111  virtual void trigger (__attribute__((unused)) AlarmClock& clock) {
112  if( last != 0 ) {
113  sdev.channel(last < 0 ? DownChannel : UpChannel).state(StateButton<>::longreleased);
114  last = 0;
115  }
116  }
117 };
118 
119 
120 #define remoteISR(device,chan,pin) class device##chan##ISRHandler { \
121  public: \
122  static void isr () { device.channel(chan).irq(); } \
123 }; \
124 device.channel(chan).button().init(pin); \
125 if( digitalPinToInterrupt(pin) == NOT_AN_INTERRUPT ) \
126  enableInterrupt(pin,device##chan##ISRHandler::isr,CHANGE); \
127 else \
128  attachInterrupt(digitalPinToInterrupt(pin),device##chan##ISRHandler::isr,CHANGE);
129 
130 #define remoteChannelISR(chan,pin) class __##pin##ISRHandler { \
131  public: \
132  static void isr () { chan.irq(); } \
133 }; \
134 chan.button().init(pin); \
135 if( digitalPinToInterrupt(pin) == NOT_AN_INTERRUPT ) \
136  enableInterrupt(pin,__##pin##ISRHandler::isr,CHANGE); \
137 else \
138  attachInterrupt(digitalPinToInterrupt(pin),__##pin##ISRHandler::isr,CHANGE);
139 
140 }
141 
142 #endif
as::Alarm
Definition: Alarm.h:15
as::Channel
Definition: Channel.h:21
as::AlarmClock
Definition: AlarmClock.h:32
as::BaseEncoder
Definition: Button.h:288
as::RemoteEncoder
Definition: Remote.h:88
as::RemoteEventMsg
Definition: Message.h:463
as::DeviceType
Definition: Device.h:43
as::StateButton< HIGH, LOW, INPUT_PULLUP >
as::RemoteChannel
Definition: Remote.h:30