| 1 | /* |
| 2 | TMRh20 2014 |
| 3 | |
| 4 | This program is free software; you can redistribute it and/or |
| 5 | modify it under the terms of the GNU General Public License |
| 6 | version 2 as published by the Free Software Foundation. |
| 7 | */ |
| 8 | |
| 9 | /** |
| 10 | Reliably transmitting large volumes of data with a low signal or in noisy environments |
| 11 | This example demonstrates data transfer functionality with the use of auto-retry |
| 12 | and auto-reUse functionality enabled. This sketch demonstrates how a user can extend |
| 13 | the auto-retry functionality to any chosen time period, preventing data loss and ensuring |
| 14 | the consistency of data. |
| 15 | |
| 16 | This sketch demonstrates use of the writeBlocking() functionality, and extends the standard |
| 17 | retry functionality of the radio. Payloads will be auto-retried until successful or the |
| 18 | extended timeout period is reached. |
| 19 | */ |
| 20 | |
| 21 | |
| 22 | |
| 23 | #include <SPI.h> |
| 24 | #include "nRF24L01.h" |
| 25 | #include "RF24.h" |
| 26 | #include "printf.h" |
| 27 | |
| 28 | /************* USER Configuration *****************************/ |
| 29 | |
| 30 | RF24 radio(7, 8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8 |
| 31 | unsigned long timeoutPeriod = 3000; // Set a user-defined timeout period. With auto-retransmit set to (15,15) retransmission will take up to 60ms and as little as 7.5ms with it set to (1,15). |
| 32 | // With a timeout period of 1000, the radio will retry each payload for up to 1 second before giving up on the transmission and starting over |
| 33 | |
| 34 | /***************************************************************/ |
| 35 | |
| 36 | const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate. |
| 37 | |
| 38 | byte data[32]; //Data buffer |
| 39 | |
| 40 | volatile unsigned long counter; |
| 41 | unsigned long rxTimer, startTime, stopTime, payloads = 0; |
| 42 | bool tx = 1, rx = 0, role = 0, transferInProgress = 0; |
| 43 | |
| 44 | |
| 45 | void setup(void) { |
| 46 | |
| 47 | Serial.begin(115200); |
| 48 | printf_begin(); |
| 49 | |
| 50 | radio.begin(); // Setup and configure rf radio |
| 51 | radio.setChannel(1); // Set the channel |
| 52 | radio.setPALevel(RF24_PA_LOW); // Set PA LOW for this demonstration. We want the radio to be as lossy as possible for this example. |
| 53 | radio.setDataRate(RF24_1MBPS); // Raise the data rate to reduce transmission distance and increase lossiness |
| 54 | radio.setAutoAck(1); // Ensure autoACK is enabled |
| 55 | radio.setRetries(2, 15); // Optionally, increase the delay between retries. Want the number of auto-retries as high as possible (15) |
| 56 | radio.setCRCLength(RF24_CRC_16); // Set CRC length to 16-bit to ensure quality of data |
| 57 | radio.openWritingPipe(pipes[0]); // Open the default reading and writing pipe |
| 58 | radio.openReadingPipe(1, pipes[1]); |
| 59 | |
| 60 | radio.startListening(); // Start listening |
| 61 | radio.printDetails(); // Dump the configuration of the rf unit for debugging |
| 62 | |
| 63 | printf("\n\rRF24/examples/Transfer Rates/\n\r"); |
| 64 | printf("*** PRESS 'T' to begin transmitting to the other node\n\r"); |
| 65 | |
| 66 | randomSeed(analogRead(0)); //Seed for random number generation |
| 67 | for (int i = 0; i < 32; i++) { |
| 68 | data[i] = random(255); //Load the buffer with random data |
| 69 | } |
| 70 | radio.powerUp(); //Power up the radio |
| 71 | } |
| 72 | |
| 73 | |
| 74 | |
| 75 | void loop(void) { |
| 76 | |
| 77 | |
| 78 | if (role == tx) { |
| 79 | delay(2000); // Pause for a couple seconds between transfers |
| 80 | printf("Initiating Extended Timeout Data Transfer\n\r"); |
| 81 | |
| 82 | unsigned long cycles = 1000; // Change this to a higher or lower number. This is the number of payloads that will be sent. |
| 83 | |
| 84 | unsigned long transferCMD[] = { 'H', 'S', cycles }; // Indicate to the other radio that we are starting, and provide the number of payloads that will be sent |
| 85 | radio.writeFast(&transferCMD, 12); // Send the transfer command |
| 86 | if (radio.txStandBy(timeoutPeriod)) { // If transfer initiation was successful, do the following |
| 87 | |
| 88 | startTime = millis(); // For calculating transfer rate |
| 89 | boolean timedOut = 0; // Boolean for keeping track of failures |
| 90 | |
| 91 | for (unsigned long i = 0; i < cycles; i++) // Loop through a number of cycles |
| 92 | { |
| 93 | data[0] = i; // Change the first byte of the payload for identification |
| 94 | |
| 95 | if (!radio.writeBlocking(&data, 32, timeoutPeriod)) { // If retries are failing and the user defined timeout is exceeded |
| 96 | timedOut = 1; // Indicate failure |
| 97 | counter = cycles; // Set the fail count to maximum |
| 98 | break; // Break out of the for loop |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | |
| 103 | stopTime = millis(); // Capture the time of completion or failure |
| 104 | |
| 105 | //This should be called to wait for completion and put the radio in standby mode after transmission, returns 0 if data still in FIFO (timed out), 1 if success |
| 106 | if (timedOut) { |
| 107 | radio.txStandBy(); //Partially blocking standby, blocks until success or max retries. FIFO flushed if auto timeout reached |
| 108 | } else { |
| 109 | radio.txStandBy(timeoutPeriod); //Standby, block until FIFO empty (sent) or user specified timeout reached. FIFO flushed if user timeout reached. |
| 110 | } |
| 111 | |
| 112 | } else { |
| 113 | Serial.println("Communication not established"); //If unsuccessful initiating transfer, exit and retry later |
| 114 | } |
| 115 | |
| 116 | float rate = cycles * 32 / (stopTime - startTime); //Display results: |
| 117 | |
| 118 | Serial.print("Transfer complete at "); |
| 119 | Serial.print(rate); |
| 120 | Serial.println(" KB/s"); |
| 121 | Serial.print(counter); |
| 122 | Serial.print(" of "); |
| 123 | Serial.print(cycles); |
| 124 | Serial.println(" Packets Failed to Send"); |
| 125 | counter = 0; |
| 126 | } |
| 127 | |
| 128 | |
| 129 | |
| 130 | if (role == rx) { |
| 131 | |
| 132 | if (!transferInProgress) { // If a bulk data transfer has not been started |
| 133 | if (radio.available()) { |
| 134 | radio.read(&data, 32); //Read any available payloads for analysis |
| 135 | |
| 136 | if (data[0] == 'H' && data[4] == 'S') { // If a bulk data transfer command has been received |
| 137 | payloads = data[8]; // Read the first two bytes of the unsigned long. Need to read the 3rd and 4th if sending more than 65535 payloads |
| 138 | payloads |= data[9] << 8; // This is the number of payloads that will be sent |
| 139 | counter = 0; // Reset the payload counter to 0 |
| 140 | transferInProgress = 1; // Indicate it has started |
| 141 | startTime = rxTimer = millis(); // Capture the start time to measure transfer rate and calculate timeouts |
| 142 | } |
| 143 | } |
| 144 | } else { |
| 145 | if (radio.available()) { // If in bulk transfer mode, and a payload is available |
| 146 | radio.read(&data, 32); // Read the payload |
| 147 | rxTimer = millis(); // Reset the timeout timer |
| 148 | counter++; // Keep a count of received payloads |
| 149 | } else if (millis() - rxTimer > timeoutPeriod) { // If no data available, check the timeout period |
| 150 | Serial.println("Transfer Failed"); // If per-payload timeout exceeded, end the transfer |
| 151 | transferInProgress = 0; |
| 152 | } else if (counter >= payloads) { // If the specified number of payloads is reached, transfer is completed |
| 153 | startTime = millis() - startTime; // Calculate the total time spent during transfer |
| 154 | float numBytes = counter * 32; // Calculate the number of bytes transferred |
| 155 | Serial.print("Rate: "); // Print the transfer rate and number of payloads |
| 156 | Serial.print(numBytes / startTime); |
| 157 | Serial.println(" KB/s"); |
| 158 | Serial.print("Payload Count: "); |
| 159 | Serial.println(counter); |
| 160 | transferInProgress = 0; // End the transfer as complete |
| 161 | } |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | // |
| 166 | // Change roles |
| 167 | // |
| 168 | |
| 169 | if (Serial.available()) { |
| 170 | char c = toupper(Serial.read()); |
| 171 | if (c == 'T' && role == rx) { |
| 172 | printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r"); |
| 173 | radio.openWritingPipe(pipes[1]); |
| 174 | radio.openReadingPipe(1, pipes[0]); |
| 175 | radio.stopListening(); |
| 176 | role = tx; // Become the primary transmitter (ping out) |
| 177 | } else if (c == 'R' && role == tx) { |
| 178 | radio.openWritingPipe(pipes[0]); |
| 179 | radio.openReadingPipe(1, pipes[1]); |
| 180 | radio.startListening(); |
| 181 | printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r"); |
| 182 | role = rx; // Become the primary receiver (pong back) |
| 183 | } |
| 184 | } |
| 185 | } |