MySensors Library & Examples  2.3.2-62-ge298769
PJON.h
1 
2 /*-O//\ __ __
3  |-gfo\ |__| | | | |\ | ®
4  |!y°o:\ | __| |__| | \| 13.0
5  |y"s§+`\ multi-master, multi-media bus network protocol
6  /so+:-..`\ Copyright 2010-2020 by Giovanni Blu Mitolo [email protected]
7  |+/:ngr-*.`\
8  |5/:%&-a3f.:;\
9  \+//u/+g%{osv,,\
10  \=+&/osw+olds.\\
11  \:/+-.-°-:+oss\
12  | | \oy\\
13  > <
14 ______-| |-__________________________________________________________________
15 
16 For the PJON® Protocol specification see the specification directory.
17 
18 Thanks to the support, expertise, kindness and talent of the following
19 contributors, the protocol's documentation, specification and implementation
20 have been strongly tested, enhanced and verified:
21 
22  Fred Larsen, Zbigniew Zasieczny, Matheus Garbelini, sticilface,
23  Felix Barbalet, Oleh Halitskiy, fotosettore, fabpolli, Adrian Sławiński,
24  Osman Selçuk Aktepe, Jorgen-VikingGod, drtrigon, Endre Karlson,
25  Wilfried Klaas, budaics, ibantxo, gonnavis, maxidroms83, Evgeny Dontsov,
26  zcattacz, Valerii Koval, Ivan Kravets, Esben Soeltoft, Alex Grishin,
27  Andrew Grande, Michael Teeww, Paolo Paolucci, per1234, Santiago Castro,
28  pacproduct, elusive-code, Emanuele Iannone, Christian Pointner,
29  Fabian Gärtner, Mauro Mombelli, Remo Kallio, hyndruide, sigmaeo, filogranaf,
30  Maximiliano Duarte, Viktor Szépe, Shachar Limor, Andrei Volkau, maniekq,
31  DetAtHome, Michael Branson, chestwood96, Mattze96, Steven Bense,
32  Jack Anderson, callalilychen and Julio Aguirre.
33 
34 Compatible tools:
35 
36  - ModuleInterface - https://github.com/fredilarsen/ModuleInterface
37  - PJON-cython - https://github.com/xlfe/PJON-cython
38  - PJON-piper - https://github.com/Girgitt/PJON-piper
39  - PJON-python - https://github.com/Girgitt/PJON-python
40  - PJON-gRPC - https://github.com/Galitskiy/PJON-gRPC
41 _____________________________________________________________________________
42 
43 This software is experimental and it is distributed "AS IS" without any
44 warranty, use it at your own risk.
45 
46 Copyright 2010-2020 by Giovanni Blu Mitolo [email protected]
47 
48 Licensed under the Apache License, Version 2.0 (the "License");
49 you may not use this file except in compliance with the License.
50 You may obtain a copy of the License at
51 
52  http://www.apache.org/licenses/LICENSE-2.0
53 
54 Unless required by applicable law or agreed to in writing, software
55 distributed under the License is distributed on an "AS IS" BASIS,
56 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
57 See the License for the specific language governing permissions and
58 limitations under the License. */
59 
60 #pragma once
61 #include "interfaces/PJON_Interfaces.h"
62 #include "PJONDefines.h"
63 
64 static void PJON_dummy_receiver_handler(
65  uint8_t *, // payload
66  uint16_t, // length
67  const PJON_Packet_Info & // packet_info
68 ) {};
69 
70 static void PJON_dummy_error_handler(
71  uint8_t, // code
72  uint16_t, // data
73  void * // custom_pointer
74 ) {};
75 
76 template<typename Strategy>
77 class PJON
78 {
79 public:
80  Strategy strategy;
81  uint8_t config = PJON_TX_INFO_BIT | PJON_ACK_REQ_BIT;
82  uint8_t data[PJON_PACKET_MAX_LENGTH];
83  PJON_Packet_Info last_packet_info;
84  PJON_Packet packets[PJON_MAX_PACKETS];
85  PJON_Endpoint tx;
86 
87 #if(PJON_INCLUDE_PACKET_ID)
88  PJON_Packet_Record recent_packet_ids[PJON_MAX_RECENT_PACKET_IDS];
89 #endif
90 
91 #if(PJON_INCLUDE_PORT)
92  uint16_t port = PJON_BROADCAST;
93 #endif
94 
95  /* PJON initialization with no parameters:
96  State: Local (bus_id: 0.0.0.0)
97  Acknowledge: true
98  device id: PJON_NOT_ASSIGNED (255)
99  Mode: PJON_HALF_DUPLEX
100  Sender info: true (Sender info is included in the packet)
101 
102  PJON<SoftwareBitBang> bus; */
103 
104  PJON() : strategy(Strategy())
105  {
106  set_default();
107  };
108 
109  /* PJON initialization passing device id:
110  PJON<SoftwareBitBang> bus(1); */
111 
112  PJON(uint8_t device_id) : strategy(Strategy())
113  {
114  tx.id = device_id;
115  set_default();
116  };
117 
118  /* PJON initialization passing bus and device id:
119  uint8_t my_bus = {1, 1, 1, 1};
120  PJON<SoftwareBitBang> bus(my_bys, 1); */
121 
122  PJON(const uint8_t *b_id, uint8_t device_id) : strategy(Strategy())
123  {
124  tx.id = device_id;
125  PJONTools::copy_id(tx.bus_id, b_id, 4);
126  config |= PJON_MODE_BIT;
127  set_default();
128  };
129 
130 #if(PJON_INCLUDE_MAC)
131 
132  /* PJON initialization passing the mac address:
133  const uint8_t mac[6] = {1, 2, 3, 4, 5, 6};
134  PJON<SoftwareBitBang> bus(mac); */
135 
136  PJON(const uint8_t *mac_addr) : strategy(Strategy())
137  {
138  PJONTools::copy_id(tx.mac, mac_addr, 6);
139  config |= PJON_MAC_BIT;
140  set_default();
141  };
142 
143 #endif
144 
145  /* Begin function to be called after initialization: */
146 
147  void begin()
148  {
149  PJON_RANDOM_SEED(PJON_ANALOG_READ(_random_seed) + tx.id);
150  strategy.begin(tx.id);
151 #if(PJON_INCLUDE_PACKET_ID)
152  _packet_id_seed = PJON_RANDOM(65535) + tx.id;
153 #endif
154  };
155 
156  /* Compose packet in PJON format: */
157 
158  uint16_t compose_packet(
159  PJON_Packet_Info info,
160  uint8_t *destination,
161  const void *source,
162  uint16_t length
163  )
164  {
165  info.header = (info.header == PJON_NO_HEADER) ? config : info.header;
166  info.tx = tx;
167 #if(PJON_INCLUDE_PACKET_ID)
168  if(!info.id && (info.header & PJON_PACKET_ID_BIT)) {
169  info.id = PJONTools::new_packet_id(_packet_id_seed++);
170  }
171 #endif
172 #if(PJON_INCLUDE_PORT)
173  if(
174  (port != PJON_BROADCAST) && (info.port == PJON_BROADCAST) &&
175  (info.header & PJON_PORT_BIT)
176  ) {
177  info.port = port;
178  }
179 #endif
180 #if(PJON_INCLUDE_MAC)
181  if(info.header & PJON_MAC_BIT) {
182  PJONTools::copy_id(info.tx.mac, tx.mac, 6);
183  }
184 #endif
185  uint16_t l = PJONTools::compose_packet(
186  info, destination, source, length
187  );
188  if(l < PJON_PACKET_MAX_LENGTH) {
189  return l;
190  }
191  _error(PJON_CONTENT_TOO_LONG, l, _custom_pointer);
192  return 0;
193  };
194 
195  /* Get device id: */
196 
197  uint8_t device_id() const
198  {
199  return tx.id;
200  };
201 
202  /* Add packet to buffer (delivery attempt by the next update() call): */
203 
204  uint16_t dispatch(
205  const PJON_Packet_Info &info,
206  const void *packet,
207  uint16_t length,
208  uint32_t timing = 0,
209  uint16_t packet_index = PJON_FAIL
210  )
211  {
212  bool p = (packet_index != PJON_FAIL);
213  for(uint16_t i = ((p) ? packet_index : 0); i < PJON_MAX_PACKETS; i++)
214  if(packets[i].state == 0 || p) {
215  if(!(length = compose_packet(
216  info, packets[i].content, packet, length
217  ))) {
218  return PJON_FAIL;
219  }
220  packets[i].length = length;
221  packets[i].state = PJON_TO_BE_SENT;
222  packets[i].registration = PJON_MICROS();
223  packets[i].timing = timing;
224  return i;
225  }
226  _error(PJON_PACKETS_BUFFER_FULL, PJON_MAX_PACKETS, _custom_pointer);
227  return PJON_FAIL;
228  };
229 
230  /* Returns a pointer to the bus id used by the instance: */
231 
232  const uint8_t *get_bus_id() const
233  {
234  return tx.bus_id;
235  };
236 
237  /* Get count of packets:
238  Don't pass any parameter to count all dispatched packets
239  Pass a device id to count all it's related packets */
240 
241  uint16_t get_packets_count(uint8_t device_id = PJON_NOT_ASSIGNED) const
242  {
243  uint16_t packets_count = 0;
244  for(uint16_t i = 0; i < PJON_MAX_PACKETS; i++) {
245  if(packets[i].state == 0) {
246  continue;
247  }
248  if(
249  device_id == PJON_NOT_ASSIGNED ||
250  packets[i].content[0] == device_id
251  ) {
252  packets_count++;
253  }
254  }
255  return packets_count;
256  };
257 
258  /* Fill a PJON_Packet_Info using parameters: */
259 
260  PJON_Packet_Info fill_info(
261  uint8_t rx_id,
262  uint8_t header,
263  uint16_t packet_id,
264  uint16_t rx_port
265  )
266  {
267  PJON_Packet_Info info;
268  info.rx.id = rx_id;
269  info.header = header;
270  PJONTools::copy_id(info.rx.bus_id, tx.bus_id, 4);
271 #if(PJON_INCLUDE_PACKET_ID)
272  info.id = packet_id;
273 #else
274  (void)packet_id;
275 #endif
276 #if(PJON_INCLUDE_PORT)
277  info.port = rx_port;
278 #else
279  (void)rx_port;
280 #endif
281  return info;
282  };
283 
284  /* Calculate packet overhead: */
285 
286  uint8_t packet_overhead(uint8_t header = PJON_NO_HEADER) const
287  {
288  return PJONTools::packet_overhead(
289  (header == PJON_NO_HEADER) ? config : header
290  );
291  };
292 
293  /* Fill a PJON_Packet_Info struct with data parsing a packet: */
294 
295  void parse(const uint8_t *packet, PJON_Packet_Info &packet_info) const
296  {
297  PJONTools::parse_header(packet, packet_info);
298  packet_info.custom_pointer = _custom_pointer;
299  };
300 
301  /* Try to receive data: */
302 
303  uint16_t receive()
304  {
305  uint16_t length = PJON_PACKET_MAX_LENGTH;
306  uint16_t batch_length = 0;
307  uint8_t overhead = 0;
308  bool extended_length = false, mac = false, drop = false;
309  for(uint16_t i = 0; i < length; i++) {
310  if(!batch_length) {
311  batch_length = strategy.receive_frame(data + i, length - i);
312  if(batch_length == PJON_FAIL || batch_length == 0) {
313  return PJON_FAIL;
314  }
315  }
316  batch_length--;
317 
318  if(i == 0)
319  if((data[i] != tx.id) && (data[i] != PJON_BROADCAST) && !_router) {
320  drop = true;
321  }
322 
323  if(i == 1) {
324  mac = (data[1] & PJON_MAC_BIT);
325  if(
326  (
327  !_router &&
328  ((config & PJON_MODE_BIT) && !(data[1] & PJON_MODE_BIT))
329  ) || (
330  (data[0] == PJON_BROADCAST) && (data[1] & PJON_ACK_REQ_BIT)
331  ) || (
332  (data[1] & PJON_EXT_LEN_BIT) && !(data[1] & PJON_CRC_BIT)
333  ) || (
334  !PJON_INCLUDE_PACKET_ID && (data[1] & PJON_PACKET_ID_BIT)
335  ) || (
336  !PJON_INCLUDE_PORT && (data[1] & PJON_PORT_BIT)
337  ) || (
338  (!PJON_INCLUDE_MAC && mac) || (mac && !(data[1] & PJON_CRC_BIT))
339  ) || (drop && !mac)
340  ) {
341  return PJON_BUSY;
342  }
343  extended_length = data[i] & PJON_EXT_LEN_BIT;
344  overhead = packet_overhead(data[i]);
345  }
346 
347  if((i == 2) && !extended_length) {
348  length = data[i];
349  if(
350  length < (uint8_t)(overhead + 1) ||
351  length >= PJON_PACKET_MAX_LENGTH
352  ) {
353  return PJON_BUSY;
354  }
355  if(length > 15 && !(data[1] & PJON_CRC_BIT)) {
356  return PJON_BUSY;
357  }
358  }
359 
360  if((i == 3) && extended_length) {
361  length = (data[i - 1] << 8) | (data[i] & 0xFF);
362  if(
363  length < (uint8_t)(overhead + 1) ||
364  length >= PJON_PACKET_MAX_LENGTH
365  ) {
366  return PJON_BUSY;
367  }
368  if(length > 15 && !(data[1] & PJON_CRC_BIT)) {
369  return PJON_BUSY;
370  }
371  }
372 
373  if(
374  ((data[1] & PJON_MODE_BIT) && !_router && !mac) &&
375  (i > (uint8_t)(3 + extended_length)) &&
376  (i < (uint8_t)(8 + extended_length))
377  ) {
378  if(config & PJON_MODE_BIT) {
379  if(tx.bus_id[i - 4 - extended_length] != data[i]) {
380  return PJON_BUSY;
381  }
382  } else if(data[i] != 0) {
383  return PJON_BUSY; // Do not reject localhost
384  }
385  }
386  }
387 
388  if(
389  PJON_crc8::compute(data, 3 + extended_length) !=
390  data[3 + extended_length]
391  ) {
392  return PJON_NAK;
393  }
394 
395  if(data[1] & PJON_CRC_BIT) {
396  if(
397  !PJON_crc32::compare(
398  PJON_crc32::compute(data, length - 4), data + (length - 4)
399  )
400  ) {
401  return PJON_NAK;
402  }
403  } else if(PJON_crc8::compute(data, length - 1) != data[length - 1]) {
404  return PJON_NAK;
405  }
406 
407 #if(PJON_INCLUDE_MAC)
408  if(mac && (length > 15) && !_router)
409  if(!PJONTools::id_equality(data + (overhead - 16), tx.mac, 6))
410  if(!
411  PJONTools::id_equality(
412  data + (overhead - 16),
413  PJONTools::no_mac(), 6
414  )
415  ) {
416  return PJON_BUSY;
417  }
418 #endif
419 
420  if(data[1] & PJON_ACK_REQ_BIT && data[0] != PJON_BROADCAST)
421  if((_mode != PJON_SIMPLEX) && !_router) {
422  strategy.send_response(PJON_ACK);
423  }
424 
425  parse(data, last_packet_info);
426 
427 #if(PJON_INCLUDE_PACKET_ID)
428  if(
429  !_router &&
430  (last_packet_info.header & PJON_PACKET_ID_BIT) &&
431  known_packet_id(last_packet_info)
432  ) {
433  return PJON_ACK;
434  }
435 #endif
436 
437 #if(PJON_INCLUDE_PORT)
438  if((port != PJON_BROADCAST) && (port != last_packet_info.port)) {
439  return PJON_BUSY;
440  }
441 #endif
442 
443  _receiver(
444  data + (overhead - PJONTools::crc_overhead(data[1])),
445  length - overhead,
446  last_packet_info
447  );
448 
449  return PJON_ACK;
450  };
451 
452  /* Try to receive data repeatedly with a maximum duration: */
453 
454  uint16_t receive(uint32_t duration)
455  {
456  uint32_t time = PJON_MICROS();
457  uint16_t response;
458  do {
459  response = receive();
460  } while(
461  (response != PJON_ACK) &&
462  ((uint32_t)(PJON_MICROS() - time) <= duration)
463  );
464  return response;
465  };
466 
467  /* Remove a packet from buffer: */
468 
469  void remove(uint16_t index)
470  {
471  if((index >= 0) && (index < PJON_MAX_PACKETS)) {
472  packets[index].attempts = 0;
473  packets[index].length = 0;
474  packets[index].registration = 0;
475  packets[index].state = 0;
476  }
477  };
478 
479  /* Remove all packets from the buffer:
480  Don't pass any parameter to delete all packets
481  Pass a device id to delete all it's related packets */
482 
483  void remove_all_packets(uint8_t device_id = 0)
484  {
485  for(uint16_t i = 0; i < PJON_MAX_PACKETS; i++) {
486  if(packets[i].state == 0) {
487  continue;
488  }
489  if(!device_id || packets[i].content[0] == device_id) {
490  remove(i);
491  }
492  }
493  };
494 
495  /* Reset a packet sending present in the buffer: */
496 
497  bool reset_packet(uint16_t id)
498  {
499  if(!packets[id].timing) {
500  if(_auto_delete) {
501  remove(id);
502  return true;
503  }
504  } else {
505  packets[id].attempts = 0;
506  packets[id].registration = PJON_MICROS();
507  packets[id].state = PJON_TO_BE_SENT;
508  }
509  return false;
510  };
511 
512  /* Schedule a packet sending to the sender of the last packet received.
513  This function is typically called within the receive callback to
514  deliver a response to a request. */
515 
516  uint16_t reply(const void *payload, uint16_t length)
517  {
518  PJON_Packet_Info info;
519  info = last_packet_info;
520  info.rx = info.tx;
521  info.header = config;
522 #ifndef PJON_LOCAL
523  info.hops = 0;
524 #endif
525  return dispatch(info, payload, length);
526  };
527 
528  uint16_t reply_blocking(const void *payload, uint16_t length)
529  {
530  PJON_Packet_Info info;
531  info = last_packet_info;
532  info.rx = info.tx;
533  info.header = config;
534 #ifndef PJON_LOCAL
535  info.hops = 0;
536 #endif
537  return send_packet_blocking(info, payload, length);
538  };
539 
540  /* Schedule a packet sending: */
541 
542  uint16_t send(
543  uint8_t rx_id,
544  const void *payload,
545  uint16_t length,
546  uint8_t header = PJON_NO_HEADER,
547  uint16_t packet_id = 0,
548  uint16_t rx_port = PJON_BROADCAST
549  )
550  {
551  PJON_Packet_Info info = fill_info(rx_id, header, packet_id, rx_port);
552  return dispatch(info, payload, length);
553  };
554 
555  uint16_t send(
556  const PJON_Packet_Info &info,
557  const void *payload,
558  uint16_t length
559  )
560  {
561  return dispatch(info, payload, length);
562  };
563 
564  /* Forward a packet: */
565 
566  uint16_t forward(
567  PJON_Packet_Info info,
568  const void *payload,
569  uint16_t length
570  )
571  {
572  PJON_Endpoint original_end_point = tx;
573  tx = info.tx;
574 #ifndef PJON_LOCAL
575  if(++info.hops > PJON_MAX_HOPS) {
576  return PJON_FAIL;
577  }
578 #endif
579  uint16_t result = dispatch(info, payload, length);
580  tx = original_end_point;
581  return result;
582  };
583 
584  /* Forward a packet: */
585 
586  uint16_t forward_blocking(
587  PJON_Packet_Info info,
588  const void *payload,
589  uint16_t length
590  )
591  {
592  PJON_Endpoint original_end_point = tx;
593  tx = info.tx;
594 #ifndef PJON_LOCAL
595  if(++info.hops > PJON_MAX_HOPS) {
596  return PJON_FAIL;
597  }
598 #endif
599  uint16_t result = send_packet_blocking(info, payload, length);
600  tx = original_end_point;
601  return result;
602  };
603 
604  /* IMPORTANT: send_repeatedly timing maximum
605  is 4293014170 microseconds or 71.55 minutes */
606 
607  uint16_t send_repeatedly(
608  uint8_t rx_id,
609  const void *payload,
610  uint16_t length,
611  uint32_t timing,
612  uint8_t header = PJON_NO_HEADER,
613  uint16_t packet_id = 0,
614  uint16_t rx_port = PJON_BROADCAST
615  )
616  {
617  PJON_Packet_Info info = fill_info(rx_id, header, packet_id, rx_port);
618  return dispatch(info, payload, length, timing);
619  };
620 
621  uint16_t send_repeatedly(
622  const PJON_Packet_Info &info,
623  const void *payload,
624  uint16_t length,
625  uint32_t timing
626  )
627  {
628  return dispatch(info, payload, length, timing);
629  };
630 
631  /* Transmit an already composed packet: */
632 
633  uint16_t send_packet(const uint8_t *payload, uint16_t length)
634  {
635  if(!payload) {
636  return PJON_FAIL;
637  }
638  if(_mode != PJON_SIMPLEX && !strategy.can_start()) {
639  return PJON_BUSY;
640  }
641  strategy.send_frame((uint8_t *)payload, length);
642  if(
643  payload[0] == PJON_BROADCAST ||
644  !(payload[1] & PJON_ACK_REQ_BIT) ||
645  _mode == PJON_SIMPLEX
646  ) {
647  return PJON_ACK;
648  }
649  return (strategy.receive_response() == PJON_ACK) ? PJON_ACK : PJON_FAIL;
650  };
651 
652  /* Compose and transmit a packet passing its info as parameters: */
653 
654  uint16_t send_packet(
655  uint8_t rx_id,
656  const void *payload,
657  uint16_t length,
658  uint8_t header = PJON_NO_HEADER,
659  uint16_t packet_id = 0,
660  uint16_t rx_port = PJON_BROADCAST
661  )
662  {
663  PJON_Packet_Info info = fill_info(rx_id, header, packet_id, rx_port);
664  if(!(length = compose_packet(info, data, payload, length))) {
665  return PJON_FAIL;
666  }
667  return send_packet(data, length);
668  };
669 
670  uint16_t send_packet(
671  const PJON_Packet_Info &info,
672  const void *payload,
673  uint16_t length
674  )
675  {
676  if(!(length = compose_packet(info, data, payload, length))) {
677  return PJON_FAIL;
678  }
679  return send_packet(data, length);
680  };
681 
682  /* Transmit a packet without using the packet's buffer. Tries to transmit
683  a packet multiple times within an internal cycle until the packet is
684  delivered, or timing limit is reached. */
685 
686  uint16_t send_packet_blocking(
687  const PJON_Packet_Info &packet_info,
688  const void *payload,
689  uint16_t length,
690  uint32_t timeout = 3500000
691  )
692  {
693  uint16_t state = PJON_FAIL;
694  uint32_t attempts = 0;
695  uint32_t start = PJON_MICROS();
696  uint16_t old_length = length;
697 
698  _recursion++;
699  while(
700  (state != PJON_ACK) && (attempts <= strategy.get_max_attempts()) &&
701  (uint32_t)(PJON_MICROS() - start) <= timeout
702  ) {
703  if(!(length = compose_packet(packet_info, data, payload, old_length))) {
704  _recursion--;
705  return PJON_FAIL;
706  }
707  state = send_packet(data, length);
708  if(state == PJON_ACK) {
709  _recursion--;
710  return state;
711  }
712  attempts++;
713  if(state != PJON_FAIL) {
714  strategy.handle_collision();
715  }
716 #if(PJON_RECEIVE_WHILE_SENDING_BLOCKING)
717  if(_recursion <= 1) {
718  receive(strategy.back_off(attempts));
719  } else
720 #endif
721  PJON_DELAY((uint32_t)(strategy.back_off(attempts) / 1000));
722  }
723  _recursion--;
724  return state;
725  };
726 
727  uint16_t send_packet_blocking(
728  uint8_t rx_id,
729  const void *payload,
730  uint16_t length,
731  uint8_t header = PJON_NO_HEADER,
732  uint16_t packet_id = 0,
733  uint16_t rx_port = PJON_BROADCAST,
734  uint32_t timeout = 3500000
735  )
736  {
737  PJON_Packet_Info info = fill_info(rx_id, header, packet_id, rx_port);
738  return send_packet_blocking(info, payload, length, timeout);
739  };
740 
741  /* In router mode, the receiver function can acknowledge
742  for selected receiver device ids for which the route is known */
743 
744  void send_acknowledge()
745  {
746  strategy.send_response(PJON_ACK);
747  };
748 
749  /* Set the config bit state: */
750 
751  void set_config_bit(bool new_state, uint8_t bit)
752  {
753  if(new_state) {
754  config |= bit;
755  } else {
756  config &= ~bit;
757  }
758  };
759 
760  /* Configure acknowledge:
761  state = true -> Request acknowledgement
762  state = false -> Do not request acknowledgement */
763 
764  void set_acknowledge(bool state)
765  {
766  set_config_bit(state, PJON_ACK_REQ_BIT);
767  };
768 
769  /* Configure CRC selected for packet checking:
770  state = true -> Use CRC32
771  state = false -> Use CRC8 */
772 
773  void set_crc_32(bool state)
774  {
775  set_config_bit(state, PJON_CRC_BIT);
776  };
777 
778  /* Set communication mode:
779  mode = 0 or PJON_SIMPLEX -> Communication is mono-directional
780  mode = 1 or PJON_HALF_DUPLEX -> Communication is bi-directional */
781 
782  void set_communication_mode(bool mode)
783  {
784  _mode = mode;
785  };
786 
787  /* Set a custom receiver callback pointer:
788  (Generally needed to call a custom member function) */
789 
790  void set_custom_pointer(void *pointer)
791  {
792  _custom_pointer = pointer;
793  };
794 
795  /* Set bus state default configuration: */
796 
797  void set_default()
798  {
799  _mode = PJON_HALF_DUPLEX;
800  set_error(PJON_dummy_error_handler);
801  set_receiver(PJON_dummy_receiver_handler);
802  };
803 
804  /* Pass as a parameter a function you previously defined in the code.
805  This function is called when PJON detects an error
806 
807  void error_handler(uint8_t code, uint16_t data) {
808  Serial.print(code);
809  Serial.print(" ");
810  Serial.println(data);
811  };
812 
813  bus.set_error(error_handler); */
814 
815  void set_error(PJON_Error e)
816  {
817  _error = e;
818  };
819 
820  /* Set the device id passing a single byte (watch out to id collision): */
821 
822  void set_id(uint8_t id)
823  {
824  tx.id = id;
825  };
826 
827  /* Setting bus id */
828 
829  void set_bus_id(const uint8_t *b_id)
830  {
831  PJONTools::copy_id(tx.bus_id, b_id, 4);
832  };
833 
834  /* Configure sender's information inclusion in the packet.
835  state = true -> +8 bits (device id) in local mode
836  +40 bits (bus id + device id) in shared mode
837  state = false -> No overhead added
838 
839  If you don't need the sender info disable the inclusion to reduce
840  overhead and higher communication speed. */
841 
842  void include_sender_info(bool state)
843  {
844  set_config_bit(state, PJON_TX_INFO_BIT);
845  };
846 
847  /* Configure network interface identification inclusion in the packet.
848  state = true -> +96 bits (sender's and recipient's MAC address)
849  state = false -> No overhead added */
850 
851  void include_mac(bool state)
852  {
853  set_config_bit(state, PJON_MAC_BIT);
854  };
855 
856 #if(PJON_INCLUDE_MAC)
857 
858  /* Returns a pointer to the mac address used by the instance: */
859 
860  const uint8_t *get_mac() const
861  {
862  return tx.mac;
863  };
864 
865  /* Set the mac address used by the instance:
866  It receives a pointer to the mac address */
867 
868  void set_mac(const uint8_t *mac)
869  {
870  PJONTools::copy_id(tx.mac, mac, 6);
871  };
872 
873 #endif
874 
875  /* Configure the bus network behaviour.
876  state = true -> Include 32 bits bus id or group identification.
877  state = false -> Use only a 8 bits local device identification. */
878 
879  void set_shared_network(bool state)
880  {
881  set_config_bit(state, PJON_MODE_BIT);
882  };
883 
884  /* Set if packets are automatically deleted in case of success or failure:
885  state = true -> Packets are deleted automatically
886  state = false -> Packets are not deleted */
887 
888  void set_packet_auto_deletion(bool state)
889  {
890  _auto_delete = state;
891  };
892 
893  /* Set the analog pin used as a seed for random generation: */
894 
895  void set_random_seed(uint8_t seed)
896  {
897  _random_seed = seed;
898  };
899 
900  /* Pass as a parameter a receiver function you previously defined in your
901  code that should be called when a message is received.
902  Inside there you can code how to react when data is received. */
903 
904  void set_receiver(PJON_Receiver r)
905  {
906  _receiver = r;
907  };
908 
909  /* Configure if device acts as a router:
910  state = true -> All packets are received (acknowledgement not sent)
911  state = false -> Normal operation */
912 
913  void set_router(bool state)
914  {
915  _router = state;
916  };
917 
918  /* Update the state of the send list:
919  Checks if there are packets to be sent or to be erased if correctly
920  delivered. Returns the actual number of packets to be sent. */
921 
922  uint16_t update()
923  {
924  uint16_t packets_count = 0;
925  for(uint16_t i = 0; i < PJON_MAX_PACKETS; i++) {
926  if(packets[i].state == 0) {
927  continue;
928  }
929  packets_count++;
930 
931  if(
932  (uint32_t)(PJON_MICROS() - packets[i].registration) >
933  (uint32_t)(
934  packets[i].timing +
935  strategy.back_off(packets[i].attempts)
936  )
937  ) {
938  if(packets[i].state != PJON_ACK)
939  packets[i].state =
940  send_packet(packets[i].content, packets[i].length);
941  } else {
942  continue;
943  }
944 
945  packets[i].attempts++;
946 
947  if(packets[i].state == PJON_ACK) {
948  packets_count -= reset_packet(i);
949  continue;
950  }
951 
952  if(packets[i].state != PJON_FAIL && packets[i].state != PJON_ACK) {
953  strategy.handle_collision();
954  }
955 
956  if(packets[i].attempts > strategy.get_max_attempts()) {
957  _error(PJON_CONNECTION_LOST, i, _custom_pointer);
958  packets_count -= reset_packet(i);
959  }
960  }
961  return packets_count;
962  };
963 
964 #if(PJON_INCLUDE_PACKET_ID)
965 
966  /* Checks if the packet id and its transmitter info are already present
967  in the known packets buffer, if not add it to the buffer */
968 
969  bool known_packet_id(const PJON_Packet_Info &info)
970  {
971  for(uint8_t i = 0; i < PJON_MAX_RECENT_PACKET_IDS; i++)
972  if(
973  info.id == recent_packet_ids[i].id &&
974  info.tx.id == recent_packet_ids[i].sender_id && (
975  (
976  (info.header & PJON_MODE_BIT) &&
977  (recent_packet_ids[i].header & PJON_MODE_BIT) &&
978  PJONTools::id_equality(
979  (uint8_t *)info.tx.bus_id,
980  (uint8_t *)recent_packet_ids[i].sender_bus_id,
981  4
982  )
983  ) || (
984  !(info.header & PJON_MODE_BIT) &&
985  !(recent_packet_ids[i].header & PJON_MODE_BIT)
986  )
987  )
988  ) {
989  return true;
990  }
991  save_packet_id(info);
992  return false;
993  };
994 
995  /* Save packet id in the buffer: */
996 
997  void save_packet_id(const PJON_Packet_Info &info)
998  {
999  for(uint8_t i = PJON_MAX_RECENT_PACKET_IDS - 1; i > 0; i--) {
1000  recent_packet_ids[i] = recent_packet_ids[i - 1];
1001  }
1002  recent_packet_ids[0].id = info.id;
1003  recent_packet_ids[0].header = info.header;
1004  recent_packet_ids[0].sender_id = info.tx.id;
1005  PJONTools::copy_id(
1006  recent_packet_ids[0].sender_bus_id,
1007  info.tx.bus_id,
1008  4
1009  );
1010  };
1011 
1012  /* Configure packet id presence:
1013  state = true -> Include 16 bits packet id
1014  state = false -> Avoid packet id inclusion */
1015 
1016  void set_packet_id(bool state)
1017  {
1018  set_config_bit(state, PJON_PACKET_ID_BIT);
1019  };
1020 
1021 #endif
1022 
1023 #if(PJON_INCLUDE_PORT)
1024 
1025  /* Include the port:
1026  p = 1-65535 -> Include 16 bits port id
1027  p = 0 -> Avoid port id inclusion */
1028 
1029  void include_port(uint16_t p)
1030  {
1031  set_config_bit((p != 0) ? 1 : 0, PJON_PORT_BIT);
1032  port = p;
1033  };
1034 
1035 #endif
1036 
1037 private:
1038  bool _auto_delete = true;
1039  void *_custom_pointer;
1040  PJON_Error _error;
1041  bool _mode;
1042  uint16_t _packet_id_seed = 0;
1043  uint8_t _random_seed = A0;
1044  PJON_Receiver _receiver;
1045  uint8_t _recursion = 0;
1046  bool _router = false;
1047 };
data
char data[MAX_PAYLOAD_SIZE+1]
Buffer for raw payload data.
Definition: MyMessage.h:654
PJON_Packet
Definition: PJONDefines.h:177
config
Config file.
Definition: config.h:30
PJON_Packet_Info
Definition: PJONDefines.h:207
destination
uint8_t destination
8 bit - Id of destination node
Definition: MyMessage.h:336
PJON
Definition: PJON.h:77
PJON_Endpoint
Definition: PJONDefines.h:197
PJON_Packet_Record
Definition: PJONDefines.h:186