Extended timeouts, txStandBy changes
- For use in noisy or low signal scenarios - Allows user specified timeout period of extended duration - Modified txStandBy() and writeBlocking() functions to rely on a user defined timeout period, automatic retries and payload reUse
This commit is contained in:
@@ -471,25 +471,27 @@ bool RF24::write( const void* buf, uint8_t len )
|
||||
/****************************************************************************/
|
||||
|
||||
//For general use, the interrupt flags are not important to clear
|
||||
bool RF24::writeBlocking( const void* buf, uint8_t len )
|
||||
bool RF24::writeBlocking( const void* buf, uint8_t len, unsigned long timeout )
|
||||
{
|
||||
//Block until the FIFO is NOT full.
|
||||
//Keep track of the MAX retries and set auto-retry if seeing failures
|
||||
//This way the FIFO will fill up and allow blocking until packets go through
|
||||
//The radio will auto-clear everything in the FIFO as long as CE remains high
|
||||
|
||||
unsigned long timer = millis(); //Get the time that the payload transmission started
|
||||
|
||||
while ( (read_register(FIFO_STATUS) & _BV(FIFO_FULL))){ //Blocking only if FIFO is full. This will loop and block until TX is successful
|
||||
|
||||
if( get_status() & _BV(MAX_RT)){
|
||||
reUseTX(); //Set re-transmit
|
||||
if( get_status() & _BV(MAX_RT)){ //If MAX Retries have been reached
|
||||
reUseTX(); //Set re-transmit and clear the MAX_RT interrupt flag
|
||||
}
|
||||
|
||||
if(millis() - timer > timeout){ return 0; } //If this payload has exceeded the user-defined timeout, exit and return 0
|
||||
}
|
||||
//Start Writing
|
||||
startFastWrite(buf,len);
|
||||
|
||||
return 1;
|
||||
//Start Writing
|
||||
startFastWrite(buf,len); //Write the payload if a buffer is clear
|
||||
|
||||
return 1; //Return 1 to indicate successful transmission
|
||||
}
|
||||
|
||||
|
||||
@@ -504,7 +506,6 @@ void RF24::reUseTX(){
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
//This is for when every bit of data is important
|
||||
bool RF24::writeFast( const void* buf, uint8_t len )
|
||||
{
|
||||
//Block until the FIFO is NOT full.
|
||||
@@ -516,9 +517,7 @@ bool RF24::writeFast( const void* buf, uint8_t len )
|
||||
while ( (read_register(FIFO_STATUS) & _BV(FIFO_FULL))){ //Blocking only if FIFO is full. This will loop and block until TX is successful
|
||||
|
||||
if( get_status() & _BV(MAX_RT)){
|
||||
write_register(STATUS,_BV(MAX_RT) ); //Clear max retry flag
|
||||
reUseTX(); //Set re-transmit
|
||||
delayMicroseconds(15); //CE needs to stay high for 10us, for TX_REUSE to engage
|
||||
return 0; //Return 0. The previous payload has been retransmitted
|
||||
//From the user perspective, if you get a 0, just keep trying to send the same payload
|
||||
}
|
||||
@@ -565,23 +564,31 @@ void RF24::startWrite( const void* buf, uint8_t len )
|
||||
}
|
||||
|
||||
bool RF24::txStandBy(){
|
||||
txStandBy(0);
|
||||
while( ! (read_register(FIFO_STATUS) & _BV(TX_EMPTY)) ){
|
||||
if( get_status() & _BV(MAX_RT)){
|
||||
write_register(STATUS,_BV(MAX_RT) );
|
||||
flush_tx(); //Non blocking, flush the data
|
||||
ce(LOW); //Set STANDBY-I mode
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ce(LOW); //Set STANDBY-I mode
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool RF24::txStandBy(bool block){
|
||||
bool RF24::txStandBy(unsigned long timeout){
|
||||
|
||||
unsigned long start = millis();
|
||||
|
||||
while( ! (read_register(FIFO_STATUS) & _BV(TX_EMPTY)) ){
|
||||
if( get_status() & _BV(MAX_RT)){
|
||||
write_register(STATUS,_BV(MAX_RT) );
|
||||
if(block){
|
||||
if(timeout > 0){
|
||||
ce(LOW); //Set re-transmit
|
||||
ce(HIGH);
|
||||
delayMicroseconds(15);
|
||||
if(millis() - start > timeout){ ce(LOW); flush_tx(); return 0; }
|
||||
|
||||
}else{
|
||||
flush_tx(); //Non blocking, flush the data
|
||||
ce(LOW); //Set STANDBY-I mode
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,13 +152,6 @@ protected:
|
||||
*/
|
||||
uint8_t flush_rx(void);
|
||||
|
||||
/**
|
||||
* Empty the transmit buffer
|
||||
*
|
||||
* @return Current value of status register
|
||||
*/
|
||||
uint8_t flush_tx(void);
|
||||
|
||||
/**
|
||||
* Retrieve the current status of the chip
|
||||
*
|
||||
@@ -270,7 +263,7 @@ public:
|
||||
void stopListening(void);
|
||||
|
||||
/**
|
||||
* @note Optimization: Improved performance and reliability
|
||||
* @note Optimization: Improved performance slightly
|
||||
* Write to the open writing pipe
|
||||
*
|
||||
* Be sure to call openWritingPipe() first to set the destination
|
||||
@@ -293,56 +286,57 @@ public:
|
||||
bool write( const void* buf, uint8_t len );
|
||||
|
||||
/**
|
||||
* @note Optimization: New Command
|
||||
* Write to the open writing pipe filling up the FIFO buffers
|
||||
*
|
||||
* Be sure to call openWritingPipe() first to set the destination
|
||||
* of where to write to.
|
||||
*
|
||||
* @note Optimization: New Command *
|
||||
* This will not block until the 3 FIFO buffers are filled with data.
|
||||
* Once the FIFOs are full, writeFast will simply wait for success or
|
||||
* timeout, and return 1 or 0 respectively. From a user perspective, just
|
||||
* keep trying to send the same data. The library will keep auto retrying
|
||||
* the current payload using the built in functionality.
|
||||
*
|
||||
* The maximum size of data written is the fixed payload size, see
|
||||
* getPayloadSize(). However, you can write less, and the remainder
|
||||
* will just be filled with zeroes.
|
||||
*
|
||||
* ONLY max retry interrupt flags will be cleared when writeFast is called
|
||||
*
|
||||
* @code
|
||||
* Example (Partial blocking):
|
||||
*
|
||||
* radio.writeFast(&buf,32); // Writes 1 payload to the buffers
|
||||
* txStandBy(); // Returns 0 if failed. 1 if success. Blocks only until MAX_RT timeout or success. Data flushed on fail.
|
||||
* @endcode
|
||||
*
|
||||
* @see txStandBy()
|
||||
* @see write()
|
||||
* @see writeBlocking()
|
||||
*
|
||||
* @param buf Pointer to the data to be sent
|
||||
* @param len Number of bytes to be sent
|
||||
* @return True if the payload was delivered successfully false if not
|
||||
*/
|
||||
bool writeFast( const void* buf, uint8_t len );
|
||||
|
||||
/**
|
||||
* @note Optimization: New Command
|
||||
* Write to the open writing pipe
|
||||
*
|
||||
* Be sure to call openWritingPipe() first to set the destination
|
||||
* of where to write to.
|
||||
*
|
||||
* This will not block until the 3 FIFO buffers are filled with data or
|
||||
* a timeout is detected. If so the library will auto retry until a new
|
||||
* payload is written or the TX buffers are flushed. Interrupts can be
|
||||
* used to control the timeout period.
|
||||
*
|
||||
* This will never return a 0. It will not return until a packet is
|
||||
* loaded successfully into the FIFO and TX is complete.
|
||||
*
|
||||
* The maximum size of data written is the fixed payload size, see
|
||||
* getPayloadSize(). However, you can write less, and the remainder
|
||||
* will just be filled with zeroes.
|
||||
*
|
||||
* ONLY max retry interrupt flags will be cleared when writeBlocking is called
|
||||
*
|
||||
* @param buf Pointer to the data to be sent
|
||||
* @param len Number of bytes to be sent
|
||||
* @return True if the payload was delivered successfully false if not
|
||||
*/
|
||||
bool writeBlocking( const void* buf, uint8_t len );
|
||||
/**
|
||||
* @note Optimization: New Command
|
||||
* This function extends the auto-retry mechanism to any specified duration.
|
||||
* It will not block until the 3 FIFO buffers are filled with data.
|
||||
* If so the library will auto retry until a new payload is written
|
||||
* or the user specified timeout period is reached.
|
||||
*
|
||||
* ONLY max retry interrupt flags will be cleared when writeBlocking is called
|
||||
* @code
|
||||
* Example (Full blocking):
|
||||
*
|
||||
* radio.writeBlocking(&buf,32,1000); //Writes 1 payload to the buffers with extended timeout of 1 second
|
||||
* txStandBy(1000); //Returns 0 if failed after timeout period. 1 if success.
|
||||
* //Blocks only until user timeout or success. Data flushed on fail.
|
||||
* @endcode
|
||||
* @see txStandBy()
|
||||
* @see write()
|
||||
* @see writeFast()
|
||||
*
|
||||
* @param buf Pointer to the data to be sent
|
||||
* @param len Number of bytes to be sent
|
||||
* @param timeout User defined timeout in milliseconds.
|
||||
* @return True if the payload was delivered successfully false if not
|
||||
*/
|
||||
bool writeBlocking( const void* buf, uint8_t len, uint32_t timeout );
|
||||
|
||||
/**
|
||||
* @note Optimization: New Command
|
||||
@@ -355,29 +349,42 @@ public:
|
||||
* the manufacturer to drop the radio out of TX or STANDBY-II mode if there is
|
||||
* time enough between sends for the FIFOs to empty.
|
||||
*
|
||||
* @note This does NOT need to be called when using per-payload noACK commands,
|
||||
* or when using the regular write command since it is only capable of single
|
||||
* payload transmission..
|
||||
* Per the datasheet, the radio will automatically engage STANDBY-I mode when
|
||||
* using the W_TX_PAYLOAD_NOACK command.
|
||||
* Relies on built-in auto retry functionality.
|
||||
*
|
||||
* @code
|
||||
* Example:
|
||||
* Example (Partial blocking):
|
||||
*
|
||||
* radio.writeFast(&buf,32);
|
||||
* radio.writeFast(&buf,32);
|
||||
* radio.writeFast(&buf,32); //Fills the FIFO buffers up
|
||||
* bool ok = txStandBy(0); //Returns 0 if failed. 1 if success.
|
||||
* //Blocks only until timeout or success. Data flushed on fail.
|
||||
*
|
||||
* Using txStandBy(1) will not return until the data is transmitted. It will never return 0.
|
||||
*
|
||||
* bool ok = txStandBy(); //Returns 0 if failed. 1 if success.
|
||||
* //Blocks only until MAX_RT timeout or success. Data flushed on fail.
|
||||
* @endcode
|
||||
*
|
||||
* @see txStandBy(unsigned long timeout)
|
||||
* @return True if transmission is successful
|
||||
*
|
||||
*/
|
||||
bool txStandBy();
|
||||
bool txStandBy(bool block);
|
||||
bool txStandBy();
|
||||
|
||||
/**
|
||||
* @note Optimization: New Command
|
||||
*
|
||||
* This function allows extended blocking and auto-retries per a user defined timeout
|
||||
* @code
|
||||
* Fully Blocking Example:
|
||||
*
|
||||
* radio.writeFast(&buf,32);
|
||||
* radio.writeFast(&buf,32);
|
||||
* radio.writeFast(&buf,32); //Fills the FIFO buffers up
|
||||
* bool ok = txStandBy(1000); //Returns 0 if failed after 1 second of retries. 1 if success.
|
||||
* //Blocks only until user defined timeout or success. Data flushed on fail.
|
||||
* @endcode
|
||||
*
|
||||
* @param timeout Number of milliseconds to retry failed payloads
|
||||
* @return True if transmission is successful
|
||||
*
|
||||
*/
|
||||
bool txStandBy(unsigned long timeout);
|
||||
|
||||
/**
|
||||
* Non-blocking write to the open writing pipe used for buffered writes
|
||||
@@ -386,7 +393,9 @@ public:
|
||||
* will remain in TX or STANDBY-II Mode until a txStandBy() command is issued.
|
||||
* This allows the chip to be used to its full potential in TX mode.
|
||||
*
|
||||
* @see write()
|
||||
* @see writeFast()
|
||||
* @see startWrite()
|
||||
* @see writeBlocking()
|
||||
*
|
||||
* @param buf Pointer to the data to be sent
|
||||
@@ -401,9 +410,14 @@ public:
|
||||
* @note Optimization: The available functino now checks the FIFO
|
||||
* buffers directly for data instead of relying of interrupt flags.
|
||||
*
|
||||
* @note: Interrupt flags will not be cleared until a payload is
|
||||
* @note Interrupt flags will not be cleared until a payload is
|
||||
* actually read from the FIFO
|
||||
*
|
||||
* @see txStandBy()
|
||||
* @see startWrite()
|
||||
* @see write()
|
||||
* @see writeFast()
|
||||
*
|
||||
* @return True if there is a payload available, false if none is
|
||||
*/
|
||||
bool available(void);
|
||||
@@ -422,7 +436,7 @@ public:
|
||||
*
|
||||
* @param buf Pointer to a buffer where the data should be written
|
||||
* @param len Maximum number of bytes to read into the buffer
|
||||
* @return No return value. Use available.
|
||||
* @return No return value. Use available().
|
||||
*/
|
||||
void read( void* buf, uint8_t len );
|
||||
|
||||
@@ -526,7 +540,7 @@ public:
|
||||
* For dynamic payloads, this pulls the size of the payload off
|
||||
* the chip
|
||||
*
|
||||
* Optimization: Corrupt packets are now detected and flushed per the
|
||||
* @note Optimization: Corrupt packets are now detected and flushed per the
|
||||
* manufacturer.
|
||||
*
|
||||
* @return Payload length of last-received dynamic payload
|
||||
@@ -663,7 +677,7 @@ public:
|
||||
* To return to normal power mode, either write() some data or
|
||||
* startListening, or powerUp().
|
||||
*
|
||||
* Optimization: The radio will never enter power down unless instructed
|
||||
* @note Optimization: The radio will never enter power down unless instructed
|
||||
* by the MCU via this command.
|
||||
*/
|
||||
void powerDown(void);
|
||||
@@ -681,10 +695,12 @@ public:
|
||||
* Just like write(), but it returns immediately. To find out what happened
|
||||
* to the send, catch the IRQ and then call whatHappened().
|
||||
*
|
||||
* @note Optimization: This function again behaves as it did previously.
|
||||
* startFastWrite() has been moved to an internal function
|
||||
* @note Optimization: This function again behaves as it did previously for backwards-compatibility.
|
||||
* with user code. The library uses startFastWrite() internally.
|
||||
* This is mainly used for single-payload transactions.
|
||||
*
|
||||
* @see write()
|
||||
* @see writeFast()
|
||||
* @see startFastWrite()
|
||||
* @see whatHappened()
|
||||
*
|
||||
@@ -708,6 +724,8 @@ public:
|
||||
*
|
||||
* @note This is to be used AFTER auto-retry fails if wanting to resend
|
||||
* using the built-in payload reuse features.
|
||||
* After issuing reUseTX(), it will keep reending the same payload forever or until
|
||||
* a payload is written to the FIFO, or a flush_tx command is given.
|
||||
*/
|
||||
void reUseTX();
|
||||
|
||||
@@ -735,7 +753,7 @@ public:
|
||||
*
|
||||
* @note Optimization: Calling this function NO LONGER clears the interrupt
|
||||
* flag. The new functionality checks the RX FIFO buffer for an ACK payload
|
||||
* instead of relying on interrupt flags.
|
||||
* instead of relying on interrupt flags.Reading the payload will clear the flags.
|
||||
*
|
||||
* @return True if an ack payload is available.
|
||||
*/
|
||||
@@ -766,6 +784,13 @@ public:
|
||||
*/
|
||||
void whatHappened(bool& tx_ok,bool& tx_fail,bool& rx_ready);
|
||||
|
||||
/**
|
||||
* Empty the transmit buffer
|
||||
*
|
||||
* @return Current value of status register
|
||||
*/
|
||||
uint8_t flush_tx(void);
|
||||
|
||||
/**
|
||||
* Test whether there was a carrier on the line for the
|
||||
* previous listening period.
|
||||
@@ -797,6 +822,11 @@ public:
|
||||
*/
|
||||
bool isValid() { return ce_pin != 0xff && csn_pin != 0xff; }
|
||||
|
||||
/**
|
||||
* @see txStandBy()
|
||||
*/
|
||||
bool txStandBy(bool block);
|
||||
|
||||
/**@}*/
|
||||
};
|
||||
|
||||
@@ -824,6 +854,18 @@ public:
|
||||
* with the receiver displaying the payload count. (32Byte Payloads)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example TransferTimeouts.ino
|
||||
* Updated: TMRh20
|
||||
* This example demonstrates the use of and extended timeout period and
|
||||
* auto-retries/auto-reUse to increase reliability in noisy or low signal scenarios.
|
||||
*
|
||||
* Write this sketch to two different nodes. Put one of the nodes into 'transmit'
|
||||
* mode by connecting with the serial monitor and sending a 'T'. The data
|
||||
* transfer will begin, with the receiver displaying the payload count and the
|
||||
* data transfer rate.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example nordic_fob.pde
|
||||
*
|
||||
|
||||
@@ -89,8 +89,8 @@ void loop(void)
|
||||
|
||||
unsigned long time = millis(); // Take the time, and send it. This will block until complete
|
||||
printf("Now sending %lu...",time);
|
||||
bool ok = radio.writeFast( &time, sizeof(unsigned long) );//New function for proper use of FIFO buffers
|
||||
while( ! radio.txStandBy() ){} //Called when STANDBY-I mode is engaged (User is finished sending)
|
||||
radio.writeFast( &time, sizeof(unsigned long) ); //New function for proper use of FIFO buffers
|
||||
bool ok = radio.txStandBy(); //Called when STANDBY-I mode is engaged (User is finished sending)
|
||||
if (!ok)
|
||||
printf("failed.\n\r");
|
||||
|
||||
@@ -142,8 +142,8 @@ void loop(void)
|
||||
|
||||
radio.stopListening(); // First, stop listening so we can talk
|
||||
|
||||
radio.write( &got_time, sizeof(unsigned long) ); // Send the final one back.
|
||||
|
||||
radio.writeFast( &got_time, sizeof(unsigned long) ); // Send the final one back.
|
||||
radio.txStandBy();
|
||||
radio.startListening(); // Now, resume listening so we catch the next packets.
|
||||
|
||||
//printf("Sent response.\n\r");
|
||||
@@ -163,17 +163,16 @@ void loop(void)
|
||||
printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");
|
||||
|
||||
role = role_ping_out; // Become the primary transmitter (ping out)
|
||||
//radio.openWritingPipe(pipes[0]);
|
||||
//radio.openReadingPipe(1,pipes[1]);
|
||||
radio.openWritingPipe(pipes[0]);
|
||||
radio.openReadingPipe(1,pipes[1]);
|
||||
}
|
||||
else if ( c == 'R' && role == role_ping_out )
|
||||
{
|
||||
printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
|
||||
|
||||
role = role_pong_back; // Become the primary receiver (pong back)
|
||||
//radio.openWritingPipe(pipes[1]);
|
||||
//radio.openReadingPipe(1,pipes[0]);
|
||||
radio.openWritingPipe(pipes[1]);
|
||||
radio.openReadingPipe(1,pipes[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -1,227 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Example for Getting Started with nRF24L01+ radios.
|
||||
*
|
||||
* This is an example of how to use the RF24 class. Write this sketch to two
|
||||
* different nodes. Put one of the nodes into 'transmit' mode by connecting
|
||||
* with the serial monitor and sending a 'T'. The ping node sends the current
|
||||
* time to the pong node, which responds by sending the value back. The ping
|
||||
* node can then see how long the whole cycle took.
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include "nRF24L01.h"
|
||||
#include "RF24.h"
|
||||
#include "printf.h"
|
||||
|
||||
//
|
||||
// Hardware configuration
|
||||
//
|
||||
|
||||
// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
|
||||
|
||||
RF24 radio(9,10);
|
||||
|
||||
//
|
||||
// Topology
|
||||
//
|
||||
|
||||
// Radio pipe addresses for the 2 nodes to communicate.
|
||||
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
|
||||
|
||||
//
|
||||
// Role management
|
||||
//
|
||||
// Set up role. This sketch uses the same software for all the nodes
|
||||
// in this system. Doing so greatly simplifies testing.
|
||||
//
|
||||
|
||||
// The various roles supported by this sketch
|
||||
typedef enum { role_ping_out = 1, role_pong_back } role_e;
|
||||
|
||||
// The debug-friendly names of those roles
|
||||
const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};
|
||||
|
||||
// The role of the current running sketch
|
||||
role_e role = role_pong_back;
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
//
|
||||
// Print preamble
|
||||
//
|
||||
|
||||
Serial.begin(57600);
|
||||
printf_begin();
|
||||
printf("\n\rRF24/examples/GettingStarted/\n\r");
|
||||
printf("ROLE: %s\n\r",role_friendly_name[role]);
|
||||
printf("*** PRESS 'T' to begin transmitting to the other node\n\r");
|
||||
|
||||
//
|
||||
// Setup and configure rf radio
|
||||
//
|
||||
|
||||
radio.begin();
|
||||
|
||||
// optionally, increase the delay between retries & # of retries
|
||||
radio.setRetries(15,15);
|
||||
|
||||
// optionally, reduce the payload size. seems to
|
||||
// improve reliability
|
||||
//radio.setPayloadSize(8);
|
||||
|
||||
//
|
||||
// Open pipes to other nodes for communication
|
||||
//
|
||||
|
||||
// This simple sketch opens two pipes for these two nodes to communicate
|
||||
// back and forth.
|
||||
// Open 'our' pipe for writing
|
||||
// Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)
|
||||
|
||||
//if ( role == role_ping_out )
|
||||
{
|
||||
//radio.openWritingPipe(pipes[0]);
|
||||
radio.openReadingPipe(1,pipes[1]);
|
||||
}
|
||||
//else
|
||||
{
|
||||
//radio.openWritingPipe(pipes[1]);
|
||||
//radio.openReadingPipe(1,pipes[0]);
|
||||
}
|
||||
|
||||
//
|
||||
// Start listening
|
||||
//
|
||||
|
||||
radio.startListening();
|
||||
|
||||
//
|
||||
// Dump the configuration of the rf unit for debugging
|
||||
//
|
||||
|
||||
radio.printDetails();
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
//
|
||||
// Ping out role. Repeatedly send the current time
|
||||
//
|
||||
|
||||
if (role == role_ping_out)
|
||||
{
|
||||
// First, stop listening so we can talk.
|
||||
radio.stopListening();
|
||||
|
||||
// Take the time, and send it. This will block until complete
|
||||
unsigned long time = millis();
|
||||
printf("Now sending %lu...",time);
|
||||
bool ok = radio.write( &time, sizeof(unsigned long) );
|
||||
|
||||
if (ok)
|
||||
printf("ok...");
|
||||
else
|
||||
printf("failed.\n\r");
|
||||
|
||||
// Now, continue listening
|
||||
radio.startListening();
|
||||
|
||||
// Wait here until we get a response, or timeout (250ms)
|
||||
unsigned long started_waiting_at = millis();
|
||||
bool timeout = false;
|
||||
while ( ! radio.available() && ! timeout )
|
||||
if (millis() - started_waiting_at > 200 )
|
||||
timeout = true;
|
||||
|
||||
// Describe the results
|
||||
if ( timeout )
|
||||
{
|
||||
printf("Failed, response timed out.\n\r");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Grab the response, compare, and send to debugging spew
|
||||
unsigned long got_time;
|
||||
radio.read( &got_time, sizeof(unsigned long) );
|
||||
|
||||
// Spew it
|
||||
printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time);
|
||||
}
|
||||
|
||||
// Try again 1s later
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
//
|
||||
// Pong back role. Receive each packet, dump it out, and send it back
|
||||
//
|
||||
|
||||
if ( role == role_pong_back )
|
||||
{
|
||||
// if there is data ready
|
||||
if ( radio.available() )
|
||||
{
|
||||
// Dump the payloads until we've gotten everything
|
||||
unsigned long got_time;
|
||||
bool done = false;
|
||||
while (!done)
|
||||
{
|
||||
// Fetch the payload, and see if this was the last one.
|
||||
done = radio.read( &got_time, sizeof(unsigned long) );
|
||||
|
||||
// Spew it
|
||||
printf("Got payload %lu...",got_time);
|
||||
|
||||
// Delay just a little bit to let the other unit
|
||||
// make the transition to receiver
|
||||
delay(20);
|
||||
}
|
||||
|
||||
// First, stop listening so we can talk
|
||||
radio.stopListening();
|
||||
|
||||
// Send the final one back.
|
||||
radio.write( &got_time, sizeof(unsigned long) );
|
||||
printf("Sent response.\n\r");
|
||||
|
||||
// Now, resume listening so we catch the next packets.
|
||||
radio.startListening();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Change roles
|
||||
//
|
||||
|
||||
if ( Serial.available() )
|
||||
{
|
||||
char c = toupper(Serial.read());
|
||||
if ( c == 'T' && role == role_pong_back )
|
||||
{
|
||||
printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");
|
||||
|
||||
// Become the primary transmitter (ping out)
|
||||
role = role_ping_out;
|
||||
radio.openWritingPipe(pipes[0]);
|
||||
radio.openReadingPipe(1,pipes[1]);
|
||||
}
|
||||
else if ( c == 'R' && role == role_ping_out )
|
||||
{
|
||||
printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
|
||||
|
||||
// Become the primary receiver (pong back)
|
||||
role = role_pong_back;
|
||||
radio.openWritingPipe(pipes[1]);
|
||||
radio.openReadingPipe(1,pipes[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// vim:cin:ai:sts=2 sw=2 ft=cpp
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
TMRh20 2014
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/** Reliably transmitting large volumes of data with a low signal or in noisy environments
|
||||
* This example demonstrates data transfer functionality with the use of auto-retry
|
||||
and auto-reUse functionality enabled. This sketch demonstrates how a user can extend
|
||||
the auto-retry functionality to any chosen time period, preventing data loss and ensuring
|
||||
the consistency of data.
|
||||
|
||||
This sketh demonstrates use of the writeBlocking() functionality, and extends the standard
|
||||
retry functionality of the radio. Payloads will be auto-retried until successful or the
|
||||
extended timeout period is reached.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <SPI.h>
|
||||
#include "nRF24L01.h"
|
||||
#include "RF24.h"
|
||||
#include "printf.h"
|
||||
|
||||
/************* USER Configuration *****************************/
|
||||
|
||||
RF24 radio(48,49); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8
|
||||
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).
|
||||
// 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
|
||||
|
||||
/***************************************************************/
|
||||
|
||||
const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate.
|
||||
|
||||
byte data[32]; //Data buffer
|
||||
|
||||
volatile unsigned long counter;
|
||||
unsigned long rxTimer,startTime, stopTime, payloads = 0;
|
||||
bool TX=1,RX=0,role=0, transferInProgress = 0;
|
||||
|
||||
|
||||
void setup(void) {
|
||||
|
||||
Serial.begin(57600);
|
||||
printf_begin();
|
||||
|
||||
radio.begin(); // Setup and configure rf radio
|
||||
radio.setChannel(1); // Set the channel
|
||||
radio.setPALevel(RF24_PA_LOW); // Set PA LOW for this demonstration. We want the radio to be as lossy as possible for this example.
|
||||
radio.setDataRate(RF24_1MBPS); // Raise the data rate to reduce transmission distance and increase lossiness
|
||||
radio.setAutoAck(1); // Ensure autoACK is enabled
|
||||
radio.setRetries(2,15); // Optionally, increase the delay between retries. Want the number of auto-retries as high as possible (15)
|
||||
radio.setCRCLength(RF24_CRC_16); // Set CRC length to 16-bit to ensure quality of data
|
||||
radio.openWritingPipe(pipes[0]); // Open the default reading and writing pipe
|
||||
radio.openReadingPipe(1,pipes[1]);
|
||||
|
||||
radio.startListening(); // Start listening
|
||||
radio.printDetails(); // Dump the configuration of the rf unit for debugging
|
||||
|
||||
printf("\n\rRF24/examples/Transfer Rates/\n\r");
|
||||
printf("*** PRESS 'T' to begin transmitting to the other node\n\r");
|
||||
|
||||
randomSeed(analogRead(0)); //Seed for random number generation
|
||||
for(int i=0; i<32; i++){
|
||||
data[i] = random(255); //Load the buffer with random data
|
||||
}
|
||||
radio.powerUp(); //Power up the radio
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void loop(void){
|
||||
|
||||
|
||||
if(role == TX){
|
||||
delay(2000); // Pause for a couple seconds between transfers
|
||||
printf("Initiating Extended Timeout Data Transfer\n\r");
|
||||
|
||||
unsigned long cycles = 1000; // Change this to a higher or lower number. This is the number of payloads that will be sent.
|
||||
|
||||
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
|
||||
radio.writeFast(&transferCMD,12); // Send the transfer command
|
||||
if(radio.txStandBy(timeoutPeriod)){ // If transfer initiation was successful, do the following
|
||||
|
||||
startTime = millis(); // For calculating transfer rate
|
||||
boolean timedOut = 0; // Boolean for keeping track of failures
|
||||
|
||||
for(int i=0; i<cycles; i++){ // Loop through a number of cycles
|
||||
data[0] = i; // Change the first byte of the payload for identification
|
||||
|
||||
if(!radio.writeBlocking(&data,32,timeoutPeriod)){ // If retries are failing and the user defined timeout is exceeded
|
||||
timedOut = 1; // Indicate failure
|
||||
counter = cycles; // Set the fail count to maximum
|
||||
break; // Break out of the for loop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stopTime = millis(); // Capture the time of completion or failure
|
||||
|
||||
//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
|
||||
if(timedOut){ radio.txStandBy(); } //Partially blocking standby, blocks until success or max retries. FIFO flushed if auto timeout reached
|
||||
else{ radio.txStandBy(timeoutPeriod); } //Standby, block until FIFO empty (sent) or user specified timeout reached. FIFO flushed if user timeout reached.
|
||||
|
||||
}else{
|
||||
Serial.println("Communication not established"); //If unsuccessful initiating transfer, exit and retry later
|
||||
}
|
||||
|
||||
float rate = cycles * 32 / (stopTime - startTime); //Display results:
|
||||
|
||||
Serial.print("Transfer complete at "); Serial.print(rate); printf(" KB/s \n\r");
|
||||
Serial.print(counter);
|
||||
Serial.print(" of ");
|
||||
Serial.print(cycles); Serial.println(" Packets Failed to Send");
|
||||
counter = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(role == RX){
|
||||
|
||||
if(!transferInProgress){ // If a bulk data transfer has not been started
|
||||
if(radio.available()){
|
||||
radio.read(&data,32); //Read any available payloads for analysis
|
||||
|
||||
if(data[0] == 'H' && data[4] == 'S'){ // If a bulk data transfer command has been received
|
||||
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
|
||||
payloads |= data[9] << 8; // This is the number of payloads that will be sent
|
||||
counter = 0; // Reset the payload counter to 0
|
||||
transferInProgress = 1; // Indicate it has started
|
||||
startTime = rxTimer = millis(); // Capture the start time to measure transfer rate and calculate timeouts
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(radio.available()){ // If in bulk transfer mode, and a payload is available
|
||||
radio.read(&data,32); // Read the payload
|
||||
rxTimer = millis(); // Reset the timeout timer
|
||||
counter++; // Keep a count of received payloads
|
||||
}else
|
||||
if(millis() - rxTimer > timeoutPeriod){ // If no data available, check the timeout period
|
||||
Serial.println("Transfer Failed"); // If per-payload timeout exceeeded, end the transfer
|
||||
transferInProgress = 0;
|
||||
}else
|
||||
if(counter >= payloads){ // If the specified number of payloads is reached, transfer is completed
|
||||
startTime = millis() - startTime; // Calculate the total time spent during transfer
|
||||
float numBytes = counter*32; // Calculate the number of bytes transferred
|
||||
Serial.print("Rate: "); // Print the transfer rate and number of payloads
|
||||
Serial.print(numBytes/startTime);
|
||||
Serial.println(" KB/s");
|
||||
printf("Payload Count: %d \n\r", counter);
|
||||
transferInProgress = 0; // End the transfer as complete
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Change roles
|
||||
//
|
||||
|
||||
if ( Serial.available() )
|
||||
{
|
||||
char c = toupper(Serial.read());
|
||||
if ( c == 'T' && role == RX )
|
||||
{
|
||||
printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r");
|
||||
radio.openWritingPipe(pipes[1]);
|
||||
radio.openReadingPipe(1,pipes[0]);
|
||||
radio.stopListening();
|
||||
role = TX; // Become the primary transmitter (ping out)
|
||||
}
|
||||
else if ( c == 'R' && role == TX )
|
||||
{
|
||||
radio.openWritingPipe(pipes[0]);
|
||||
radio.openReadingPipe(1,pipes[1]);
|
||||
radio.startListening();
|
||||
printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r");
|
||||
role = RX; // Become the primary receiver (pong back)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file printf.h
|
||||
*
|
||||
* Setup necessary to direct stdout to the Arduino Serial library, which
|
||||
* enables 'printf'
|
||||
*/
|
||||
|
||||
#ifndef __PRINTF_H__
|
||||
#define __PRINTF_H__
|
||||
|
||||
#ifdef ARDUINO
|
||||
|
||||
int serial_putc( char c, FILE * )
|
||||
{
|
||||
Serial.write( c );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void printf_begin(void)
|
||||
{
|
||||
fdevopen( &serial_putc, 0 );
|
||||
}
|
||||
|
||||
#else
|
||||
#error This example is only for use on Arduino.
|
||||
#endif // ARDUINO
|
||||
|
||||
#endif // __PRINTF_H__
|
||||
Reference in New Issue
Block a user