AskSin++
Message.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 __Message_h__
7 #define __Message_h__
8 
9 #include "HMID.h"
10 #include "Peer.h"
11 #include "Defines.h"
12 #include "Debug.h"
13 
14 //#define MaxDataLen 60 // maximum length of received bytes
15 #define MaxDataLen 30
16 
17 namespace as {
18 
19 // some forward declarations
20 class ConfigPeerAddMsg;
21 class ConfigPeerRemoveMsg;
22 class ConfigPeerListReqMsg;
23 class ConfigParamReqMsg;
24 class ConfigStartMsg;
25 class ConfigEndMsg;
26 class ConfigWriteIndexMsg;
27 
28 class AckMsg;
29 class Ack2Msg;
30 class AckStatusMsg;
31 class NackMsg;
32 class AckAesMsg;
33 class AesChallengeMsg;
34 class AesResponseMsg;
35 class AesExchangeMsg;
36 
37 class InfoActuatorStatusMsg;
38 class InfoParamResponsePairsMsg;
39 class InfoPeerListMsg;
40 
41 class SerialInfoMsg;
42 class DeviceInfoMsg;
43 class RemoteEventMsg;
44 class SensorEventMsg;
45 class ActionMsg;
46 class ActionSetMsg;
47 class ActionCommandMsg;
48 
49 class ValuesMsg;
50 
51 class Message {
52 public:
53 
54  enum Flags {
55  WKUP = 0x01, // send initially to keep the device awake
56  WKMEUP = 0x02, // awake - hurry up to send messages
57  BCAST = 0x04, // broadcast message
58  BURST = 0x10, // this message was sent with burst
59  BIDI = 0x20, // response is expected
60  RPTED = 0x40, // repeated (repeater operation)
61  RPTEN = 0x80, // this message is allowed to be repeated
62  };
63 
64 protected:
65  uint8_t len; // message length
66  uint8_t cnt; // counter, if it is an answer counter has to reflect the answered message, otherwise own counter has to be used
67  uint8_t flag; // see structure of message flags
68  uint8_t typ; // type of message
69  HMID fromID; // sender ID
70  HMID toID; // receiver id, broadcast for 0
71  uint8_t comm; // type of message
72  uint8_t subcom; // type of message
73  uint8_t pload[MaxDataLen]; // payload
74 
75 public:
76  Message () : len(0), cnt(0), flag(0), typ(0), comm(0), subcom(0) {}
77 
78  void clear () {
79  len = 0;
80  }
81 
82  uint8_t* buffer () {
83  return &cnt;
84  }
85 
86  const uint8_t* buffer () const {
87  return &cnt;
88  }
89 
90  uint8_t buffersize () {
91  return sizeof(Message)-1;
92  }
93 
94  uint8_t* data () {
95  return pload;
96  }
97 
98  const uint8_t* data () const {
99  return pload;
100  }
101 
102  uint8_t datasize () const {
103  return len >= 11 ? len - 11 : 0;
104  }
105 
106  void append (uint8_t data) {
107  *(buffer() + len) = data;
108  len++;
109  }
110 
111  void append (uint16_t data) {
112  uint8_t* ptr = buffer() + len;
113  *ptr = (uint8_t)(data >> 8);
114  *(ptr+1) = (uint8_t)(data & 0xff);
115  len += 2;
116  }
117 
118  void append (uint32_t data) {
119  append((uint16_t)(data >> 16));
120  append((uint16_t)(data & 0xffff));
121  }
122 
123  void append (void* data,uint8_t l) {
124  memcpy(buffer()+len,data,l);
125  len += l;
126  }
127 
128  void append (uint8_t d1, uint8_t d2, uint8_t d3) {
129  uint8_t* ptr = buffer() + len;
130  *ptr = d1;
131  *(ptr+1) = d2;
132  *(ptr+2) = d3;
133  len += 3;
134  }
135 
136  void append (uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4) {
137  uint8_t* ptr = buffer() + len;
138  *ptr = d1;
139  *(ptr+1) = d2;
140  *(ptr+2) = d3;
141  *(ptr+3) = d4;
142  len += 4;
143  }
144 
145  void initWithCount(uint8_t length, uint8_t typ, uint8_t flags, uint8_t comm) {
146  this->len = length;
147  this->typ = typ;
148  this->flag = flags;
149  this->comm = comm;
150  }
151 
152  void init(uint8_t length, uint8_t cnt, uint8_t typ, uint8_t flags, uint8_t comm, uint8_t sub) {
153  initWithCount(length,typ,flags,comm);
154  this->cnt = cnt;
155  this->subcom = sub;
156  }
157 
158  void length (uint8_t l) {
159  len = l;
160  }
161 
162  uint8_t length () const {
163  return len;
164  }
165 
166  void count (uint8_t c) {
167  cnt = c;
168  }
169 
170  uint8_t count () const {
171  return cnt;
172  }
173 
174  void from(const HMID& hmid) {
175  fromID = hmid;
176  }
177 
178  const HMID& from () const {
179  return fromID;
180  }
181 
182  HMID& from () {
183  return fromID;
184  }
185 
186  void to(const HMID& hmid) {
187  toID = hmid;
188  if( hmid == HMID::broadcast ) {
189  flag |= BCAST;
190  flag &= ~BIDI;
191  }
192  }
193 
194  const HMID& to () const {
195  return toID;
196  }
197 
198  HMID& to () {
199  return toID;
200  }
201 
202  void type (uint8_t t) {
203  typ=t;
204  }
205 
206  uint8_t type () const {
207  return typ;
208  }
209 
210  void flags (uint8_t f) {
211  flag = f;
212  }
213 
214  uint8_t flags () const {
215  return flag;
216  }
217 
218  void command (uint8_t c) {
219  comm = c;
220  }
221 
222  uint8_t command () const {
223  return comm;
224  }
225 
226  void subcommand (uint8_t c) {
227  subcom = c;
228  }
229 
230  uint8_t subcommand () const {
231  return subcom;
232  }
233 
234  void decode () {
235  decode(buffer(),length());
236  }
237 
238  void decode(uint8_t *buf, uint8_t len) {
239  uint8_t prev = buf[0];
240  buf[0] = (~buf[0]) ^ 0x89;
241  uint8_t i, t;
242  for (i=1; i<len-1; i++) {
243  t = buf[i];
244  buf[i] = (prev + 0xdc) ^ buf[i];
245  prev = t;
246  }
247  buf[i] ^= buf[1];
248  }
249 
250  void encode () {
251  encode(buffer(),length());
252  }
253 
254  void encode(uint8_t *buf,uint8_t len) {
255  buf[0] = (~buf[0]) ^ 0x89;
256  uint8_t buf2 = buf[1];
257  uint8_t prev = buf[0];
258  uint8_t i;
259  for (i=1; i<len-1; i++) {
260  prev = (prev + 0xdc) ^ buf[i];
261  buf[i] = prev;
262  }
263  buf[i] ^= buf2;
264  }
265 
266  void dump () const {
267  DHEX(length());
268  DPRINT(F(" "));
269  DHEX(count());
270  DPRINT(F(" "));
271  DHEX(flags());
272  DPRINT(F(" "));
273  DHEX(type());
274  DPRINT(F(" "));
275  from().dump();
276  DPRINT(F(" "));
277  to().dump();
278  DPRINT(F(" "));
279  DHEX(buffer()+9,length()-9);
280  DPRINT(F(" - "));
281  DDECLN((uint32_t)millis());
282  }
283 
284  void setRepeated () {
285  flag |= RPTED;
286  }
287 
288  void setRpten () {
289  flag |= RPTEN;
290  }
291 
292  void setAck () {
293  flag |= BIDI;
294  }
295 
296  void clearAck () {
297  flag &= ~BIDI;
298  }
299 
300  bool isKeepAwake () const {
301  return (flag & WKUP) == WKUP;
302  }
303 
304  bool isWakeMeUp () const {
305  return (flag & WKMEUP) == WKMEUP;
306  }
307 
308  void setWakeMeUp () {
309  flag |= WKMEUP;
310  }
311 
312  void setBroadcast () {
313  flag |= BCAST;
314  }
315 
316  bool isBroadcast () const {
317  return (flag & BCAST) == BCAST;
318  }
319 
320  bool isRepeated () const {
321  return (flag & RPTED) == RPTED;
322  }
323 
324  bool ackRequired () const {
325  return (flag & BIDI) == BIDI;
326  }
327 
328  bool burstRequired () const {
329  return (flag & BURST) == BURST;
330  }
331 
332  void burstRequired (bool value) {
333  if( value == true ) {
334  flag |= BURST;
335  }
336  else {
337  flag &= ~BURST;
338  }
339  }
340 
341  bool isPairSerial () const {
342  return typ==AS_MESSAGE_CONFIG && subcom==AS_CONFIG_PAIR_SERIAL;
343  }
344 
345  bool isAck () const {
346  return typ==AS_MESSAGE_RESPONSE && (comm & AS_RESPONSE_NACK) == AS_RESPONSE_ACK;
347  }
348 
349  bool isNack () const {
350  return typ==AS_MESSAGE_RESPONSE && (comm & AS_RESPONSE_NACK) == AS_RESPONSE_NACK;
351  }
352 
353  bool isResponseAes () const {
354  return typ==AS_MESSAGE_RESPONSE_AES;
355  }
356 
357  bool isChallengeAes () const {
358  return typ==AS_MESSAGE_RESPONSE && (comm & AS_RESPONSE_AES_CHALLANGE) == AS_RESPONSE_AES_CHALLANGE;
359  }
360 
361  bool isRemoteEvent () const {
362  return typ==AS_MESSAGE_REMOTE_EVENT;
363  }
364 
365  bool isSensorEvent () const {
366  return typ==AS_MESSAGE_SENSOR_EVENT;
367  }
368 
369  bool isInfoActuatorStatusMsg () const {
370  return typ==AS_MESSAGE_INFO && comm==AS_INFO_ACTUATOR_STATUS;
371  }
372 
373  // cast to specific read-only message types
374  const ConfigPeerAddMsg& configPeerAdd () const { return *(ConfigPeerAddMsg*)this; }
375  const ConfigPeerRemoveMsg& configPeerRemove () const { return *(ConfigPeerRemoveMsg*)this; }
376  const ConfigPeerListReqMsg& configPeerListReq () const { return *(ConfigPeerListReqMsg*)this; }
377  const ConfigParamReqMsg& configParamReq () const { return *(ConfigParamReqMsg*)this; }
378  const ConfigStartMsg& configStart () const { return *(ConfigStartMsg*)this; }
379  const ConfigEndMsg& configEnd () const { return *(ConfigEndMsg*)this; }
380  const ConfigWriteIndexMsg& configWriteIndex () const { return *(ConfigWriteIndexMsg*)this; }
381 
382  const RemoteEventMsg& remoteEvent () const { return *(RemoteEventMsg*)this; }
383  const SensorEventMsg& sensorEvent () const { return *(SensorEventMsg*)this; }
384  const ActionMsg& action () const { return *(ActionMsg*)this; }
385  const ActionSetMsg& actionSet () const { return *(ActionSetMsg*)this; }
386  const ActionCommandMsg& actionCommand () const { return *(ActionCommandMsg*)this; }
387 
388  // cast to write message types
389  AckMsg& ack () { return *(AckMsg*)this; }
390  Ack2Msg& ack2 () { return *(Ack2Msg*)this; }
391  AckStatusMsg& ackStatus () { return *(AckStatusMsg*)this; }
392  NackMsg& nack () { return *(NackMsg*)this; }
393  AckAesMsg& ackAes () { return *(AckAesMsg*)this; }
394  AesChallengeMsg& aesChallenge () { return *(AesChallengeMsg*)this; }
395  AesResponseMsg& aesResponse () { return *(AesResponseMsg*)this; }
396  AesExchangeMsg& aesExchange () { return *(AesExchangeMsg*)this; }
397 
398  InfoActuatorStatusMsg& infoActuatorStatus () { return *(InfoActuatorStatusMsg*)this; }
399  InfoParamResponsePairsMsg& infoParamResponsePairs () { return *(InfoParamResponsePairsMsg*)this; }
400  InfoPeerListMsg& infoPeerList () { return *(InfoPeerListMsg*)this; }
401 
402  DeviceInfoMsg& deviceInfo () { return *(DeviceInfoMsg*)this; }
403  SerialInfoMsg& serialInfo () { return *(SerialInfoMsg*)this; }
404 
405  ValuesMsg& values () { return *(ValuesMsg*)this; }
406 };
407 
408 
409 class ConfigMsg : public Message {
410 protected:
411  ConfigMsg () {}
412 public:
413  uint8_t channel () const { return command(); }
414 };
415 
416 class ConfigPeerAddMsg : public ConfigMsg {
417 protected:
418  ConfigPeerAddMsg () {}
419 public:
420  const Peer& peer1 () const { return *((const Peer*)data()); }
421  Peer peer2 () const { return Peer(peer1(),*(data()+sizeof(Peer))); }
422  // if channel of peer2 == 0 or
423  // both channels are the same then we peer single mode
424  uint8_t peers () const {
425  Peer p2 = peer2();
426  return (p2.channel() == 0) || (p2 == peer1()) ? 1 : 2;
427  }
428 };
429 
431 protected:
432  ConfigPeerRemoveMsg () {}
433 };
434 
436 protected:
438 };
439 
440 class ConfigParamReqMsg : public ConfigMsg {
441 protected:
442  ConfigParamReqMsg () {}
443 public:
444  const Peer& peer () const { return *((const Peer*)data()); }
445  uint8_t list () const { return *(data()+sizeof(Peer)); }
446 };
447 
449 protected:
450  ConfigStartMsg () {}
451 };
452 
453 class ConfigEndMsg : public ConfigMsg {
454 protected:
455  ConfigEndMsg () {}
456 };
457 
459 protected:
460  ConfigWriteIndexMsg () {}
461 };
462 
463 class RemoteEventMsg : public Message {
464 protected:
465  RemoteEventMsg() {}
466 public:
467  void init(uint8_t msgcnt,uint8_t ch,uint8_t counter,bool lg,bool lowbat) {
468  uint8_t flags = lg ? 0x40 : 0x00;
469  if( lowbat == true ) {
470  flags |= 0x80; // low battery
471  }
472  Message::init(0xb,msgcnt,AS_MESSAGE_REMOTE_EVENT,BIDI|WKMEUP,(ch & 0x3f) | flags,counter);
473  }
474 
475  Peer peer () const { return Peer(from(),command() & 0x3f); }
476  uint8_t counter () const { return subcommand(); }
477  bool isLong () const { return (command() & 0x40) == 0x40; }
478 };
479 
481 protected:
482  SensorEventMsg() {}
483 public:
484  void init(uint8_t msgcnt,uint8_t ch,uint8_t counter,uint8_t value,bool lowbat) {
485  init(msgcnt,ch,counter,value,false,lowbat);
486  }
487  void init(uint8_t msgcnt,uint8_t ch,uint8_t counter,uint8_t value,bool lg,bool lowbat) {
488  uint8_t flags = lg ? 0x40 : 0x00;
489  if( lowbat == true ) {
490  flags |= 0x80; // low battery
491  }
492  Message::init(0xc,msgcnt,AS_MESSAGE_SENSOR_EVENT,BIDI|WKMEUP,(ch & 0x3f) | flags,counter);
493  *data() = value;
494  }
495  uint8_t value () const { return *data(); }
496 };
497 
498 class ActionMsg : public Message {
499 protected:
500  ActionMsg() {}
501 public:
502  uint8_t channel () const { return subcommand(); }
503 };
504 
505 class ActionSetMsg : public ActionMsg {
506 protected:
507  ActionSetMsg() {}
508 public:
509  uint8_t channel () const { return subcommand(); }
510  uint8_t value () const { return *data(); }
511  uint16_t ramp () const {
512  uint16_t value = 0;
513  if( datasize() >= 3) {
514  value = (*(data()+1) << 8) + *(data()+2);
515  }
516  return value;
517  }
518  uint16_t delay () const {
519  uint16_t dly = 0xffff;
520  if( datasize() >= 5) {
521  dly = (*(data()+3) << 8) + *(data()+4);
522  }
523  if( dly == 0 ) dly = 0xffff;
524  return dly;
525  }
526 };
527 
528 class ActionCommandMsg : public ActionMsg {
529 protected:
530  ActionCommandMsg() {}
531 public:
532  uint8_t channel () const { return subcommand(); }
533  uint8_t len () const { return (datasize()); }
534  uint8_t value (uint8_t idx) const { return *(data()+idx); }
535  bool eot (uint8_t eot_char=AS_ACTION_COMMAND_EOT) const { return (length() >= 12) ? (*(data()+length()-12) == eot_char) : false; }
536 };
537 
538 class AckMsg : public Message {
539 public:
540  void init(uint8_t flags=0x00) {
541  initWithCount(0x0a,AS_MESSAGE_RESPONSE,flags,AS_RESPONSE_ACK);
542  }
543 };
544 
545 class Ack2Msg : public Message {
546 public:
547  void init(uint8_t flags=0x00) {
548  initWithCount(0x0a,AS_MESSAGE_RESPONSE,flags,AS_RESPONSE_ACK2);
549  }
550 };
551 
552 class AckStatusMsg : public Message {
553 public:
554  template <class ChannelType>
555  void init(ChannelType& ch,uint8_t rssi) {
556  initWithCount(0x0e,AS_MESSAGE_RESPONSE,0x00,AS_RESPONSE_ACK_STATUS);
557  subcom = ch.number();
558  pload[0] = ch.status();
559  pload[1] = ch.flags();
560  pload[2] = rssi;
561  }
562 };
563 
564 class NackMsg : public Message {
565 public:
566  void init() {
567  initWithCount(0x0a,AS_MESSAGE_RESPONSE,0x00,AS_RESPONSE_NACK);
568  }
569 };
570 
571 class AckAesMsg : public Message {
572 public:
573  void init(const uint8_t* data) {
574  initWithCount(0x12,AS_MESSAGE_RESPONSE,0x00,AS_RESPONSE_ACK);
575  subcom = data[0];
576  pload[0] = data[1];
577  pload[1] = data[2];
578  pload[2] = data[3];
579  }
580 };
581 
582 class AesChallengeMsg : public Message {
583 public:
584  void init(const Message& msg,uint8_t keyidx) {
585  initWithCount(0x11,AS_MESSAGE_RESPONSE,RPTEN|BIDI,AS_RESPONSE_AES_CHALLANGE);
586  to(msg.from());
587  from(msg.to());
588  count(msg.count());
589  uint8_t* tmp = data()-1;
590  for( uint8_t i=0; i<6; i++ ) {
591  *tmp = (uint8_t)rand();
592  tmp++;
593  }
594  *tmp = keyidx;
595  }
596  const uint8_t* challenge () const {
597  return data()-1;
598  }
599  uint8_t keyindex () const {
600  return *(challenge()+6);
601  }
602 };
603 
604 class AesResponseMsg : public Message {
605 public:
606  void init(const Message& msg) {
607  initWithCount(0x19,AS_MESSAGE_RESPONSE_AES,BIDI,0x00);
608  count(msg.count());
609  }
610  uint8_t* data () {
611  return Message::data()-2;
612  }
613 };
614 
615 class AesExchangeMsg : public Message {
616 public:
617  uint8_t* data () {
618  return Message::data()-2;
619  }
620 };
621 
623 public:
624  template <class ChannelType>
625  void init (uint8_t count,ChannelType& ch,uint8_t rssi) {
626  Message::init(0x0e,count,AS_MESSAGE_INFO,BIDI|WKMEUP,AS_INFO_ACTUATOR_STATUS,ch.number());
627  pload[0] = ch.status();
628  pload[1] = ch.flags();
629  pload[2] = rssi;
630  }
631 };
632 
634 public:
635  void init (uint8_t count) {
636  initWithCount(0x0b-1+(8*2),AS_MESSAGE_INFO,BIDI,AS_INFO_PARAM_RESPONSE_PAIRS);
637  cnt = count;
638  }
639  uint8_t* data() { return Message::data()-1; }
640  void entries (uint8_t num) { length(0x0b-1+(num*2)); };
641 };
642 
643 class InfoPeerListMsg : public Message {
644 public:
645  void init (uint8_t count) {
646  initWithCount(0x0b-1+(4*sizeof(Peer)),AS_MESSAGE_INFO,Message::BIDI,AS_INFO_PEER_LIST);
647  cnt = count;
648  }
649  uint8_t* data() { return Message::data()-1; }
650  void entries (uint8_t num) { length(0x0b-1+(num*sizeof(Peer))); };
651 };
652 
653 class DeviceInfoMsg : public Message {
654 public:
655  void init (__attribute__((unused)) const HMID& to,uint8_t count) {
656  Message::init(0x1a,count,AS_MESSAGE_DEVINFO,0x00,AS_INFO_SERIAL,0x00);
657  }
658  uint8_t* data() { return Message::data()-2; }
659  void fill(uint8_t firmversion,uint8_t modelid[2],const char* serial,uint8_t subtype,uint8_t devinfo[3]) {
660  uint8_t* buf = data();
661  *buf = firmversion;
662  memcpy(buf+1,modelid,2);
663  memcpy(buf+3,serial,10);
664  *(buf+13) = subtype;
665  memcpy(buf+14,devinfo,3);
666  }
667  void fill(uint8_t firmversion,uint8_t subtype) {
668  uint8_t* buf = data();
669  *buf = firmversion;
670  *(buf+13) = subtype;
671  }
672  uint8_t* serial () { return data() + 3; }
673  uint8_t* model () { return data() + 1; }
674  uint8_t* info () { return data() + 14; }
675 };
676 
677 class SerialInfoMsg : public Message {
678 public:
679  void init (__attribute__((unused)) const HMID& to,uint8_t count) {
680  Message::init(0x14,count,AS_MESSAGE_INFO,0x00,AS_INFO_SERIAL,0x00);
681  }
682  uint8_t* data() { return Message::data()-4; }
683  void fill(const char* serial) {
684  uint8_t* buf = data();
685  memcpy(buf+3,serial,10);
686  }
687  uint8_t* serial () { return data() + 3; }
688 };
689 
690 class ValuesMsg : public Message {
691 public:
692  void init(uint8_t msgcnt,uint8_t ch) {
693  Message::init(0x0b,msgcnt,AS_MESSAGE_SENSOR_DATA,BIDI|WKMEUP,ch,0);
694  }
695  template <typename T>
696  void add (T value) {
697  uint8_t* values = buffer() + len + sizeof(T) - 1;
698  uint8_t num = sizeof(T);
699  while( num > 0 ) {
700  *values = value & 0xff;
701  value >>= 8;
702  --values;
703  --num;
704  }
705  // update length of message
706  len += sizeof(T);
707  // store number of values inside this message
708  subcommand(subcommand()+1);
709  }
710 };
711 
712 }
713 
714 #endif
as::InfoActuatorStatusMsg
Definition: Message.h:622
as::ConfigStartMsg
Definition: Message.h:448
as::ConfigWriteIndexMsg
Definition: Message.h:458
as::ActionSetMsg
Definition: Message.h:505
as::Message
Definition: Message.h:51
as::Peer
Definition: Peer.h:14
as::ActionMsg
Definition: Message.h:498
as::ValuesMsg
Definition: Message.h:690
as::AckAesMsg
Definition: Message.h:571
as::ConfigEndMsg
Definition: Message.h:453
as::AesExchangeMsg
Definition: Message.h:615
as::ConfigPeerListReqMsg
Definition: Message.h:435
as::SerialInfoMsg
Definition: Message.h:677
as::AckStatusMsg
Definition: Message.h:552
as::ConfigParamReqMsg
Definition: Message.h:440
as::ConfigPeerRemoveMsg
Definition: Message.h:430
as::NackMsg
Definition: Message.h:564
as::ConfigMsg
Definition: Message.h:409
as::InfoPeerListMsg
Definition: Message.h:643
as::RemoteEventMsg
Definition: Message.h:463
as::SensorEventMsg
Definition: Message.h:480
as::ActionCommandMsg
Definition: Message.h:528
as::AckMsg
Definition: Message.h:538
as::Ack2Msg
Definition: Message.h:545
as::AesChallengeMsg
Definition: Message.h:582
as::DeviceInfoMsg
Definition: Message.h:653
as::AesResponseMsg
Definition: Message.h:604
as::InfoParamResponsePairsMsg
Definition: Message.h:633
as::ConfigPeerAddMsg
Definition: Message.h:416
as::HMID
Definition: HMID.h:14