diff options
Diffstat (limited to '.pio/libdeps/esp32-s3-n16r8/RF24/examples/InterruptConfigure')
| -rw-r--r-- | .pio/libdeps/esp32-s3-n16r8/RF24/examples/InterruptConfigure/InterruptConfigure.ino | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/InterruptConfigure/InterruptConfigure.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/InterruptConfigure/InterruptConfigure.ino new file mode 100644 index 0000000..9d59759 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/InterruptConfigure/InterruptConfigure.ino @@ -0,0 +1,353 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * This example uses Acknowledgement (ACK) payloads attached to ACK packets to + * demonstrate how the nRF24L01's IRQ (Interrupt Request) pin can be + * configured to detect when data is received, or when data has transmitted + * successfully, or when data has failed to transmit. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Monitor to change each node's behavior. + */ +#include <SPI.h> +#include "printf.h" +#include "RF24.h" + +// We will be using the nRF24L01's IRQ pin for this example +#define IRQ_PIN 2 // this needs to be a digital input capable pin +volatile bool got_interrupt = false; // used to signal processing of interrupt +volatile bool wait_for_event = false; // used to wait for an IRQ event to trigger + +#define CE_PIN 7 +#define CSN_PIN 8 +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// Let these addresses be used for the pair +uint8_t address[][6] = { "1Node", "2Node" }; +// It is very helpful to think of an address as a path instead of as +// an identifying device destination + +// to use different addresses on a pair of radios, we need a variable to +// uniquely identify which address this radio will use to transmit +bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + +// Used to control whether this node is sending or receiving +bool role = false; // true = TX node, false = RX node + +// For this example, we'll be using a payload containing +// a string that changes on every transmission. (successful or not) +// Make a couple arrays of payloads & an iterator to traverse them +const uint8_t tx_pl_size = 5; +const uint8_t ack_pl_size = 4; +uint8_t pl_iterator = 0; +// The " + 1" compensates for the c-string's NULL terminating 0 +char tx_payloads[][tx_pl_size + 1] = { "Ping ", "Pong ", "Radio", "1FAIL" }; +char ack_payloads[][ack_pl_size + 1] = { "Yak ", "Back", " ACK" }; + +void interruptHandler(); // prototype to handle IRQ events +void printRxFifo(); // prototype to print RX FIFO with 1 buffer + + +void setup() { + Serial.begin(115200); + while (!Serial) { + // some boards need to wait to ensure access to serial over USB + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + Serial.println(F("radio hardware is not responding!!")); + while (1) {} // hold in infinite loop + } + + // print example's introductory prompt + Serial.println(F("RF24/examples/InterruptConfigure")); + + // To set the radioNumber via the Serial monitor on startup + Serial.println(F("Which radio is this? Enter '0' or '1'. Defaults to '0'")); + while (!Serial.available()) { + // wait for user input + } + char input = Serial.parseInt(); + radioNumber = input == 1; + Serial.print(F("radioNumber = ")); + Serial.println((int)radioNumber); + + // role variable is hardcoded to RX behavior, inform the user of this + Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); + + // setup the IRQ_PIN + pinMode(IRQ_PIN, INPUT); + attachInterrupt(digitalPinToInterrupt(IRQ_PIN), interruptHandler, FALLING); + // IMPORTANT: do not call radio.available() before calling + // radio.whatHappened() when the interruptHandler() is triggered by the + // IRQ pin FALLING event. According to the datasheet, the pipe information + // is unreliable during the IRQ pin FALLING transition. + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // For this example we use acknowledgment (ACK) payloads to trigger the + // IRQ pin when data is received on the TX node. + // to use ACK payloads, we need to enable dynamic payload lengths + radio.enableDynamicPayloads(); // ACK payloads are dynamically sized + + // Acknowledgement packets have no payloads by default. We need to enable + // this feature for all nodes (TX & RX) to use ACK payloads. + radio.enableAckPayload(); + + // set the TX address of the RX node for use on the TX pipe (pipe 0) + radio.stopListening(address[radioNumber]); // put radio in TX mode + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // additional setup specific to the node's RX role + if (!role) { + // setup for RX mode + + // 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 + radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); + + radio.startListening(); // put radio in RX mode + } + + // For debugging info + // printf_begin(); // needed only once for printing details + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data +} + +void loop() { + if (got_interrupt) { + assessInterruptEvent(); + } + + if (role && !wait_for_event) { + + // This device is a TX node. This if block is only triggered when + // NOT waiting for an IRQ event to happen + + if (pl_iterator == 0) { + // Test the "data ready" event with the IRQ pin + + Serial.println(F("\nConfiguring IRQ pin to ignore the 'data sent' event")); + 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.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 + // 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 + if (radio.write(&tx_payloads[pl_iterator], tx_pl_size)) { + if (radio.rxFifoFull()) { + Serial.println(F("RX node's FIFO is full; it is not listening any more")); + } else { + Serial.println("Transmission successful, but the RX node might still be listening."); + } + } else { + Serial.println(F("Transmission failed or timed out. Continuing anyway.")); + radio.flush_tx(); // discard payload(s) that failed to transmit + } + + } else if (pl_iterator == 3) { + // test the "data fail" event with the IRQ pin + + Serial.println(F("\nConfiguring IRQ pin to reflect all events")); + radio.setStatusFlags(RF24_IRQ_ALL); + Serial.println(F(" Pinging inactive RX node for 'data fail' event...")); + } + + if (pl_iterator < 4 && pl_iterator != 2) { + + // IRQ pin is LOW when activated. Otherwise it is always HIGH + // Wait until IRQ pin is activated. + wait_for_event = true; + + // use the non-blocking call to write a payload and begin transmission + // the "false" argument means we are expecting an ACK packet response + radio.startFastWrite(tx_payloads[pl_iterator++], tx_pl_size, false); + + // In this example, the "data fail" event is always configured to + // trigger the IRQ pin active. Because the auto-ACK feature is on by + // default, we don't need a timeout check to prevent an infinite loop. + + } else if (pl_iterator == 4) { + // all IRQ tests are done; flush_tx() and print the ACK payloads for fun + + // CE pin is still HIGH which consumes more power. Example is now idling so... + radio.stopListening(); // ensure CE pin is LOW + // stopListening() also calls flush_tx() when ACK payloads are enabled + + printRxFifo(); + pl_iterator++; + + + // inform user what to do next + Serial.println(F("\n*** PRESS 'T' to restart the transmissions")); + Serial.println(F("*** PRESS 'R' to change to Receive role\n")); + + + } else if (pl_iterator == 2) { + pl_iterator++; // proceed from step 3 to last step (stop at step 4 for readability) + } + + } else if (!role && radio.rxFifoFull()) { + // This device is a RX node: + // wait until RX FIFO is full then stop listening + + delay(100); // let ACK payload finish transmitting + radio.stopListening(); // also discards unused ACK payloads + printRxFifo(); // flush the RX FIFO + + // Fill the TX FIFO with 3 ACK payloads for the first 3 received + // transmissions on pipe 1. + radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); + + delay(100); // let TX node finish its role + radio.startListening(); // We're ready to start over. Begin listening. + + } // role + + if (Serial.available()) { + // change the role via the serial monitor + + char c = toupper(Serial.read()); + if (c == 'T') { + // Become the TX node + if (!role) + Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); + else + Serial.println(F("*** RESTARTING IRQ PIN TEST ***")); + + role = true; + wait_for_event = false; + pl_iterator = 0; // reset the iterator + radio.flush_tx(); // discard any payloads in the TX FIFO + + // startListening() clears the IRQ masks also. This is required for + // continued TX operations when a transmission fails. + radio.stopListening(); // this also discards any unused ACK payloads + + } else if (c == 'R' && role) { + // Become the RX node + Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); + + role = false; + + // 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 + radio.flush_tx(); // make sure there is room for 3 new ACK payloads + radio.flush_rx(); // make sure there is room for 3 incoming payloads + radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); + radio.startListening(); + } + } // Serial.available() +} // loop + + +/** + * when the IRQ pin goes active LOW. + * Here we just tell the main loop() to call `assessInterruptEve4nt()`. + */ +void interruptHandler() { + got_interrupt = true; // forward event handling back to main loop() +} + +/** + * Called when an event has been triggered. + * Here, we want to verify the expected IRQ flag has been asserted. + */ +void assessInterruptEvent() { + // print IRQ status and all masking flags' states + + Serial.println(F("\tIRQ pin is actively LOW")); // show that this function was called + delayMicroseconds(250); + uint8_t 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) + + Serial.print(F("\tdata_sent: ")); + Serial.print((flags & RF24_TX_DS) > 0); // print "data sent" flag state + Serial.print(F(", data_fail: ")); + Serial.print((flags & RF24_TX_DF) > 0); // print "data fail" flag state + Serial.print(F(", data_ready: ")); + Serial.println((flags & RF24_RX_DR) > 0); // print "data ready" flag state + + 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(flags & RF24_RX_DR ? F("passed") : F("failed")); + } else if (pl_iterator == 2) { + Serial.print(F(" 'Data Sent' event test ")); + Serial.println(flags & RF24_TX_DS ? F("passed") : F("failed")); + } else if (pl_iterator == 4) { + Serial.print(F(" 'Data Fail' event test ")); + 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 +} + +/** + * Print the entire RX FIFO with one buffer. This will also flush the RX FIFO. + * Remember that the payload sizes are declared as tx_pl_size and ack_pl_size. + */ +void printRxFifo() { + if (radio.available()) { // if there is data in the RX FIFO + // to flush the data from the RX FIFO, we'll fetch it all using 1 buffer + + uint8_t pl_size = !role ? tx_pl_size : ack_pl_size; + char rx_fifo[pl_size * 3 + 1]; // RX FIFO is full & we know ACK payloads' size + if (radio.rxFifoFull()) { + rx_fifo[pl_size * 3] = 0; // add a NULL terminating char to use as a c-string + radio.read(&rx_fifo, pl_size * 3); // this clears the RX FIFO (for this example) + } else { + uint8_t i = 0; + while (radio.available()) { + radio.read(&rx_fifo + (i * pl_size), pl_size); + i++; + } + rx_fifo[i * pl_size] = 0; // add a NULL terminating char to use as a c-string + } + Serial.print(F("Complete RX FIFO: ")); + Serial.println(rx_fifo); // print the entire RX FIFO with 1 buffer + } +} |
