diff --git a/README.md b/README.md index cc7b97f..054d80d 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,23 @@ Design Goals: This library is designed to be... -* More compliant with the manufacturer specified operation of the chip +* More compliant with the manufacturer specified operation of the chip, while allowing advanced users +* to work outside the reccommended operation. +* Utilize the capabilities of the radio to their full potential via Arduino * More reliable and feature rich -* Easy for beginners to use +* Easy for beginners to use, with well documented examples and features * Consumed with a public interface that's similiar to other Arduino standard libraries * Built against the standard SPI library. -March 2014: Optimization begun -April 2014: Optimization nearing completion -* The library has been tweaked to allow full use of the FIFO buffers for maximum transfer speeds -* Changes to read() 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 -* Arduino Due fully supported with extended SPI functions -* More! See the links below and class documentation for more info. +April 2014: Official Release: Still some work to do, but most benefits have been realized + +* 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. +* More! See the links below and class documentation for more info. Please refer to: @@ -27,4 +30,11 @@ Please refer to: This chip uses the SPI bus, plus two chip control pins. Remember that pin 10 must still remain an output, or the SPI hardware will go into 'slave' mode. - + +Supported Boards: + +* Uno, Nano, etc (328 based boards) +* Mega Types (2560, 1280, etc) +* ARM (Arduino Due) via extended SPI methods +* ATTiny 24/44/84 25/45/85 +* See the [documentation](http://tmrh20.github.io/) for more info \ No newline at end of file diff --git a/RF24.cpp b/RF24.cpp index 4fe07bb..36d8b3f 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -135,7 +135,7 @@ uint8_t RF24::write_register(uint8_t reg, uint8_t value) /****************************************************************************/ -uint8_t RF24::write_payload(const void* buf, uint8_t data_len) +uint8_t RF24::write_payload(const void* buf, uint8_t data_len, const uint8_t writeType) { uint8_t status; const uint8_t* current = reinterpret_cast(buf); @@ -147,7 +147,7 @@ uint8_t RF24::write_payload(const void* buf, uint8_t data_len) #if defined (__arm__) - status = SPI.transfer(csn_pin, W_TX_PAYLOAD , SPI_CONTINUE); + status = SPI.transfer(csn_pin, writeType , SPI_CONTINUE); if(blank_len){ while ( data_len--){ @@ -160,14 +160,14 @@ uint8_t RF24::write_payload(const void* buf, uint8_t data_len) }else{ while( --data_len ){ SPI.transfer(csn_pin,*current++, SPI_CONTINUE); - } + } SPI.transfer(csn_pin,*current); } #else csn(LOW); - status = SPI.transfer( W_TX_PAYLOAD ); + status = SPI.transfer( writeType ); while ( data_len-- ) { SPI.transfer(*current++); } @@ -205,7 +205,7 @@ uint8_t RF24::read_payload(void* buf, uint8_t data_len) } while ( --blank_len ){ SPI.transfer(csn_pin,0xFF, SPI_CONTINUE); - } + } SPI.transfer(csn_pin,0xFF); }else{ while ( --data_len ){ @@ -346,7 +346,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(true), p_variant(false), + ce_pin(_cepin), csn_pin(_cspin), wide_band(false), p_variant(false), payload_size(32), ack_payload_available(false), dynamic_payloads_enabled(false), pipe0_reading_address(0) { @@ -466,8 +466,6 @@ void RF24::begin(void) csn(HIGH); #endif - - // Must allow the radio time to settle else configuration bits will not necessarily stick. // This is actually only required following power up but some settling time also appears to // be required after resets too. For full coverage, we'll always assume the worst. @@ -479,7 +477,7 @@ void RF24::begin(void) // Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier // WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet // sizes must never be used. See documentation for a more complete explanation. - write_register(SETUP_RETR,(B0100 << ARD) | (B1111 << ARC)); + setRetries(5,15); // Restore our default PA level setPALevel( RF24_PA_MAX ) ; @@ -516,9 +514,10 @@ void RF24::begin(void) flush_rx(); flush_tx(); - powerUp(); - delay(5); - //Enable PTX, do not write CE high so radio will remain in standby I mode ( 130us max to transition to RX or TX instead of 1500us from powerUp ) + powerUp(); //Power up by default when begin() is called + + // Enable PTX, do not write CE high so radio will remain in standby I mode ( 130us max to transition to RX or TX instead of 1500us from powerUp ) + // PTX should use only 22uA of power write_register(CONFIG, ( read_register(CONFIG) ) & ~_BV(PRIM_RX) ); @@ -528,7 +527,8 @@ void RF24::begin(void) void RF24::startListening(void) { - write_register(CONFIG, read_register(CONFIG) | _BV(PWR_UP) | _BV(PRIM_RX)); + powerUp(); + write_register(CONFIG, read_register(CONFIG) | _BV(PRIM_RX)); write_register(STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); // Restore the pipe0 adddress, if exists @@ -559,6 +559,7 @@ void RF24::stopListening(void) void RF24::powerDown(void) { + ce(LOW); // Guarantee CE is low on powerDown write_register(CONFIG,read_register(CONFIG) & ~_BV(PWR_UP)); } @@ -567,17 +568,23 @@ void RF24::powerDown(void) //Power up now. Radio will not power down unless instructed by MCU for config changes etc. void RF24::powerUp(void) { - write_register(CONFIG,read_register(CONFIG) | _BV(PWR_UP)); - delay(5); + uint8_t cfg = read_register(CONFIG); + + // if not powered up then power up and wait for the radio to initialize + if (!(cfg & _BV(PWR_UP))){ + write_register(CONFIG,read_register(CONFIG) | _BV(PWR_UP)); + delayMicroseconds(1500); + + } } /******************************************************************/ //Similar to the previous write, clears the interrupt flags -bool RF24::write( const void* buf, uint8_t len ) +bool RF24::write( const void* buf, uint8_t len, const bool multicast ) { //Start Writing - startWrite(buf,len); + startWrite(buf,len,multicast); //Wait until complete or failed //ACK payloads that are handled improperly will cause this to hang @@ -595,6 +602,9 @@ bool RF24::write( const void* buf, uint8_t len ) return 1; } +bool RF24::write( const void* buf, uint8_t len ){ + write(buf,len,0); +} /****************************************************************************/ //For general use, the interrupt flags are not important to clear @@ -617,7 +627,7 @@ bool RF24::writeBlocking( const void* buf, uint8_t len, uint32_t timeout ) } //Start Writing - startFastWrite(buf,len); //Write the payload if a buffer is clear + startFastWrite(buf,len,0); //Write the payload if a buffer is clear return 1; //Return 1 to indicate successful transmission } @@ -638,7 +648,7 @@ void RF24::reUseTX(){ /****************************************************************************/ -bool RF24::writeFast( const void* buf, uint8_t len ) +bool RF24::writeFast( const void* buf, uint8_t len, const bool multicast ) { //Block until the FIFO is NOT full. //Keep track of the MAX retries and set auto-retry if seeing failures @@ -656,12 +666,14 @@ bool RF24::writeFast( const void* buf, uint8_t len ) } //Start Writing - startFastWrite(buf,len); + startFastWrite(buf,len,multicast); return 1; } - +bool RF24::writeFast( const void* buf, uint8_t len ){ + writeFast(buf,len,0); +} /****************************************************************************/ @@ -670,9 +682,10 @@ bool RF24::writeFast( const void* buf, uint8_t len ) //Otherwise we enter Standby-II mode, which is still faster than standby mode //Also, we remove the need to keep writing the config register over and over and delaying for 150 us each time if sending a stream of data -void RF24::startFastWrite( const void* buf, uint8_t len ){ //TMRh20 +void RF24::startFastWrite( const void* buf, uint8_t len, const bool multicast){ //TMRh20 - write_payload( buf,len); + //write_payload( buf,len); + write_payload( buf, len,multicast?static_cast(W_TX_PAYLOAD_NO_ACK):static_cast(W_TX_PAYLOAD) ) ; ce(HIGH); } @@ -680,11 +693,12 @@ void RF24::startFastWrite( const void* buf, uint8_t len ){ //TMRh20 //Added the original startWrite back in so users can still use interrupts, ack payloads, etc //Allows the library to pass all tests -void RF24::startWrite( const void* buf, uint8_t len ){ +void RF24::startWrite( const void* buf, uint8_t len, const bool multicast ){ // Send the payload - write_payload( buf, len ); + //write_payload( buf, len ); + write_payload( buf, len,multicast?static_cast(W_TX_PAYLOAD_NO_ACK):static_cast(W_TX_PAYLOAD) ) ; ce(HIGH); ce(LOW); @@ -933,6 +947,27 @@ void RF24::enableAckPayload(void) /****************************************************************************/ +void RF24::enableDynamicAck(void){ + // + // enable dynamic ack features + // + + write_register(FEATURE,read_register(FEATURE) | _BV(EN_DYN_ACK) ); + + // If it didn't work, the features are not enabled + if ( ! read_register(FEATURE) & _BV(EN_DYN_ACK) ){ + // So enable them and try again + toggle_features(); + write_register(FEATURE,read_register(FEATURE) | _BV(EN_DYN_ACK) ); + } + + IF_SERIAL_DEBUG(printf("FEATURE=%i\r\n",read_register(FEATURE))); + + +} + +/****************************************************************************/ + void RF24::writeAckPayload(uint8_t pipe, const void* buf, uint8_t len) { const uint8_t* current = reinterpret_cast(buf); diff --git a/RF24.h b/RF24.h index e92d7c4..e2e0b77 100644 --- a/RF24.h +++ b/RF24.h @@ -256,6 +256,22 @@ public: */ void powerUp(void) ; + /** + * Write for single NOACK writes. Disables acknowledgements/autoretries for a single write. + * + * @note enableDynamicAck() must be called to enable this feature + * + * Can be used with enableAckPayload() to request a response + * @see enableDynamicAck() + * @see setAutoAck() + * @see write() + * + * @param buf Pointer to the data to be sent + * @param len Number of bytes to be sent + * @param multicast Request ACK (0), NOACK (1) + */ + bool write( const void* buf, uint8_t len, const bool multicast ); + /** * @note Optimization: New Command * * This will not block until the 3 FIFO buffers are filled with data. @@ -289,6 +305,19 @@ public: */ bool writeFast( const void* buf, uint8_t len ); + /** + * WriteFast for single NOACK writes. Disables acknowledgements/autoretries for a single write. + * + * @note enableDynamicAck() must be called to enable this feature + * @see enableDynamicAck() + * @see setAutoAck() + * + * @param buf Pointer to the data to be sent + * @param len Number of bytes to be sent + * @param multicast Request ACK (0) or NOACK (1) + */ + bool writeFast( const void* buf, uint8_t len, const bool multicast ); + /** * @note Optimization: New Command * This function extends the auto-retry mechanism to any specified duration. @@ -383,6 +412,20 @@ public: */ 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(). @@ -424,11 +467,16 @@ public: * @see startWrite() * @see writeBlocking() * + * For single noAck writes see: + * @see enableDynamicAck() + * @see setAutoAck() + * * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent + * @param multicast Request ACK (0) or NOACK (1) * @return True if the payload was delivered successfully false if not */ - void startFastWrite( const void* buf, uint8_t len ); + void startFastWrite( const void* buf, uint8_t len, const bool multicast ); /** * Non-blocking write to the open writing pipe @@ -445,11 +493,16 @@ public: * @see startFastWrite() * @see whatHappened() * + * For single noAck writes see: + * @see enableDynamicAck() + * @see setAutoAck() + * * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent + * @param multicast Request ACK (0) or NOACK (1) * */ - void startWrite( const void* buf, uint8_t len ); + void startWrite( const void* buf, uint8_t len, const bool multicast ); /** * Optimization: New Command @@ -776,7 +829,7 @@ private: * @param len Number of bytes to be sent * @return Current value of status register */ - uint8_t write_payload(const void* buf, uint8_t len); + uint8_t write_payload(const void* buf, uint8_t len, const uint8_t writeType); /** * Read the receive payload @@ -1003,18 +1056,18 @@ private: * @section Goals Design Goals * * This library fork is designed to be... - * @li More compliant with the manufacturer specified operation of the chip + * @li More compliant with the manufacturer specified operation of the chip, while allowing advanced users + * to work outside the reccommended 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 + * @li Easy for beginners to use, with well documented examples and features * @li Consumed with a public interface that's similiar to other Arduino standard libraries * * @section News News * - * March 2014: Optimization begun
- * April 2014: Optimization nearing completion

+ * April 2014: Official Release: Still some work to do, but most benefits have been realized
* - The library has been tweaked to allow full use of the FIFO buffers for maximum transfer speeds - * - Changes to read() functionality have increased reliability and response + * - 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 diff --git a/nRF24L01.h b/nRF24L01.h index 2012ce6..132de94 100644 --- a/nRF24L01.h +++ b/nRF24L01.h @@ -1,24 +1,25 @@ /* Copyright (c) 2007 Stefan Engelke + Portions Copyright (C) 2011 Greg Copeland - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ @@ -117,6 +118,7 @@ /* P model memory Map */ #define RPD 0x09 +#define W_TX_PAYLOAD_NO_ACK 0xB0 /* P model bit Mnemonics */ #define RF_DR_LOW 5