diff --git a/RF24.cpp b/RF24.cpp index fc85f47b..aaade07f 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -329,7 +329,7 @@ void RF24::print_address_register(const char* name, uint8_t reg, uint8_t qty) /****************************************************************************/ RF24::RF24(uint8_t _cepin, uint8_t _cspin): - ce_pin(_cepin), csn_pin(_cspin), wide_band(false), p_variant(false), + ce_pin(_cepin), csn_pin(_cspin), p_variant(false), payload_size(32), dynamic_payloads_enabled(false), addr_width(5)//,pipe0_reading_address(0) { } @@ -338,9 +338,6 @@ RF24::RF24(uint8_t _cepin, uint8_t _cspin): void RF24::setChannel(uint8_t channel) { - // TODO: This method could take advantage of the 'wide_band' calculation - // done in setChannel() to require certain channel spacing. - const uint8_t max_channel = 127; write_register(RF_CH,min(channel,max_channel)); } @@ -568,6 +565,13 @@ void RF24::powerUp(void) } } +/******************************************************************/ +#if defined (FAILURE_HANDLING) +void RF24::errNotify(){ + IF_SERIAL_DEBUG(printf_P(PSTR("HARDWARE FAIL\r\n"))); + failureDetected = 1; +} +#endif /******************************************************************/ //Similar to the previous write, clears the interrupt flags @@ -577,9 +581,18 @@ bool RF24::write( const void* buf, uint8_t len, const bool multicast ) startFastWrite(buf,len,multicast); //Wait until complete or failed - //ACK payloads that are handled improperly will cause this to hang - //If autoAck is ON, a payload has to be written prior to reading a payload, else write after reading a payload - while( ! ( get_status() & ( _BV(TX_DS) | _BV(MAX_RT) ))) { } + #if defined (FAILURE_HANDLING) + uint32_t timer = millis(); + #endif + + while( ! ( get_status() & ( _BV(TX_DS) | _BV(MAX_RT) ))) { + #if defined (FAILURE_HANDLING) + if(millis() - timer > 75){ + errNotify(); + return 0; + } + #endif + } ce(LOW); @@ -615,6 +628,12 @@ bool RF24::writeBlocking( const void* buf, uint8_t len, uint32_t timeout ) 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 } + #if defined (FAILURE_HANDLING) + if(millis() - timer > (timeout+75) ){ + errNotify(); + return 0; + } + #endif } @@ -642,6 +661,10 @@ bool RF24::writeFast( const void* buf, uint8_t len, const bool multicast ) //Return 0 so the user can control the retrys and set a timer or failure counter if required //The radio will auto-clear everything in the FIFO as long as CE remains high + #if defined (FAILURE_HANDLING) + uint32_t timer = millis(); + #endif + while( ( get_status() & ( _BV(TX_FULL) ))) { //Blocking only if FIFO is full. This will loop and block until TX is successful or fail if( get_status() & _BV(MAX_RT)){ @@ -650,7 +673,12 @@ bool RF24::writeFast( const void* buf, uint8_t len, const bool multicast ) 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 } - + #if defined (FAILURE_HANDLING) + if(millis() - timer > 75 ){ + errNotify(); + return 0; + } + #endif } //Start Writing startFastWrite(buf,len,multicast); @@ -696,7 +724,9 @@ void RF24::startWrite( const void* buf, uint8_t len, const bool multicast ){ } bool RF24::txStandBy(){ - + #if defined (FAILURE_HANDLING) + uint32_t timeout = millis(); + #endif while( ! (read_register(FIFO_STATUS) & _BV(TX_EMPTY)) ){ if( get_status() & _BV(MAX_RT)){ write_register(STATUS,_BV(MAX_RT) ); @@ -704,6 +734,12 @@ bool RF24::txStandBy(){ flush_tx(); //Non blocking, flush the data return 0; } + #if defined (FAILURE_HANDLING) + if( millis() - timeout > 75){ + errNotify(); + return 0; + } + #endif } ce(LOW); //Set STANDBY-I mode @@ -723,7 +759,15 @@ bool RF24::txStandBy(uint32_t timeout){ ce(LOW); flush_tx(); return 0; } } + #if defined (FAILURE_HANDLING) + if( millis() - start > (timeout+75)){ + errNotify(); + return 0; + } + #endif } + + ce(LOW); //Set STANDBY-I mode return 1; @@ -1115,13 +1159,11 @@ bool RF24::setDataRate(rf24_datarate_e speed) uint8_t setup = read_register(RF_SETUP) ; // HIGH and LOW '00' is 1Mbs - our default - wide_band = false ; setup &= ~(_BV(RF_DR_LOW) | _BV(RF_DR_HIGH)) ; if( speed == RF24_250KBPS ) { // Must set the RF_DR_LOW to 1; RF_DR_HIGH (used to be RF_DR) is already 0 // Making it '10'. - wide_band = false ; setup |= _BV( RF_DR_LOW ) ; } else @@ -1130,14 +1172,8 @@ bool RF24::setDataRate(rf24_datarate_e speed) // Making it '01' if ( speed == RF24_2MBPS ) { - wide_band = true ; setup |= _BV(RF_DR_HIGH); } - else - { - // 1Mbs - wide_band = false ; - } } write_register(RF_SETUP,setup); @@ -1146,10 +1182,6 @@ bool RF24::setDataRate(rf24_datarate_e speed) { result = true; } - else - { - wide_band = false; - } return result; } diff --git a/RF24.h b/RF24.h index e1c576f4..9964d510 100644 --- a/RF24.h +++ b/RF24.h @@ -47,12 +47,13 @@ class RF24 private: uint8_t ce_pin; /**< "Chip Enable" pin, activates the RX or TX role */ uint8_t csn_pin; /**< SPI Chip select */ - bool wide_band; /* 2Mbs data rate in use? */ + bool p_variant; /* False for RF24L01 and true for RF24L01P */ uint8_t payload_size; /**< Fixed size of payloads */ bool dynamic_payloads_enabled; /**< Whether dynamic payloads are enabled. */ uint8_t pipe0_reading_address[5]; /**< Last address set on pipe 0 for reading. */ uint8_t addr_width; + public: @@ -770,7 +771,30 @@ class RF24 * */ void disableCRC( void ) ; - + + /** + * Enable error detection by un-commenting #define FAILURE_HANDLING in RF24_config.h + * If a failure has been detected, it usually indicates a hardware issue. By default the library + * will cease operation when a failure is detected. + * This should allow advanced users to detect and resolve intermittent hardware issues. + * + * In most cases, the radio must be re-enabled via radio.begin(); and the appropriate settings + * applied after a failure occurs, if wanting to re-enable the device immediately. + * + * Usage: (Failure handling must be enabled per above) + * @code + * if(radio.failureDetected){ + * radio.begin(); // Attempt to re-configure the radio with defaults + * radio.failureDetected = 0; // Reset the detection value + * radio.openWritingPipe(addresses[1]); // Re-configure pipe addresses + * radio.openReadingPipe(1,addresses[0]); + * report_failure(); // Blink leds, send a message, etc. to indicate failure + * } + * @endcode + */ + #if defined (FAILURE_HANDLING) + bool failureDetected; + #endif /**@}*/ /** * @name Deprecated @@ -974,6 +998,11 @@ class RF24 */ uint8_t spiTrans(uint8_t cmd); + + #if defined (FAILURE_HANDLING) + void errNotify(void); + #endif + /**@}*/ }; @@ -1124,7 +1153,7 @@ class RF24 * * This library fork is designed to be... * @li More compliant with the manufacturer specified operation of the chip, while allowing advanced users - * to work outside the reccommended operation. + * to work outside the recommended operation. * @li Utilize the capabilities of the radio to their full potential via Arduino * @li More reliable, responsive and feature rich * @li Easy for beginners to use, with well documented examples and features @@ -1132,17 +1161,17 @@ class RF24 * * @section News News * - * April 2014: Official Release: Still some work to do, but most benefits have been realized
+ * Main changes:
* - The library has been tweaked to allow full use of the FIFO buffers for maximum transfer speeds * - Changes to read() and available () functionality have increased reliability and response * - Extended timeout periods have been added to aid in noisy or otherwise unreliable environments * - Delays have been removed where possible to ensure maximum efficiency * - Full Due support with extended SPI functions - * - ATTiny 24/44/84 25/45/85 now supported. + * - ATTiny now supported. * - Raspberry Pi now supported * - More! See the links below and class documentation for more info. * - * If issues are discovered with the documentation, please report them here: here + * If issues are discovered with the documentation, please report them here * @section Useful Useful References * * Please refer to: @@ -1150,7 +1179,7 @@ class RF24 * @li Documentation Main Page * @li RF24 Class Documentation * @li Source Code - * @li Downloads Page + * @li Download * @li Chip Datasheet * @li Original Library * @@ -1162,13 +1191,13 @@ class RF24 * Most standard Arduino based boards are supported: * - ATMega 328 based boards (Uno, Nano, etc) * - Mega Boards (1280, 2560, etc) - * - ARM based boards (Arduino Due) Note: Do not include printf.h or use printf begin. This functionality is already present. Must use one of the - * hardware SS/CSN pins as extended SPI methods are used. + * - Arduino Due: Must use one of the hardware SS/CSN pins as extended SPI methods are used. * Initial Due support taken from https://github.com/mcrosson/RF24/tree/due * - ATTiny board support added from https://github.com/jscrane/RF24 * Note: ATTiny support is built into the library. Do not include SPI.h.
* ATTiny 85: D0(pin 5): MISO, D1(pin6) MOSI, D2(pin7) SCK, D3(pin2):CSN/SS, D4(pin3): CE
* ATTiny 84: PA6:MISO, PA5:MOSI, PA4:SCK, PA7:CSN/SS, CE as desired
+ * See https://github.com/TCWORLD/ATTinyCore/tree/master/PCREL%20Patch%20for%20GCC for ATTiny patch * - Raspberry Pi Support: See the readme at https://github.com/TMRh20/RF24/tree/master/RPi * * @section More More Information @@ -1177,7 +1206,7 @@ class RF24 * * @li Project blog: * @li TMRh20.blogspot.com - * @li RF24 Wireless Audio Library (Coming Soon) + * @li RF24 Wireless Audio Library * @li Optimized RF24 Network Layer * @li ManiacBug on GitHub (Original Library Author) */ diff --git a/RF24_config.h b/RF24_config.h index 583268a2..28d912cd 100644 --- a/RF24_config.h +++ b/RF24_config.h @@ -20,9 +20,12 @@ #include - //TMRh20: + /*** USER DEFINES: ***/ + //#define FAILURE_HANDLING + //#define SERIAL_DEBUG //#define MINIMAL - + /**********************/ + // Define _BV for non-Arduino platforms and for Arduino DUE #if defined (ARDUINO) && !defined (__arm__) #include @@ -47,8 +50,7 @@ #endif - - #undef SERIAL_DEBUG + #ifdef SERIAL_DEBUG #define IF_SERIAL_DEBUG(x) ({x;}) #else diff --git a/RPi/RF24/RF24.cpp b/RPi/RF24/RF24.cpp index bee0f85a..6d7709bc 100644 --- a/RPi/RF24/RF24.cpp +++ b/RPi/RF24/RF24.cpp @@ -265,18 +265,15 @@ void RF24::print_address_register(const char* name, uint8_t reg, uint8_t qty) /****************************************************************************/ RF24::RF24(uint8_t _cepin, uint8_t _cspin, uint32_t _spi_speed): - ce_pin(_cepin), csn_pin(_cspin), spi_speed(_spi_speed), wide_band(true), p_variant(false), + ce_pin(_cepin), csn_pin(_cspin), spi_speed(_spi_speed),p_variant(false), payload_size(32), dynamic_payloads_enabled(false),addr_width(5)//,pipe0_reading_address(0) -{ +{ } /****************************************************************************/ void RF24::setChannel(uint8_t channel) { - // TODO: This method could take advantage of the 'wide_band' calculation - // done in setChannel() to require certain channel spacing. - const uint8_t max_channel = 127; write_register(RF_CH,min(channel,max_channel)); } @@ -408,8 +405,10 @@ void RF24::printDetails(void) bool RF24::begin(void) { debug = false; - //debug = true; - // This initialize the SPI bus with + #if defined(DEBUG) + debug = true; + #endif + // This initialize the SPI bus with // csn pin as chip select (custom or not) @@ -488,7 +487,7 @@ bool RF24::begin(void) setChannel(76); // Flush buffers - flush_rx(); + //flush_rx(); flush_tx(); powerUp(); @@ -513,7 +512,7 @@ void RF24::startListening(void) write_register(RX_ADDR_P0, pipe0_reading_address,addr_width); } // Flush buffers - flush_rx(); + //flush_rx(); flush_tx(); // Go! @@ -559,6 +558,14 @@ void RF24::powerUp(void) /******************************************************************/ +#if defined (FAILURE_HANDLING) +void RF24::errNotify(){ + if(debug){ printf("HARDWARE FAIL\n\r"); } + failureDetect = true; +} +#endif +/******************************************************************/ + bool RF24::write( const void* buf, uint8_t len, const bool multicast ){ // Begin the write @@ -566,9 +573,18 @@ bool RF24::write( const void* buf, uint8_t len, const bool multicast ){ //Wait until complete or failed + #if defined (FAILURE_HANDLING) + uint32_t timer = millis(); + #endif // If this hangs, it ain't coming back, no sense in timing out - while( ! ( get_status() & ( _BV(TX_DS) | _BV(MAX_RT) ))) { } - + while( ! ( get_status() & ( _BV(TX_DS) | _BV(MAX_RT) ))) { + #if defined (FAILURE_HANDLING) + if(millis() - timer > 175){ + errNotify(); + return 0; + } + #endif + } bcm2835_gpio_write(ce_pin, LOW); uint8_t status = write_register(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); @@ -604,7 +620,12 @@ bool RF24::writeBlocking( const void* buf, uint8_t len, uint32_t timeout ) 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 } - + #if defined (FAILURE_HANDLING) + if(millis() - timer > (timeout+75) ){ + errNotify(); + return 0; + } + #endif } //Start Writing @@ -632,6 +653,10 @@ bool RF24::writeFast( const void* buf, uint8_t len, const bool multicast ) //Return 0 so the user can control the retrys and set a timer or failure counter if required //The radio will auto-clear everything in the FIFO as long as CE remains high + #if defined (FAILURE_HANDLING) + uint32_t timer = millis(); + #endif + while( ( get_status() & ( _BV(TX_FULL) ))) { //Blocking only if FIFO is full. This will loop and block until TX is successful or fail if( get_status() & _BV(MAX_RT)){ @@ -640,7 +665,12 @@ bool RF24::writeFast( const void* buf, uint8_t len, const bool multicast ) 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 } - + #if defined (FAILURE_HANDLING) + if(millis() - timer > 75 ){ + errNotify(); + return 0; + } + #endif } //Start Writing startFastWrite(buf,len,multicast); @@ -683,7 +713,9 @@ void RF24::startWrite( const void* buf, uint8_t len, const bool multicast ) /****************************************************************************/ bool RF24::txStandBy(){ - + #if defined (FAILURE_HANDLING) + uint32_t timer = millis(); + #endif while( ! (read_register(FIFO_STATUS) & _BV(TX_EMPTY)) ){ if( get_status() & _BV(MAX_RT)){ write_register(STATUS,_BV(MAX_RT) ); @@ -691,6 +723,12 @@ bool RF24::txStandBy(){ flush_tx(); //Non blocking, flush the data return 0; } + #if defined (FAILURE_HANDLING) + if( millis() - timer > 75){ + errNotify(); + return 0; + } + #endif } bcm2835_gpio_write(ce_pin, LOW); //Set STANDBY-I mode @@ -714,6 +752,12 @@ bool RF24::txStandBy(uint32_t timeout){ return 0; } } + #if defined (FAILURE_HANDLING) + if( millis() - start > (timeout+75)){ + errNotify(); + return 0; + } + #endif } bcm2835_gpio_write(ce_pin, LOW); //Set STANDBY-I mode return 1; @@ -1079,13 +1123,11 @@ bool RF24::setDataRate(rf24_datarate_e speed) uint8_t setup = read_register(RF_SETUP) ; // HIGH and LOW '00' is 1Mbs - our default - wide_band = false ; setup &= ~(_BV(RF_DR_LOW) | _BV(RF_DR_HIGH)) ; if( speed == RF24_250KBPS ) { // Must set the RF_DR_LOW to 1; RF_DR_HIGH (used to be RF_DR) is already 0 // Making it '10'. - wide_band = false ; setup |= _BV( RF_DR_LOW ) ; } else @@ -1094,14 +1136,8 @@ bool RF24::setDataRate(rf24_datarate_e speed) // Making it '01' if ( speed == RF24_2MBPS ) { - wide_band = true ; setup |= _BV(RF_DR_HIGH); } - else - { - // 1Mbs - wide_band = false ; - } } write_register(RF_SETUP,setup); @@ -1110,10 +1146,6 @@ bool RF24::setDataRate(rf24_datarate_e speed) { result = true; } - else - { - wide_band = false; - } return result; } diff --git a/RPi/RF24/RF24.h b/RPi/RF24/RF24.h index 5d8b20a6..b913d89f 100644 --- a/RPi/RF24/RF24.h +++ b/RPi/RF24/RF24.h @@ -51,6 +51,30 @@ typedef enum { RF24_CRC_DISABLED = 0, RF24_CRC_8, RF24_CRC_16 } rf24_crclength_e class RF24 { +public: + /** + * Enable error detection by un-commenting #define FAILURE_HANDLING in RF24_config.h + * If a failure has been detected, it usually indicates a hardware issue. By default the library + * will cease operation when a failure is detected. + * This should allow advanced users to detect and resolve intermittent hardware issues. + * + * In most cases, the radio must be re-enabled via radio.begin(); and the appropriate settings + * applied after a failure occurs, if wanting to re-enable the device immediately. + * + * Usage: (Failure handling must be enabled per above) + * @code + * if(radio.failureDetected){ + * radio.begin(); // Attempt to re-configure the radio with defaults + * radio.failureDetected = 0; // Reset the detection value + * radio.openWritingPipe(addresses[1]); // Re-configure pipe addresses + * radio.openReadingPipe(1,addresses[0]); + * report_failure(); // Blink leds, send a message, etc. to indicate failure + * } + * @endcode + **/ + #if defined (FAILURE_HANDLING) + bool failureDetect; + #endif private: uint8_t ce_pin; /**< "Chip Enable" pin, activates the RX or TX role */ uint8_t csn_pin; /**< SPI Chip select */ @@ -87,7 +111,7 @@ class RF24 * @return Current value of status register */ uint8_t read_register(uint8_t reg, uint8_t* buf, uint8_t len); - + /** * Read single byte from a register * @@ -95,7 +119,7 @@ class RF24 * @return Current value of register @p reg */ uint8_t read_register(uint8_t reg); - + /** * Write a chunk of data to a register * @@ -202,6 +226,11 @@ class RF24 * are enabled. See the datasheet for details. */ void toggle_features(void); + + #if defined (FAILURE_HANDLING) + void errNotify(void); + #endif + /**@}*/ public: @@ -424,6 +453,20 @@ class RF24 */ void enableDynamicPayloads(void); + /** + * Enable dynamic ACKs (single write multicasting) for chosen messages + * + * @note To enable full multicasting or per-pipe multicast, use setAutoAck() + * + * @warning This MUST be called prior to attempting single write NOACK calls + * @code + * radio.enableDynamicAck(); + * radio.write(&data,32,1); // Sends a payload with no acknowledgement requested + * radio.write(&data,32,0); // Sends a payload using auto-retry/autoACK + * @endcode + */ + void enableDynamicAck(void); + /** * Determine whether the hardware is an nRF24L01+ or not. * @@ -513,6 +556,8 @@ class RF24 */ void disableCRC( void ) ; + + /**@}*/ /** * @name Deprecated @@ -837,20 +882,6 @@ class RF24 */ void writeAckPayload(uint8_t pipe, const void* buf, uint8_t len); - /** - * Enable dynamic ACKs (single write multicasting) for chosen messages - * - * @note To enable full multicasting or per-pipe multicast, use setAutoAck() - * - * @warning This MUST be called prior to attempting single write NOACK calls - * @code - * radio.enableDynamicAck(); - * radio.write(&data,32,1); // Sends a payload with no acknowledgement requested - * radio.write(&data,32,0); // Sends a payload using auto-retry/autoACK - * @endcode - */ - void enableDynamicAck(); - /** * Determine if an ack payload was received in the most recent call to * write(). diff --git a/RPi/RF24/RF24_config.h b/RPi/RF24/RF24_config.h index eef07047..304e29d3 100644 --- a/RPi/RF24/RF24_config.h +++ b/RPi/RF24/RF24_config.h @@ -15,6 +15,11 @@ #ifndef __RF24_CONFIG_H__ #define __RF24_CONFIG_H__ + /*** USER DEFINES: ***/ + //#define FAILURE_HANDLING + //#define DEBUG + /**********************/ + #include #include #include