Linux examples

gettingstarted.cpp

A simple example of sending data from 1 nRF24L01 transceiver to another. This example was written to be used on 2 devices acting as “nodes”. Use ctrl+c to quit at any time, but remember state of the radio will persist until another example or application uses it.

/examples_linux/gettingstarted.cpp
 13#include <ctime>       // time()
 14#include <iostream>    // cin, cout, endl
 15#include <string>      // string, getline()
 16#include <time.h>      // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
 17#include <RF24Revamped/RF24Revamped.h> // RF24, RF24_PA_LOW, delay()
 18
 19using namespace std;
 20
 21/****************** Linux ***********************/
 22// Radio CE Pin, CSN Pin, SPI Speed
 23// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
 24// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
 25// ie: RF24Revamped radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
 26
 27// Generic:
 28RF24Revamped radio(22, 0);
 29/****************** Linux (BBB,x86,etc) ***********************/
 30// See http://2bndy5.github.io/RF24/pages.html for more information on usage
 31// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
 32// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
 33
 34// For this example, we'll be using a payload containing
 35// a single float number that will be incremented
 36// on every successful transmission
 37float payload = 0.0;
 38
 39void setRole(); // prototype to set the node's role
 40void master();  // prototype of the TX node's behavior
 41void slave();   // prototype of the RX node's behavior
 42
 43// custom defined timer for evaluating transmission time in microseconds
 44struct timespec startTimer, endTimer;
 45uint32_t getMicros(); // prototype to get ellapsed time in microseconds
 46
 47int main(int argc, char** argv) {
 48
 49    // perform hardware check
 50    if (!radio.begin()) {
 51        cout << "radio hardware is not responding!!" << endl;
 52        return 0; // quit now
 53    }
 54
 55    // to use different addresses on a pair of radios, we need a variable to
 56    // uniquely identify which address this radio will use to transmit
 57    bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
 58
 59    // print example's name
 60    cout << argv[0] << endl;
 61
 62    // Let these addresses be used for the pair
 63    uint8_t address[2][6] = {"1Node", "2Node"};
 64    // It is very helpful to think of an address as a path instead of as
 65    // an identifying device destination
 66
 67    // Set the radioNumber via the terminal on startup
 68    cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' ";
 69    string input;
 70    getline(cin, input);
 71    radioNumber = input.length() > 0 && (uint8_t)input[0] == 49;
 72
 73    // save on transmission time by setting the radio to only transmit the
 74    // number of bytes we need to transmit a float
 75    radio.setPayloadLength(sizeof(payload)); // float datatype occupies 4 bytes
 76
 77    // Set the PA Level low to try preventing power supply related problems
 78    // because these examples are likely run with nodes in close proximity to
 79    // each other.
 80    radio.setPaLevel(RF24_PA_LOW); // RF24_PA_MAX is default.
 81
 82    // set the TX address of the RX node into the TX pipe
 83    radio.openWritingPipe(address[radioNumber]);     // always uses pipe 0
 84
 85    // set the RX address of the TX node into a RX pipe
 86    radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
 87
 88    radio.setAutoRetry(4000, 15);
 89    // For debugging info
 90    radio.printDetails();
 91
 92    // ready to execute program now
 93    setRole(); // calls master() or slave() based on user input
 94    return 0;
 95}
 96
 97
 98/**
 99 * set this node's role from stdin stream.
100 * this only considers the first char as input.
101 */
102void setRole() {
103    string input = "";
104    while (!input.length()) {
105        cout << "*** PRESS 'T' to begin transmitting to the other node\n";
106        cout << "*** PRESS 'R' to begin receiving from the other node\n";
107        cout << "*** PRESS 'Q' to exit" << endl;
108        getline(cin, input);
109        if (input.length() >= 1) {
110            if (input[0] == 'T' || input[0] == 't')
111                master();
112            else if (input[0] == 'R' || input[0] == 'r')
113                slave();
114            else if (input[0] == 'Q' || input[0] == 'q')
115                break;
116            else
117                cout << input[0] << " is an invalid input. Please try again." << endl;
118        }
119        input = ""; // stay in the while loop
120    } // while
121} // setRole()
122
123
124/**
125 * make this node act as the transmitter
126 */
127void master() {
128    radio.stopListening(); // put radio in TX mode
129
130    unsigned int failure = 0;                              // keep track of failures
131    while (failure < 6) {
132        clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);   // start the timer
133        bool report = radio.send(&payload, sizeof(float)); // transmit & save the report
134        uint32_t timerEllapsed = getMicros();              // end the timer
135
136        if (report) {
137            // payload was delivered
138            cout << "Transmission successful! ";
139            cout << "Time to transmit = ";
140            cout << timerEllapsed;                    // print the timer result
141            cout << " us. Sent: " << payload << endl; // print payload sent
142            payload += 0.01;                          // increment float payload
143
144        } else {
145            // payload was not delivered
146            cout << "Transmission failed or timed out" << endl;
147            failure++;
148        }
149
150        // to make this example readable in the terminal
151        delay(1000);  // slow transmissions down by 1 second
152    }
153    cout << failure << " failures detected. Leaving TX role." << endl;
154}
155
156/**
157 * make this node act as the receiver
158 */
159void slave() {
160
161    radio.startListening(); // put radio in RX mode
162
163    time_t startTimer = time(nullptr);         // start a timer
164    while (time(nullptr) - startTimer < 6) {   // use 6 second timeout
165        if (radio.available()) {               // is there a payload?
166            unsigned int pipe = radio.pipe();  // get the pipe number that recieved it
167            unsigned int bytes = radio.any();  // get the size of the payload
168            radio.read(&payload, bytes);       // fetch payload from FIFO
169            cout << "Received " << bytes;      // print the size of the payload
170            cout << " bytes on pipe " << pipe; // print the pipe number
171            cout << ": " << payload << endl;   // print the payload's value
172            startTimer = time(nullptr);        // reset timer
173        }
174    }
175    cout << "Nothing received in 6 seconds. Leaving RX role." << endl;
176    radio.stopListening();
177}
178
179
180/**
181 * Calculate the ellapsed time in microseconds
182 */
183uint32_t getMicros() {
184    // this function assumes that the timer was started using
185    // `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);`
186
187    clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer);
188    uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec;
189    uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000;
190
191    return ((seconds) * 1000 + useconds) + 0.5;
192}

acknowledgementPayloads.cpp

