MySensors Library & Examples  2.3.2-62-ge298769
PJONDefines.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 "utils/crc/PJON_CRC8.h"
62 #include "utils/crc/PJON_CRC32.h"
63 
64 /* Protocol symbols: */
65 #define PJON_ACK 6
66 #define PJON_BUSY 666
67 #define PJON_NAK 21
68 
69 /* Id used for broadcasting to all devices */
70 #ifndef PJON_BROADCAST
71 #define PJON_BROADCAST 0
72 #endif
73 
74 /* Device id of still unindexed devices */
75 #ifndef PJON_NOT_ASSIGNED
76 #define PJON_NOT_ASSIGNED 255
77 #endif
78 
79 /* Internal constants: */
80 #define PJON_FAIL 65535
81 #define PJON_TO_BE_SENT 74
82 
83 /* Communication modes: */
84 #define PJON_SIMPLEX false
85 #define PJON_HALF_DUPLEX true
86 
87 /* Header bits definition: */
88 
89 /* No header present (unacceptable value used)*/
90 #define PJON_NO_HEADER 0B01001000
91 /* 0 - Local network
92  1 - Shared network */
93 #define PJON_MODE_BIT 0B00000001
94 /* 0 - No info inclusion
95  1 - Local: Sender device id included
96  Shared: Sender device id + Sender bus id */
97 #define PJON_TX_INFO_BIT 0B00000010
98 /* 0 - Synchronous acknowledgement disabled
99  1 - Synchronous acknowledgement enabled */
100 #define PJON_ACK_REQ_BIT 0B00000100
101 /* 0 - MAC address inclusion disabled
102  1 - MAC address inclusion enabled (2x 48 bits) */
103 #define PJON_MAC_BIT 0B00001000
104 /* 0 - No port id contained
105  1 - Port id contained (2 bytes integer) */
106 #define PJON_PORT_BIT 0B00010000
107 /* 0 - CRC8 (1 byte) included at the end of the packet
108  1 - CRC32 (4 bytes) included at the end of the packet */
109 #define PJON_CRC_BIT 0B00100000
110 /* 0 - 1 byte long (max 255 bytes)
111  1 - 2 bytes long (max 65535 bytes) */
112 #define PJON_EXT_LEN_BIT 0B01000000
113 /* 0 - Packet id not present
114  1 - Packet id present */
115 #define PJON_PACKET_ID_BIT 0B10000000
116 
117 /* Errors: */
118 
119 #define PJON_CONNECTION_LOST 101
120 #define PJON_PACKETS_BUFFER_FULL 102
121 #define PJON_CONTENT_TOO_LONG 104
122 
123 /* Constraints: */
124 
125 /* Maximum amount of routers a packet can pass before being discarded: */
126 #ifndef PJON_MAX_HOPS
127 #define PJON_MAX_HOPS 15
128 #endif
129 
130 /* Packet buffer length, if full PJON_PACKETS_BUFFER_FULL error is thrown.
131  The packet buffer is preallocated, so its length strongly affects
132  memory consumption */
133 #ifndef PJON_MAX_PACKETS
134 #define PJON_MAX_PACKETS 5
135 #endif
136 
137 /* Max packet length, higher if necessary.
138  The max packet length defines the length of packets pre-allocated buffers
139  so it strongly affects memory consumption */
140 #ifndef PJON_PACKET_MAX_LENGTH
141 #define PJON_PACKET_MAX_LENGTH 50
142 #endif
143 
144 /* Maximum packet ids record kept in memory (to avoid duplicated exchanges) */
145 #ifndef PJON_MAX_RECENT_PACKET_IDS
146 #define PJON_MAX_RECENT_PACKET_IDS 10
147 #endif
148 
149 /* Optional features: */
150 
151 /* If defined includes the packet id feature */
152 #ifdef PJON_INCLUDE_PACKET_ID
153 #undef PJON_INCLUDE_PACKET_ID
154 #define PJON_INCLUDE_PACKET_ID true
155 #else
156 #define PJON_INCLUDE_PACKET_ID false
157 #endif
158 
159 /* If defined includes the port id feature */
160 #ifdef PJON_INCLUDE_PORT
161 #undef PJON_INCLUDE_PORT
162 #define PJON_INCLUDE_PORT true
163 #else
164 #define PJON_INCLUDE_PORT false
165 #endif
166 
167 /* If defined includes the mac address feature */
168 #ifdef PJON_INCLUDE_MAC
169 #undef PJON_INCLUDE_MAC
170 #define PJON_INCLUDE_MAC true
171 #else
172 #define PJON_INCLUDE_MAC false
173 #endif
174 
175 /* Data structures: */
176 
177 struct PJON_Packet {
178  uint8_t attempts = 0;
179  uint8_t content[PJON_PACKET_MAX_LENGTH];
180  uint16_t length;
181  uint32_t registration;
182  uint16_t state = 0;
183  uint32_t timing = 0;
184 };
185 
187  uint8_t header;
188  uint8_t sender_id;
189 #ifndef PJON_LOCAL
190  uint8_t sender_bus_id[4];
191 #endif
192 #if(PJON_INCLUDE_PACKET_ID)
193  uint16_t id;
194 #endif
195 };
196 
198  uint8_t id = PJON_NOT_ASSIGNED;
199 #ifndef PJON_LOCAL
200  uint8_t bus_id[4] = {0, 0, 0, 0};
201 #endif
202 #if(PJON_INCLUDE_MAC)
203  uint8_t mac[6] = {0, 0, 0, 0, 0, 0};
204 #endif
205 };
206 
208  PJON_Endpoint tx;
209  PJON_Endpoint rx;
210  uint8_t header = PJON_NO_HEADER;
211 #ifndef PJON_LOCAL
212  void *custom_pointer;
213  uint8_t hops = 0;
214 #endif
215 #if(PJON_INCLUDE_PACKET_ID)
216  uint16_t id = 0;
217 #endif
218 #if(PJON_INCLUDE_PORT)
219  uint16_t port = PJON_BROADCAST;
220 #endif
221 };
222 
223 typedef void (* PJON_Receiver)(
224  uint8_t *payload,
225  uint16_t length,
226  const PJON_Packet_Info &packet_info
227 );
228 
229 typedef void (* PJON_Error)(
230  uint8_t code,
231  uint16_t data,
232  void *custom_pointer
233 );
234 
235 /* PJON general purpose functions: */
236 
237 struct PJONTools {
238  /* Bus id used as localhost (used by shared mode broadcast and NAT) */
239 
240  static const uint8_t* localhost()
241  {
242  static const uint8_t lh[4] = {0, 0, 0, 0};
243  return lh;
244  };
245 
246  /* Unused MAC address value */
247 
248  static const uint8_t* no_mac()
249  {
250  static const uint8_t lh[6] = {0, 0, 0, 0, 0, 0};
251  return lh;
252  };
253 
254  /* Calculates the packet's overhead using the header: */
255 
256  static uint8_t packet_overhead(uint8_t header)
257  {
258  return (
259  (
260  (header & PJON_MODE_BIT) ?
261  (header & PJON_TX_INFO_BIT ? 11 : 6) :
262  (header & PJON_TX_INFO_BIT ? 2 : 1)
263  ) + (header & PJON_EXT_LEN_BIT ? 2 : 1)
264  + (header & PJON_CRC_BIT ? 4 : 1)
265  + (header & PJON_PORT_BIT ? 2 : 0)
266  + (header & PJON_PACKET_ID_BIT ? 2 : 0)
267  + (header & PJON_MAC_BIT ? 12 : 0)
268  + 2 // header + header's CRC
269  );
270  };
271 
272  /* Calculates the packet's CRC overhead using the header: */
273 
274  static uint8_t crc_overhead(uint8_t header)
275  {
276  return (header & PJON_CRC_BIT) ? 4 : 1;
277  };
278 
279  /* Generates a new unique packet id: */
280 
281  static uint16_t new_packet_id(uint16_t seed)
282  {
283  if(!(++seed)) {
284  seed = 1;
285  }
286  return seed;
287  };
288 
289  /* Copy an id: */
290 
291  static void copy_id(uint8_t dest[], const uint8_t src[], uint8_t length)
292  {
293  memcpy(dest, src, length);
294  };
295 
296  /* Check equality between two ids: */
297 
298  static bool id_equality(
299  const uint8_t *n_one,
300  const uint8_t *n_two,
301  uint8_t length
302  )
303  {
304  for(uint8_t i = 0; i < length; i++)
305  if(n_one[i] != n_two[i]) {
306  return false;
307  }
308  return true;
309  };
310 
311  /* Composes a packet in PJON format: */
312 
313  static uint16_t compose_packet(
314  PJON_Packet_Info info,
315  uint8_t *destination,
316  const void *source,
317  uint16_t length
318  )
319  {
320  uint8_t index = 0;
321  if(length > 255) {
322  info.header |= PJON_EXT_LEN_BIT;
323  }
324 #if(PJON_INCLUDE_PORT)
325  if(info.port != PJON_BROADCAST) {
326  info.header |= PJON_PORT_BIT;
327  }
328  if((info.header & PJON_PORT_BIT) && (info.port == PJON_BROADCAST)) {
329  info.header &= ~PJON_PORT_BIT;
330  }
331 #endif
332  if(info.rx.id == PJON_BROADCAST) {
333  info.header &= ~(PJON_ACK_REQ_BIT);
334  }
335  uint16_t new_length = length + packet_overhead(info.header);
336  bool extended_length = info.header & PJON_EXT_LEN_BIT;
337  if(new_length > 15 && !(info.header & PJON_CRC_BIT)) {
338  info.header |= PJON_CRC_BIT;
339  new_length = (uint16_t)(length + packet_overhead(info.header));
340  }
341  if(new_length > 255 && !extended_length) {
342  info.header |= PJON_EXT_LEN_BIT;
343  new_length = (uint16_t)(length + packet_overhead(info.header));
344  }
345  if(new_length >= PJON_PACKET_MAX_LENGTH) {
346  return new_length;
347  }
348  destination[index++] = info.rx.id;
349  destination[index++] = (uint8_t)info.header;
350  if(extended_length) {
351  destination[index++] = (uint8_t)(new_length >> 8);
352  destination[index++] = (uint8_t)new_length;
353  destination[index++] = PJON_crc8::compute((uint8_t *)destination, 4);
354  } else {
355  destination[index++] = (uint8_t)new_length;
356  destination[index++] = PJON_crc8::compute((uint8_t *)destination, 3);
357  }
358 #ifndef PJON_LOCAL
359  if(info.header & PJON_MODE_BIT) {
360  copy_id((uint8_t*) &destination[index], info.rx.bus_id, 4);
361  index += 4;
362  if(info.header & PJON_TX_INFO_BIT) {
363  copy_id((uint8_t*) &destination[index], info.tx.bus_id, 4);
364  index += 4;
365  }
366  destination[index++] = info.hops;
367  }
368 #endif
369  if(info.header & PJON_TX_INFO_BIT) {
370  destination[index++] = info.tx.id;
371  }
372 #if(PJON_INCLUDE_PACKET_ID)
373  if(info.header & PJON_PACKET_ID_BIT) {
374  destination[index++] = (uint8_t)(info.id >> 8);
375  destination[index++] = (uint8_t)info.id;
376  }
377 #endif
378 #if(PJON_INCLUDE_PORT)
379  if(info.header & PJON_PORT_BIT) {
380  if(info.port != PJON_BROADCAST) {
381  destination[index++] = (uint8_t)(info.port >> 8);
382  destination[index++] = (uint8_t)info.port;
383  }
384  }
385 #endif
386 #if(PJON_INCLUDE_MAC)
387  if(info.header & PJON_MAC_BIT) {
388  copy_id(&destination[index], info.rx.mac, 6);
389  index += 6;
390  copy_id(&destination[index], info.tx.mac, 6);
391  index += 6;
392  }
393 #endif
394  memcpy(destination + index, source, length);
395  if(info.header & PJON_CRC_BIT) {
396  uint32_t computed_crc =
397  PJON_crc32::compute((uint8_t *)destination, new_length - 4);
398  destination[new_length - 4] =
399  (uint8_t)((uint32_t)(computed_crc) >> 24);
400  destination[new_length - 3] =
401  (uint8_t)((uint32_t)(computed_crc) >> 16);
402  destination[new_length - 2] =
403  (uint8_t)((uint32_t)(computed_crc) >> 8);
404  destination[new_length - 1] =
405  (uint8_t)((uint32_t)computed_crc);
406  } else destination[new_length - 1] =
407  PJON_crc8::compute((uint8_t *)destination, new_length - 1);
408  return new_length;
409  };
410 
411  /* Fills a PJON_Packet_Info struct with data parsing a packet: */
412 
413  static void parse_header(const uint8_t *packet, PJON_Packet_Info &info)
414  {
415  uint8_t index = 0;
416  info = PJON_Packet_Info{};
417 
418  info.rx.id = packet[index++];
419  bool extended_length = packet[index] & PJON_EXT_LEN_BIT;
420  info.header = packet[index++];
421  index += extended_length + 2; // + LENGTH + HEADER CRC
422 #ifndef PJON_LOCAL
423  if(info.header & PJON_MODE_BIT) {
424  copy_id(info.rx.bus_id, packet + index, 4);
425  index += 4;
426  if(info.header & PJON_TX_INFO_BIT) {
427  copy_id(info.tx.bus_id, packet + index, 4);
428  index += 4;
429  }
430  info.hops = packet[index++];
431  }
432 #endif
433  if(info.header & PJON_TX_INFO_BIT) {
434  info.tx.id = packet[index++];
435  }
436 #if(PJON_INCLUDE_PACKET_ID)
437  if(info.header & PJON_PACKET_ID_BIT) {
438  info.id = (packet[index] << 8) | (packet[index + 1] & 0xFF);
439  index += 2;
440  }
441 #endif
442 #if(PJON_INCLUDE_PORT)
443  if(info.header & PJON_PORT_BIT) {
444  info.port = (packet[index] << 8) | (packet[index + 1] & 0xFF);
445  index += 2;
446  }
447 #endif
448 #if(PJON_INCLUDE_MAC)
449  copy_id(info.rx.mac, packet + index, 6);
450  index += 6;
451  copy_id(info.tx.mac, packet + index, 6);
452 #endif
453  };
454 };
data
char data[MAX_PAYLOAD_SIZE+1]
Buffer for raw payload data.
Definition: MyMessage.h:654
PJON_Packet
Definition: PJONDefines.h:177
PJON_Packet_Info
Definition: PJONDefines.h:207
destination
uint8_t destination
8 bit - Id of destination node
Definition: MyMessage.h:336
PJON_Endpoint
Definition: PJONDefines.h:197
PJONTools
Definition: PJONDefines.h:237
PJON_Packet_Record
Definition: PJONDefines.h:186