MySensors Library & Examples  2.3.2-62-ge298769
SoftwareBitBang.h
1 
2 /* SoftwareBitBang
3  1 or 2 wires software-defined asynchronous serial data link layer
4  used as a Strategy by PJON (included in version v3.0)
5  Compliant with PJDL (Padded Jittering Data Link) specification v5.0
6  ___________________________________________________________________________
7 
8  Copyright 2010-2020 Giovanni Blu Mitolo [email protected]
9 
10  Licensed under the Apache License, Version 2.0 (the "License");
11  you may not use this file except in compliance with the License.
12  You may obtain a copy of the License at
13 
14  http://www.apache.org/licenses/LICENSE-2.0
15 
16  Unless required by applicable law or agreed to in writing, software
17  distributed under the License is distributed on an "AS IS" BASIS,
18  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  See the License for the specific language governing permissions and
20  limitations under the License. */
21 
22 #pragma once
23 
24 /* Set here the selected transmission mode - default STANDARD */
25 #ifndef SWBB_MODE
26 #define SWBB_MODE 1
27 #endif
28 
29 // Used to signal communication failure
30 #define SWBB_FAIL 65535
31 // Used for pin handling
32 #define SWBB_NOT_ASSIGNED 255
33 
34 /* Transmission speed modes (see Timing.h)
35  MODE 1: 1.97kB/s - 15808Bd
36  MODE 2: 2.21kB/s - 17696Bd
37  MODE 3: 3.10kB/s - 24844Bd
38  MODE 4: 3.34kB/s - 26755Bd */
39 #include "Timing.h"
40 
41 // Recommended receive time for this strategy, in microseconds
42 #ifndef SWBB_RECEIVE_TIME
43 #define SWBB_RECEIVE_TIME 1000
44 #endif
45 
47 {
48 public:
49  /* Returns the delay related to the attempts passed as parameter: */
50 
51  uint32_t back_off(uint8_t attempts)
52  {
53  uint32_t result = attempts;
54  for(uint8_t d = 0; d < SWBB_BACK_OFF_DEGREE; d++) {
55  result *= (uint32_t)(attempts);
56  }
57  return result;
58  };
59 
60 
61  /* Begin method, to be called on initialization:
62  (returns always true) */
63 
64  bool begin(uint8_t did = 0)
65  {
66  PJON_DELAY(PJON_RANDOM(SWBB_INITIAL_DELAY) + did);
67  return true;
68  };
69 
70 
71  /* Check if the channel is free for transmission:
72  If reading 10 bits no 1 is detected there is no active transmission */
73 
74  bool can_start()
75  {
76  PJON_IO_MODE(_input_pin, INPUT);
77  // Look for ongoing transmission for 1 padding bit + 9 data bits
78  PJON_DELAY_MICROSECONDS(SWBB_BIT_SPACER / 2);
79  if(PJON_IO_READ(_input_pin)) {
80  return false;
81  }
82  PJON_DELAY_MICROSECONDS((SWBB_BIT_SPACER / 2));
83  if(PJON_IO_READ(_input_pin)) {
84  return false;
85  }
86  PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH / 2);
87  for(uint8_t i = 0; i < 9; i++) {
88  if(PJON_IO_READ(_input_pin)) {
89  return false;
90  }
91  PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH);
92  }
93  if(PJON_IO_READ(_input_pin)) {
94  return false;
95  }
96  // Delay for the maximum expected latency and then check again
97  PJON_DELAY_MICROSECONDS(SWBB_LATENCY);
98  if(PJON_IO_READ(_input_pin)) {
99  return false;
100  }
101  // Delay for a small random time and then check again
102  PJON_DELAY_MICROSECONDS(PJON_RANDOM(SWBB_COLLISION_DELAY));
103  if(PJON_IO_READ(_input_pin)) {
104  return false;
105  }
106  return true;
107  };
108 
109 
110  /* Returns the maximum number of attempts for each transmission: */
111 
112  static uint8_t get_max_attempts()
113  {
114  return SWBB_MAX_ATTEMPTS;
115  };
116 
117 
118  /* Returns the recommended receive time for this strategy: */
119 
120  static uint16_t get_receive_time()
121  {
122  return SWBB_RECEIVE_TIME;
123  };
124 
125 
126  /* Handle a collision: */
127 
128  void handle_collision()
129  {
130  PJON_DELAY_MICROSECONDS(PJON_RANDOM(SWBB_COLLISION_DELAY));
131  };
132 
133 
134  /* Read a byte from the pin */
135 
136  uint8_t read_byte()
137  {
138  uint8_t byte_value = 0B00000000;
139  // Delay until the center of the first bit
140  PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH / 2);
141  for(uint8_t i = 0; i < 7; i++) {
142  // Read in the center of the bit
143  byte_value += PJON_IO_READ(_input_pin) << i;
144  // Delay until the center of the next one
145  PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH);
146  }
147  // Read in the center of the last one
148  byte_value += PJON_IO_READ(_input_pin) << 7;
149  // Delay until the end of the last bit
150  PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH / 2);
151  return byte_value;
152  };
153 
154 
155  /* Receive byte if in sync: */
156 
157  uint16_t receive_byte()
158  {
159  if(sync()) {
160  return read_byte();
161  }
162  return SWBB_FAIL;
163  };
164 
165 
166  /* Receive byte response:
167  Transmitter emits a SWBB_BIT_WIDTH / 4 long bit and tries
168  to get a response cyclically for SWBB_RESPONSE_TIMEOUT microseconds.
169  Receiver synchronizes to the falling edge of the last incoming
170  bit and transmits PJON_ACK */
171 
172  uint16_t receive_response()
173  {
174  if(_output_pin != _input_pin && _output_pin != SWBB_NOT_ASSIGNED) {
175  PJON_IO_WRITE(_output_pin, LOW);
176  }
177  uint16_t response = SWBB_FAIL;
178  uint32_t time = PJON_MICROS();
179  while((uint32_t)(PJON_MICROS() - time) < _timeout) {
180  PJON_IO_WRITE(_input_pin, LOW);
181  if(sync()) {
182  response = receive_byte();
183  }
184  if(response == SWBB_FAIL) {
185  PJON_IO_MODE(_output_pin, OUTPUT);
186  PJON_IO_WRITE(_output_pin, HIGH);
187  PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH / 4);
188  PJON_IO_PULL_DOWN(_output_pin);
189  } else {
190  return response;
191  }
192  }
193  return response;
194  };
195 
196 
197  /* Receive a frame: */
198 
199  uint16_t receive_frame(uint8_t *data, uint16_t max_length)
200  {
201  uint16_t result;
202  if(max_length == PJON_PACKET_MAX_LENGTH) {
203  uint32_t time = PJON_MICROS();
204  // Look for a frame initializer
205  if(!sync_preamble() || !sync() || !sync()) {
206  return SWBB_FAIL;
207  }
208  // Check its timing consistency
209  if(
210  (uint32_t)(PJON_MICROS() - time) <
211  (((SWBB_BIT_WIDTH * 3) + (SWBB_BIT_SPACER * 3)) - SWBB_ACCEPTANCE)
212  ) {
213  return SWBB_FAIL;
214  }
215  } // Receive one byte
216  result = receive_byte();
217  if(result == SWBB_FAIL) {
218  return SWBB_FAIL;
219  }
220  *data = result;
221  return 1;
222  };
223 
224 
225  /* Every byte is prepended with a synchronization pad made by 2
226  padding bits. The first is a longer than standard logic 1 followed
227  by a standard logic 0.
228  __________ ___________________________
229  | SyncPad | Byte |
230  |______ |___ ___ _____ |
231  | | | | | | | | | |
232  | | 1 | 0 | 1 | 0 0 | 1 | 0 | 1 1 | 0 |
233  |__|___|___|___|_____|___|___|_____|___|
234  |
235  Minimum acceptable HIGH padding bit duration
236 
237  The reception tecnique is based on finding a logic 1 as long as the
238  first padding bit within a certain threshold, synchronizing to its
239  falling edge and checking if it is followed by a logic 0. If this
240  pattern is recognised, reception starts, if not, interference,
241  synchronization loss or simply absence of communication is
242  detected at byte level. */
243 
244  void send_byte(uint8_t b)
245  {
246  pulse(1);
247  for(uint8_t mask = 0x01; mask; mask <<= 1) {
248  PJON_IO_WRITE(_output_pin, b & mask);
249  PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH);
250  }
251  };
252 
253 
254  /* Send byte response:
255  Transmitter sends a SWBB_BIT_WIDTH / 4 microseconds long HIGH bit and
256  tries to receive a response cyclically for SWBB_RESPONSE_TIMEOUT
257  microseconds. Receiver synchronizes to the falling edge of the last
258  incoming bit and transmits its response */
259 
260  void send_response(uint8_t response)
261  {
262  PJON_IO_PULL_DOWN(_input_pin);
263  uint32_t time = PJON_MICROS();
264  while( // If initially low Wait for the next high
265  ((uint32_t)(PJON_MICROS() - time) < SWBB_BIT_WIDTH) &&
266  !PJON_IO_READ(_input_pin)
267  );
268  time = PJON_MICROS();
269  while( // If high Wait for low
270  ((uint32_t)(PJON_MICROS() - time) < (SWBB_BIT_WIDTH / 4)) &&
271  PJON_IO_READ(_input_pin)
272  ); // Transmit response prepended with a synchronization pad
273  PJON_IO_MODE(_output_pin, OUTPUT);
274  pulse(1);
275  send_byte(response);
276  PJON_IO_PULL_DOWN(_output_pin);
277  };
278 
279 
280  /* The data is prepended with a frame initializer composed by 3
281  synchronization pads to signal the start of a frame.
282  _________________ __________________________________
283  | FRAME INIT | DATA 1-65535 bytes |
284  |_____ _____ _____|________________ _________________|
285  |Sync |Sync |Sync |Sync | Byte |Sync | Byte |
286  |___ |___ |___ |___ | __ |___ | _ _|
287  | | | | | | | | | | | | | | | | | |
288  | 1 |0| 1 |0| 1 |0| 1 |0|0000|11|00| 1 |0|00000|1|0|1|
289  |___|_|___|_|___|_|___|_|____|__|__|___|_|_____|_|_|_|
290 
291  Send a frame: */
292 
293  void send_frame(uint8_t *data, uint16_t length)
294  {
295  _timeout = (length * SWBB_RESPONSE_OFFSET) + SWBB_LATENCY;
296  PJON_IO_MODE(_output_pin, OUTPUT);
297  pulse(3); // Send frame initializer
298  for(uint16_t b = 0; b < length; b++) {
299  send_byte(data[b]); // Send each byte
300  }
301  PJON_IO_PULL_DOWN(_output_pin);
302  };
303 
304 
305  /* Check if a synchronization pad is incoming:
306  __________
307  | SyncPad |
308  |______ |
309  | | | |
310  | | 1 | 0 |
311  |__|___|___|
312  |
313  Minimum acceptable HIGH padding bit duration
314 
315  The reception tecnique is based on finding a logic 1 as long as the
316  first padding bit within a certain threshold, synchronizing to its
317  falling edge and checking if it is followed by a logic 0. If this
318  pattern is recognised, synchronization may have been obtained, if
319  not, interference, synchronization loss or simply absence of
320  communication is detected at byte level: */
321 
322  bool sync(uint32_t spacer)
323  {
324  PJON_IO_PULL_DOWN(_input_pin);
325  if((_output_pin != _input_pin) && (_output_pin != SWBB_NOT_ASSIGNED)) {
326  PJON_IO_PULL_DOWN(_output_pin);
327  }
328  uint32_t time = PJON_MICROS();
329  while(
330  PJON_IO_READ(_input_pin) &&
331  ((uint32_t)(PJON_MICROS() - time) <= spacer)
332  );
333  time = PJON_MICROS() - time;
334  if(time < SWBB_ACCEPTANCE) {
335  return false;
336  } else {
337  PJON_DELAY_MICROSECONDS((SWBB_BIT_WIDTH / 2) - SWBB_READ_DELAY);
338  if(!PJON_IO_READ(_input_pin)) {
339  PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH / 2);
340  return true;
341  }
342  }
343  return false;
344  };
345 
346  bool sync()
347  {
348  return sync(SWBB_BIT_SPACER);
349  }
350 
351  bool sync_preamble()
352  {
353  return sync(SWBB_BIT_SPACER * SWBB_MAX_PREAMBLE);
354  };
355 
356  /* Emit synchronization pulse: */
357 
358  void pulse(uint8_t n)
359  {
360 #if SWBB_PREAMBLE != 1
361  if (n == 3) {
362  // Transmit preamble
363  PJON_IO_WRITE(_output_pin, HIGH);
364  PJON_DELAY_MICROSECONDS(SWBB_BIT_SPACER * SWBB_PREAMBLE);
365  PJON_IO_WRITE(_output_pin, LOW);
366  PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH);
367  n--;
368  }
369 #endif
370  while(n--) {
371  PJON_IO_WRITE(_output_pin, HIGH);
372  PJON_DELAY_MICROSECONDS(SWBB_BIT_SPACER);
373  PJON_IO_WRITE(_output_pin, LOW);
374  PJON_DELAY_MICROSECONDS(SWBB_BIT_WIDTH);
375  }
376  };
377 
378  /* Set the communicaton pin: */
379 
380  void set_pin(uint8_t pin)
381  {
382  PJON_IO_PULL_DOWN(pin);
383  _input_pin = pin;
384  _output_pin = pin;
385  };
386 
387 
388  /* Set a pair of communication pins: */
389 
390  void set_pins(
391  uint8_t input_pin = SWBB_NOT_ASSIGNED,
392  uint8_t output_pin = SWBB_NOT_ASSIGNED
393  )
394  {
395  PJON_IO_PULL_DOWN(input_pin);
396  PJON_IO_PULL_DOWN(output_pin);
397  _input_pin = input_pin;
398  _output_pin = output_pin;
399  };
400 
401 private:
402  uint16_t _timeout;
403  uint8_t _input_pin;
404  uint8_t _output_pin;
405 };
data
char data[MAX_PAYLOAD_SIZE+1]
Buffer for raw payload data.
Definition: MyMessage.h:654
HIGH
#define HIGH
Definition: bcm2835.h:572
LOW
#define LOW
Definition: bcm2835.h:574
SoftwareBitBang
Definition: SoftwareBitBang.h:46