A simple example of sending data from 1 nRF24L01 transceiver to another with Acknowledgement (ACK) payloads attached to ACK packets. This example was written to be used on 2 devices acting as “nodes”. Use ctrl+c to quit at any time, but remember state of the radio will persist until another example or application uses it.

/examples_linux/acknowledgementPayloads.cpp
 14#include <ctime>       // time()
 15#include <iostream>    // cin, cout, endl
 16#include <string>      // string, getline()
 17#include <time.h>      // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
 18#include <RF24Revamped/RF24Revamped.h> // RF24, RF24_PA_LOW, delay()
 19
 20using namespace std;
 21
 22/****************** Linux ***********************/
 23// Radio CE Pin, CSN Pin, SPI Speed
 24// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
 25// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
 26// ie: RF24Revamped radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
 27
 28// Generic:
 29RF24Revamped radio(22, 0);
 30/****************** Linux (BBB,x86,etc) ***********************/
 31// See http://2bndy5.github.io/RF24/pages.html for more information on usage
 32// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
 33// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
 34
 35// For this example, we'll be using a payload containing
 36// a string & an integer number that will be incremented
 37// on every successful transmission.
 38// Make a data structure to store the entire payload of different datatypes
 39struct PayloadStruct {
 40  char message[7]; // only using 6 characters for TX & ACK payloads
 41  uint8_t counter;
 42};
 43PayloadStruct payload;
 44
 45void setRole(); // prototype to set the node's role
 46void master();  // prototype of the TX node's behavior
 47void slave();   // prototype of the RX node's behavior
 48
 49// custom defined timer for evaluating transmission time in microseconds
 50struct timespec startTimer, endTimer;
 51uint32_t getMicros(); // prototype to get ellapsed time in microseconds
 52
 53
 54int main(int argc, char** argv) {
 55    // perform hardware check
 56    if (!radio.begin()) {
 57        cout << "radio hardware is not responding!!" << endl;
 58        return 0; // quit now
 59    }
 60
 61    // Let these addresses be used for the pair
 62    uint8_t address[2][6] = {"1Node", "2Node"};
 63    // It is very helpful to think of an address as a path instead of as
 64    // an identifying device destination
 65
 66    // to use different addresses on a pair of radios, we need a variable to
 67    // uniquely identify which address this radio will use to transmit
 68    bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
 69
 70    // print example's name
 71    cout << argv[0] << endl;
 72
 73    // Set the radioNumber via the terminal on startup
 74    cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' ";
 75    string input;
 76    getline(cin, input);
 77    radioNumber = input.length() > 0 && (uint8_t)input[0] == 49;
 78
 79    // to use ACK payloads, we need to enable dynamic payload lengths
 80    radio.setDynamicPayloads(true);    // ACK payloads are dynamically sized
 81
 82    // Acknowledgement packets have no payloads by default. We need to enable
 83    // this feature for all nodes (TX & RX) to use ACK payloads.
 84    radio.enableAckPayload();
 85
 86    // Set the PA Level low to try preventing power supply related problems
 87    // because these examples are likely run with nodes in close proximity to
 88    // each other.
 89    radio.setPaLevel(RF24_PA_LOW);  // RF24_PA_MAX is default.
 90
 91    // set the TX address of the RX node into the TX pipe
 92    radio.openWritingPipe(address[radioNumber]);     // always uses pipe 0
 93
 94    // set the RX address of the TX node into a RX pipe
 95    radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
 96
 97    // For debugging info
 98    // radio.printDetails();
 99
100    // ready to execute program now
101    setRole(); // calls master() or slave() based on user input
102    return 0;
103}
104
105
106/**
107 * set this node's role from stdin stream.
108 * this only considers the first char as input.
109 */
110void setRole() {
111    string input = "";
112    while (!input.length()) {
113        cout << "*** PRESS 'T' to begin transmitting to the other node\n";
114        cout << "*** PRESS 'R' to begin receiving from the other node\n";
115        cout << "*** PRESS 'Q' to exit" << endl;
116        getline(cin, input);
117        if (input.length() >= 1) {
118            if (input[0] == 'T' || input[0] == 't')
119                master();
120            else if (input[0] == 'R' || input[0] == 'r')
121                slave();
122            else if (input[0] == 'Q' || input[0] == 'q')
123                break;
124            else
125                cout << input[0] << " is an invalid input. Please try again." << endl;
126        }
127        input = ""; // stay in the while loop
128    } // while
129} // setRole()
130
131
132/**
133 * make this node act as the transmitter
134 */
135void master() {
136    memcpy(payload.message, "Hello ", 6);                     // set the payload message
137    radio.stopListening();                                    // put radio in TX mode
138
139    unsigned int failures = 0;                                // keep track of failures
140    while (failures < 6) {
141        clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);      // start the timer
142        bool report = radio.send(&payload, sizeof(payload)); // transmit & save the report
143        uint32_t timerEllapsed = getMicros();                 // end the timer
144
145        if (report) {
146            // payload was delivered
147            cout << "Transmission successful! Time to transmit = ";
148            cout << timerEllapsed;                                  // print the timer result
149            cout << " us. Sent: ";
150            cout << payload.message;                                // print outgoing message
151            cout << (unsigned int)payload.counter;                  // print outgoing counter counter
152
153            if (radio.available()) {
154                unsigned int pipe = radio.pipe();               // grab the pipe number that received it
155                unsigned int bytes = radio.any();               // get the size of the payload
156                PayloadStruct received;
157                radio.read(&received, sizeof(received));        // get incoming ACK payload
158                cout << " Received " << bytes;                  // print incoming payload size
159                cout << " bytes on pipe " << pipe;              // print pipe that received it
160                cout << ": " << received.message;               // print incoming message
161                cout << (unsigned int)received.counter << endl; // print incoming counter
162                payload.counter = received.counter + 1;         // save incoming counter & increment for next outgoing
163            } // if got an ACK payload
164            else {
165                cout << " Received an empty ACK packet." << endl; // ACK had no payload
166            }
167        } // if delivered
168        else {
169            cout << "Transmission failed or timed out" << endl;   // payload was not delivered
170            failures++;                                           // increment failures
171        }
172
173        // to make this example readable in the terminal
174        delay(1000);  // slow transmissions down by 1 second
175    } // while
176    cout << failures << " failures detected. Leaving TX role." << endl;
177} // master
178
179
180/**
181 * make this node act as the receiver
182 */
183void slave() {
184    memcpy(payload.message, "World ", 6); // set the payload message
185
186    // load the payload for the first received transmission on pipe 0
187    radio.writeAck(1, &payload, sizeof(payload));
188
189    radio.startListening();                         // put radio in RX mode
190    time_t startTimer = time(nullptr);              // start a timer
191    while (time(nullptr) - startTimer < 6) {        // use 6 second timeout
192        if (radio.available()) {                    // is there a payload?
193            unsigned int pipe = radio.pipe();       // get the pipe number that recieved it
194            unsigned int bytes = radio.any();       // get the size of the payload
195            PayloadStruct received;
196            radio.read(&received, sizeof(received)); // fetch payload from RX FIFO
197            cout << "Received " << bytes;            // print the size of the payload
198            cout << " bytes on pipe " << pipe;       // print the pipe number
199            cout << ": " << received.message;
200            cout << (unsigned int)received.counter;  // print received payload
201            cout << " Sent: ";
202            cout << payload.message;
203            cout << (unsigned int)payload.counter;   // print ACK payload sent
204            cout << endl;
205            startTimer = time(nullptr);              // reset timer
206
207            // save incoming counter & increment for next outgoing
208            payload.counter = received.counter + 1;
209            // load the payload for the first received transmission on pipe 0
210            radio.writeAck(1, &payload, sizeof(payload));
211        } // if received something
212    } // while
213    cout << "Nothing received in 6 seconds. Leaving RX role." << endl;
214    radio.stopListening(); // recommended idle behavior is TX mode
215} // slave
216
217
218/**
219 * Calculate the ellapsed time in microseconds
220 */
221uint32_t getMicros() {
222    // this function assumes that the timer was started using
223    // `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);`
224
225    clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer);
226    uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec;
227    uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000;
228
229    return ((seconds) * 1000 + useconds) + 0.5;
230}

