MySensors Library & Examples  2.3.2-62-ge298769
OverSampling.h
1 
2 /* OverSampling 1 or 2 wires software-defined data link
3  used as a Strategy by PJON (included in version v3.0)
4  Compliant with PJDLR (Padded Jittering Data Link Radio) specification v3.0
5 
6  It uses the over-sampling method to receive data, that is generally
7  implemented on physical layers characterized by low bandwidth and high
8  noise such as ASK/FSK radio transceivers.
9  ____________________________________________________________________________
10 
11  Copyright 2015-2018 Giovanni Blu Mitolo [email protected]
12 
13  Licensed under the Apache License, Version 2.0 (the "License");
14  you may not use this file except in compliance with the License.
15  You may obtain a copy of the License at
16 
17  http://www.apache.org/licenses/LICENSE-2.0
18 
19  Unless required by applicable law or agreed to in writing, software
20  distributed under the License is distributed on an "AS IS" BASIS,
21  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  See the License for the specific language governing permissions and
23  limitations under the License. */
24 
25 #pragma once
26 
27 /* MODE 1:
28  Medium: STX882/SRX882 433MHz ASK/FSK modules or 315/433 MHz modules (green)
29  RX http://nicerf.com/manage/upfile/indexbanner/635331970881921250.pdf
30  TX http://nicerf.com/manage/upfile/indexbanner/635169453223382155.pdf
31  Timing for other hardware can be easily implemented in Timing.h
32 
33  Performance:
34  Transfer speed: 1620Bb or 202B/s
35  Absolute communication speed: 180B/s (data length 20 of characters)
36  Data throughput: 150B/s (data length 20 of characters)
37  Range: 250m with no line of sight, 5 km with direct line of sight */
38 
39 #ifndef OS_MODE
40 #define OS_MODE 1
41 #endif
42 
43 // Recommended receive time for this strategy, in microseconds
44 #ifndef OS_RECEIVE_TIME
45 #define OS_RECEIVE_TIME 1000
46 #endif
47 
48 // Used to signal communication failure
49 #define OS_FAIL 65535
50 
51 // Used for pin handling
52 #define OS_NOT_ASSIGNED 255
53 
54 #include "Timing.h"
55 
57 {
58 public:
59 
60  /* Returns the suggested delay related to the attempts passed as parameter: */
61 
62  uint32_t back_off(uint8_t attempts)
63  {
64  uint32_t result = attempts;
65  for(uint8_t d = 0; d < OS_BACK_OFF_DEGREE; d++) {
66  result *= (uint32_t)(attempts);
67  }
68  return result;
69  };
70 
71 
72  /* Begin method, to be called on initialization:
73  (returns always true) */
74 
75  bool begin(uint8_t did = 0)
76  {
77  PJON_DELAY(PJON_RANDOM(OS_INITIAL_DELAY) + did);
78  return true;
79  };
80 
81 
82  /* Check if the channel is free for transmission:
83  If receiving 10 bits no 1s are detected
84  there is no active transmission */
85 
86  bool can_start()
87  {
88  float value = 0.5;
89  uint32_t time = PJON_MICROS();
90  PJON_IO_MODE(_input_pin, INPUT);
91  while((uint32_t)(PJON_MICROS() - time) < OS_TIMEOUT) {
92  value = (value * 0.999) + (PJON_IO_READ(_input_pin) * 0.001);
93  }
94  if(value > 0.5) {
95  return false;
96  }
97  if(PJON_IO_READ(_input_pin)) {
98  return false;
99  }
100  PJON_DELAY_MICROSECONDS(PJON_RANDOM(OS_COLLISION_DELAY));
101  if(PJON_IO_READ(_input_pin)) {
102  return false;
103  }
104  return true;
105  };
106 
107  /* Returns the maximum number of attempts for each transmission: */
108 
109  static uint8_t get_max_attempts()
110  {
111  return OS_MAX_ATTEMPTS;
112  };
113 
114 
115  /* Returns the recommended receive time for this strategy: */
116 
117  static uint16_t get_receive_time()
118  {
119  return OS_RECEIVE_TIME;
120  };
121 
122 
123  /* Handle a collision: */
124 
125  void handle_collision()
126  {
127  PJON_DELAY_MICROSECONDS(PJON_RANDOM(OS_COLLISION_DELAY));
128  };
129 
130 
131  /* Read a byte from the pin */
132 
133  uint8_t read_byte()
134  {
135  uint8_t byte_value = 0B00000000;
136  for(uint8_t i = 0; i < 8; i++) {
137  uint32_t time = PJON_MICROS();
138  float value = 0.5;
139  while((uint32_t)(PJON_MICROS() - time) < OS_BIT_WIDTH) {
140  value = ((value * 0.999) + (PJON_IO_READ(_input_pin) * 0.001));
141  }
142  byte_value += (value > 0.5) << i;
143  }
144  return byte_value;
145  };
146 
147 
148  /* Try to receive a byte: */
149 
150  uint16_t receive_byte()
151  {
152  if(sync()) {
153  return read_byte();
154  }
155  return OS_FAIL;
156  };
157 
158  /* Receive byte response:
159  Transmitter emits a OS_BIT_SPACER / 2 long bit and tries
160  to get a response cyclically for OS_TIMEOUT microseconds.
161  Receiver then can blindly send PJON_ACK */
162 
163  uint16_t receive_response()
164  {
165  if(_output_pin != _input_pin && _output_pin != OS_NOT_ASSIGNED) {
166  PJON_IO_WRITE(_output_pin, LOW);
167  }
168  uint16_t response = OS_FAIL;
169  uint32_t time = PJON_MICROS();
170  while(
171  response == OS_FAIL &&
172  (uint32_t)(PJON_MICROS() - OS_TIMEOUT) <= time
173  ) {
174  PJON_IO_WRITE(_input_pin, LOW);
175  if(sync()) {
176  response = receive_byte();
177  }
178  if(response != PJON_ACK) {
179  PJON_IO_MODE(_output_pin, OUTPUT);
180  PJON_IO_WRITE(_output_pin, HIGH);
181  PJON_DELAY_MICROSECONDS(OS_BIT_SPACER / 2);
182  PJON_IO_PULL_DOWN(_output_pin);
183  }
184  }
185  return response;
186  };
187 
188 
189  /* Receive a frame: */
190 
191  uint16_t receive_frame(uint8_t *data, uint16_t max_length)
192  {
193  uint16_t result;
194  if(max_length == PJON_PACKET_MAX_LENGTH) {
195  uint32_t time = PJON_MICROS();
196  // Look for frame initializer
197  if(!sync() || !sync() || !sync()) {
198  return OS_FAIL;
199  }
200  if( // Check its timing consistency
201  (uint32_t)(PJON_MICROS() - time) <
202  ((OS_BIT_WIDTH * 3) + (OS_BIT_SPACER * 3))
203  ) {
204  return OS_FAIL;
205  }
206  } // Receive incoming byte
207  result = receive_byte();
208  if(result == OS_FAIL) {
209  return OS_FAIL;
210  }
211  *data = result;
212  return 1;
213  };
214 
215 
216  /* Every byte is prepended with 2 synchronization padding bits. The first
217  is a shorter than standard logic 1 followed by a standard logic 0.
218  _____ ___________________________
219  |Sync | Byte |
220  |_ |___ ___ _____ |
221  | | | | | | | | |
222  |1| 0 | 1 | 0 0 | 1 | 0 | 1 1 | 0 |
223  |_|___|___|_____|___|___|_____|___|
224 
225  The reception tecnique is based on finding a logic 1 as long as the
226  first padding bit, synchronizing to its falling edge and checking if
227  it is followed by a logic 0. If this pattern is recognised, reception
228  starts, if not, interference, synchronization loss or simply absence
229  of communication is detected at byte level. */
230 
231  void send_byte(uint8_t b)
232  {
233  pulse(1);
234  for(uint8_t mask = 0x01; mask; mask <<= 1) {
235  PJON_IO_WRITE(_output_pin, b & mask);
236  PJON_DELAY_MICROSECONDS(OS_BIT_WIDTH);
237  }
238  };
239 
240  /* Send byte response:
241  Transmitter sends a OS_BIT_SPACER / 2 microseconds long HIGH bit and
242  tries to receive a response cyclically for OS_TIMEOUT
243  microseconds. Receiver then can blindly send PJON_ACK */
244 
245  void send_response(uint8_t response)
246  {
247  PJON_IO_PULL_DOWN(_input_pin);
248  PJON_IO_MODE(_output_pin, OUTPUT);
249  pulse(1);
250  send_byte(response);
251  PJON_IO_PULL_DOWN(_output_pin);
252  };
253 
254  /* Send a frame: */
255 
256  void send_frame(uint8_t *data, uint16_t length)
257  {
258  PJON_IO_MODE(_output_pin, OUTPUT);
259  pulse(3); // Send frame inititializer
260  for(uint16_t b = 0; b < length; b++) {
261  send_byte(data[b]); // Send data
262  }
263  PJON_IO_PULL_DOWN(_output_pin);
264  };
265 
266 
267  bool sync()
268  {
269  PJON_IO_PULL_DOWN(_input_pin);
270  if(_output_pin != OS_NOT_ASSIGNED && _output_pin != _input_pin) {
271  PJON_IO_PULL_DOWN(_output_pin);
272  }
273  float value = 0.5;
274  uint32_t time = PJON_MICROS();
275  /* Average pin value until the pin stops to be HIGH or passed more
276  time than BIT_SPACER duration */
277  while(
278  ((uint32_t)(PJON_MICROS() - time) < OS_BIT_SPACER) &&
279  PJON_IO_READ(_input_pin)
280  ) {
281  value = (value * 0.999) + (PJON_IO_READ(_input_pin) * 0.001);
282  }
283  /* If the pin value is in average more than 0.5, is a 1, and if lasted
284  more than OS_ACCEPTANCE (a minimum HIGH duration) and what is coming
285  after is a LOW bit probably a byte is coming so try to receive it. */
286  if(PJON_MICROS() - time < OS_ACCEPTANCE) {
287  return false;
288  }
289  if(value > 0.5) {
290  value = 0.5;
291  time = PJON_MICROS();
292  while((uint32_t)(PJON_MICROS() - time) < OS_BIT_WIDTH) {
293  value = (value * 0.999) + (PJON_IO_READ(_input_pin) * 0.001);
294  }
295  if(value < 0.5) {
296  return true;
297  }
298  return false;
299  }
300  return false;
301  };
302 
303  /* Emit synchronization pulse: */
304 
305  void pulse(uint8_t n)
306  {
307  while(n--) {
308  PJON_IO_WRITE(_output_pin, HIGH);
309  PJON_DELAY_MICROSECONDS(OS_BIT_SPACER);
310  PJON_IO_WRITE(_output_pin, LOW);
311  PJON_DELAY_MICROSECONDS(OS_BIT_WIDTH);
312  }
313  };
314 
315  /* Set the communicaton pin: */
316 
317  void set_pin(uint8_t pin)
318  {
319  PJON_IO_PULL_DOWN(pin);
320  _input_pin = pin;
321  _output_pin = pin;
322  };
323 
324 
325  /* Set a pair of communication pins: */
326 
327  void set_pins(
328  uint8_t input_pin = OS_NOT_ASSIGNED,
329  uint8_t output_pin = OS_NOT_ASSIGNED
330  )
331  {
332  PJON_IO_PULL_DOWN(input_pin);
333  PJON_IO_PULL_DOWN(output_pin);
334  _input_pin = input_pin;
335  _output_pin = output_pin;
336  };
337 
338 private:
339  uint8_t _input_pin;
340  uint8_t _output_pin;
341 };
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
OverSampling
Definition: OverSampling.h:56