Optimized high speed nRF24L01+ driver class documentation v1.4.8
TMRh20 2020 - Optimized fork of the nRF24L01+ driver
Loading...
Searching...
No Matches
examples_linux/manualAcknowledgements.cpp

Written by 2bndy5 in 2020

A simple example of sending data from 1 nRF24L01 transceiver to another with manually transmitted (non-automatic) Acknowledgement (ACK) payloads. This example still uses ACK packets, but they have no payloads. Instead the acknowledging response is sent with write(). This tactic allows for more updated acknowledgement payload data, where actual ACK payloads' data are outdated by 1 transmission because they have to loaded before receiving a transmission.

This example was written to be used on 2 devices acting as "nodes". Use ctrl+c to quit at any time.

1/*
2 * See documentation at https://nRF24.github.io/RF24
3 * See License information at root directory of this library
4 * Author: Brendan Doherty (2bndy5)
5 */
6
19#include <ctime> // time()
20#include <iostream> // cin, cout, endl
21#include <string> // string, getline()
22#include <time.h> // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
23#include <RF24/RF24.h> // RF24, RF24_PA_LOW, delay()
24
25using namespace std;
26
27/****************** Linux ***********************/
28// Radio CE Pin, CSN Pin, SPI Speed
29// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
30// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
31// ie: RF24 radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
32#define CSN_PIN 0
33#ifdef MRAA
34 #define CE_PIN 15 // GPIO22
35#elif defined(RF24_WIRINGPI)
36 #define CE_PIN 3 // GPIO22
37#else
38 #define CE_PIN 22
39#endif
40// Generic:
41RF24 radio(CE_PIN, CSN_PIN);
42/****************** Linux (BBB,x86,etc) ***********************/
43// See http://nRF24.github.io/RF24/pages.html for more information on usage
44// See https://github.com/eclipse/mraa/ for more information on MRAA
45// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
46
47// For this example, we'll be using a payload containing
48// a string & an integer number that will be incremented
49// on every successful transmission.
50// Make a data structure to store the entire payload of different datatypes
51struct PayloadStruct
52{
53 char message[7]; // only using 6 characters for TX & RX payloads
54 uint8_t counter;
55};
56PayloadStruct payload;
57
58void setRole(); // prototype to set the node's role
59void master(); // prototype of the TX node's behavior
60void slave(); // prototype of the RX node's behavior
61
62// custom defined timer for evaluating transmission time in microseconds
63struct timespec startTimer, endTimer;
64uint32_t getMicros(); // prototype to get elapsed time in microseconds
65
66int main(int argc, char** argv)
67{
68
69 // perform hardware check
70 if (!radio.begin()) {
71 cout << "radio hardware is not responding!!" << endl;
72 return 0; // quit now
73 }
74
75 // append a NULL terminating 0 for printing as a c-string
76 payload.message[6] = 0;
77
78 // Let these addresses be used for the pair of nodes used in this example
79 uint8_t address[2][6] = {"1Node", "2Node"};
80 // the TX address^ , ^the RX address
81 // It is very helpful to think of an address as a path instead of as
82 // an identifying device destination
83
84 // to use different addresses on a pair of radios, we need a variable to
85 // uniquely identify which address this radio will use to transmit
86 bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
87
88 // print example's name
89 cout << argv[0] << endl;
90
91 // Set the radioNumber via the terminal on startup
92 cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' ";
93 string input;
94 getline(cin, input);
95 radioNumber = input.length() > 0 && (uint8_t)input[0] == 49;
96
97 // Set the PA Level low to try preventing power supply related problems
98 // because these examples are likely run with nodes in close proximity to
99 // each other.
100 radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default.
101
102 // save on transmission time by setting the radio to only transmit the
103 // number of bytes we need to transmit a float
104 radio.setPayloadSize(sizeof(payload)); // char[7] & uint8_t datatypes occupy 8 bytes
105
106 // set the TX address of the RX node into the TX pipe
107 radio.openWritingPipe(address[radioNumber]); // always uses pipe 0
108
109 // set the RX address of the TX node into a RX pipe
110 radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
111
112 // For debugging info
113 // radio.printDetails(); // (smaller) function that prints raw register values
114 // radio.printPrettyDetails(); // (larger) function that prints human readable data
115
116 // ready to execute program now
117 setRole(); // calls master() or slave() based on user input
118 return 0;
119} // main
120
125void setRole()
126{
127 string input = "";
128 while (!input.length()) {
129 cout << "*** PRESS 'T' to begin transmitting to the other node\n";
130 cout << "*** PRESS 'R' to begin receiving from the other node\n";
131 cout << "*** PRESS 'Q' to exit" << endl;
132 getline(cin, input);
133 if (input.length() >= 1) {
134 if (input[0] == 'T' || input[0] == 't')
135 master();
136 else if (input[0] == 'R' || input[0] == 'r')
137 slave();
138 else if (input[0] == 'Q' || input[0] == 'q')
139 break;
140 else
141 cout << input[0] << " is an invalid input. Please try again." << endl;
142 }
143 input = ""; // stay in the while loop
144 } // while
145} // setRole()
146
150void master()
151{
152
153 memcpy(payload.message, "Hello ", 6); // set the outgoing message
154 radio.stopListening(); // put in TX mode
155
156 unsigned int failures = 0; // keep track of failures
157 while (failures < 6) {
158 clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer
159 bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report
160
161 if (report) {
162 // transmission successful; wait for response and print results
163
164 radio.startListening(); // put in RX mode
165 unsigned long start_timeout = millis(); // timer to detect no response
166 while (!radio.available()) { // wait for response
167 if (millis() - start_timeout > 200) // only wait 200 ms
168 break;
169 }
170 unsigned long elapsedTime = getMicros(); // end the timer
171 radio.stopListening(); // put back in TX mode
172
173 // print summary of transactions
174 uint8_t pipe;
175 cout << "Transmission successful! ";
176 if (radio.available(&pipe)) { // is there a payload received? grab the pipe number that received it
177 uint8_t bytes = radio.getPayloadSize(); // grab the incoming payload size
178 cout << "Round trip delay = ";
179 cout << elapsedTime; // print the timer result
180 cout << " us. Sent: " << payload.message; // print outgoing message
181 cout << (unsigned int)payload.counter; // print outgoing counter
182 PayloadStruct received;
183 radio.read(&received, sizeof(received)); // get incoming payload
184 cout << " Recieved " << (unsigned int)bytes; // print incoming payload size
185 cout << " on pipe " << (unsigned int)pipe; // print RX pipe number
186 cout << ": " << received.message; // print the incoming message
187 cout << (unsigned int)received.counter; // print the incoming counter
188 cout << endl;
189 payload.counter = received.counter; // save incoming counter for next outgoing counter
190 }
191 else {
192 cout << "Recieved no response." << endl; // no response received
193 }
194 }
195 else {
196 cout << "Transmission failed or timed out"; // payload was not delivered
197 cout << endl;
198 failures++; // increment failure counter
199 } // report
200
201 // to make this example readable in the terminal
202 delay(1000); // slow transmissions down by 1 second
203 } // while
204
205 cout << failures << " failures detected. Leaving TX role." << endl;
206} // master
207
211void slave()
212{
213 memcpy(payload.message, "World ", 6); // set the response message
214 radio.startListening(); // put in RX mode
215
216 time_t startTimer = time(nullptr); // start a timer
217 while (time(nullptr) - startTimer < 6) { // use 6 second timeout
218 uint8_t pipe;
219 if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it
220 uint8_t bytes = radio.getPayloadSize(); // get size of incoming payload
221 PayloadStruct received;
222 radio.read(&received, sizeof(received)); // get incoming payload
223 payload.counter = received.counter + 1; // increment payload for response
224
225 // transmit response & save result to `report`
226 radio.stopListening(); // put in TX mode
227 radio.writeFast(&payload, sizeof(payload)); // load response into TX FIFO
228 bool report = radio.txStandBy(150); // keep retrying for 150 ms
229 radio.startListening(); // put back in RX mode
230
231 // print summary of transactions
232 cout << "Received " << (unsigned int)bytes; // print the size of the payload
233 cout << " bytes on pipe ";
234 cout << (unsigned int)pipe; // print the pipe number
235 cout << ": " << received.message; // print incoming message
236 cout << (unsigned int)received.counter; // print incoming counter
237
238 if (report) {
239 cout << " Sent: " << payload.message; // print outgoing message
240 cout << (unsigned int)payload.counter; // print outgoing counter
241 cout << endl;
242 }
243 else {
244 cout << " Response failed to send." << endl; // failed to send response
245 }
246 startTimer = time(nullptr); // reset timer
247 } // available
248 } // while
249
250 cout << "Nothing received in 6 seconds. Leaving RX role." << endl;
251 radio.stopListening(); // recommended idle mode is TX mode
252} // slave
253
257uint32_t getMicros()
258{
259 // this function assumes that the timer was started using
260 // `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);`
261
262 clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer);
263 uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec;
264 uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000;
265
266 return ((seconds)*1000 + useconds) + 0.5;
267}
Driver class for nRF24L01(+) 2.4GHz Wireless Transceiver.
Definition RF24.h:116
@ RF24_PA_LOW
Definition RF24.h:50
#define delay(milisec)
#define millis()