manualAcknowledgements.cpp

This is a simple example of using the RF24 class on a Raspberry Pi to transmit and respond with acknowledgment (ACK) transmissions. Notice that the auto-ack feature is enabled, but this example doesn’t use automatic ACK payloads because automatic ACK payloads’ data will always be outdated by 1 transmission. Instead, this example uses a call and response paradigm. This example was written to be used on 2 devices acting as “nodes”. Use ctrl+c to quit at any time, but remember state of the radio will persist until another example or application uses it.

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

multiceiverDemo.cpp

A simple example of sending data from as many as 6 nRF24L01 transceivers to 1 receiving transceiver. This technique is trademarked by Nordic Semiconductors as “MultiCeiver”. Use ctrl+c to quit at any time, but remember state of the radio will persist until another example or application uses it.

/examples_linux/multiceiverDemo.cpp
 16#include <ctime>       // time()
 17#include <cstring>     // strcmp()
 18#include <iostream>    // cin, cout, endl
 19#include <string>      // string, getline()
 20#include <time.h>      // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
 21#include <RF24Revamped/RF24Revamped.h> // RF24, RF24_PA_LOW, delay()
 22
 23using namespace std;
 24
 25/****************** Linux ***********************/
 26// Radio CE Pin, CSN Pin, SPI Speed
 27// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
 28// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
 29// ie: RF24Revamped radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
 30
 31// Generic:
 32RF24Revamped radio(22, 0);
 33/****************** Linux (BBB,x86,etc) ***********************/
 34// See http://2bndy5.github.io/RF24/pages.html for more information on usage
 35// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
 36// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
 37
 38
 39// For this example, we'll be using 6 addresses; 1 for each TX node
 40// It is very helpful to think of an address as a path instead of as
 41// an identifying device destination
 42// Notice that the last byte is the only byte that changes in the last 5
 43// addresses. This is a limitation of the nRF24L01 transceiver for pipes 2-5
 44// because they use the same first 4 bytes from pipe 1.
 45uint64_t address[6] = {0x7878787878LL,
 46                       0xB3B4B5B6F1LL,
 47                       0xB3B4B5B6CDLL,
 48                       0xB3B4B5B6A3LL,
 49                       0xB3B4B5B60FLL,
 50                       0xB3B4B5B605LL};
 51
 52
 53// For this example, we'll be using a payload containing
 54// a node ID number and a single integer number that will be incremented
 55// on every successful transmission.
 56// Make a data structure to use as a payload.
 57struct PayloadStruct
 58{
 59  unsigned int nodeID;
 60  unsigned int payloadID;
 61};
 62PayloadStruct payload;
 63
 64void setRole();            // prototype to set the node's role
 65void master(unsigned int); // prototype of a TX node's behavior
 66void slave();              // prototype of the RX node's behavior
 67void printHelp(string);    // prototype to function that explain CLI arg usage
 68
 69// custom defined timer for evaluating transmission time in microseconds
 70struct timespec startTimer, endTimer;
 71uint32_t getMicros(); // prototype to get ellapsed time in microseconds
 72
 73
 74int main(int argc, char** argv) {
 75
 76    // perform hardware check
 77    if (!radio.begin()) {
 78        cout << "radio hardware is not responding!!" << endl;
 79        return 0; // quit now
 80    }
 81
 82    // to use different addresses on a pair of radios, we need a variable to
 83    // uniquely identify which address this radio will use to transmit
 84    unsigned int nodeNumber = 'R'; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
 85
 86    bool foundArgNode = false;
 87    if (argc > 1) {
 88        if ((argc - 1) != 2) {
 89            // CLI arg "-n"/"--node" needs an option specified for it
 90            // only 1 arg is expected, so only traverse the first "--arg option" pair
 91            printHelp(string(argv[0]));
 92            return 0;
 93        }
 94        else if (strcmp(argv[1], "-n") == 0 || strcmp(argv[1], "--node") == 0) {
 95            // "-n" or "--node" has been specified
 96            foundArgNode = true;
 97            if ((argv[2][0] - 48) < 6) {
 98                nodeNumber = argv[2][0] - 48;
 99            }
100            else if (argv[2][0] == 'R' || argv[2][0] == 'r') {
101                nodeNumber = 'R';
102            }
103            else {
104                printHelp(string(argv[0]));
105                return 0;
106            }
107        }
108        else {
109            // "-n"/"--node" arg was not specified
110            printHelp(string(argv[0]));
111            return 0;
112        }
113    }
114
115    // print example's name
116    cout << argv[0] << endl;
117
118    // Set the PA Level low to try preventing power supply related problems
119    // because these examples are likely run with nodes in close proximity to
120    // each other.
121    radio.setPaLevel(RF24_PA_LOW);         // RF24_PA_MAX is default.
122
123    // save on transmission time by setting the radio to only transmit the
124    // number of bytes we need to transmit a float
125    radio.setPayloadLength(sizeof(payload)); // 2x int datatype occupy 8 bytes
126
127    // For debugging info
128    // radio.printDetails();
129
130    // ready to execute program now
131    if (!foundArgNode) {
132        setRole(); // calls master() or slave() based on user input
133    }
134    else {
135        nodeNumber < 6 ? master(nodeNumber) : slave();
136    }
137    return 0;
138}
139
140
141/**
142 * set this node's role from stdin stream.
143 * this only considers the first char as input.
144 */
145void setRole() {
146
147    string input = "";
148    while (!input.length()) {
149        cout << "*** Enter a number between 0 and 5 (inclusive) to act as\n";
150        cout << "    a unique node number that transmits to the RX node.\n";
151        cout << "*** PRESS 'R' to begin receiving from the other nodes\n";
152        cout << "*** PRESS 'Q' to exit" << endl;
153        getline(cin, input);
154        if (input.length() >= 1) {
155            unsigned int toNumber = (unsigned int)(input[0]) - 48;
156            if (toNumber < 6 && toNumber >= 0)
157                master(toNumber);
158            else if (input[0] == 'R' || input[0] == 'r')
159                slave();
160            else if (input[0] == 'Q' || input[0] == 'q')
161                break;
162            else
163                cout << input[0] << " is an invalid input. Please try again." << endl;
164        }
165        input = ""; // stay in the while loop
166    } // while
167} // setRole
168
169
170/**
171 * act as unique TX node identified by the `role` number
172 */
173void master(unsigned int role) {
174    // set the payload's nodeID & reset the payload's identifying number
175    payload.nodeID = role;
176    payload.payloadID = 0;
177
178    // Set the address on pipe 0 to the RX node.
179    radio.stopListening(); // put radio in TX mode
180    radio.openWritingPipe(address[role]);
181
182    // According to the datasheet, the auto-retry features's delay value should
183    // be "skewed" to allow the RX node to receive 1 transmission at a time.
184    // So, use varying delay between retry attempts and 15 (at most) retry attempts
185    radio.setAutoRetry(((role * 3) % 12) + 3, 15); // maximum value is 15 for both args
186
187    unsigned int failures = 0;
188    while (failures < 6) {
189        clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);       // start the timer
190        bool report = radio.send(&payload, sizeof(payload));  // transmit & save the report
191        uint32_t timerEllapsed = getMicros();                  // end the timer
192
193        if (report) {
194            // payload was delivered
195            cout << "Transmission of PayloadID ";
196            cout << payload.payloadID;                         // print payload number
197            cout << " as node " << payload.nodeID;             // print node number
198            cout << " successful! Time to transmit = ";
199            cout << timerEllapsed << " us" << endl;            // print the timer result
200        }
201        else {
202            // payload was not delivered
203            failures++;
204            cout << "Transmission failed or timed out" << endl;
205        }
206        payload.payloadID++;                                   // increment payload number
207
208        // to make this example readable in the terminal
209        delay(1000); // slow transmissions down by 0.5 second
210    } // while
211    cout << failures << " failures detected. Leaving TX role." << endl;
212} // master
213
214
215/**
216 * act as the RX node that receives from up to 6 other TX nodes
217 */
218void slave() {
219
220    // Set the addresses for all pipes to TX nodes
221    for (uint8_t i = 0; i < 6; ++i)
222      radio.openReadingPipe(i, address[i]);
223
224    radio.startListening(); // put radio in RX mode
225
226    time_t startTimer = time(nullptr);                    // start a timer
227    while (time(nullptr) - startTimer < 6) {              // use 6 second timeout
228        if (radio.available()) {                          // is there a payload?
229            unsigned int pipe = radio.pipe();             // get the pipe number that recieved it
230            unsigned int bytes = radio.any();             // get the size of the payload
231            radio.read(&payload, bytes);                  // fetch payload from FIFO
232            cout << "Received " << bytes;                 // print the size of the payload
233            cout << " bytes on pipe " << pipe;            // print the pipe number
234            cout << " from node " << payload.nodeID;      // print the payload's origin
235            cout << ". PayloadID: " << payload.payloadID; // print the payload's number
236            cout << endl;
237            startTimer = time(nullptr);                   // reset timer
238        }
239    }
240    cout << "Nothing received in 6 seconds. Leaving RX role." << endl;
241} // slave
242
243
244/**
245 * Calculate the ellapsed time in microseconds
246 */
247uint32_t getMicros() {
248    // this function assumes that the timer was started using
249    // `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);`
250
251    clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer);
252    uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec;
253    uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000;
254
255    return ((seconds) * 1000 + useconds) + 0.5;
256}
257
258
259/**
260 * print a manual page of instructions on how to use this example's CLI args
261 */
262void printHelp(string progName) {
263    cout << "usage: " << progName << " [-h] [-n {0,1,2,3,4,5,r,R}]\n\n"
264         << "A simple example of sending data from as many as 6 nRF24L01 transceivers to\n"
265         << "1 receiving transceiver. This technique is trademarked by\n"
266         << "Nordic Semiconductors as 'MultiCeiver'.\n"
267         << "\nThis example was written to be used on up to 6 devices acting as TX nodes with\n"
268         << "another device acting as a RX node (that's a total of 7 devices).\n"
269         << "\noptional arguments:\n  -h, --help\t\tshow this help message and exit\n"
270         << "  -n {0,1,2,3,4,5,r,R}, --node {0,1,2,3,4,5,r,R}"
271         << "\n\t\t\t0-5 specifies the identifying node ID number for the TX role."
272         << "\n\t\t\t'r' or 'R' specifies the RX role." << endl;
273}

