rcProtocol  V.0.3.0
A protocol for diy transmitters/receivers
rcRemoteProtocol.cpp
Go to the documentation of this file.
1 #include <RF24.h>
2 #include <printf.h>
3 
4 #include "rcRemoteProtocol.h"
5 #include "rcSettings.h"
6 
7 RemoteProtocol::RemoteProtocol(RF24* tranceiver, const uint8_t remoteId[]) {
8  //initialize all primitive variables
9  _isConnected = false;
10 
11  for(uint8_t i = 0; i < 5; i++) {
12  _deviceId[i] = 0;
13  }
14 
15  _timer = millis();
16 
17  _radio = tranceiver;
18  _remoteId = remoteId;
19 }
20 
23  _radio->begin();
24  _radio->stopListening();
25 
26  uint8_t lastId[5];
27  getLastConnection(lastId);
28 
29  //check if the id is _DISCONNECT
30  bool isEmpty = true;
31  for(uint8_t i = 0; i < 5; i++) {
32  if(lastId[i] != _DISCONNECT[i]) {
33  isEmpty = false;
34  break;
35  }
36  }
37 
38  //If the last connection was unexpectedly cut-off, try re-establishing connection
39  if(!isEmpty) {
40  uint8_t settings[32];
41 
42  if(checkIfValid(lastId, settings)) {
43 
44  //copy lastId to _deviceId
45  for(uint8_t i = 0; i < 5; i++) {
46  _deviceId[i] = lastId[i];
47  }
48 
49  _settings.setSettings(settings);
51 
52  _radio->openWritingPipe(_deviceId);
53  _radio->openReadingPipe(1, _remoteId);
54 
55  if(!_settings.getEnableAck()) {
56  //Re-connect in noAck mode
57 
58  _radio->write(const_cast<uint8_t*>(&_PACKET_RECONNECT), 1);
59 
60  _radio->startListening();
61  if(wait_till_available(100) == -1) {
62  return -1;
63  }
64 
65  uint8_t status;
66  _radio->read(&status, 1);
67 
68  _radio->stopListening();
69 
70  if(status == _ACK) {
71  _isConnected = true;
72  return 1;
73  }
74 
75  } else {
76  if(force_send(const_cast<uint8_t*>(&_PACKET_RECONNECT), 1, 100) == 0) {
77  _isConnected = true;
78  return 1;
79  }
80  }
81  }
82 
83  return -1;
84 
85  }
86 
87 
88  return 0;
89 
90 }
91 
93  if(isConnected()) {
95  }
96 
97  uint8_t settings[32];
98  uint8_t deviceId[5];
99 
100  _radio->setPALevel(RF24_PA_LOW);
101 
103 
104  _radio->stopListening();
105  _radio->openWritingPipe(_PAIR_ADDRESS);
106 
107  //clear the buffer of any unread messages.
108  flush_buffer();
109 
110  //Send the remote's id until a receiver has acknowledged
111  if(force_send(const_cast<uint8_t*>(_remoteId), 5, RC_TIMEOUT) != 0) {
112  return RC_ERROR_TIMEOUT;
113  }
114 
115  //Start listening for the device to send data back
116  _radio->openReadingPipe(1, _remoteId);
117  _radio->startListening();
118 
119  //wait until data is available, if it takes too long, error lost connection
122  }
123 
124  //read the deviceId
125  _radio->read(&deviceId, 5);
126 
127 
128  //wait until data is available, if it takes too long, error lost connection
131  }
132 
133  //Read the settings to settings
134  _radio->read(settings, 32);
135 
136  //Save settings
137  saveSettings(deviceId, settings);
138 
139  _radio->stopListening();
140 
141  return 0;
142 }
143 
146  if(isConnected()) {
148  }
149 
150  uint8_t settings[32];
151  uint8_t testData = 0;
152  bool valid = false;
153 
154  //reset connected because if we fail connecting, we will not be connected
155  //to anything.
156  _isConnected = false;
157 
158  //Set the PA level to low since the two devices will be close to eachother
159  _radio->setPALevel(RF24_PA_LOW);
160 
162 
163  //We don't yet open a writing pipe as we don't know who we will write to.
164  _radio->openReadingPipe(1, _remoteId);
165 
166  _radio->startListening();
167 
168  //Wait for communications, timeout error if it takes too long
169  if(wait_till_available(RC_TIMEOUT) != 0) {
170  return RC_ERROR_TIMEOUT;
171  }
172 
173  //Read the device ID
174  _radio->read(&_deviceId, 5);
175 
176  //Check if we can pair with the device
177  valid = checkIfValid(_deviceId, settings);
178  _settings.setSettings(settings);
179 
180  //Start Writing
181  _radio->stopListening();
182 
183  //We now know who we will be writing to, so open the writing pipe
184  _radio->openWritingPipe(_deviceId);
185 
186  //Delay so that the device has time to switch modes
187  delay(200);
188 
189  //If the device is allowed to connect, send the _ACK command, else _NACK
190  if(valid) {
191  if(_radio->write(const_cast<uint8_t*>(&_ACK), 1) == false) {
193  }
194  } else {
195  if(_radio->write(const_cast<uint8_t*>(&_NACK), 1) == false) {
197  }
199  }
200 
201  //Set the radio settings to the settings specified by the receiver.
203 
204  _radio->setPALevel(RF24_PA_HIGH);
205 
206  delay(200);
207 
208  //Test if the settings were set correctly.
209 
210  if(_settings.getEnableAck()) {
212  //Test when ack payloads are enabled.
213  if(_radio->write(const_cast<uint8_t*>(&_TEST), 1) == false) {
215  }
216 
217  if(_radio->available()) {
218  _radio->read(&testData, 1);
219 
220  if(testData != _TEST) {
221  return RC_ERROR_BAD_DATA;
222  }
223  } else {
224  return RC_ERROR_BAD_DATA;
225  }
226 
227  } else {
228 
229  //Test When Ack Payloads are disabled
230  if(_radio->write(const_cast<uint8_t*>(&_TEST), 1) == false) {
231  return RC_ERROR_BAD_DATA;
232  }
233  }
234  } else {
235  //Test when acks are disabled
236  _radio->write(&_TEST, 1);
237 
238  _radio->startListening();
239 
242  }
243 
244  _radio->read(&testData, 1);
245 
246  if(testData != _TEST) {
247  return RC_ERROR_BAD_DATA;
248  }
249 
250  _radio->stopListening();
251  }
252 
253  setLastConnection(_deviceId);
254 
255  //We passed all of the tests, so we are connected.
256  _isConnected = true;
257  //set timer delay as a variable once so it doesn't need to be recalculated
258  //every update
259  _timerDelay = round(1000.0 / _settings.getCommsFrequency());
260 
261  return 0;
262 }
263 
265  return _isConnected;
266 }
267 
268 int8_t RemoteProtocol::send_packet(void* data, uint8_t dataSize,
269  void* telemetry, uint8_t telemetrySize) {
270  if(isConnected()) {
271 
272  //send data
273  if(_radio->write(data, dataSize)) {
274 
275  //Check if a payload was sent back.
276  if(telemetry && _radio->isAckPayloadAvailable()) {
277  //set telemetry to whatever was sent back
278  _radio->read(telemetry, telemetrySize);
279  return 1;
280  }
281  } else if(_settings.getEnableAck()) {
282  //We were expecting at least an ack, but did not get one
284  }
285 
286  return 0;
287  } else {
288  return RC_ERROR_NOT_CONNECTED;
289  }
290 }
291 
292 int8_t RemoteProtocol::update(uint16_t channels[], uint8_t telemetry[]) {
293 
294  if(!isConnected()) {
295  return RC_ERROR_NOT_CONNECTED;
296  }
297 
298  uint8_t packet[_settings.getPayloadSize()];
299 
300  uint8_t i = 0;
301 
302  //Set the Packet type
303  packet[i++] = _PACKET_CHANNELS + 0;
304  //Set the payload data
305  for(; i < min(_settings.getPayloadSize(), _settings.getNumChannels() * 2 + 1);
306  i += 2) {
307  packet[i] = (channels[(i - 1) / 2] >> 8) & 0x00FF;
308  packet[i + 1] = channels[(i - 1) / 2] & 0x00FF;
309  }
310  //Set the rest of the packet to 0.
311  for(; i < _settings.getPayloadSize(); i++) {
312  packet[i] = 0;
313  }
314 
315 
316  //Send the packet.
317  int8_t status = send_packet(packet,
318  sizeof(uint8_t) * _settings.getPayloadSize(),
319  telemetry, sizeof(uint8_t) * _settings.getPayloadSize());
320 
321 
322  //If the tick was too long, and there are no errors, set the return to Tick To Short
323  if(millis() - _timer > _timerDelay && status >= 0) {
324  status = RC_INFO_TICK_TOO_SHORT;
325  }
326  //wait until The Comms Frequency delay has passed.
327  while(millis() - _timer < _timerDelay) {
328  delay(1);
329  }
330 
331  _timer = millis();
332 
333  return status;
334 }
335 
338  int8_t status = send_packet((const_cast<uint8_t*>(&_PACKET_DISCONNECT)), 1);
339 
340  if(status >= 0) {
341  if(!_settings.getEnableAck()) {
342  _radio->startListening();
344 
345  uint8_t ack = 0;
346  _radio->read(&ack, 1);
347 
348  if(ack != _ACK) {
350  }
351  } else {
353  }
354  _radio->stopListening();
355  }
356 
357  _isConnected = false;
358 
360  }
361 
362  return status;
363 }
364 
366  return &_settings;
367 }
#define RC_ERROR_PACKET_NOT_SENT
#define RC_CONNECT_TIMEOUT
Definition: rcGlobal.h:15
#define RC_ERROR_BAD_DATA
Definition: rcGlobal.h:31
const uint8_t _PAIR_ADDRESS[5]
Definition: rcGlobal.h:59
#define RC_ERROR_TIMEOUT
Definition: rcGlobal.h:27
const uint8_t _PACKET_CHANNELS
Definition: rcGlobal.h:65
const uint8_t _TEST
Definition: rcGlobal.h:63
int8_t update(uint16_t channels[], uint8_t telemetry[]=NULL)
RF24 * _radio
Definition: rcGlobal.h:74
void apply_settings(RCSettings *settings)
Definition: rcGlobal.cpp:40
const uint8_t _ACK
Definition: rcGlobal.h:61
void setSettings(const uint8_t *settings)
Definition: rcSettings.cpp:17
#define RC_INFO_TICK_TOO_SHORT
RemoteProtocol(RF24 *tranceiver, const uint8_t remoteId[])
#define RC_TIMEOUT
Definition: rcGlobal.h:11
int8_t disconnect(setLastConnection setLastConnection)
void flush_buffer()
Definition: rcGlobal.cpp:65
const uint8_t _PACKET_DISCONNECT
Definition: rcGlobal.h:68
int8_t wait_till_available(unsigned long timeout)
Definition: rcGlobal.cpp:28
#define RC_ERROR_LOST_CONNECTION
Definition: rcGlobal.h:23
RCSettings _pairSettings
Definition: rcGlobal.h:72
uint8_t getCommsFrequency()
Definition: rcSettings.cpp:96
void() getLastConnection(uint8_t *id)
void() saveSettings(const uint8_t *id, const uint8_t *settings)
uint8_t getPayloadSize()
Definition: rcSettings.cpp:88
int8_t force_send(void *buf, uint8_t size, unsigned long timeout)
Definition: rcGlobal.cpp:15
#define RC_ERROR_ALREADY_CONNECTED
Definition: rcGlobal.h:43
#define RC_ERROR_NOT_CONNECTED
Definition: rcGlobal.h:39
RCSettings _settings
Definition: rcGlobal.h:71
void() setLastConnection(const uint8_t *id)
const uint8_t _DISCONNECT[5]
Definition: rcGlobal.h:60
bool getEnableAck()
Definition: rcSettings.cpp:43
int8_t pair(saveSettings saveSettings)
int8_t begin(getLastConnection getLastConnection, checkIfValid checkIfValid)
bool getEnableAckPayload()
Definition: rcSettings.cpp:53
#define RC_ERROR_CONNECTION_REFUSED
Definition: rcGlobal.h:35
bool() checkIfValid(const uint8_t *id, uint8_t *settings)
const uint8_t _NACK
Definition: rcGlobal.h:62
RCSettings * getSettings()
uint8_t getNumChannels()
Definition: rcSettings.cpp:114
int8_t connect(checkIfValid checkIfValid, setLastConnection setLastConnection)
const uint8_t _PACKET_RECONNECT
Definition: rcGlobal.h:69