diff --git a/RF24.cpp b/RF24.cpp index fef6a2745..e7acce84a 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -483,21 +483,17 @@ uint8_t RF24::flush_tx(void) return status; } -/****************************************************************************/ - -uint8_t RF24::get_status(void) -{ - read_register(RF24_NOP, (uint8_t*)nullptr, 0); - return status; -} - /****************************************************************************/ #if !defined(MINIMAL) -void RF24::print_status(uint8_t _status) +void RF24::printStatus(uint8_t flags) { - printf_P(PSTR("STATUS\t\t= 0x%02x RX_DR=%x TX_DS=%x MAX_RT=%x RX_P_NO=%x TX_FULL=%x\r\n"), _status, (_status & _BV(RX_DR)) ? 1 : 0, - (_status & _BV(TX_DS)) ? 1 : 0, (_status & _BV(MAX_RT)) ? 1 : 0, ((_status >> RX_P_NO) & 0x07), (_status & _BV(TX_FULL)) ? 1 : 0); + printf_P(PSTR("RX_DR=%x TX_DS=%x TX_DF=%x RX_PIPE=%x TX_FULL=%x\r\n"), + (flags & RF24_RX_DR) ? 1 : 0, + (flags & RF24_TX_DS) ? 1 : 0, + (flags & RF24_TX_DF) ? 1 : 0, + (flags >> RX_P_NO) & 0x07, + (flags & _BV(TX_FULL)) ? 1 : 0); } /****************************************************************************/ @@ -711,7 +707,9 @@ void RF24::printDetails(void) printf("================ NRF Configuration ================\n"); #endif // defined(RF24_LINUX) - print_status(get_status()); + uint8_t status = update(); + printf_P(PSTR("STATUS\t\t= 0x%02x "), status); + printStatus(status); print_address_register(PSTR("RX_ADDR_P0-1"), RX_ADDR_P0, 2); print_byte_register(PSTR("RX_ADDR_P2-5"), RX_ADDR_P2, 4); @@ -1107,7 +1105,7 @@ bool RF24::_init_radio() // Reset current status // Notice reset and flush is the last thing we do - write_register(NRF_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT)); + write_register(NRF_STATUS, RF24_IRQ_ALL); // Flush buffers flush_rx(); @@ -1152,7 +1150,7 @@ void RF24::startListening(void) #endif config_reg |= _BV(PRIM_RX); write_register(NRF_CONFIG, config_reg); - write_register(NRF_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT)); + write_register(NRF_STATUS, RF24_IRQ_ALL); ce(HIGH); // Restore the pipe0 address, if exists @@ -1248,7 +1246,7 @@ bool RF24::write(const void* buf, uint8_t len, const bool multicast) uint32_t timer = millis(); #endif // defined(FAILURE_HANDLING) || defined(RF24_LINUX) - while (!(get_status() & (_BV(TX_DS) | _BV(MAX_RT)))) { + while (!(update() & (RF24_TX_DS | RF24_TX_DF))) { #if defined(FAILURE_HANDLING) || defined(RF24_LINUX) if (millis() - timer > 95) { errNotify(); @@ -1263,10 +1261,10 @@ bool RF24::write(const void* buf, uint8_t len, const bool multicast) ce(LOW); - write_register(NRF_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT)); + write_register(NRF_STATUS, RF24_IRQ_ALL); //Max retries exceeded - if (status & _BV(MAX_RT)) { + if (status & RF24_TX_DF) { flush_tx(); // Only going to be 1 packet in the FIFO at a time using this method, so just flush return 0; } @@ -1291,10 +1289,10 @@ bool RF24::writeBlocking(const void* buf, uint8_t len, uint32_t timeout) uint32_t timer = millis(); // Get the time that the payload transmission started - while ((get_status() & (_BV(TX_FULL)))) { // Blocking only if FIFO is full. This will loop and block until TX is successful or timeout + while (update() & _BV(TX_FULL)) { // Blocking only if FIFO is full. This will loop and block until TX is successful or timeout - if (status & _BV(MAX_RT)) { // If MAX Retries have been reached - reUseTX(); // Set re-transmit and clear the MAX_RT interrupt flag + if (status & RF24_TX_DF) { // 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 } @@ -1320,7 +1318,7 @@ bool RF24::writeBlocking(const void* buf, uint8_t len, uint32_t timeout) void RF24::reUseTX() { ce(LOW); - write_register(NRF_STATUS, _BV(MAX_RT)); //Clear max retry flag + write_register(NRF_STATUS, RF24_TX_DF); //Clear max retry flag read_register(REUSE_TX_PL, (uint8_t*)nullptr, 0); IF_RF24_DEBUG(printf_P("[Reusing payload in TX FIFO]");); ce(HIGH); //Re-Transfer packet @@ -1340,8 +1338,8 @@ bool RF24::writeFast(const void* buf, uint8_t len, const bool multicast) #endif //Blocking only if FIFO is full. This will loop and block until TX is successful or fail - while ((get_status() & (_BV(TX_FULL)))) { - if (status & _BV(MAX_RT)) { + while (update() & _BV(TX_FULL)) { + if (status & RF24_TX_DF) { return 0; //Return 0. The previous payload has not been retransmitted // From the user perspective, if you get a 0, call txStandBy() } @@ -1433,8 +1431,8 @@ bool RF24::txStandBy() uint32_t timeout = millis(); #endif while (!(read_register(FIFO_STATUS) & _BV(TX_EMPTY))) { - if (status & _BV(MAX_RT)) { - write_register(NRF_STATUS, _BV(MAX_RT)); + if (status & RF24_TX_DF) { + write_register(NRF_STATUS, RF24_TX_DF); ce(LOW); flush_tx(); //Non blocking, flush the data return 0; @@ -1465,8 +1463,8 @@ bool RF24::txStandBy(uint32_t timeout, bool startTx) uint32_t start = millis(); while (!(read_register(FIFO_STATUS) & _BV(TX_EMPTY))) { - if (status & _BV(MAX_RT)) { - write_register(NRF_STATUS, _BV(MAX_RT)); + if (status & RF24_TX_DF) { + write_register(NRF_STATUS, RF24_TX_DF); ce(LOW); // Set re-transmit ce(HIGH); if (millis() - start >= timeout) { @@ -1526,7 +1524,7 @@ bool RF24::available(void) bool RF24::available(uint8_t* pipe_num) { if (available()) { // if RX FIFO is not empty - *pipe_num = (get_status() >> RX_P_NO) & 0x07; + *pipe_num = (update() >> RX_P_NO) & 0x07; return 1; } return 0; @@ -1541,7 +1539,7 @@ void RF24::read(void* buf, uint8_t len) read_payload(buf, len); //Clear the only applicable interrupt flags - write_register(NRF_STATUS, _BV(RX_DR)); + write_register(NRF_STATUS, RF24_RX_DR); } /****************************************************************************/ @@ -1550,12 +1548,44 @@ void RF24::whatHappened(bool& tx_ok, bool& tx_fail, bool& rx_ready) { // Read the status & reset the status in one easy call // Or is that such a good idea? - write_register(NRF_STATUS, _BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT)); + write_register(NRF_STATUS, RF24_IRQ_ALL); // Report to the user what happened - tx_ok = status & _BV(TX_DS); - tx_fail = status & _BV(MAX_RT); - rx_ready = status & _BV(RX_DR); + tx_ok = status & RF24_TX_DS; + tx_fail = status & RF24_TX_DF; + rx_ready = status & RF24_RX_DR; +} + +/****************************************************************************/ + +uint8_t RF24::clearStatusFlags(uint8_t flags) +{ + write_register(NRF_STATUS, flags & RF24_IRQ_ALL); + return status; +} + +/****************************************************************************/ + +void RF24::setStatusFlags(uint8_t flags) +{ + // flip the `flags` to translate from "human understanding" + config_reg = (config_reg & ~RF24_IRQ_ALL) | (~flags & RF24_IRQ_ALL); + write_register(NRF_CONFIG, config_reg); +} + +/****************************************************************************/ + +uint8_t RF24::getStatusFlags() +{ + return status; +} + +/****************************************************************************/ + +uint8_t RF24::update() +{ + read_register(RF24_NOP, (uint8_t*)nullptr, 0); + return status; } /****************************************************************************/ diff --git a/RF24.h b/RF24.h index fe72e441c..1b455470e 100644 --- a/RF24.h +++ b/RF24.h @@ -128,6 +128,30 @@ typedef enum RF24_FIFO_INVALID, } rf24_fifo_state_e; +/** + * @} + * @defgroup StatusFlags Status flags + * @{ + */ + +/** + * @brief An enumeration of constants used to configure @ref StatusFlags + */ +typedef enum +{ +#include "nRF24L01.h" + /// An alias of `0` to describe no IRQ events enabled. + RF24_IRQ_NONE = 0, + /// Represents an event where TX Data Failed to send. + RF24_TX_DF = 1 << MASK_MAX_RT, + /// Represents an event where TX Data Sent successfully. + RF24_TX_DS = 1 << TX_DS, + /// Represents an event where RX Data is Ready to `RF24::read()`. + RF24_RX_DR = 1 << RX_DR, + /// Equivalent to `RF24_RX_DR | RF24_TX_DS | RF24_TX_DF`. + RF24_IRQ_ALL = (1 << MASK_MAX_RT) | (1 << TX_DS) | (1 << RX_DR), +} rf24_irq_flags_e; + /** * @} * @brief Driver class for nRF24L01(+) 2.4GHz Wireless Transceiver @@ -378,13 +402,13 @@ class RF24 * that received the next available payload. According to the datasheet, * the data about the pipe number that received the next available payload * is "unreliable" during a FALLING transition on the IRQ pin. This means - * you should call whatHappened() before calling this function + * you should call clearStatusFlags() before calling this function * during an ISR (Interrupt Service Routine). For example: * @code * void isrCallbackFunction() { * bool tx_ds, tx_df, rx_dr; - * radio.whatHappened(tx_ds, tx_df, rx_dr); // resets the IRQ pin to HIGH - * radio.available(); // returned data should now be reliable + * uint8_t flags = radio.clearStatusFlags(); // resets the IRQ pin to HIGH + * radio.available(); // returned data should now be reliable * } * * void setup() { @@ -628,6 +652,16 @@ class RF24 */ void printDetails(void); + /** + * Decode and print the given STATUS byte to stdout. + * + * @param flags The STATUS byte to print. + * This value is fetched with update() or getStatusFlags(). + * + * @warning Does nothing if stdout is not defined. See fdevopen in stdio.h + */ + void printStatus(uint8_t flags); + /** * Print a giant block of debugging information to stdout. This function * differs from printDetails() because it makes the information more @@ -789,14 +823,13 @@ class RF24 * * @warning According to the datasheet, the data saved to `pipe_num` is * "unreliable" during a FALLING transition on the IRQ pin. This means you - * should call whatHappened() before calling this function during + * should call clearStatusFlags() before calling this function during * an ISR (Interrupt Service Routine). For example: * @code * void isrCallbackFunction() { - * bool tx_ds, tx_df, rx_dr; - * radio.whatHappened(tx_ds, tx_df, rx_dr); // resets the IRQ pin to HIGH - * uint8_t pipe; // initialize pipe data - * radio.available(&pipe); // pipe data should now be reliable + * radio.clearStatusFlags(); // resets the IRQ pin to inactive HIGH + * uint8_t pipe = 7; // initialize pipe data + * radio.available(&pipe); // pipe data should now be reliable * } * * void setup() { @@ -840,6 +873,8 @@ class RF24 /** * @deprecated Use RF24::isFifo(bool about_tx) instead. + * See our [migration guide](migration.md) to understand what you should update in your code. + * * @param about_tx `true` focuses on the TX FIFO, `false` focuses on the RX FIFO * @param check_empty * - `true` checks if the specified FIFO is empty @@ -1147,36 +1182,68 @@ class RF24 bool writeAckPayload(uint8_t pipe, const void* buf, uint8_t len); /** - * Call this when you get an Interrupt Request (IRQ) to find out why + * Clear the Status flags that caused an interrupt event. * - * This function describes what event triggered the IRQ pin to go active - * LOW and clears the status of all events. + * @remark This function is similar to `whatHappened()` because it also returns the + * Status flags that caused the interrupt event. However, this function returns + * a STATUS byte instead of bit-banging into 3 1-byte booleans + * passed by reference. * - * @see maskIRQ() + * @note When used in an ISR (Interrupt Service routine), there is a chance that the + * returned bits 0b1110 (rx_pipe number) is inaccurate. See available(uint8_t*) (or the + * datasheet) for more detail. * - * @param[out] tx_ok The transmission attempt completed (TX_DS). This does - * not imply that the transmitted data was received by another radio, rather - * this only reports if the attempt to send was completed. This will - * always be `true` when the auto-ack feature is disabled. - * @param[out] tx_fail The transmission failed to be acknowledged, meaning - * too many retries (MAX_RT) were made while expecting an ACK packet. This - * event is only triggered when auto-ack feature is enabled. - * @param[out] rx_ready There is a newly received payload (RX_DR) saved to - * RX FIFO buffers. Remember that the RX FIFO can only hold up to 3 - * payloads. Once the RX FIFO is full, all further received transmissions - * are rejected until there is space to save new data in the RX FIFO - * buffers. + * @param flags The IRQ flags to clear. Default value is all of them (`RF24_IRQ_ALL`). + * Multiple flags can be cleared by OR-ing rf24_irq_flags_e values together. * - * @note This function expects no parameters in the python wrapper. - * Instead, this function returns a 3 item tuple describing the IRQ - * events' status. To use this function in the python wrapper: - * @code{.py} - * # let`radio` be the instantiated RF24 object - * tx_ds, tx_df, rx_dr = radio.whatHappened() # get IRQ status flags - * print("tx_ds: {}, tx_df: {}, rx_dr: {}".format(tx_ds, tx_df, rx_dr)) - * @endcode + * @returns The STATUS byte from the radio's register before it was modified. Use + * enumerations of rf24_irq_flags_e as masks to interpret the STATUS byte's meaning(s). + * + * @ingroup StatusFlags */ - void whatHappened(bool& tx_ok, bool& tx_fail, bool& rx_ready); + uint8_t clearStatusFlags(uint8_t flags = RF24_IRQ_ALL); + + /** + * Set which flags shall be reflected on the radio's IRQ pin. + * + * @remarks This function is similar to maskIRQ() but with less confusing parameters. + * + * @param flags A value of rf24_irq_flags_e to influence the radio's IRQ pin. + * The default value (`RF24_IRQ_NONE`) will disable the radio's IRQ pin. + * Multiple events can be enabled by OR-ing rf24_irq_flags_e values together. + * ```cpp + * radio.setStatusFlags(RF24_IRQ_ALL); + * // is equivalent to + * radio.setStatusFlags(RF24_RX_DR | RF24_TX_DS | RF24_TX_DF); + * ``` + * + * @ingroup StatusFlags + */ + void setStatusFlags(uint8_t flags = RF24_IRQ_NONE); + + /** + * Get the latest STATUS byte returned from the last SPI transaction. + * + * @note This does not actually perform any SPI transaction with the radio. + * Use `RF24::update()` instead to get a fresh copy of the Status flags at + * the slight cost of performance. + * + * @returns The STATUS byte from the radio's register as the latest SPI transaction. Use + * enumerations of rf24_irq_flags_e as masks to interpret the STATUS byte's meaning(s). + * + * @ingroup StatusFlags + */ + uint8_t getStatusFlags(); + + /** + * Get an updated STATUS byte from the radio. + * + * @returns The STATUS byte fetched from the radio's register. Use enumerations of + * rf24_irq_flags_e as masks to interpret the STATUS byte's meaning(s). + * + * @ingroup StatusFlags + */ + uint8_t update(); /** * Non-blocking write to the open writing pipe used for buffered writes @@ -1222,13 +1289,13 @@ class RF24 * Non-blocking write to the open writing pipe * * Just like write(), but it returns immediately. To find out what happened - * to the send, catch the IRQ and then call whatHappened(). + * to the send, catch the IRQ and then call clearStatusFlags() or update(). * * @see * - write() * - writeFast() * - startFastWrite() - * - whatHappened() + * - clearStatusFlags() * - setAutoAck() (for single noAck writes) * * @param buf Pointer to the data to be sent @@ -1745,38 +1812,6 @@ class RF24 */ void disableCRC(void); - /** - * This function is used to configure what events will trigger the Interrupt - * Request (IRQ) pin active LOW. - * The following events can be configured: - * 1. "data sent": This does not mean that the data transmitted was - * received, only that the attempt to send it was complete. - * 2. "data failed": This means the data being sent was not received. This - * event is only triggered when the auto-ack feature is enabled. - * 3. "data received": This means that data from a receiving payload has - * been loaded into the RX FIFO buffers. Remember that there are only 3 - * levels available in the RX FIFO buffers. - * - * By default, all events are configured to trigger the IRQ pin active LOW. - * When the IRQ pin is active, use whatHappened() to determine what events - * triggered it. Remember that calling whatHappened() also clears these - * events' status, and the IRQ pin will then be reset to inactive HIGH. - * - * The following code configures the IRQ pin to only reflect the "data received" - * event: - * @code - * radio.maskIRQ(1, 1, 0); - * @endcode - * - * @param tx_ok `true` ignores the "data sent" event, `false` reflects the - * "data sent" event on the IRQ pin. - * @param tx_fail `true` ignores the "data failed" event, `false` reflects the - * "data failed" event on the IRQ pin. - * @param rx_ready `true` ignores the "data received" event, `false` reflects the - * "data received" event on the IRQ pin. - */ - void maskIRQ(bool tx_ok, bool tx_fail, bool rx_ready); - /** * * The driver will delay for this duration when stopListening() is called @@ -1864,7 +1899,8 @@ class RF24 /** * Open a pipe for reading * @deprecated For compatibility with old code only, see newer function - * openReadingPipe() + * openReadingPipe(). + * See our [migration guide](migration.md) to understand what you should update in your code. * * @note Pipes 1-5 should share the first 32 bits. * Only the least significant byte should be unique, e.g. @@ -1889,7 +1925,8 @@ class RF24 /** * Open a pipe for writing * @deprecated For compatibility with old code only, see newer function - * openWritingPipe() + * openWritingPipe(). + * See our [migration guide](migration.md) to understand what you should update in your code. * * Addresses are 40-bit hex values, e.g.: * @@ -1907,11 +1944,84 @@ class RF24 * * @deprecated For compatibility with old code only, see synonymous function available(). * Use read() to retrieve the ack payload and getDynamicPayloadSize() to get the ACK payload size. + * See our [migration guide](migration.md) to understand what you should update in your code. * * @return True if an ack payload is available. */ bool isAckPayloadAvailable(void); + /** + * This function is used to configure what events will trigger the Interrupt + * Request (IRQ) pin active LOW. + * + * @deprecated Use setStatusFlags() instead. + * See our [migration guide](migration.md) to understand what you should update in your code. + * + * The following events can be configured: + * 1. "data sent": This does not mean that the data transmitted was + * received, only that the attempt to send it was complete. + * 2. "data failed": This means the data being sent was not received. This + * event is only triggered when the auto-ack feature is enabled. + * 3. "data received": This means that data from a receiving payload has + * been loaded into the RX FIFO buffers. Remember that there are only 3 + * levels available in the RX FIFO buffers. + * + * By default, all events are configured to trigger the IRQ pin active LOW. + * When the IRQ pin is active, use clearStatusFlags() or getStatusFlags() to + * determine what events triggered it. + * Remember that calling clearStatusFlags() also clears these + * events' status, and the IRQ pin will then be reset to inactive HIGH. + * + * The following code configures the IRQ pin to only reflect the "data received" + * event: + * @code + * radio.maskIRQ(1, 1, 0); + * @endcode + * + * @param tx_ok `true` ignores the "data sent" event, `false` reflects the + * "data sent" event on the IRQ pin. + * @param tx_fail `true` ignores the "data failed" event, `false` reflects the + * "data failed" event on the IRQ pin. + * @param rx_ready `true` ignores the "data received" event, `false` reflects the + * "data received" event on the IRQ pin. + */ + void maskIRQ(bool tx_ok, bool tx_fail, bool rx_ready); + + /** + * Call this when you get an Interrupt Request (IRQ) to find out why + * + * This function describes what event triggered the IRQ pin to go active + * LOW and clears the status of all events. + * + * @deprecated Use clearStatusFlags() instead. + * See our [migration guide](migration.md) to understand what you should update in your code. + * + * @see setStatusFlags() + * + * @param[out] tx_ok The transmission attempt completed (TX_DS). This does + * not imply that the transmitted data was received by another radio, rather + * this only reports if the attempt to send was completed. This will + * always be `true` when the auto-ack feature is disabled. + * @param[out] tx_fail The transmission failed to be acknowledged, meaning + * too many retries (MAX_RT) were made while expecting an ACK packet. This + * event is only triggered when auto-ack feature is enabled. + * @param[out] rx_ready There is a newly received payload (RX_DR) saved to + * RX FIFO buffers. Remember that the RX FIFO can only hold up to 3 + * payloads. Once the RX FIFO is full, all further received transmissions + * are rejected until there is space to save new data in the RX FIFO + * buffers. + * + * @note This function expects no parameters in the python wrapper. + * Instead, this function returns a 3 item tuple describing the IRQ + * events' status. To use this function in the python wrapper: + * @code{.py} + * # let`radio` be the instantiated RF24 object + * tx_ds, tx_df, rx_dr = radio.whatHappened() # get IRQ status flags + * print("tx_ds: {}, tx_df: {}, rx_dr: {}".format(tx_ds, tx_df, rx_dr)) + * @endcode + */ + void whatHappened(bool& tx_ok, bool& tx_fail, bool& rx_ready); + private: /**@}*/ /** @@ -1999,24 +2109,8 @@ class RF24 */ void read_payload(void* buf, uint8_t len); - /** - * Retrieve the current status of the chip - * - * @return Current value of status register - */ - uint8_t get_status(void); - #if !defined(MINIMAL) - /** - * Decode and print the given status to stdout - * - * @param status Status value to print - * - * @warning Does nothing if stdout is not defined. See fdevopen in stdio.h - */ - void print_status(uint8_t status); - /** * Decode and print the given 'observe_tx' value to stdout * diff --git a/docs/main_page.md b/docs/main_page.md index 197f9fdc2..f1f44b83b 100644 --- a/docs/main_page.md +++ b/docs/main_page.md @@ -19,6 +19,13 @@ See the releases' descriptions on [the library's release page](http://github.com/nRF24/RF24/releases) for a list of changes. +> [!IMPORTANT] +> There's going to be major changes in v2.0. +> As of v1.5, there is [newer API](migration.md) that should be used instead of +> the @ref deprecated "deprecated API". +> +> See our [migration guide](migration.md) to understand what you should update in your code. + ## Useful References - [RF24 Class Documentation](classRF24.html) diff --git a/docs/migration.md b/docs/migration.md new file mode 100644 index 000000000..f3139a05c --- /dev/null +++ b/docs/migration.md @@ -0,0 +1,213 @@ +# Migration guide + +@tableofcontents + + + +This is a collection of snippets that highlight preferred API over the deprecated original API. + +## isAckPayloadAvailable() + +> **Deprecated since v1.4.2** + +This function is equivalent to `RF24::available()`. +Any use of `RF24::isAckPayloadAvailable()` is interchangeable with `RF24::available()`. + + + + +
OldNew (supported)
+ +```cpp +if radio.isAckPayloadAvailable() { /* .. */ } +``` + + + +```cpp +if radio.available() { /* .. */ } +``` + +
+ +## openReadingPipe(uint8_t, uint64_t) and openWritingPipe(uint64_t) + +> **Deprecated since v1.3.11** + +These functions' address parameter used a 64-bit unsigned integer (`uint64_t`). +The nRF24L01 can only use up to 40 bit addresses. +Thus, there was an unused 24 bits being allocated for addresses using this function. + +There are overloaded functions that use a buffer instead: + +- `RF24::openReadingPipe(uint8_t, const uint8_t*)` +- `RF24::openWritingPipe(const uint8_t*)` + +These eliminate the unnecessary 24 bits by only using the length of the buffer (`uint8_t*`) +specified by `RF24::setAddressWidth()`. + +> [!CAUTION] +> The endianness (byte order) of a buffer is reversed compared to a 64-bit integer. +> ```c +> uint64_t address = 0xB3B4B5B6C2; +> // is the same address as +> uint8_t address[5] = {0xC2, 0xB6, 0xB5, 0xB4, 0xB3}; +> ``` +> Notice the MSB (Most Significant Byte) `0xC2` is last in the integer but first in the buffer. + + + + +
OldNew (supported)
+ +```cpp +uint64_t address = 0xB3B4B5B6C2; +radio.openReadingPipe(1, address); +``` + + + +```cpp +uint8_t address[5] = {0xC2, 0xB6, 0xB5, 0xB4, 0xB3}; +radio.openReadingPipe(1, address); +``` + +
+ +> [!NOTE] +> Our examples actually use a C-string casted as an array of 6 bytes. +> That's because a C-string (`char*`) must be NULL terminated (`\0` at the end) in memory. +> ```c +> uint8_t address[][6] = { "1Node", "2Node" }; +> // is equivalent to +> uint8_t address[][6] = { { '1', 'N', 'o', 'd', 'e', '\0' }, +> { '2', 'N', 'o', 'd', 'e', '\0' } }; +> ``` + +## isFifo(bool, bool) + +> **Deprecated since v1.4.11** + +Introduced as a compliment to `RF24::isFifo(bool)` in v1.4.3, this function was +supposed to provide a specific detail about a specified radio's FIFO. However, it was +discovered that the function may not highlight binary corruption (`RF24_FIFO_INVALID`) +observed in the SPI bus' MISO line. + +A fix was introduced using enumerated values of `rf24_fifo_state_e`. +Since then, `RF24::isFifo(bool)` is now preferred as it accurately describes the result. + + + + +
OldNew (supported)
+ +```cpp +bool rxFifoEmpty = radio.isFifo(false, true); +``` + + + +```cpp +bool rxFifoEmpty = radio.isFifo(false) == RF24_FIFO_EMPTY; +``` + +
+ +## maskIRQ() + +> **Deprecated since v1.5** + +Originally `RF24::maskIRQ()` was the only function provided to influence the radio's IRQ pin. +However, the 3 required boolean parameters made this prone to bugs in user code. +The parameters' meaning was confusingly reversed, and they were easily misplaced in the wrong order. + +A better approach was introduced with `RF24::setStatusFlags()`. +It's 1 parameter accepts values defined by the `rf24_irq_flags_e` enumerated constants. +These constant values specify individual events; +they can also be OR'd together to specify multiple events. + + + + +
OldNew (supported)
+ +```cpp +// IRQ pin only activated by "RX Data Ready" event +radio.maskIRQ(1, 1, 0); + +// IRQ pin activated by "TX Data Sent" and TX Data Failed" events +radio.maskIRQ(0, 0, 1); + +// IRQ pin activated by all events +radio.maskIRQ(0, 0, 0); + +// IRQ pin disabled +radio.maskIRQ(1, 1, 1); +``` + + + +```cpp +// IRQ pin only activated by "RX Data Ready" event +radio.setStatusFlags(RF24_RX_DR); + +// IRQ pin activated by "TX Data Sent" and TX Data Failed" events +radio.setStatusFlags(RF24_TX_DS | RF24_TX_DF); + +// IRQ pin activated by all events +radio.setStatusFlags(RF24_IRQ_ALL); + +// IRQ pin disabled +radio.setStatusFlags(RF24_IRQ_NONE); +// or equivalently +radio.setStatusFlags(); +``` + +
+ +## whatHappened() + +> **Deprecated since v1.5** + +Originally, `RF24::whatHappened()` was the only way to clear the events that triggered the IRQ pin. +Like `maskIRQ()`, this was also prone to bugs because of the 3 required boolean parameters +(passed by reference). + +The aptly named `RF24::clearStatusFlags()` is designed to be a replacement for `RF24::whatHappened()`. +Like `RF24::clearStatusFlags()`, `RF24::setStatusFlags()` takes 1 parameter whose value is defined by +the `rf24_irq_flags_e` enumerated constants. These constant values specify individual flags; +they can also be OR'd together to specify multiple flags. +Additionally, `RF24::clearStatusFlags()` returns the STATUS byte containing the flags that +caused the IRQ pin to go active LOW. +This allows the user code to allocate less memory when diagnosing the IRQ pin's meaning. + + + + +
OldNew (supported)
+ +```cpp +bool tx_ds, tx_df, rx_dr; +radio.whatHappened(tx_ds, tx_df, rx_dr); +``` + + + +```cpp +uint8_t flags = radio.clearStatusFlags(); +// or equivalently +uint8_t flags = radio.clearStatusFlags(RF24_IRQ_ALL); + +// focus on the events you care about +if (flags & RF24_TX_DS) { /* TX data sent */ } +if (flags & RF24_TX_DF) { /* TX data failed to send */ } +if (flags & RF24_RX_DR) { /* RX data is in the RX FIFO */ } + +// only clear the "TX Data Sent" and TX Data Failed" events +radio.clearStatusFlags(RF24_TX_DS | RF24_TX_DF); + +// only clear the "RX Data Ready" event +radio.clearStatusFlags(RF24_RX_DR); +``` + +
diff --git a/examples/InterruptConfigure/InterruptConfigure.ino b/examples/InterruptConfigure/InterruptConfigure.ino index 19ef9c504..48f6a4c9c 100644 --- a/examples/InterruptConfigure/InterruptConfigure.ino +++ b/examples/InterruptConfigure/InterruptConfigure.ino @@ -118,8 +118,8 @@ void setup() { } else { // setup for RX mode - // let IRQ pin only trigger on "data ready" event in RX mode - radio.maskIRQ(1, 1, 0); // args = "data_sent", "data_fail", "data_ready" + // let IRQ pin only trigger on "data_ready" event in RX mode + radio.setStatusFlags(RF24_RX_DR); // Fill the TX FIFO with 3 ACK payloads for the first 3 received // transmissions on pipe 1 @@ -150,21 +150,22 @@ void loop() { // Test the "data ready" event with the IRQ pin Serial.println(F("\nConfiguring IRQ pin to ignore the 'data sent' event")); - radio.maskIRQ(true, false, false); // args = "data_sent", "data_fail", "data_ready" + radio.setStatusFlags(RF24_RX_DR | RF24_TX_DF); Serial.println(F(" Pinging RX node for 'data ready' event...")); } else if (pl_iterator == 1) { // Test the "data sent" event with the IRQ pin Serial.println(F("\nConfiguring IRQ pin to ignore the 'data ready' event")); - radio.maskIRQ(false, false, true); // args = "data_sent", "data_fail", "data_ready" + radio.setStatusFlags(RF24_TX_DS | RF24_TX_DF); Serial.println(F(" Pinging RX node for 'data sent' event...")); } else if (pl_iterator == 2) { // Use this iteration to fill the RX node's FIFO which sets us up for the next test. // write() uses virtual interrupt flags that work despite the masking of the IRQ pin - radio.maskIRQ(1, 1, 1); // disable IRQ masking for this step + // disable IRQ pin for this step + radio.setStatusFlags(); Serial.println(F("\nSending 1 payload to fill RX node's FIFO. IRQ pin is neglected.")); // write() will call flush_tx() on 'data fail' events @@ -183,7 +184,7 @@ void loop() { // test the "data fail" event with the IRQ pin Serial.println(F("\nConfiguring IRQ pin to reflect all events")); - radio.maskIRQ(0, 0, 0); // args = "data_sent", "data_fail", "data_ready" + radio.setStatusFlags(RF24_IRQ_ALL); Serial.println(F(" Pinging inactive RX node for 'data fail' event...")); } @@ -266,7 +267,8 @@ void loop() { role = false; - radio.maskIRQ(0, 0, 0); // the IRQ pin should only trigger on "data ready" event + // let IRQ pin only trigger on "data_ready" event in RX mode + radio.setStatusFlags(RF24_RX_DR); // Fill the TX FIFO with 3 ACK payloads for the first 3 received // transmissions on pipe 1 @@ -298,33 +300,32 @@ void assessInterruptEvent() { Serial.println(F("\tIRQ pin is actively LOW")); // show that this function was called delayMicroseconds(250); - bool tx_ds, tx_df, rx_dr; // declare variables for IRQ masks - radio.whatHappened(tx_ds, tx_df, rx_dr); // get values for IRQ masks - // whatHappened() clears the IRQ masks also. This is required for + uint8_t flags = radio.clearStatusFlags(); + // Resetting the tx_df flag is required for // continued TX operations when a transmission fails. - // clearing the IRQ masks resets the IRQ pin to its inactive state (HIGH) + // clearing the status flags resets the IRQ pin to its inactive state (HIGH) Serial.print(F("\tdata_sent: ")); - Serial.print(tx_ds); // print "data sent" mask state + Serial.print((flags & RF24_TX_DS) > 0); // print "data sent" flag state Serial.print(F(", data_fail: ")); - Serial.print(tx_df); // print "data fail" mask state + Serial.print((flags & RF24_TX_DF) > 0); // print "data fail" flag state Serial.print(F(", data_ready: ")); - Serial.println(rx_dr); // print "data ready" mask state + Serial.println((flags & RF24_RX_DR) > 0); // print "data ready" flag state - if (tx_df) // if TX payload failed - radio.flush_tx(); // clear all payloads from the TX FIFO + if (flags & RF24_TX_DF) // if TX payload failed + radio.flush_tx(); // clear all payloads from the TX FIFO // print if test passed or failed. Unintentional fails mean the RX node was not listening. // pl_iterator has already been incremented by now if (pl_iterator <= 1) { Serial.print(F(" 'Data Ready' event test ")); - Serial.println(rx_dr ? F("passed") : F("failed")); + Serial.println(flags & RF24_RX_DR ? F("passed") : F("failed")); } else if (pl_iterator == 2) { Serial.print(F(" 'Data Sent' event test ")); - Serial.println(tx_ds ? F("passed") : F("failed")); + Serial.println(flags & RF24_TX_DS ? F("passed") : F("failed")); } else if (pl_iterator == 4) { Serial.print(F(" 'Data Fail' event test ")); - Serial.println(tx_df ? F("passed") : F("failed")); + Serial.println(flags & RF24_TX_DF ? F("passed") : F("failed")); } got_interrupt = false; // reset this flag to prevent calling this function from loop() wait_for_event = false; // ready to continue with loop() operations diff --git a/examples/StreamingData/StreamingData.ino b/examples/StreamingData/StreamingData.ino index 3a2153b42..0c3d6458f 100644 --- a/examples/StreamingData/StreamingData.ino +++ b/examples/StreamingData/StreamingData.ino @@ -113,8 +113,15 @@ void loop() { while (i < SIZE) { makePayload(i); // make the payload if (!radio.writeFast(&buffer, SIZE)) { - failures++; - radio.reUseTX(); + uint8_t flags = radio.getStatusFlags(); + if (flags & RF24_TX_DF) { + failures++; + // now we need to reset the tx_df flag and the radio's CE pin + radio.ce(LOW); + radio.clearStatusFlags(RF24_TX_DF); + radio.ce(HIGH); + } + // else the TX FIFO is full; just continue loop. } else { i++; } diff --git a/examples_linux/interruptConfigure.cpp b/examples_linux/interruptConfigure.cpp index ec71b7a51..fc68131a1 100644 --- a/examples_linux/interruptConfigure.cpp +++ b/examples_linux/interruptConfigure.cpp @@ -174,22 +174,23 @@ void master() // Test the "data ready" event with the IRQ pin cout << "\nConfiguring IRQ pin to ignore the 'data sent' event\n"; - radio.maskIRQ(true, false, false); // args = "data_sent", "data_fail", "data_ready" + radio.setStatusFlags(RF24_RX_DR | RF24_TX_DF); cout << " Pinging RX node for 'data ready' event..." << endl; ping_n_wait(); // transmit a payload and detect the IRQ pin pl_iterator++; // increment iterator for next test // Test the "data sent" event with the IRQ pin cout << "\nConfiguring IRQ pin to ignore the 'data ready' event\n"; - radio.maskIRQ(false, false, true); // args = "data_sent", "data_fail", "data_ready" + radio.setStatusFlags(RF24_TX_DS | RF24_TX_DF); cout << " Pinging RX node for 'data sent' event..." << endl; radio.flush_tx(); // flush payloads from any failed prior test ping_n_wait(); // transmit a payload and detect the IRQ pin pl_iterator++; // increment iterator for next test // Use this iteration to fill the RX node's FIFO which sets us up for the next test. - // write() uses virtual interrupt flags that work despite the masking of the IRQ pin - radio.maskIRQ(1, 1, 1); // disable IRQ masking for this step + // write() uses virtual interrupt flags that work despite the masking of the IRQ pin. + // disable IRQ pin for this step + radio.setStatusFlags(); cout << "\nSending 1 payload to fill RX node's FIFO. IRQ pin is neglected.\n"; // write() will call flush_tx() on 'data fail' events @@ -203,7 +204,7 @@ void master() // test the "data fail" event with the IRQ pin cout << "\nConfiguring IRQ pin to reflect all events\n"; - radio.maskIRQ(0, 0, 0); // args = "data_sent", "data_fail", "data_ready" + radio.setStatusFlags(RF24_IRQ_ALL); cout << " Pinging inactive RX node for 'data fail' event..." << endl; ping_n_wait(); // transmit a payload and detect the IRQ pin @@ -223,7 +224,7 @@ void slave() { // let IRQ pin only trigger on "data_ready" event in RX mode - radio.maskIRQ(1, 1, 0); // args = "data_sent", "data_fail", "data_ready" + radio.setStatusFlags(RF24_RX_DR); // Fill the TX FIFO with 3 ACK payloads for the first 3 received // transmissions on pipe 0. @@ -277,26 +278,24 @@ void ping_n_wait() cout << "\tIRQ pin is actively LOW" << endl; // show that this function was called - bool tx_ds, tx_df, rx_dr; // declare variables for IRQ masks - radio.whatHappened(tx_ds, tx_df, rx_dr); // get values for IRQ masks - // whatHappened() clears the IRQ masks also. This is required for + uint8_t flags = radio.clearStatusFlags(); + // Resetting the tx_df flag is required for // continued TX operations when a transmission fails. - // clearing the IRQ masks resets the IRQ pin to its inactive state (HIGH) + // clearing the status flags resets the IRQ pin to its inactive state (HIGH) - cout << "\tdata_sent: " << tx_ds; // print "data sent" mask state - cout << ", data_fail: " << tx_df; // print "data fail" mask state - cout << ", data_ready: " << rx_dr << endl; // print "data ready" mask state + cout << "\t"; + radio.printStatus(flags); // print StatusFlags description - if (tx_df) // if TX payload failed - radio.flush_tx(); // clear all payloads from the TX FIFO + if (flags & RF24_TX_DF) // if TX payload failed + radio.flush_tx(); // clear all payloads from the TX FIFO // print if test passed or failed. Unintentional fails mean the RX node was not listening. if (pl_iterator == 0) - cout << " 'Data Ready' event test " << (rx_dr ? "passed" : "failed") << endl; + cout << " 'Data Ready' event test " << (flags & RF24_RX_DR ? "passed" : "failed") << endl; else if (pl_iterator == 1) - cout << " 'Data Sent' event test " << (tx_ds ? "passed" : "failed") << endl; + cout << " 'Data Sent' event test " << (flags & RF24_TX_DS ? "passed" : "failed") << endl; else if (pl_iterator == 3) - cout << " 'Data Fail' event test " << (tx_df ? "passed" : "failed") << endl; + cout << " 'Data Fail' event test " << (flags & RF24_TX_DF ? "passed" : "failed") << endl; got_interrupt = false; } diff --git a/examples_linux/interrupt_configure.py b/examples_linux/interrupt_configure.py index 54aea0bb1..72f945c5a 100644 --- a/examples_linux/interrupt_configure.py +++ b/examples_linux/interrupt_configure.py @@ -6,7 +6,15 @@ """ import time -from RF24 import RF24, RF24_PA_LOW, RF24_DRIVER +from RF24 import ( + RF24, + RF24_PA_LOW, + RF24_DRIVER, + RF24_TX_DF, + RF24_TX_DS, + RF24_RX_DR, + RF24_IRQ_ALL, +) try: import gpiod @@ -97,14 +105,25 @@ def interrupt_handler(): """This function is called when IRQ pin is detected active LOW""" print("\tIRQ pin went active LOW.") - tx_ds, tx_df, rx_dr = radio.whatHappened() # update IRQ status flags - print(f"\ttx_ds: {tx_ds}, tx_df: {tx_df}, rx_dr: {rx_dr}") + flags = radio.clearStatusFlags() + # Resetting the tx_df flag is required for + # continued TX operations when a transmission fails. + # clearing the status flags resets the IRQ pin to its inactive state (HIGH) + print("\t", end="", flush=True) + radio.printStatus(flags) if pl_iterator[0] == 0: - print(" 'data ready' event test", ("passed" if rx_dr else "failed")) + print( + " 'data ready' event test", + ("passed" if flags & RF24_RX_DR else "failed"), + ) elif pl_iterator[0] == 1: - print(" 'data sent' event test", ("passed" if tx_ds else "failed")) + print( + " 'data sent' event test", ("passed" if flags & RF24_TX_DS else "failed") + ) elif pl_iterator[0] == 2: - print(" 'data fail' event test", ("passed" if tx_df else "failed")) + print( + " 'data fail' event test", ("passed" if flags & RF24_TX_DF else "failed") + ) # setup IRQ GPIO pin @@ -143,7 +162,7 @@ def master(): # on data ready test print("\nConfiguring IRQ pin to only ignore 'on data sent' event") - radio.maskIRQ(True, False, False) # args = tx_ds, tx_df, rx_dr + radio.setStatusFlags(RF24_RX_DR | RF24_TX_DF) print(" Pinging slave node for an ACK payload...") pl_iterator[0] = 0 radio.startFastWrite(tx_payloads[0], False) # False means expecting an ACK @@ -152,7 +171,7 @@ def master(): # on "data sent" test print("\nConfiguring IRQ pin to only ignore 'on data ready' event") - radio.maskIRQ(False, False, True) # args = tx_ds, tx_df, rx_dr + radio.setStatusFlags(RF24_TX_DS | RF24_TX_DF) print(" Pinging slave node again...") pl_iterator[0] = 1 radio.startFastWrite(tx_payloads[1], False) # False means expecting an ACK @@ -162,7 +181,7 @@ def master(): # trigger slave node to exit by filling the slave node's RX FIFO print("\nSending one extra payload to fill RX FIFO on slave node.") print("Disabling IRQ pin for all events.") - radio.maskIRQ(True, True, True) # args = tx_ds, tx_df, rx_dr + radio.setStatusFlags() if radio.write(tx_payloads[2]): print("Slave node should not be listening anymore.") else: @@ -170,7 +189,7 @@ def master(): # on "data fail" test print("\nConfiguring IRQ pin to go active for all events.") - radio.maskIRQ(False, False, False) # args = tx_ds, tx_df, rx_dr + radio.setStatusFlags(RF24_IRQ_ALL) print(" Sending a ping to inactive slave node...") radio.flush_tx() # just in case any previous tests failed pl_iterator[0] = 2 @@ -189,7 +208,7 @@ def slave(timeout=6): # will listen for 6 seconds before timing out # the "data sent" or "data fail" events will trigger when we # receive with ACK payloads enabled (& loaded in TX FIFO) print("\nDisabling IRQ pin for all events.") - radio.maskIRQ(True, True, True) # args = tx_ds, tx_df, rx_dr + radio.setStatusFlags() # setup radio to receive pings, fill TX FIFO with ACK payloads radio.writeAckPayload(1, ack_payloads[0]) radio.writeAckPayload(1, ack_payloads[1]) diff --git a/examples_linux/streamingData.cpp b/examples_linux/streamingData.cpp index e1a9b26ca..30ca66b92 100644 --- a/examples_linux/streamingData.cpp +++ b/examples_linux/streamingData.cpp @@ -208,8 +208,16 @@ void master() while (i < SIZE) { makePayload(i); if (!radio.writeFast(&buffer, SIZE)) { - failures++; - radio.reUseTX(); + uint8_t flags = radio.getStatusFlags(); + if (flags & RF24_TX_DF) { + failures++; + // failed to transmit a previous payload. + // Now we need to reset the tx_df flag and the CE pin + radio.ce(LOW); + radio.clearStatusFlags(RF24_TX_DF); + radio.ce(HIGH); + } + // else the TX FIFO is full; just continue loop } else { i++; @@ -241,10 +249,10 @@ void slave() time_t startTimer = time(nullptr); // start a timer while (time(nullptr) - startTimer < 6) { // use 6 second timeout if (radio.available()) { // is there a payload + counter++; // increment counter radio.read(&buffer, SIZE); // fetch payload from FIFO cout << "Received: " << buffer; // print the payload's value cout << " - " << counter << endl; // print the counter - counter++; // increment counter startTimer = time(nullptr); // reset timer } } diff --git a/examples_linux/streaming_data.py b/examples_linux/streaming_data.py index 717a7efeb..eb38ab26c 100644 --- a/examples_linux/streaming_data.py +++ b/examples_linux/streaming_data.py @@ -7,7 +7,7 @@ """ import time -from RF24 import RF24, RF24_PA_LOW, RF24_DRIVER +from RF24 import RF24, RF24_PA_LOW, RF24_DRIVER, RF24_TX_DF print(__file__) # print example name @@ -94,27 +94,32 @@ def master(count: int = 1): radio.stopListening() # put radio in TX mode radio.flush_tx() # clear the TX FIFO so we can use all 3 levels failures = 0 # keep track of manual retries - start_timer = time.monotonic_ns() # start timer for multiplier in range(count): # repeat transmit the same data stream buf_iter = 0 # iterator of payloads for the while loop + start_timer = time.monotonic_ns() # start timer while buf_iter < SIZE: # cycle through all the payloads buffer = make_buffer(buf_iter) # make a payload if not radio.writeFast(buffer): # transmission failed - failures += 1 # increment manual retry count + flags = radio.getStatusFlags() + if flags & RF24_TX_DF: + failures += 1 # increment manual retry count + # now we need to reset the tx_df flag and the radio's CE pin + radio.ce(False) + flags = radio.clearStatusFlags(RF24_TX_DF) + radio.ce(True) if failures > 99 and buf_iter < 7 and multiplier < 2: # we need to prevent an infinite loop print("Too many failures detected. Aborting at payload ", buffer[0]) multiplier = count # be sure to exit the for loop break # exit the while loop - radio.reUseTX() # resend payload in top level of TX FIFO else: # transmission succeeded buf_iter += 1 - end_timer = time.monotonic_ns() # end timer - print( - f"Time to transmit data = {(end_timer - start_timer) / 1000} us.", - f"Detected {failures} failures.", - ) + end_timer = time.monotonic_ns() # end timer + print( + f"Time to transmit data = {(end_timer - start_timer) / 1000} us.", + f"Detected {failures} failures.", + ) def slave(timeout: int = 6): diff --git a/examples_pico/interruptConfigure.cpp b/examples_pico/interruptConfigure.cpp index 27a272696..b1414d567 100644 --- a/examples_pico/interruptConfigure.cpp +++ b/examples_pico/interruptConfigure.cpp @@ -75,6 +75,7 @@ bool setup() printf("radioNumber = %d\n", (int)radioNumber); // setup the IRQ_PIN + gpio_init(IRQ_PIN); gpio_set_irq_enabled_with_callback(IRQ_PIN, GPIO_IRQ_EDGE_FALL, true, &interruptHandler); // IMPORTANT: do not call radio.available() before calling // radio.whatHappened() when the interruptHandler() is triggered by the @@ -110,8 +111,8 @@ bool setup() else { // setup for RX mode - // let IRQ pin not trigger in RX mode - radio.maskIRQ(1, 1, 1); // args = "data_sent", "data_fail", "data_ready" + // disable IRQ pin in RX mode + radio.setStatusFlags(); // Fill the TX FIFO with 3 ACK payloads for the first 3 received // transmissions on pipe 1 @@ -142,21 +143,22 @@ void loop() // Test the "data ready" event with the IRQ pin printf("\nConfiguring IRQ pin to ignore the 'data sent' event\n"); - radio.maskIRQ(true, false, false); // args = "data_sent", "data_fail", "data_ready" + radio.setStatusFlags(RF24_RX_DR | RF24_TX_DF); printf(" Pinging RX node for 'data ready' event...\n"); } else if (pl_iterator == 1) { // Test the "data sent" event with the IRQ pin printf("\nConfiguring IRQ pin to ignore the 'data ready' event\n"); - radio.maskIRQ(false, false, true); // args = "data_sent", "data_fail", "data_ready" + radio.setStatusFlags(RF24_TX_DS | RF24_TX_DF); printf(" Pinging RX node for 'data sent' event...\n"); } else if (pl_iterator == 2) { // Use this iteration to fill the RX node's FIFO which sets us up for the next test. // write() uses virtual interrupt flags that work despite the masking of the IRQ pin - radio.maskIRQ(1, 1, 1); // disable IRQ masking for this step + // disable IRQ pin for this step + radio.setStatusFlags(); printf("\nSending 1 payload to fill RX node's FIFO. IRQ pin is neglected.\n"); // write() will call flush_tx() on 'data fail' events @@ -177,7 +179,7 @@ void loop() // test the "data fail" event with the IRQ pin printf("\nConfiguring IRQ pin to reflect all events\n"); - radio.maskIRQ(0, 0, 0); // args = "data_sent", "data_fail", "data_ready" + radio.setStatusFlags(RF24_IRQ_ALL); printf(" Pinging inactive RX node for 'data fail' event...\n"); } @@ -263,7 +265,8 @@ void loop() printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n"); role = false; - radio.maskIRQ(1, 1, 1); // the IRQ pin should not trigger in this example's RX rode + // do not trigger IRQ pin in RX mode + radio.setStatusFlags(); // Fill the TX FIFO with 3 ACK payloads for the first 3 received // transmissions on pipe 1 @@ -287,7 +290,7 @@ void loop() */ void interruptHandler(uint gpio, uint32_t events) { - if (gpio != IRQ_PIN && !(events | GPIO_IRQ_EDGE_FALL)) { + if (gpio != IRQ_PIN && (events & GPIO_IRQ_EDGE_FALL) == 0) { // the gpio pin and event does not match the configuration we specified return; } @@ -301,32 +304,28 @@ void interruptHandler(uint gpio, uint32_t events) void assessInterruptEvent() { // print IRQ status and all masking flags' states - printf("\tIRQ pin is actively LOW\n"); // show that this function was called - bool tx_ds, tx_df, rx_dr; // declare variables for IRQ masks - radio.whatHappened(tx_ds, tx_df, rx_dr); // get values for IRQ masks - // whatHappened() clears the IRQ masks also. This is required for + printf("\tIRQ pin is actively LOW\n"); // show that this function was called + uint8_t flags = radio.clearStatusFlags(); + // Resetting the tx_df flag is required for // continued TX operations when a transmission fails. - // clearing the IRQ masks resets the IRQ pin to its inactive state (HIGH) + // clearing the status flags resets the IRQ pin to its inactive state (HIGH) - // print "data sent", "data fail", "data ready" mask states - printf("\tdata_sent: %s, data_fail: %s, data_ready: %s\n", - tx_ds ? "true" : "false", - tx_df ? "true" : "false", - rx_dr ? "true" : "false"); + printf("\t"); + radio.printStatus(flags); // print status flags info - if (tx_df) // if TX payload failed - radio.flush_tx(); // clear all payloads from the TX FIFO + if (flags & RF24_TX_DF) // if TX payload failed + radio.flush_tx(); // clear all payloads from the TX FIFO // print if test passed or failed. Unintentional fails mean the RX node was not listening. // pl_iterator has already been incremented by now if (pl_iterator <= 1) { - printf(" 'Data Ready' event test %s\n", rx_dr ? "passed" : "failed"); + printf(" 'Data Ready' event test %s\n", flags & RF24_RX_DR ? "passed" : "failed"); } else if (pl_iterator == 2) { - printf(" 'Data Sent' event test %s\n", tx_ds ? "passed" : "failed"); + printf(" 'Data Sent' event test %s\n", flags & RF24_TX_DS ? "passed" : "failed"); } else if (pl_iterator == 4) { - printf(" 'Data Fail' event test %s\n", tx_df ? "passed" : "failed"); + printf(" 'Data Fail' event test %s\n", flags & RF24_TX_DF ? "passed" : "failed"); } got_interrupt = false; // reset this flag to prevent calling this function from loop() wait_for_event = false; // ready to continue with loop() operations diff --git a/examples_pico/streamingData.cpp b/examples_pico/streamingData.cpp index 4d02e1024..8e8d61138 100644 --- a/examples_pico/streamingData.cpp +++ b/examples_pico/streamingData.cpp @@ -110,8 +110,15 @@ void loop() while (i < SIZE) { makePayload(i); // make the payload if (!radio.writeFast(&buffer, SIZE)) { - failures++; - radio.reUseTX(); + uint8_t flags = radio.getStatusFlags(); + if (flags & RF24_TX_DF) { + failures++; + // now we need to reset the tx_df flag and the radio's CE pin. + radio.ce(LOW); + radio.clearStatusFlags(RF24_TX_DF); + radio.ce(HIGH); + } + // else the TX FIFO is full; just continue loop. } else { i++; diff --git a/pyRF24/pyRF24.cpp b/pyRF24/pyRF24.cpp index 197a42a83..92ceeb158 100644 --- a/pyRF24/pyRF24.cpp +++ b/pyRF24/pyRF24.cpp @@ -287,6 +287,14 @@ BOOST_PYTHON_MODULE(RF24) .value("RF24_FIFO_INVALID", RF24_FIFO_INVALID) .export_values(); + bp::enum_("rf24_irq_flags_e") + .value("RF24_TX_DF", RF24_TX_DF) + .value("RF24_TX_DS", RF24_TX_DS) + .value("RF24_RX_DR", RF24_RX_DR) + .value("RF24_IRQ_ALL", RF24_IRQ_ALL) + .value("RF24_IRQ_NONE", RF24_IRQ_NONE) + .export_values(); + // ******************** RF24 class ************************** bp::class_("RF24", bp::init((bp::arg("_cepin"), bp::arg("_cspin")))) #if defined(RF24_LINUX) && !defined(MRAA) @@ -323,6 +331,7 @@ BOOST_PYTHON_MODULE(RF24) .def("powerDown", &RF24::powerDown) .def("powerUp", &RF24::powerUp) .def("printDetails", &RF24::printDetails) + .def("printStatus", &RF24::printStatus) .def("printPrettyDetails", &RF24::printPrettyDetails) .def("sprintfPrettyDetails", &sprintfPrettyDetails_wrap) .def("reUseTX", &RF24::reUseTX) @@ -349,6 +358,12 @@ BOOST_PYTHON_MODULE(RF24) .def("setRadiation", &RF24::setRadiation) .def("txStandBy", (bool(::RF24::*)(::uint32_t, bool))(&RF24::txStandBy), txStandBy_wrap1(bp::args("timeout", "startTx"))) .def("whatHappened", &whatHappened_wrap) + .def("setStatusFlags", (uint8_t(::RF24::*)(void))(&RF24::setStatusFlags)) + .def("setStatusFlags", (uint8_t(::RF24::*)(uint8_t))(&RF24::setStatusFlags), (bp::arg("flags"))) + .def("clearStatusFlags", (uint8_t(::RF24::*)(void))(&RF24::clearStatusFlags)) + .def("clearStatusFlags", (uint8_t(::RF24::*)(uint8_t))(&RF24::clearStatusFlags), (bp::arg("flags"))) + .def("getStatusFlags", &RF24::getStatusFlags) + .def("update", &RF24::update) .def("startConstCarrier", &RF24::startConstCarrier, (bp::arg("level"), bp::arg("channel"))) .def("stopConstCarrier", &RF24::stopConstCarrier) .def("write", &write_wrap1, (bp::arg("buf")))