streamingData.cpp

This is a simple example of using the RF24 class on a Raspberry Pi for streaming multiple payloads. This example was written to be used on 2 devices acting as “nodes”. Use ctrl+c to quit at any time, but remember state of the radio will persist until another example or application uses it.

/examples_linux/streamingData.cpp
 13#include <cmath>       // abs()
 14#include <ctime>       // time()
 15#include <cstring>     // strcmp()
 16#include <iostream>    // cin, cout, endl
 17#include <string>      // string, getline()
 18#include <time.h>      // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
 19#include <RF24Revamped/RF24Revamped.h> // RF24, RF24_PA_LOW, delay()
 20
 21using namespace std;
 22
 23/****************** Linux ***********************/
 24// Radio CE Pin, CSN Pin, SPI Speed
 25// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
 26// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
 27// ie: RF24Revamped radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
 28
 29// Generic:
 30RF24Revamped radio(22, 0);
 31/****************** Linux (BBB,x86,etc) ***********************/
 32// See http://2bndy5.github.io/RF24/pages.html for more information on usage
 33// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
 34// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
 35
 36// For this example, we'll be sending 32 payloads each containing
 37// 32 bytes of data that looks like ASCII art when printed to the serial
 38// monitor. The TX node and RX node needs only a single 32 byte buffer.
 39#define SIZE 32            // this is the maximum for this example. (minimum is 1)
 40char buffer[SIZE + 1];     // for the RX node
 41unsigned int counter = 0;  // for counting the number of received payloads
 42void makePayload(uint8_t); // prototype to construct a payload dynamically
 43void setRole();            // prototype to set the node's role
 44void master();             // prototype of the TX node's behavior
 45void slave();              // prototype of the RX node's behavior
 46void printHelp(string);    // prototype to function that explain CLI arg usage
 47
 48// custom defined timer for evaluating transmission time in microseconds
 49struct timespec startTimer, endTimer;
 50uint32_t getMicros(); // prototype to get ellapsed time in microseconds
 51
 52
 53int main(int argc, char** argv) {
 54
 55    // perform hardware check
 56    if (!radio.begin()) {
 57        cout << "radio hardware is not responding!!" << endl;
 58        return 0; // quit now
 59    }
 60
 61    // add a NULL terminating 0 for printing as a c-string
 62    buffer[SIZE] = 0;
 63
 64    // Let these addresses be used for the pair of nodes used in this example
 65    uint8_t address[2][6] = {"1Node", "2Node"};
 66    //             the TX address^ ,  ^the RX address
 67    // It is very helpful to think of an address as a path instead of as
 68    // an identifying device destination
 69
 70    // to use different addresses on a pair of radios, we need a variable to
 71    // uniquely identify which address this radio will use to transmit
 72    bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
 73
 74    bool foundArgNode = false;
 75    bool foundArgRole = false;
 76    bool role = false;
 77    if (argc > 1) {
 78        // CLI args are specified
 79        if ((argc - 1) % 2 != 0) {
 80            // some CLI arg doesn't have an option specified for it
 81            printHelp(string(argv[0])); // all args need an option in this example
 82            return 0;
 83        }
 84        else {
 85            // iterate through args starting after program name
 86            int a = 1;
 87            while (a < argc) {
 88                bool invalidOption = false;
 89                if (strcmp(argv[a], "-n") == 0 || strcmp(argv[a], "--node") == 0) {
 90                    // "-n" or "--node" has been specified
 91                    foundArgNode = true;
 92                    if (argv[a + 1][0] - 48 <= 1) {
 93                        radioNumber = (argv[a + 1][0] - 48) == 1;
 94                    }
 95                    else {
 96                        // option is invalid
 97                        invalidOption = true;
 98                    }
 99                }
100                else if (strcmp(argv[a], "-r") == 0 || strcmp(argv[a], "--role") == 0) {
101                    // "-r" or "--role" has been specified
102                    foundArgRole = true;
103                    if (argv[a + 1][0] - 48 <= 1) {
104                        role = (argv[a + 1][0] - 48) == 1;
105                    }
106                    else {
107                        // option is invalid
108                        invalidOption = true;
109                    }
110                }
111                if (invalidOption) {
112                    printHelp(string(argv[0]));
113                    return 0;
114                }
115                a += 2;
116            } // while
117            if (!foundArgNode && !foundArgRole) {
118                // no valid args were specified
119                printHelp(string(argv[0]));
120                return 0;
121            }
122        } // else
123    } // if
124
125    // print example's name
126    cout << argv[0] << endl;
127
128    if (!foundArgNode) {
129        // Set the radioNumber via the terminal on startup
130        cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' ";
131        string input;
132        getline(cin, input);
133        radioNumber = input.length() > 0 && (uint8_t)input[0] == 49;
134    }
135
136    // save on transmission time by setting the radio to only transmit the
137    // number of bytes we need to transmit a float
138    radio.setPayloadLength(SIZE);    // default value is the maximum 32 bytes
139
140    // Set the PA Level low to try preventing power supply related problems
141    // because these examples are likely run with nodes in close proximity to
142    // each other.
143    radio.setPaLevel(RF24_PA_LOW); // RF24_PA_MAX is default.
144
145    // set the TX address of the RX node into the TX pipe
146    radio.openWritingPipe(address[radioNumber]);     // always uses pipe 0
147
148    // set the RX address of the TX node into a RX pipe
149    radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
150
151    // For debugging info
152    // radio.printDetails();
153
154    // ready to execute program now
155    if (!foundArgRole) {           // if CLI arg "-r"/"--role" was not specified
156        setRole();                 // calls master() or slave() based on user input
157    }
158    else {                         // if CLI arg "-r"/"--role" was specified
159        role ? master() : slave(); // based on CLI arg option
160    }
161    return 0;
162}
163
164
165/**
166 * set this node's role from stdin stream.
167 * this only considers the first char as input.
168 */
169void setRole() {
170    string input = "";
171    while (!input.length()) {
172        cout << "*** PRESS 'T' to begin transmitting to the other node\n";
173        cout << "*** PRESS 'R' to begin receiving from the other node\n";
174        cout << "*** PRESS 'Q' to exit" << endl;
175        getline(cin, input);
176        if (input.length() >= 1) {
177            if (input[0] == 'T' || input[0] == 't')
178                master();
179            else if (input[0] == 'R' || input[0] == 'r')
180                slave();
181            else if (input[0] == 'Q' || input[0] == 'q')
182                break;
183            else
184                cout << input[0] << " is an invalid input. Please try again." << endl;
185        }
186        input = ""; // stay in the while loop
187    } // while
188} // setRole()
189
190
191/**
192 * make this node act as the transmitter
193 */
194void master() {
195    radio.stopListening();                           // put radio in TX mode
196    radio.flushTx();
197    unsigned int failures = 0;                       // keep track of failures
198    uint8_t i = 0;
199    makePayload(i);
200    clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer); // start the timer
201    while (i < SIZE && failures < 100) {
202        while (!radio.write(&buffer, SIZE, false, false) && i < SIZE) {
203            i++;
204            makePayload(i);
205        }
206        radio.ce(true);
207        if (!radio.isFifo(true, true)) {
208            if (radio.irqDf()) {
209                failures++;
210                radio.ce(false);
211                radio.clearStatusFlags();
212                radio.ce(true);
213            }
214            if (failures >= 100) {
215                // most likely no device is listening for the data stream
216                cout << "Too many failures detected. ";
217                cout << "Aborting at payload " << buffer[0];
218                break;
219            }
220        }
221    } // while
222    radio.ce(false);
223    uint32_t ellapsedTime = getMicros();             // end the timer
224    cout << "Time to transmit data = ";
225    cout << ellapsedTime;                            // print the timer result
226    cout << " us. " << failures;                     // print number of retries
227    cout << " failures detected. Leaving TX role." << endl;
228} // master
229
230
231/**
232 * make this node act as the receiver
233 */
234void slave() {
235
236    counter = 0;
237    radio.startListening();                   // put radio in RX mode
238    time_t startTimer = time(nullptr);        // start a timer
239    while (time(nullptr) - startTimer < 6) {  // use 6 second timeout
240        if (radio.available()) {              // is there a payload
241            radio.read(&buffer, SIZE);        // fetch payload from FIFO
242            cout << "Received: " << buffer;   // print the payload's value
243            cout << " - " << counter << endl; // print the counter
244            counter++;                        // increment counter
245            startTimer = time(nullptr);       // reset timer
246        }
247    }
248    radio.stopListening();                    // use TX mode for idle behavior
249
250    cout << "Nothing received in 6 seconds. Leaving RX role." << endl;
251}
252
253
254/**
255 * Make a single payload based on position in stream.
256 * This example employs this function to save on memory allocated.
257 */
258void makePayload(uint8_t i) {
259
260    // let the first character be an identifying alphanumeric prefix
261    // this lets us see which payload didn't get received
262    buffer[0] = i + (i < 26 ? 65 : 71);
263    for (uint8_t j = 0; j < SIZE - 1; ++j) {
264        char chr = j >= (SIZE - 1) / 2 + abs((SIZE - 1) / 2 - i);
265        chr |= j < (SIZE - 1) / 2 - abs((SIZE - 1) / 2 - i);
266        buffer[j + 1] = chr + 48;
267    }
268}
269
270
271/**
272 * Calculate the ellapsed time in microseconds
273 */
274uint32_t getMicros() {
275    // this function assumes that the timer was started using
276    // `clock_gettime(CLOCK_MONOTONIC_RAW, &startTimer);`
277
278    clock_gettime(CLOCK_MONOTONIC_RAW, &endTimer);
279    uint32_t seconds = endTimer.tv_sec - startTimer.tv_sec;
280    uint32_t useconds = (endTimer.tv_nsec - startTimer.tv_nsec) / 1000;
281
282    return ((seconds) * 1000 + useconds) + 0.5;
283}
284
285
286/**
287 * print a manual page of instructions on how to use this example's CLI args
288 */
289void printHelp(string progName) {
290    cout << "usage: " << progName << " [-h] [-n {0,1}] [-r {0,1}]\n\n"
291         << "A simple example of streaming data from 1 nRF24L01 transceiver to another.\n"
292         << "\nThis example was written to be used on 2 devices acting as 'nodes'.\n"
293         << "\noptional arguments:\n  -h, --help\t\tshow this help message and exit\n"
294         << "  -n {0,1}, --node {0,1}\n\t\t\tthe identifying radio number\n"
295         << "  -r {0,1}, --role {0,1}\n\t\t\t'1' specifies the TX role."
296         << " '0' specifies the RX role." << endl;
297}

