Skip to content

Commit

Permalink
Extended timeouts, txStandBy changes
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
TMRh20 committed Mar 29, 2014
1 parent 0ddec52 commit 6263bcc
Show file tree
Hide file tree
Showing 6 changed files with 363 additions and 316 deletions.
43 changes: 25 additions & 18 deletions RF24.cpp
Expand Up @@ -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
}


Expand All @@ -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.
Expand All @@ -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
}
Expand Down Expand Up @@ -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;
}
}
}
Expand Down
166 changes: 104 additions & 62 deletions RF24.h
Expand Up @@ -152,13 +152,6 @@ class RF24
*/
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
*
Expand Down Expand Up @@ -270,7 +263,7 @@ class RF24
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
Expand All @@ -293,56 +286,57 @@ class RF24
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
Expand All @@ -355,29 +349,42 @@ class RF24
* 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.
* 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
*
* Using txStandBy(1) will not return until the data is transmitted. It will never return 0.
*/
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();
bool txStandBy(bool block);
bool txStandBy(unsigned long timeout);

/**
* Non-blocking write to the open writing pipe used for buffered writes
Expand All @@ -386,7 +393,9 @@ class RF24
* 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
Expand All @@ -401,9 +410,14 @@ class RF24
* @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);
Expand All @@ -422,7 +436,7 @@ class RF24
*
* @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 );

Expand Down Expand Up @@ -526,7 +540,7 @@ class RF24
* 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
Expand Down Expand Up @@ -663,7 +677,7 @@ class RF24
* 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);
Expand All @@ -681,10 +695,12 @@ class RF24
* 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()
*
Expand All @@ -708,6 +724,8 @@ class RF24
*
* @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();

Expand Down Expand Up @@ -735,7 +753,7 @@ class RF24
*
* @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.
*/
Expand Down Expand Up @@ -766,6 +784,13 @@ class RF24
*/
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.
Expand Down Expand Up @@ -797,6 +822,11 @@ class RF24
*/
bool isValid() { return ce_pin != 0xff && csn_pin != 0xff; }

/**
* @see txStandBy()
*/
bool txStandBy(bool block);

/**@}*/
};

Expand Down Expand Up @@ -824,6 +854,18 @@ class RF24
* 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
*
Expand Down

0 comments on commit 6263bcc

Please sign in to comment.