interruptConfigure.cpp

This is a simple example of using the RF24 class on a Raspberry Pi to detecting (and verifying) the IRQ (interrupt) pin on the nRF24L01. This example was written to be used on 2 devices acting as “nodes”. Use ctrl+c to quit at any time, but remember state of the radio will persist until another example or application uses it.

/examples_linux/interruptConfigure.cpp
 16#include <ctime>       // time()
 17#include <iostream>    // cin, cout, endl
 18#include <string>      // string, getline()
 19#include <time.h>      // CLOCK_MONOTONIC_RAW, timespec, clock_gettime()
 20#include <RF24Revamped/RF24Revamped.h> // RF24, RF24_PA_LOW, delay(), pinMode(), INPUT, attachInterrupt(), INT_EDGE_FALLING
 21
 22using namespace std;
 23
 24// We will be using the nRF24L01's IRQ pin for this example
 25#define IRQ_PIN 12 // this needs to be a digital input capable pin
 26
 27// this example is a sequential program. so we need to wait for the event to be handled
 28volatile bool wait_for_event = false; // used to signify that the event is handled
 29
 30/****************** Linux ***********************/
 31// Radio CE Pin, CSN Pin, SPI Speed
 32// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
 33// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
 34// ie: RF24Revamped radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
 35
 36// Generic:
 37RF24Revamped radio(22, 0);
 38/****************** Linux (BBB,x86,etc) ***********************/
 39// See http://2bndy5.github.io/RF24/pages.html for more information on usage
 40// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
 41// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
 42
 43// For this example, we'll be using a payload containing
 44// a string that changes on every transmission. (successful or not)
 45// Make a couple arrays of payloads & an iterator to traverse them
 46const uint8_t tx_pl_size = 5;
 47const uint8_t ack_pl_size = 4;
 48uint8_t pl_iterator = 0;
 49// The " + 1" compensates for the c-string's NULL terminating 0
 50char tx_payloads[4][tx_pl_size + 1] = {"Ping ", "Pong ", "Radio", "1FAIL"};
 51char ack_payloads[3][ack_pl_size + 1] = {"Yak ", "Back", " ACK"};
 52
 53void interruptHandler();         // prototype to handle the interrupt request (IRQ) pin
 54void setRole();                  // prototype to set the node's role
 55void master();                   // prototype of the TX node's behavior
 56void slave();                    // prototype of the RX node's behavior
 57void ping_n_wait();              // prototype that sends a payload and waits for the IRQ pin to get triggered
 58void printRxFifo(const uint8_t); // prototype to print entire contents of RX FIFO with 1 buffer
 59
 60
 61int main(int argc, char** argv) {
 62
 63    // perform hardware check
 64    if (!radio.begin()) {
 65        cout << "radio hardware is not responding!!" << endl;
 66        return 0; // quit now
 67    }
 68
 69    // Let these addresses be used for the pair
 70    uint8_t address[2][6] = {"1Node", "2Node"};
 71    // It is very helpful to think of an address as a path instead of as
 72    // an identifying device destination
 73
 74    // to use different addresses on a pair of radios, we need a variable to
 75    // uniquely identify which address this radio will use to transmit
 76    bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit
 77
 78    // print example's name
 79    cout << argv[0] << endl;
 80
 81    // Set the radioNumber via the terminal on startup
 82    cout << "Which radio is this? Enter '0' or '1'. Defaults to '0' ";
 83    string input;
 84    getline(cin, input);
 85    radioNumber = input.length() > 0 && (uint8_t)input[0] == 49;
 86
 87    // to use ACK payloads, we need to enable dynamic payload lengths
 88    radio.setDynamicPayloads(true);    // ACK payloads are dynamically sized
 89
 90    // Acknowledgement packets have no payloads by default. We need to enable
 91    // this feature for all nodes (TX & RX) to use ACK payloads.
 92    radio.enableAckPayload();
 93
 94    // Set the PA Level low to try preventing power supply related problems
 95    // because these examples are likely run with nodes in close proximity to
 96    // each other.
 97    radio.setPaLevel(RF24_PA_LOW);  // RF24_PA_MAX is default.
 98
 99    // set the TX address of the RX node into the TX pipe
100    radio.openWritingPipe(address[radioNumber]);     // always uses pipe 0
101
102    // set the RX address of the TX node into a RX pipe
103    radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1
104
105    // For debugging info
106    // radio.printDetails();
107
108    // setup the digital input pin connected to the nRF24L01's IRQ pin
109    pinMode(IRQ_PIN, INPUT);
110
111    // register the interrupt request (IRQ) to call our
112    // Interrupt Service Routine (ISR) callback function interruptHandler()
113    attachInterrupt(IRQ_PIN, INT_EDGE_FALLING, &interruptHandler);
114    // IMPORTANT: do not call radio.available() before calling
115    // radio.clearStatusFlags() when the interruptHandler() is triggered by the
116    // IRQ pin FALLING event. According to the datasheet, the pipe information
117    // is unreliable during the IRQ pin FALLING transition.
118
119    // ready to execute program now
120    setRole(); // calls master() or slave() based on user input
121    return 0;
122} // main
123
124
125/**
126 * set this node's role from stdin stream.
127 * this only considers the first char as input.
128 */
129void setRole() {
130    string input = "";
131    while (!input.length()) {
132        cout << "*** PRESS 'T' to begin transmitting to the other node\n";
133        cout << "*** PRESS 'R' to begin receiving from the other node\n";
134        cout << "*** PRESS 'Q' to exit" << endl;
135        getline(cin, input);
136        if (input.length() >= 1) {
137            if (input[0] == 'T' || input[0] == 't')
138                master();
139            else if (input[0] == 'R' || input[0] == 'r')
140                slave();
141            else if (input[0] == 'Q' || input[0] == 'q')
142                break;
143            else
144                cout << input[0] << " is an invalid input. Please try again." << endl;
145        }
146        input = ""; // stay in the while loop
147    } // while
148} // setRole
149
150
151/**
152 * act as the transmitter to show 3 different IRQ events by sending 4 payloads:
153 * 1. Successfully receive ACK payload first
154 * 2. Successfully transmit on second
155 * 3. Send a third payload to fill RX node's RX FIFO (supposedly making RX node unresponsive)
156 * 4. intentionally fail transmit on the fourth
157 */
158void master() {
159    pl_iterator = 0; // reset the iterator for the following tests done in master()
160
161    // Test the "data ready" event with the IRQ pin
162    cout << "\nConfiguring IRQ pin to ignore the 'data sent' event\n";
163    radio.interruptConfig(true, false, true); // args = dataReady, dataSent, dataFail
164    cout << "   Pinging RX node for 'data ready' event...";
165    ping_n_wait();                     // transmit a payload and detect the IRQ pin
166    pl_iterator++;                     // increment iterator for next test
167
168
169    // Test the "data sent" event with the IRQ pin
170    cout << "\nConfiguring IRQ pin to ignore the 'data ready' event\n";
171    radio.interruptConfig(false, true, true); // args = dataReady, dataSent, dataFail
172    cout << "   Pinging RX node for 'data sent' event...";
173    radio.flushTx();                  // flush payloads from any failed prior test
174    ping_n_wait();                     // transmit a payload and detect the IRQ pin
175    pl_iterator++;                     // increment iterator for next test
176
177
178    // Use this iteration to fill the RX node's FIFO which sets us up for the next test.
179    // send() uses virtual interrupt flags that work despite the masking of the IRQ pin
180    radio.interruptConfig(false, false, false); // disable IRQ masking for this step
181
182    cout << "\nSending 1 payload to fill RX node's FIFO. IRQ pin is neglected.\n";
183    // send() will call flushTx() before calling write()
184    if (radio.send(&tx_payloads[pl_iterator], tx_pl_size))
185        cout << "RX node's FIFO is full; it is not listening any more" << endl;
186    else {
187        cout << "Transmission failed or timed out. Continuing anyway." << endl;
188        radio.flushTx();
189    }
190    pl_iterator++;                     // increment iterator for next test
191
192
193    // test the "data fail" event with the IRQ pin
194    cout << "\nConfiguring IRQ pin to reflect all events\n";
195    radio.interruptConfig(); // all args default to true
196    cout << "   Pinging inactive RX node for 'data fail' event...";
197    ping_n_wait();                     // transmit a payload and detect the IRQ pin
198
199    // CE pin is still HIGH which consumes more power. Example is now idling so...
200    radio.stopListening(); // ensure CE pin is LOW
201    // stopListening() also calls flushTx() when ACK payloads are enabled
202
203    if (radio.available()) {
204        printRxFifo(ack_pl_size); // doing this will flush the RX FIFO
205    }
206} // master
207
208
209/**
210 * act as the receiver
211 */
212void slave() {
213
214    // let IRQ pin only trigger on "data_ready" event in RX mode
215    radio.interruptConfig(true, false, false); // args = dataReady, dataSent, dataFail
216
217    // Fill the TX FIFO with 3 ACK payloads for the first 3 received
218    // transmissions on pipe 0.
219    radio.writeAck(1, &ack_payloads[0], ack_pl_size);
220    radio.writeAck(1, &ack_payloads[1], ack_pl_size);
221    radio.writeAck(1, &ack_payloads[2], ack_pl_size);
222
223    radio.startListening();            // put radio in RX mode
224    time_t startTimer = time(nullptr); // start a timer
225    while (time(nullptr) - startTimer < 6 && !radio.isFifo(false, true)) {
226        // use 6 second timeout & wait till RX FIFO is full
227    }
228    delay(100);                        // wait for ACK payload to finish transmitting
229    radio.stopListening();             // also discards unused ACK payloads
230
231    if (radio.available()) {
232        printRxFifo(tx_pl_size);
233    }
234    else {
235        cout << "Timeout was reached. Going back to setRole()" << endl;
236    }
237} // slave
238
239
240/**
241 * pings the receiver with a non-blocking startWrite(), then waits till
242 * the IRQ pin is triggered
243 */
244void ping_n_wait() {
245    // use the non-blocking call to write a payload and begin transmission
246    // the "false" argument means we are expecting an ACK packet response
247    radio.write(tx_payloads[pl_iterator], tx_pl_size, false);
248
249    wait_for_event = true;
250    while (wait_for_event) {
251        /*
252         * IRQ pin is LOW when activated. Otherwise it is always HIGH
253         * Wait in this empty loop until IRQ pin is activated.
254         *
255         * In this example, the "data fail" event is always configured to
256         * trigger the IRQ pin active. Because the auto-ACK feature is on by
257         * default, we don't need a timeout check to prevent an infinite loop.
258         */
259    }
260}
261
262
263/**
264 * when the IRQ pin goes active LOW, call this fuction print out why
265 */
266void interruptHandler() {
267    // print IRQ status and all masking flags' states
268
269    cout << "\tIRQ pin is actively LOW" << endl;  // show that this function was called
270
271    radio.clearStatusFlags();      // get values for IRQ masks
272    // clearStatusFlags() clears the IRQ masks also. This is required for
273    // continued TX operations when a transmission fails.
274    // clearing the IRQ masks resets the IRQ pin to its inactive state (HIGH)
275
276    cout << "\tdata_sent: " << radio.irqDs();             // print "data sent" mask state
277    cout << ", data_fail: " << radio.irqDf();             // print "data fail" mask state
278    cout << ", data_ready: " << radio.irqDr() << endl;    // print "data ready" mask state
279
280    if (radio.irqDf())                                    // if TX payload failed
281        radio.flushTx();                         // clear all payloads from the TX FIFO
282
283    // print if test passed or failed. Unintentional fails mean the RX node was not listening.
284    if (pl_iterator == 0)
285        cout << "   'Data Ready' event test " << (radio.irqDr() ? "passed" : "failed") << endl;
286    else if (pl_iterator == 1)
287        cout << "   'Data Sent' event test " << (radio.irqDs() ? "passed" : "failed") << endl;
288    else if (pl_iterator == 3)
289        cout << "   'Data Fail' event test " << (radio.irqDf() ? "passed" : "failed") << endl;
290
291    wait_for_event = false; // ready to continue
292} // interruptHandler
293
294
295/**
296 * Print the entire RX FIFO with one buffer. This will also flush the RX FIFO.
297 * @param pl_size used to determine received payload size. Remember that the
298 * payload sizes are declared as tx_pl_size and ack_pl_size.
299 */
300void printRxFifo(const uint8_t pl_size) {
301    char rx_fifo[pl_size * 3 + 1];         // assuming RX FIFO is full; declare a buffer to hold it all
302    if (radio.isFifo(false, true)) {
303        rx_fifo[pl_size * 3] = 0;          // add a NULL terminating char to use as a c-string
304        radio.read(&rx_fifo, pl_size * 3); // this clears the RX FIFO (for this example)
305    }
306    else {
307        uint8_t i = 0;
308        while (radio.available()) {
309            radio.read(&rx_fifo + (i * pl_size), pl_size);
310            i++;
311        }
312        rx_fifo[i * pl_size] = 0;          // add a NULL terminating char to use as a c-string
313    }
314
315    // print the entire RX FIFO with 1 buffer
316    cout << "Complete RX FIFO: " << rx_fifo << endl;
317}

scanner.cpp

This example is best used as a diagnostic tool to determine what RF channels have less interference in your vicinity. Use ctrl+c to quit at any time, but remember state of the radio will persist until another example or application uses it.

/examples_linux/scanner.cpp
 25#include <cstdlib>
 26#include <iostream>
 27#include <RF24Revamped/RF24Revamped.h>
 28
 29using namespace std;
 30
 31/****************** Linux ***********************/
 32// Radio CE Pin, CSN Pin, SPI Speed
 33// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering
 34// CS Pin addresses the SPI bus number at /dev/spidev<a>.<b>
 35// ie: RF24Revamped radio(<ce_pin>, <a>*10+<b>); spidev1.0 is 10, spidev1.1 is 11 etc..
 36
 37// Generic:
 38RF24Revamped radio(22, 0);
 39/****************** Linux (BBB,x86,etc) ***********************/
 40// See http://nRF24.github.io/RF24/pages.html for more information on usage
 41// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA
 42// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV
 43
 44// Channel info
 45const uint8_t num_channels = 126;
 46uint8_t values[num_channels];
 47
 48const int num_reps = 100;
 49int reset_array = 0;
 50
 51int main(int argc, char** argv)
 52{
 53    // Print preamble
 54
 55    // print example's name
 56    printf("%s", argv[0]);
 57
 58    //
 59    // Setup and configure rf radio
 60    //
 61    radio.begin();
 62
 63    radio.setAutoAck(false);
 64
 65    // Get into standby mode
 66    radio.startListening();
 67    radio.stopListening();
 68
 69    radio.printDetails();
 70
 71    // Print out header, high then low digit
 72    int i = 0;
 73
 74    while (i < num_channels) {
 75        printf("%x", i >> 4);
 76        ++i;
 77    }
 78    printf("\n");
 79
 80    i = 0;
 81    while (i < num_channels) {
 82        printf("%x", i & 0xf);
 83        ++i;
 84    }
 85    printf("\n");
 86
 87    // forever loop
 88    while (1) {
 89        // Clear measurement values
 90        memset(values, 0, sizeof(values));
 91
 92        // Scan all channels num_reps times
 93        int rep_counter = num_reps;
 94        while (rep_counter--) {
 95
 96            int i = num_channels;
 97            while (i--) {
 98
 99                // Select this channel
100                radio.setChannel(i);
101
102                // Listen for a little
103                radio.startListening();
104                delayMicroseconds(128);
105                radio.stopListening();
106
107                // Did we get a carrier?
108                if (radio.testRpd()) {
109                    ++values[i];
110                }
111            }
112        }
113
114        // Print out channel measurements, clamped to a single hex digit
115        i = 0;
116        while (i < num_channels) {
117            if (values[i])
118                printf("%x", min(0xf, (values[i] & 0xf)));
119            else
120                printf("-");
121
122            ++i;
123        }
124        printf("\n");
125    }
126
127    return 0;
128}
129
130// vim:ai:cin:sts=2 sw=2 ft=cpp