diff options
| author | krolyxon <me@krolyxon.com> | 2026-06-08 23:10:46 +0530 |
|---|---|---|
| committer | krolyxon <me@krolyxon.com> | 2026-06-08 23:10:46 +0530 |
| commit | 3120783000d0025b183b0397acaa8b769499eb38 (patch) | |
| tree | 1c4f93be213f1b1d48f59e554562d847b4e7c25e /.pio/libdeps/esp32-s3-n16r8/RF24/examples | |
Initial gh-pages firmware hosting
Diffstat (limited to '.pio/libdeps/esp32-s3-n16r8/RF24/examples')
24 files changed, 4682 insertions, 0 deletions
diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/.clang-format b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/.clang-format new file mode 100644 index 0000000..f95490c --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/.clang-format @@ -0,0 +1,145 @@ +# See: https://releases.llvm.org/11.0.1/tools/clang/docs/ClangFormatStyleOptions.html +--- +Language: Cpp +# LLVM is the default style setting, used when a configuration option is not set here +BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveBitFields: false +AlignConsecutiveDeclarations: false +AlignConsecutiveMacros: false +AlignEscapedNewlines: DontAlign +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Always +AllowShortLambdasOnASingleLine: Empty +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: No +BinPackArguments: true +BinPackParameters: true +# Only used when "BreakBeforeBraces" set to "Custom" +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + #AfterObjCDeclaration: + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +# Java-specific +#BreakAfterJavaFieldAnnotations: +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: false +ColumnLimit: 0 +# "" matches none +CommentPragmas: "" +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: false +DeriveLineEnding: true +DerivePointerAlignment: true +DisableFormat: false +# Docs say "Do not use this in config files". The default (LLVM 11.0.1) is "false". +#ExperimentalAutoDetectBinPacking: +FixNamespaceComments: false +ForEachMacros: [] +IncludeBlocks: Preserve +IncludeCategories: [] +# "" matches none +IncludeIsMainRegex: "" +IncludeIsMainSourceRegex: "" +IndentCaseBlocks: true +IndentCaseLabels: true +IndentExternBlock: Indent +IndentGotoLabels: false +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +# Java-specific +#JavaImportGroups: +# JavaScript-specific +#JavaScriptQuotes: +#JavaScriptWrapImports +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: "" +MacroBlockEnd: "" +# Set to a large number to effectively disable +MaxEmptyLinesToKeep: 100000 +NamespaceIndentation: None +NamespaceMacros: [] +# Objective C-specific +#ObjCBinPackProtocolList: +#ObjCBlockIndentWidth: +#ObjCBreakBeforeNestedBlockParam: +#ObjCSpaceAfterProperty: +#ObjCSpaceBeforeProtocolList +PenaltyBreakAssignment: 1 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 1 +PenaltyBreakFirstLessLess: 1 +PenaltyBreakString: 1 +PenaltyBreakTemplateDeclaration: 1 +PenaltyExcessCharacter: 1 +PenaltyReturnTypeOnItsOwnLine: 1 +# Used as a fallback if alignment style can't be detected from code (DerivePointerAlignment: true) +PointerAlignment: Right +RawStringFormats: [] +ReflowComments: false +SortIncludes: false +SortUsingDeclarations: false +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +StatementMacros: [] +TabWidth: 2 +TypenameMacros: [] +# Default to LF if line endings can't be detected from the content (DeriveLineEnding). +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: [] diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/AcknowledgementPayloads/AcknowledgementPayloads.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/AcknowledgementPayloads/AcknowledgementPayloads.ino new file mode 100644 index 0000000..af0d7db --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/AcknowledgementPayloads/AcknowledgementPayloads.ino @@ -0,0 +1,207 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with Acknowledgement (ACK) payloads attached to ACK packets. + * + * 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" + +#define CE_PIN 7 +#define CSN_PIN 8 +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// an identifying device destination +// 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 role, false = RX role + +// For this example, we'll be using a payload containing +// a string & an integer number that will be incremented +// on every successful transmission. +// Make a data structure to store the entire payload of different datatypes +struct PayloadStruct { + char message[7]; // only using 6 characters for TX & ACK payloads + uint8_t counter; +}; +PayloadStruct payload; + +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/AcknowledgementPayloads")); + + // 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")); + + // 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. + + // to use ACK payloads, we need to enable dynamic payload lengths (for all nodes) + 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 role + if (role) { + // setup the TX payload + memcpy(payload.message, "Hello ", 6); // set the payload message + } else { + // setup the ACK payload & load the first response into the FIFO + + memcpy(payload.message, "World ", 6); // set the payload message + // load the payload for the first received transmission on pipe 0 + radio.writeAckPayload(1, &payload, sizeof(payload)); + + 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 (role) { + // This device is a TX node + + unsigned long start_timer = micros(); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + unsigned long end_timer = micros(); // end the timer + + if (report) { + Serial.print(F("Transmission successful! ")); // payload was delivered + Serial.print(F("Time to transmit = ")); + Serial.print(end_timer - start_timer); // print the timer result + Serial.print(F(" us. Sent: ")); + Serial.print(payload.message); // print the outgoing message + Serial.print(payload.counter); // print the outgoing counter + uint8_t pipe; + if (radio.available(&pipe)) { // is there an ACK payload? grab the pipe number that received it + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming ACK payload + Serial.print(F(" Received ")); + Serial.print(radio.getDynamicPayloadSize()); // print incoming payload size + Serial.print(F(" bytes on pipe ")); + Serial.print(pipe); // print pipe number that received the ACK + Serial.print(F(": ")); + Serial.print(received.message); // print incoming message + Serial.println(received.counter); // print incoming counter + + // save incoming counter & increment for next outgoing + payload.counter = received.counter + 1; + + } else { + Serial.println(F(" Received: an empty ACK packet")); // empty ACK packet received + } + + + } else { + Serial.println(F("Transmission failed or timed out")); // payload was not delivered + } + + // to make this example readable in the serial monitor + delay(1000); // slow transmissions down by 1 second + + } else { + // This device is a RX node + + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that received it + uint8_t bytes = radio.getDynamicPayloadSize(); // get the size of the payload + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming payload + Serial.print(F("Received ")); + Serial.print(bytes); // print the size of the payload + Serial.print(F(" bytes on pipe ")); + Serial.print(pipe); // print the pipe number + Serial.print(F(": ")); + Serial.print(received.message); // print incoming message + Serial.print(received.counter); // print incoming counter + Serial.print(F(" Sent: ")); + Serial.print(payload.message); // print outgoing message + Serial.println(payload.counter); // print outgoing counter + + // save incoming counter & increment for next outgoing + payload.counter = received.counter + 1; + // load the payload for the first received transmission on pipe 0 + radio.writeAckPayload(1, &payload, sizeof(payload)); + } + } // role + + if (Serial.available()) { + // change the role via the serial monitor + + char c = toupper(Serial.read()); + if (c == 'T' && !role) { + // Become the TX node + + role = true; + Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); + + memcpy(payload.message, "Hello ", 6); // change payload message + radio.stopListening(); // this also discards any unused ACK payloads + + } else if (c == 'R' && role) { + // Become the RX node + + role = false; + Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); + memcpy(payload.message, "World ", 6); // change payload message + + // load the payload for the first received transmission on pipe 0 + radio.writeAckPayload(1, &payload, sizeof(payload)); + radio.startListening(); + } + } +} // loop diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/GettingStarted/GettingStarted.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/GettingStarted/GettingStarted.ino new file mode 100644 index 0000000..8273457 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/GettingStarted/GettingStarted.ino @@ -0,0 +1,154 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from 1 nRF24L01 transceiver to another. + * + * 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" + +#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 role, false = RX role + +// For this example, we'll be using a payload containing +// a single float number that will be incremented +// on every successful transmission +float payload = 0.0; + +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/GettingStarted")); + + // 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")); + + // 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. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // float datatype occupies 4 bytes + + // 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) { + 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 + +} // setup + +void loop() { + + if (role) { + // This device is a TX node + + unsigned long start_timer = micros(); // start the timer + bool report = radio.write(&payload, sizeof(float)); // transmit & save the report + unsigned long end_timer = micros(); // end the timer + + if (report) { + Serial.print(F("Transmission successful! ")); // payload was delivered + Serial.print(F("Time to transmit = ")); + Serial.print(end_timer - start_timer); // print the timer result + Serial.print(F(" us. Sent: ")); + Serial.println(payload); // print payload sent + payload += 0.01; // increment float payload + } else { + Serial.println(F("Transmission failed or timed out")); // payload was not delivered + } + + // to make this example readable in the serial monitor + delay(1000); // slow transmissions down by 1 second + + } else { + // This device is a RX node + + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that received it + uint8_t bytes = radio.getPayloadSize(); // get the size of the payload + radio.read(&payload, bytes); // fetch payload from FIFO + Serial.print(F("Received ")); + Serial.print(bytes); // print the size of the payload + Serial.print(F(" bytes on pipe ")); + Serial.print(pipe); // print the pipe number + Serial.print(F(": ")); + Serial.println(payload); // print the payload's value + } + } // role + + if (Serial.available()) { + // change the role via the serial monitor + + char c = toupper(Serial.read()); + if (c == 'T' && !role) { + // Become the TX node + + role = true; + Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); + radio.stopListening(); + + } else if (c == 'R' && role) { + // Become the RX node + + role = false; + Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); + radio.startListening(); + } + } + +} // loop 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 + } +} diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/ManualAcknowledgements/ManualAcknowledgements.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/ManualAcknowledgements/ManualAcknowledgements.ino new file mode 100644 index 0000000..e4fbb38 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/ManualAcknowledgements/ManualAcknowledgements.ino @@ -0,0 +1,222 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with manually transmitted (non-automatic) Acknowledgement (ACK) payloads. + * This example still uses ACK packets, but they have no payloads. Instead the + * acknowledging response is sent with `write()`. This tactic allows for more + * updated acknowledgement payload data, where actual ACK payloads' data are + * outdated by 1 transmission because they have to loaded before receiving a + * transmission. + * + * 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" + +#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 & an integer number that will be incremented +// on every successful transmission. +// Make a data structure to store the entire payload of different datatypes +struct PayloadStruct { + char message[7]; // only using 6 characters for TX & RX payloads + uint8_t counter; +}; +PayloadStruct payload; + +void setup() { + + // append a NULL terminating character for printing as a c-string + payload.message[6] = 0; + + 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/ManualAcknowledgements")); + + // 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")); + + // 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. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // char[7] & uint8_t datatypes occupy 8 bytes + + // 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 + + if (role) { + // setup the TX node + + memcpy(payload.message, "Hello ", 6); // set the outgoing message + } else { + // setup the RX node + + memcpy(payload.message, "World ", 6); // set the outgoing message + 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 + +} // setup() + +void loop() { + + if (role) { + // This device is a TX node + + unsigned long start_timer = micros(); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + + if (report) { + // transmission successful; wait for response and print results + + radio.startListening(); // put in RX mode + unsigned long start_timeout = millis(); // timer to detect timeout + while (!radio.available()) { // wait for response + if (millis() - start_timeout > 200) // only wait 200 ms + break; + delayMicroseconds(200); // relax probing of available() + } + unsigned long end_timer = micros(); // end the timer + radio.stopListening(); // put back in TX mode + + // print summary of transactions + Serial.print(F("Transmission successful!")); // payload was delivered + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload received + Serial.print(F(" Round-trip delay: ")); + Serial.print(end_timer - start_timer); // print the timer result + Serial.print(F(" us. Sent: ")); + Serial.print(payload.message); // print the outgoing payload's message + Serial.print(payload.counter); // print outgoing payload's counter + PayloadStruct received; + radio.read(&received, sizeof(received)); // get payload from RX FIFO + Serial.print(F(" Received ")); + Serial.print(radio.getPayloadSize()); // print the size of the payload + Serial.print(F(" bytes on pipe ")); + Serial.print(pipe); // print the pipe number + Serial.print(F(": ")); + Serial.print(received.message); // print the incoming payload's message + Serial.println(received.counter); // print the incoming payload's counter + payload.counter = received.counter; // save incoming counter for next outgoing counter + } else { + Serial.println(F(" Received no response.")); // no response received + } + } else { + Serial.println(F("Transmission failed or timed out")); // payload was not delivered + } // report + + // to make this example readable in the serial monitor + delay(1000); // slow transmissions down by 1 second + + } else { + // This device is a RX node + + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that received it + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming payload + payload.counter = received.counter + 1; // increment incoming counter for next outgoing response + + // transmit response & save result to `report` + radio.stopListening(); // put in TX mode + + radio.writeFast(&payload, sizeof(payload)); // load response to TX FIFO + bool report = radio.txStandBy(150); // keep retrying for 150 ms + + radio.startListening(); // put back in RX mode + + // print summary of transactions + Serial.print(F("Received ")); + Serial.print(radio.getPayloadSize()); // print the size of the payload + Serial.print(F(" bytes on pipe ")); + Serial.print(pipe); // print the pipe number + Serial.print(F(": ")); + Serial.print(received.message); // print incoming message + Serial.print(received.counter); // print incoming counter + + if (report) { + Serial.print(F(" Sent: ")); + Serial.print(payload.message); // print outgoing message + Serial.println(payload.counter); // print outgoing counter + } else { + Serial.println(" Response failed."); // failed to send response + } + } + } // role + + if (Serial.available()) { + // change the role via the serial monitor + + char c = toupper(Serial.read()); + if (c == 'T' && !role) { + // Become the TX node + + role = true; + memcpy(payload.message, "Hello ", 6); // set the outgoing message + Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); + radio.stopListening(); // put in TX mode + + } else if (c == 'R' && role) { + // Become the RX node + + role = false; + memcpy(payload.message, "World ", 6); // set the response message + Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); + radio.startListening(); // put in RX mode + } + } +} // loop diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/MulticeiverDemo/MulticeiverDemo.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/MulticeiverDemo/MulticeiverDemo.ino new file mode 100644 index 0000000..99295bf --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/MulticeiverDemo/MulticeiverDemo.ino @@ -0,0 +1,194 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty 2bndy5 + */ + +/** + * A simple example of sending data from as many as 6 nRF24L01 transceivers to + * 1 receiving transceiver. This technique is trademarked by + * Nordic Semiconductors as "MultiCeiver". + * + * This example was written to be used on up to 6 devices acting as TX nodes & + * only 1 device acting as the RX node (that's a maximum of 7 devices). + * Use the Serial Monitor to change each node's behavior. + */ +#include <SPI.h> +#include "printf.h" +#include "RF24.h" + +#define CE_PIN 7 +#define CSN_PIN 8 +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// For this example, we'll be using 6 addresses; 1 for each TX node +// It is very helpful to think of an address as a path instead of as +// an identifying device destination +// Notice that the last byte is the only byte that changes in the last 5 +// addresses. This is a limitation of the nRF24L01 transceiver for pipes 2-5 +// because they use the same first 4 MSBytes from pipe 1. +uint8_t address[6][5] = { { 0x78, 0x78, 0x78, 0x78, 0x78 }, + { 0xF1, 0xB6, 0xB5, 0xB4, 0xB3 }, + { 0xCD, 0xB6, 0xB5, 0xB4, 0xB3 }, + { 0xA3, 0xB6, 0xB5, 0xB4, 0xB3 }, + { 0x0F, 0xB6, 0xB5, 0xB4, 0xB3 }, + { 0x05, 0xB6, 0xB5, 0xB4, 0xB3 } }; + +// role variable is used to control whether this node is sending or receiving +char role = 'R'; // integers 0-5 = TX node; character 'R' or integer 82 = RX node + +// For this example, we'll be using a payload containing +// a node ID number and a single integer number that will be incremented +// on every successful transmission. +// Make a data structure to use as a payload. +struct PayloadStruct { + unsigned long nodeID; + unsigned long payloadID; +}; +PayloadStruct payload; + +// This example uses all 6 pipes to receive while TX nodes only use 2 pipes +// To make this easier we'll use a function to manage the addresses, and the +// payload's nodeID +void setRole(); // declare a prototype; definition is found after the loop() + +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/MulticeiverDemo")); + Serial.println(F("*** Enter a number between 0 and 5 (inclusive) to change")); + Serial.println(F(" the identifying node number that transmits.")); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity of + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // 2x int datatype occupy 8 bytes + + // Set the pipe addresses accordingly. This function additionally also + // calls startListening() or stopListening() and sets the payload's nodeID + setRole(); + + // 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 + +} // setup() + +void loop() { + + if (role <= 53) { + // This device is a TX node + + unsigned long start_timer = micros(); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + unsigned long end_timer = micros(); // end the timer + + if (report) { + // payload was delivered + + Serial.print(F("Transmission of payloadID ")); + Serial.print(payload.payloadID); // print payloadID + Serial.print(F(" as node ")); + Serial.print(payload.nodeID); // print nodeID + Serial.print(F(" successful!")); + Serial.print(F(" Time to transmit: ")); + Serial.print(end_timer - start_timer); // print the timer result + Serial.println(F(" us")); + } else { + Serial.println(F("Transmission failed or timed out")); // payload was not delivered + } + payload.payloadID++; // increment payload number + + // to make this example readable in the serial monitor + delay(1000); // slow transmissions down by 1 second + + } else if (role == 'R') { + // This device is the RX node + + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that received it + uint8_t bytes = radio.getPayloadSize(); // get the size of the payload + radio.read(&payload, bytes); // fetch payload from FIFO + Serial.print(F("Received ")); + Serial.print(bytes); // print the size of the payload + Serial.print(F(" bytes on pipe ")); + Serial.print(pipe); // print the pipe number + Serial.print(F(" from node ")); + Serial.print(payload.nodeID); // print the payload's origin + Serial.print(F(". PayloadID: ")); + Serial.println(payload.payloadID); // print the payload's number + } + } // role + + if (Serial.available()) { + // change the role via the serial monitor + + char c = Serial.read(); + if (toupper(c) == 'R' && role <= 53) { + // Become the RX node + + role = 'R'; + Serial.println(F("*** CHANGING ROLE TO RECEIVER ***")); + Serial.println(F("--- Enter a number between 0 and 5 (inclusive) to act as")); + Serial.println(F(" a unique node number that transmits to the RX node.")); + setRole(); // change address on all pipes to TX nodes + + } else if (c >= 48 && c <= 53 && c != role) { + // Become a TX node with identifier 'c' + + role = c - 48; + Serial.print(F("*** CHANGING ROLE TO NODE ")); + Serial.print(c); + Serial.println(F(" ***")); + Serial.println(F("--- Enter a number between 0 and 5 (inclusive) to change")); + Serial.println(F(" the identifying node number that transmits.")); + Serial.println(F("--- PRESS 'R' to act as the RX node.")); + setRole(); // change address on pipe 0 to the RX node + } + } + +} // loop + +void setRole() { + if (role == 'R') { + // For the RX node + + // Set the addresses for all pipes to TX nodes + for (uint8_t i = 0; i < 6; ++i) + radio.openReadingPipe(i, address[i]); + + radio.startListening(); // put radio in RX mode + + } else { + // For the TX node + + // set the payload's nodeID & reset the payload's identifying number + payload.nodeID = role; + payload.payloadID = 0; + + // set the TX address of the RX node for use on the TX pipe (pipe 0) + radio.stopListening(address[role]); // put radio in TX mode + + // According to the datasheet, the auto-retry features's delay value should + // be "skewed" to allow the RX node to receive 1 transmission at a time. + // So, use varying delay between retry attempts and 15 (at most) retry attempts + radio.setRetries(((role * 3) % 12) + 3, 15); // maximum value is 15 for both args + } +} // setRole diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/StreamingData/StreamingData.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/StreamingData/StreamingData.ino new file mode 100644 index 0000000..e4a4bc6 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/StreamingData/StreamingData.ino @@ -0,0 +1,192 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty 2bndy5 + */ + +/** + * A simple example of streaming data from 1 nRF24L01 transceiver to another. + * + * 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" + +#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; // 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 sending 32 payloads each containing +// 32 bytes of data that looks like ASCII art when printed to the serial +// monitor. The TX node and RX node needs only a single 32 byte buffer. +#define SIZE 32 // this is the maximum for this example. (minimum is 1) +char buffer[SIZE + 1]; // for the RX node +uint8_t counter = 0; // for counting the number of received payloads +void makePayload(uint8_t); // prototype to construct a payload dynamically + + +void setup() { + + buffer[SIZE] = 0; // add a NULL terminating character (for easy printing) + + 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/StreamingData")); + + // 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")); + + // 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. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit + radio.setPayloadSize(SIZE); // default value is the maximum 32 bytes + + // 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) { + 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 + +} // setup() + + +void loop() { + + if (role) { + // This device is a TX node + + radio.flush_tx(); + uint8_t i = 0; + uint8_t failures = 0; + unsigned long start_timer = micros(); // start the timer + while (i < SIZE) { + makePayload(i); // make the payload + if (!radio.writeFast(&buffer, SIZE)) { + 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++; + } + + if (failures >= 100) { + Serial.print(F("Too many failures detected. Aborting at payload ")); + Serial.println(buffer[0]); + break; + } + } + unsigned long end_timer = micros(); // end the timer + + Serial.print(F("Time to transmit = ")); + Serial.print(end_timer - start_timer); // print the timer result + Serial.print(F(" us with ")); + Serial.print(failures); // print failures detected + Serial.println(F(" failures detected")); + + // to make this example readable in the serial monitor + delay(1000); // slow transmissions down by 1 second + + } else { + // This device is a RX node + + if (radio.available()) { // is there a payload? + radio.read(&buffer, SIZE); // fetch payload from FIFO + Serial.print(F("Received: ")); + Serial.print(buffer); // print the payload's value + Serial.print(F(" - ")); + Serial.println(counter++); // print the received counter + } + } // role + + if (Serial.available()) { + // change the role via the serial monitor + + char c = toupper(Serial.read()); + if (c == 'T' && !role) { + // Become the TX node + + role = true; + counter = 0; //reset the RX node's counter + Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); + radio.stopListening(); + + } else if (c == 'R' && role) { + // Become the RX node + + role = false; + Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); + radio.startListening(); + } + } + +} // loop + + +void makePayload(uint8_t i) { + // Make a single payload based on position in stream. + // This example employs function to save memory on certain boards. + + // let the first character be an identifying alphanumeric prefix + // this lets us see which payload didn't get received + buffer[0] = i + (i < 26 ? 65 : 71); + for (uint8_t j = 0; j < SIZE - 1; ++j) { + char chr = j >= (SIZE - 1) / 2 + abs((SIZE - 1) / 2 - i); + chr |= j < (SIZE - 1) / 2 - abs((SIZE - 1) / 2 - i); + buffer[j + 1] = chr + 48; + } +} diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/encodeRadioDetails/encodeRadioDetails.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/encodeRadioDetails/encodeRadioDetails.ino new file mode 100644 index 0000000..6aee593 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/encodeRadioDetails/encodeRadioDetails.ino @@ -0,0 +1,123 @@ +/* + See documentation at https://nRF24.github.io/RF24 + See License information at root directory of this library + Authors: Brendan Doherty (2bndy5), Douglas Quigg (dstroy0) +*/ + +/** + A simple example of getting debug info from the nRF24L01 transceiver. + + This example was written to demonstrate alternative methods to get debugging data. + 1. radio.encodeRadioDetails() will provide a data dump of all the nRF24L01's registers. + 2. radio.sprintfPrettyDetails() will behave similarly to printPrettyDetails(), but it + outputs to a char buffer that can be printed to any Serial (or other output) stream. + + Additionally, this example will show all default configuration values. +*/ +#include <SPI.h> +#include "RF24.h" + +#define CE_PIN 7 +#define CSN_PIN 8 +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +/* + For this example, we'll be using a data buffer containing + radio details encoded with RF24::encodeRadioDetails(). + It is meant to be decoded by an external program. + + There is a python script located in this example's folder that + will take a space-delimited string of hexadecimal characters and + decode then print it out as human readable information. +*/ +uint8_t encoded_details[43] = { 0 }; + +// Use this function to print out the encoded_details as a +// space-delimited string of hexadecimal characters. +void dumpRegData() { + for (uint8_t i = 0; i < 43; ++i) { + Serial.print(encoded_details[i], HEX); + if (i < 42) + Serial.print(F(" ")); + } +} + +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/encodedRadioDetails")); + + Serial.println(F("Press any key to show debugging information")); + while (!Serial.available()) { + // wait for user input + } + + // For debugging info + char *debug_info = new char[870]; + uint16_t str_len = radio.sprintfPrettyDetails(debug_info); + Serial.println(debug_info); + Serial.print(F("\nThe above output used ")); + Serial.print(str_len); + Serial.println(F(" characters.")); + + // encoded_details is NOT human readable. + // encodeRadioDetails() is very small when used on its own because it puts debugging information into a byte array + // No printf() support needed because it doesn't use an output stream. + radio.encodeRadioDetails(encoded_details); + Serial.println(F("\nhexadecimal dump of all registers:")); + dumpRegData(); + + Serial.println(F("\n\nCopy the above string of hexadecimal characters (including spaces).")); + Serial.print(F("Then paste it into a terminal using the print_details.py located in")); + Serial.print(F(" this example's folder. Like so:\npython print_details.py \"")); + dumpRegData(); + Serial.println(F("\"\n***You may need to use 'python3' (without quotes) on Linux")); +} // setup + +/* Registers corresponding to index of encoded_details array + 0: NRF_CONFIG + 1: EN_AA + 2: EN_RXADDR + 3: SETUP_AW + 4: SETUP_RETR + 5: RF_CH + 6: RF_SETUP + 7: NRF_STATUS + 8: OBSERVE_TX + 9: CD (aka RPD) + 10-14: RX_ADDR_P0 + 15-19: RX_ADDR_P1 + 20: RX_ADDR_P2 + 21: RX_ADDR_P3 + 22: RX_ADDR_P4 + 23: RX_ADDR_P5 + 24-28: TX_ADDR + 29: RX_PW_P0 + 30: RX_PW_P1 + 31: RX_PW_P2 + 32: RX_PW_P3 + 33: RX_PW_P4 + 34: RX_PW_P5 + 35: FIFO_STATUS + 36: DYNPD + 37: FEATURE + 38-39: ce_pin + 40-41: csn_pin + 42: SPI speed MHz | (isPlusVariant << 4) +*/ + +void loop() { + // Nothing to do here. We did it all at the end of setup() +} diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/encodeRadioDetails/print_details.py b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/encodeRadioDetails/print_details.py new file mode 100644 index 0000000..2d09e2c --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/encodeRadioDetails/print_details.py @@ -0,0 +1,196 @@ +"""A simple script to take all data dumped from the nRF24L01 registers and +output it in human readable form. + +Example usage: + print_details.py "0e 3f 02 03 00 02 00 0e" + +Notes: + * The radio's power state is represented under the assumption that + the radio's CE pin is inactive low. +""" +# pylint: disable=consider-using-f-string +import struct +import argparse + + +def hex_str_to_bytes(s_in: str) -> bytes: + """Used to convert a string from CLI to a bytearray object. + + .. warning:: This function assumes that the string consists of only + hexadecimal characters. + """ + return bytes([int(i, 16) for i in s_in.split()]) + + +argparser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, +) +argparser.add_argument( + "buffer", + type=hex_str_to_bytes, + help="The encoded buffer from the Arduino Serial Monitor. The string passed is " + "expected to contain only hexadecimal digits. It should be 38 words long " + "(separated by spaces).", +) + + +def address_repr(buf, reverse: bool = True, delimit: str = "") -> str: + """Convert a buffer into a hexadecimal string.""" + order = range(len(buf) - 1, -1, -1) if reverse else range(len(buf)) + return delimit.join(["%02X" % buf[byte] for byte in order]) + + +# pylint: disable=too-many-locals,too-many-statements +def print_details(encoded_buf: bytearray): + """This debugging function outputs all details about the nRF24L01.""" + # declare sequences + pipes = [bytearray(5)] * 2 + [0] * 4 + pl_len = [0] * 6 + + # unpack bytearray + ( + config, # 0x00 + auto_ack, # 0x01 + open_pipes, # 0x02 + addr_len, # 0x03 + retry_setup, # 0x04 + channel, # 0x05 + rf_setup, # 0x06 + status, # 0x07 + observer, # 0x08 + rpd, # 0x09 + ) = struct.unpack("10B", encoded_buf[:10]) + pipes[0] = encoded_buf[10:15] # 0x0A + pipes[1] = encoded_buf[15:20] # 0x0B + ( + pipes[2], # 0x0C + pipes[3], # 0x0D + pipes[4], # 0x0E + pipes[5], # 0x0F + ) = struct.unpack("4B", encoded_buf[20:24]) + tx_address = encoded_buf[24:29] # 0x10 + ( + pl_len[0], # 0x11 + pl_len[1], # 0x12 + pl_len[2], # 0x13 + pl_len[3], # 0x14 + pl_len[4], # 0x15 + pl_len[5], # 0x16 + fifo, # 0x17 + dyn_pl, # 0x1C + features, # 0x1D + ) = struct.unpack("9B", encoded_buf[29:38]) + ce_pin, csn_pin, spi_speed = struct.unpack(">2H1B", encoded_buf[38:44]) + + # do some deciphering arithmetic + addr_len += 2 + crc = (2 if config & 4 else 1) if auto_ack else max(0, ((config & 0x0C) >> 2) - 1) + d_rate = rf_setup & 0x28 + d_rate = (2 if d_rate == 8 else 250) if d_rate else 1 + pa_level = (3 - ((rf_setup & 6) >> 1)) * -6 + pa_level = ( + "MIN" + if pa_level == -18 + else ("LOW" if pa_level == -12 else ("HIGH" if pa_level == -6 else "MAX")) + ) + dyn_p = ( + ("_Enabled" if dyn_pl else "Disabled") + if dyn_pl == 0x3F or not dyn_pl + else "0b" + "0" * (8 - len(bin(dyn_pl))) + bin(dyn_pl)[2:] + ) + auto_ack = ( + ("Enabled" if auto_ack else "Disabled") + if auto_ack == 0x3F or not auto_ack + else "0b" + "0" * (8 - len(bin(auto_ack))) + bin(auto_ack)[2:] + ) + pwr = "Standby" if config & 2 else "Off" + is_plus_variant = bool(spi_speed >> 4) + spi_speed = spi_speed & 0xF + + # print it all out + print("CE pin____________________{}".format(ce_pin)) + print("CSN pin___________________{}".format(csn_pin)) + print("SPI speed_________________{} MHz".format(spi_speed)) + print("Is a plus variant_________{}".format(is_plus_variant)) + print( + "Channel___________________{}".format(channel), + "~ {} GHz".format((channel + 2400) / 1000), + ) + print( + "RF Data Rate______________{}".format(d_rate), + "Mbps" if d_rate != 250 else "Kbps", + ) + print("RF Power Amplifier________PA_{}".format(pa_level)) + print( + "RF Low Noise Amplifier____{}abled".format( + "En" if bool(rf_setup & 1) else "Dis" + ) + ) + print("CRC Length________________{} bits".format(crc * 8)) + print("Address length____________{} bytes".format(addr_len)) + print("TX Payload lengths________{} bytes".format(pl_len[0])) + print( + "Auto retry delay__________{} microseconds".format( + ((retry_setup & 0xF0) >> 4) * 250 + 250 + ) + ) + print("Auto retry attempts_______{} maximum".format(retry_setup & 0x0F)) + print("Re-use TX FIFO____________{}".format(bool(fifo & 64))) + print("Received Power Detected___{}".format(bool(rpd))) + print( + "Packets lost on current channel_____________________{}".format(observer >> 4) + ) + print( + "Retry attempts made for last transmission___________{}".format(observer & 0xF) + ) + print( + "IRQ on Data Ready__{}abled".format("Dis" if config & 64 else "_En"), + " Data Ready___________{}".format(bool(status & 0x40)), + ) + print( + "IRQ on Data Sent___{}abled".format("Dis" if config & 32 else "_En"), + " Data Sent____________{}".format(bool(status & 0x20)), + ) + print( + "IRQ on Data Fail___{}abled".format("Dis" if config & 16 else "_En"), + " Data Failed__________{}".format(bool(status & 0x10)), + ) + print( + "TX FIFO full__________{}e".format("_Tru" if fifo & 0x20 else "Fals"), + " TX FIFO empty________{}".format(bool(fifo & 0x10)), + ) + print( + "RX FIFO full__________{}e".format("_Tru" if fifo & 2 else "Fals"), + " RX FIFO empty________{}".format(bool(fifo & 1)), + ) + print( + "Multicast__________{}ed Custom ACK Payload___{}abled".format( + "_Allow" if features & 1 else "Disabl", + "En" if features & 2 else "Dis", + ), + ) + print("Dynamic Payloads___{} Auto Acknowledgment__{}".format(dyn_p, auto_ack)) + print( + "Primary Mode_____________{}X".format("R" if config & 1 else "T"), + " Power Mode___________{}".format(pwr), + ) + print("TX address____________ 0x{}".format(address_repr(tx_address))) + for i in range(6): + is_open = open_pipes & (1 << i) + address = pipes[i] if i < 2 else bytes([pipes[i]]) + pipes[1][1:] + print( + "Pipe {} ({}) bound: 0x{}".format( + i, " open " if is_open else "closed", address_repr(address) + ), + ) + if is_open and not dyn_pl & (1 << i): + print("\t\texpecting {} byte static payloads".format(pl_len[i])) + + +# pylint: enable=too-many-locals,too-many-statements + + +if __name__ == "__main__": + args = argparser.parse_args() + print_details(args.buffer) diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/GettingStarted_HandlingFailures/GettingStarted_HandlingFailures.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/GettingStarted_HandlingFailures/GettingStarted_HandlingFailures.ino new file mode 100644 index 0000000..1b6695f --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/GettingStarted_HandlingFailures/GettingStarted_HandlingFailures.ino @@ -0,0 +1,217 @@ + +/* + Getting Started example sketch for nRF24L01+ radios + This is a very basic example of how to send data from one node to another + but modified to include failure handling. + + The nrf24l01+ radios are fairly reliable devices, but on breadboards etc, with inconsistent wiring, failures may + occur randomly after many hours to days or weeks. This sketch demonstrates how to handle the various failures and + keep the radio operational. + + The three main failure modes of the radio include: + Writing to radio: Radio unresponsive - Fixed internally by adding a timeout to the internal write functions in RF24 (failure handling) + Reading from radio: Available returns true always - Fixed by adding a timeout to available functions by the user. This is implemented internally in RF24Network. + Radio configuration settings are lost - Fixed by monitoring a value that is different from the default, and re-configuring the radio if this setting reverts to the default. + + The printDetails output should appear as follows for radio #0: + + STATUS = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0 + RX_ADDR_P0-1 = 0x65646f4e31 0x65646f4e32 + RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6 + TX_ADDR = 0x65646f4e31 + RX_PW_P0-6 = 0x20 0x20 0x00 0x00 0x00 0x00 + EN_AA = 0x3f + EN_RXADDR = 0x02 + RF_CH = 0x4c + RF_SETUP = 0x03 + CONFIG = 0x0f + DYNPD/FEATURE = 0x00 0x00 + Data Rate = 1MBPS + Model = nRF24L01+ + CRC Length = 16 bits + PA Power = PA_LOW + + Users can use this sketch to troubleshoot radio module wiring etc. as it makes the radios hot-swappable + + Updated: 2019 by TMRh20 +*/ + +#include <SPI.h> +#include "RF24.h" +#include "printf.h" + +/****************** User Config ***************************/ +/*** Set this radio as radio number 0 or 1 ***/ +bool radioNumber = 0; + +/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ +RF24 radio(7, 8); +/**********************************************************/ + +byte addresses[][6] = { "1Node", "2Node" }; + +// Used to control whether this node is sending or receiving +bool role = 0; + + +/**********************************************************/ +//Function to configure the radio +void configureRadio() { + + radio.begin(); + + // Set the PA Level low to prevent power supply related issues since this is a + // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default. + radio.setPALevel(RF24_PA_LOW); + + // Open a writing and reading pipe on each radio, with opposite addresses + if (radioNumber) { + radio.openWritingPipe(addresses[1]); + radio.openReadingPipe(1, addresses[0]); + } else { + radio.openWritingPipe(addresses[0]); + radio.openReadingPipe(1, addresses[1]); + } + + // Start the radio listening for data + radio.startListening(); + radio.printDetails(); +} + + +/**********************************************************/ + +void setup() { + Serial.begin(115200); + Serial.println(F("RF24/examples/GettingStarted")); + Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); + + printf_begin(); + + configureRadio(); +} + +uint32_t configTimer = millis(); + +void loop() { + + if (radio.failureDetected) { + radio.failureDetected = false; + delay(250); + Serial.println("Radio failure detected, restarting radio"); + configureRadio(); + } + // Every 5 seconds, verify the configuration of the radio. This can be + // done using any setting that is different from the radio defaults. + if (millis() - configTimer > 5000) { + configTimer = millis(); + if (radio.getDataRate() != RF24_1MBPS) { + radio.failureDetected = true; + Serial.print("Radio configuration error detected"); + } + } + + + /****************** Ping Out Role ***************************/ + + if (role == 1) { + + radio.stopListening(); // First, stop listening so we can talk. + + Serial.println(F("Now sending")); + + unsigned long start_time = micros(); // Take the time, and send it. This will block until complete + if (!radio.write(&start_time, sizeof(unsigned long))) { + Serial.println(F("failed")); + } + + radio.startListening(); // Now, continue listening + + unsigned long started_waiting_at = micros(); // Set up a timeout period, get the current microseconds + bool timeout = false; // Set up a variable to indicate if a response was received or not + + while (!radio.available()) // While nothing is received + { + if (micros() - started_waiting_at > 200000) // If waited longer than 200ms, indicate timeout and exit while loop + { + timeout = true; + break; + } + } + + if (timeout) { + // Describe the results + Serial.println(F("Failed, response timed out.")); + } else { + // Grab the response, compare, and send to debugging spew + + unsigned long got_time; // Variable for the received timestamp + + // Failure Handling + uint32_t failTimer = millis(); + while (radio.available()) // If available() always returns true, there is a problem + { + if (millis() - failTimer > 250) { + radio.failureDetected = true; + Serial.println("Radio available failure detected"); + break; + } + radio.read(&got_time, sizeof(unsigned long)); + } + unsigned long end_time = micros(); + + // Spew it + Serial.print(F("Sent ")); + Serial.print(start_time); + Serial.print(F(", Got response ")); + Serial.print(got_time); + Serial.print(F(", Round-trip delay ")); + Serial.print(end_time - start_time); + Serial.println(F(" microseconds")); + } + + delay(1000); // Try again 1s later + } + + + /****************** Pong Back Role ***************************/ + + if (role == 0) { + unsigned long got_time; // Variable for the received timestamp + + if (radio.available()) { + uint32_t failTimer = millis(); + + while (radio.available()) // While there is data ready + { + if (millis() - failTimer > 500) { + Serial.println("Radio available failure detected"); + radio.failureDetected = true; + break; + } + radio.read(&got_time, sizeof(unsigned long)); // Get the payload + } + + radio.stopListening(); // First, stop listening so we can talk + radio.write(&got_time, sizeof(unsigned long)); // Send the final one back. + radio.startListening(); // Now, resume listening so we catch the next packets. + Serial.print(F("Sent response ")); + Serial.println(got_time); + } + } + + + /****************** Change Roles via Serial Commands ***************************/ + + if (Serial.available()) { + char c = toupper(Serial.read()); + if (c == 'T' && role == 0) { + Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK")); + role = 1; // Become the primary transmitter (ping out) + } else if (c == 'R' && role == 1) { + Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK")); + role = 0; // Become the primary receiver (pong back) + radio.startListening(); + } + } +} // Loop diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/TransferTimeouts/TransferTimeouts.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/TransferTimeouts/TransferTimeouts.ino new file mode 100644 index 0000000..2b831a8 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/TransferTimeouts/TransferTimeouts.ino @@ -0,0 +1,185 @@ +/* + TMRh20 2014 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. +*/ + +/** + Reliably transmitting large volumes of data with a low signal or in noisy environments + This example demonstrates data transfer functionality with the use of auto-retry + and auto-reUse functionality enabled. This sketch demonstrates how a user can extend + the auto-retry functionality to any chosen time period, preventing data loss and ensuring + the consistency of data. + + This sketch demonstrates use of the writeBlocking() functionality, and extends the standard + retry functionality of the radio. Payloads will be auto-retried until successful or the + extended timeout period is reached. +*/ + + + +#include <SPI.h> +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +/************* USER Configuration *****************************/ + +RF24 radio(7, 8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8 +unsigned long timeoutPeriod = 3000; // Set a user-defined timeout period. With auto-retransmit set to (15,15) retransmission will take up to 60ms and as little as 7.5ms with it set to (1,15). +// With a timeout period of 1000, the radio will retry each payload for up to 1 second before giving up on the transmission and starting over + +/***************************************************************/ + +const uint64_t pipes[2] = { 0xABCDABCD71LL, 0x544d52687CLL }; // Radio pipe addresses for the 2 nodes to communicate. + +byte data[32]; //Data buffer + +volatile unsigned long counter; +unsigned long rxTimer, startTime, stopTime, payloads = 0; +bool tx = 1, rx = 0, role = 0, transferInProgress = 0; + + +void setup(void) { + + Serial.begin(115200); + printf_begin(); + + radio.begin(); // Setup and configure rf radio + radio.setChannel(1); // Set the channel + radio.setPALevel(RF24_PA_LOW); // Set PA LOW for this demonstration. We want the radio to be as lossy as possible for this example. + radio.setDataRate(RF24_1MBPS); // Raise the data rate to reduce transmission distance and increase lossiness + radio.setAutoAck(1); // Ensure autoACK is enabled + radio.setRetries(2, 15); // Optionally, increase the delay between retries. Want the number of auto-retries as high as possible (15) + radio.setCRCLength(RF24_CRC_16); // Set CRC length to 16-bit to ensure quality of data + radio.openWritingPipe(pipes[0]); // Open the default reading and writing pipe + radio.openReadingPipe(1, pipes[1]); + + radio.startListening(); // Start listening + radio.printDetails(); // Dump the configuration of the rf unit for debugging + + printf("\n\rRF24/examples/Transfer Rates/\n\r"); + printf("*** PRESS 'T' to begin transmitting to the other node\n\r"); + + randomSeed(analogRead(0)); //Seed for random number generation + for (int i = 0; i < 32; i++) { + data[i] = random(255); //Load the buffer with random data + } + radio.powerUp(); //Power up the radio +} + + + +void loop(void) { + + + if (role == tx) { + delay(2000); // Pause for a couple seconds between transfers + printf("Initiating Extended Timeout Data Transfer\n\r"); + + unsigned long cycles = 1000; // Change this to a higher or lower number. This is the number of payloads that will be sent. + + unsigned long transferCMD[] = { 'H', 'S', cycles }; // Indicate to the other radio that we are starting, and provide the number of payloads that will be sent + radio.writeFast(&transferCMD, 12); // Send the transfer command + if (radio.txStandBy(timeoutPeriod)) { // If transfer initiation was successful, do the following + + startTime = millis(); // For calculating transfer rate + boolean timedOut = 0; // Boolean for keeping track of failures + + for (unsigned long i = 0; i < cycles; i++) // Loop through a number of cycles + { + data[0] = i; // Change the first byte of the payload for identification + + if (!radio.writeBlocking(&data, 32, timeoutPeriod)) { // If retries are failing and the user defined timeout is exceeded + timedOut = 1; // Indicate failure + counter = cycles; // Set the fail count to maximum + break; // Break out of the for loop + } + } + + + stopTime = millis(); // Capture the time of completion or failure + + //This should be called to wait for completion and put the radio in standby mode after transmission, returns 0 if data still in FIFO (timed out), 1 if success + if (timedOut) { + radio.txStandBy(); //Partially blocking standby, blocks until success or max retries. FIFO flushed if auto timeout reached + } else { + radio.txStandBy(timeoutPeriod); //Standby, block until FIFO empty (sent) or user specified timeout reached. FIFO flushed if user timeout reached. + } + + } else { + Serial.println("Communication not established"); //If unsuccessful initiating transfer, exit and retry later + } + + float rate = cycles * 32 / (stopTime - startTime); //Display results: + + Serial.print("Transfer complete at "); + Serial.print(rate); + Serial.println(" KB/s"); + Serial.print(counter); + Serial.print(" of "); + Serial.print(cycles); + Serial.println(" Packets Failed to Send"); + counter = 0; + } + + + + if (role == rx) { + + if (!transferInProgress) { // If a bulk data transfer has not been started + if (radio.available()) { + radio.read(&data, 32); //Read any available payloads for analysis + + if (data[0] == 'H' && data[4] == 'S') { // If a bulk data transfer command has been received + payloads = data[8]; // Read the first two bytes of the unsigned long. Need to read the 3rd and 4th if sending more than 65535 payloads + payloads |= data[9] << 8; // This is the number of payloads that will be sent + counter = 0; // Reset the payload counter to 0 + transferInProgress = 1; // Indicate it has started + startTime = rxTimer = millis(); // Capture the start time to measure transfer rate and calculate timeouts + } + } + } else { + if (radio.available()) { // If in bulk transfer mode, and a payload is available + radio.read(&data, 32); // Read the payload + rxTimer = millis(); // Reset the timeout timer + counter++; // Keep a count of received payloads + } else if (millis() - rxTimer > timeoutPeriod) { // If no data available, check the timeout period + Serial.println("Transfer Failed"); // If per-payload timeout exceeded, end the transfer + transferInProgress = 0; + } else if (counter >= payloads) { // If the specified number of payloads is reached, transfer is completed + startTime = millis() - startTime; // Calculate the total time spent during transfer + float numBytes = counter * 32; // Calculate the number of bytes transferred + Serial.print("Rate: "); // Print the transfer rate and number of payloads + Serial.print(numBytes / startTime); + Serial.println(" KB/s"); + Serial.print("Payload Count: "); + Serial.println(counter); + transferInProgress = 0; // End the transfer as complete + } + } + } + + // + // Change roles + // + + if (Serial.available()) { + char c = toupper(Serial.read()); + if (c == 'T' && role == rx) { + printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n\r"); + radio.openWritingPipe(pipes[1]); + radio.openReadingPipe(1, pipes[0]); + radio.stopListening(); + role = tx; // Become the primary transmitter (ping out) + } else if (c == 'R' && role == tx) { + radio.openWritingPipe(pipes[0]); + radio.openReadingPipe(1, pipes[1]); + radio.startListening(); + printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n\r"); + role = rx; // Become the primary receiver (pong back) + } + } +} diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/pingpair_dyn/pingpair_dyn.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/pingpair_dyn/pingpair_dyn.ino new file mode 100644 index 0000000..8df9524 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/pingpair_dyn/pingpair_dyn.ino @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2011 J. Coliz <maniacbug@ymail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +/** + * Example using Dynamic Payloads + * + * This is an example of how to use payloads of a varying (dynamic) size. + */ + +#include <SPI.h> +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +// Hardware configuration +RF24 radio(7, 8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8 + +// Radio pipe addresses for the 2 nodes to communicate. +const uint64_t addresses[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; + +/************************* Role management ****************************/ +// Set up role. This sketch uses the same software for all the nodes in this +// system. Doing so greatly simplifies testing. + +// The role_pin is a digital input pin used to set the role of this radio. +// Connect the role_pin to GND to be the 'pong' receiver +// Leave the role_pin open to be the 'ping' transmitter +const short role_pin = 5; // use pin 5 +typedef enum { role_ping_out = 1, + role_pong_back } role_e; // The various roles supported by this sketch +const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back" }; // The debug-friendly names of those roles +role_e role; // The role of the current running sketch + + +// variables used for changing the payload size dynamically (used when role == role_ping_out) +const int min_payload_size = 4; +const int max_payload_size = 32; +const int payload_size_increment = 1; +int send_payload_size = min_payload_size; + +char receive_payload[max_payload_size + 1]; // +1 to allow room for a terminating NULL char + +void setup(void) { + pinMode(role_pin, INPUT); // set up the role pin + digitalWrite(role_pin, HIGH); + delay(20); // Just to get a solid reading on the role pin + + // read the role_pin, establish our role + if (digitalRead(role_pin)) { + role = role_ping_out; + } else { + role = role_pong_back; + } + + Serial.begin(115200); + printf_begin(); // needed for printDetails() + + // Print preamble + Serial.println(F("RF24/examples/pingpair_dyn/")); + Serial.print(F("ROLE: ")); + Serial.println(role_friendly_name[role]); + + // Setup and configure rf radio + radio.begin(); + radio.enableDynamicPayloads(); // Enable dynamic payloads + radio.setRetries(5, 15); // delay between retries = 5 * 250 + 250 = 1500 microseconds, number of retries = 15 + + // Open a writing and reading pipe on each radio, with opposite addresses + if (role == role_ping_out) { + radio.openWritingPipe(addresses[0]); + radio.openReadingPipe(1, addresses[1]); + } else { + radio.openWritingPipe(addresses[1]); + radio.openReadingPipe(1, addresses[0]); + } + + radio.startListening(); // Start listening + radio.printDetails(); // Dump the configuration of the rf unit for debugging +} + +void loop() { + + + /****************** Ping Out Role ***************************/ + + if (role == role_ping_out) { + // The payload will always be the same, what will change is how much of it we send. + static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012"; + + radio.stopListening(); // First, stop listening so we can talk. + + // Send the payload + Serial.print(F("Now sending length ")); + Serial.println(send_payload_size); + radio.write(send_payload, send_payload_size); // This will block until complete + + radio.startListening(); // Now, continue listening + + unsigned long started_waiting_at = millis(); // Start a timer for measuring timeout + bool timeout = false; + while (!radio.available() && !timeout) // Wait until we get a response or timeout is reached + { + if (millis() - started_waiting_at > 500) // Only wait for 500 milliseconds + timeout = true; + } + + // Describe the results + if (timeout) { + Serial.println(F("Failed, response timed out.")); + } else { + // Grab the response and print it + + uint8_t len = radio.getDynamicPayloadSize(); // get payload's length + + // If an illegal payload size was detected, all RX payloads will be flushed + if (!len) + return; + + radio.read(receive_payload, len); + + // Use payload as a C-string (for easy printing) + receive_payload[len] = 0; // put a NULL terminating zero at the end + + // Spew it + Serial.print(F("Got response size=")); + Serial.print(len); + Serial.print(F(" value=")); + Serial.println(receive_payload); + } + + send_payload_size += payload_size_increment; // Update size for next time. + if (send_payload_size > max_payload_size) // if payload length is larger than the radio can handle + send_payload_size = min_payload_size; // reset the payload length + + delay(1000); // Try again 1s later + } + + + /****************** Pong Back Role ***************************/ + // Receive each packet, send it back, and dump it out + + if (role == role_pong_back) { + while (radio.available()) // if there is data ready + { + + uint8_t len = radio.getDynamicPayloadSize(); // Fetch the the payload size + + // If an illegal payload size was detected, all RX payloads will be flushed + if (!len) + continue; + + radio.read(receive_payload, len); + + // Use payload as a C-string (for easy printing) + receive_payload[len] = 0; // put a NULL terminating zero at the end + + // Spew it + Serial.print(F("Got response size=")); + Serial.print(len); + Serial.print(F(" value=")); + Serial.println(receive_payload); + + radio.stopListening(); // First, stop listening so we can talk + + // Send a reply that the packet was received + // + // You will have better luck delivering your message if + // you wait for the other node to start listening first + delay(20); + radio.write(receive_payload, len); + Serial.println(F("Sent response.")); + + radio.startListening(); // Now, resume listening so we catch the next packets. + } + } +} // loop +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/pingpair_irq/pingpair_irq.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/pingpair_irq/pingpair_irq.ino new file mode 100644 index 0000000..19623cc --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/pingpair_irq/pingpair_irq.ino @@ -0,0 +1,173 @@ +/* + Copyright (C) 2011 J. Coliz <maniacbug@ymail.com> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + + Update 2014 - TMRh20 +*/ + +/** + Example of using interrupts + + This is an example of how to user interrupts to interact with the radio, and a demonstration + of how to use them to sleep when receiving, and not miss any payloads. + The pingpair_sleepy example expands on sleep functionality with a timed sleep option for the transmitter. + Sleep functionality is built directly into my fork of the RF24Network library +*/ + +#include <SPI.h> +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +// Hardware configuration +RF24 radio(7, 8); // Set up nRF24L01 radio on SPI bus plus pins 7 & 8 + +// Our ACK payload will simply be 4 bytes containing the number of payloads received +static uint32_t message_count = 1; // start counting at 1 + +// Demonstrates another method of setting up the addresses +byte address[][5] = { 0xCC, 0xCE, 0xCC, 0xCE, 0xCC, 0xCE, 0xCC, 0xCE, 0xCC, 0xCE }; + +/************************* Role management ****************************/ +// Set up role. This sketch uses the same software for all the nodes in this +// system. Doing so greatly simplifies testing. + +// The role_pin is a digital input pin used to set the role of this radio. +// Connect the role_pin to GND to be the 'pong' receiver +// Leave the role_pin open to be the 'ping' transmitter +const short role_pin = 5; // use pin 5 +typedef enum { role_sender = 1, + role_receiver } role_e; // The various roles supported by this sketch +const char* role_friendly_name[] = { "invalid", "Sender", "Receiver" }; // The debug-friendly names of those roles +role_e role; // The role of the current running sketch + + +void setup() { + + pinMode(role_pin, INPUT); // set up the role pin + digitalWrite(role_pin, HIGH); // Change this to LOW/HIGH instead of using an external pin + delay(20); // Just to get a solid reading on the role pin + + if (digitalRead(role_pin)) // read the role_pin pin to establish our role + role = role_sender; + else + role = role_receiver; + + + Serial.begin(115200); + printf_begin(); // needed for printDetails() + + // print introduction + Serial.print(F("\n\rRF24/examples/pingpair_irq\n\rROLE: ")); + Serial.println(role_friendly_name[role]); + + + /********************** Setup and configure rf radio *********************/ + radio.begin(); + + // Examples are usually run with both radios in close proximity to each other + radio.setPALevel(RF24_PA_LOW); // defaults to RF24_PA_MAX + radio.enableAckPayload(); // We will be using the ACK Payload feature which is not enabled by default + radio.enableDynamicPayloads(); // Ack payloads are dynamic payloads + + // Open a writing and reading pipe on each radio, with opposite addresses + if (role == role_sender) { + radio.openWritingPipe(address[0]); + radio.openReadingPipe(1, address[1]); + } else { + radio.openWritingPipe(address[1]); + radio.openReadingPipe(1, address[0]); + radio.startListening(); // First we need to start listening + + // Add an ACK payload for the first time around; 1 is the pipe number to acknowledge + radio.writeAckPayload(1, &message_count, sizeof(message_count)); + ++message_count; // increment counter by 1 for next ACK payload + } + + radio.printDetails(); // Dump the configuration of the rf unit for debugging + delay(50); + + // Attach interrupt handler to interrupt #0 (using pin 2) on BOTH the sender and receiver + attachInterrupt(0, check_radio, LOW); +} // setup + + +void loop() { + + + /****************** Ping Out Role ***************************/ + + if (role == role_sender) { + // Repeatedly send the current time + + unsigned long time = millis(); // Take the time + Serial.print(F("Now sending ")); + Serial.println(time); + radio.startWrite(&time, sizeof(unsigned long), 0); // Send the time + delay(2000); // Try again soon (in 2 seconds) + } + + + /****************** Pong Back Role ***************************/ + // Receiver does nothing! All the work is in Interrupt Handler + + if (role == role_receiver) {} + +} // loop + + +/********************** Interrupt Handler *********************/ + +void check_radio(void) { + + bool tx, fail, rx; // declare variables to store IRQ flags + radio.whatHappened(tx, fail, rx); // What happened? + + if (tx) { // Have we successfully transmitted? + if (role == role_sender) + Serial.println(F("Send:OK")); + if (role == role_receiver) + Serial.println(F("Ack Payload:Sent")); + } + + if (fail) { // Have we failed to transmit? + if (role == role_sender) + Serial.println(F("Send:Failed")); + if (role == role_receiver) + Serial.println(F("Ack Payload:Failed")); + } + + if (rx || radio.available()) { // Did we receive a message? + + + + + /**************** Ping Out Role (about received ACK payload) ************************/ + // If we're the sender, we've received an ack payload + if (role == role_sender) { + // Get the payload and dump it + radio.read(&message_count, sizeof(message_count)); + Serial.print(F("Ack: ")); + Serial.println(message_count); + } + + + /****************** Pong Back Role ***************************/ + // If we're the receiver, we've received a time message + if (role == role_receiver) { + // Get the payload and dump it + + static unsigned long got_time; // variable to hold the received time + radio.read(&got_time, sizeof(got_time)); // get the payload + Serial.print(F("Got payload ")); + Serial.println(got_time); + + // Add an ACK payload for the next time around; 1 is the pipe number to acknowledge + radio.writeAckPayload(1, &message_count, sizeof(message_count)); + ++message_count; // increment packet counter + } + } +} // check_radio diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/pingpair_multi_dyn/pingpair_multi_dyn.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/pingpair_multi_dyn/pingpair_multi_dyn.ino new file mode 100644 index 0000000..8e32879 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/pingpair_multi_dyn/pingpair_multi_dyn.ino @@ -0,0 +1,252 @@ +/* + Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. +*/ + +/** + Example using Dynamic Payloads + + This is an example of how to use payloads of a varying (dynamic) size. +*/ + +#include <SPI.h> +#include "RF24.h" + +// +// Hardware configuration +// + +// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 +RF24 radio(7, 8); + +// Use multicast? +// sets the multicast behavior this unit in hardware. Connect to GND to use unicast +// Leave open (default) to use multicast. +const int multicast_pin = 6; + +// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver +// Leave open to be the 'ping' transmitter +const int role_pin = 5; +bool multicast = true; + +// +// Topology +// + +// Radio pipe addresses for the 2 nodes to communicate. +const uint64_t pipes[2] = { 0xEEFAFDFDEELL, 0xEEFDFAF50DFLL }; + +// +// Role management +// +// Set up role. This sketch uses the same software for all the nodes +// in this system. Doing so greatly simplifies testing. The hardware itself specifies +// which node it is. +// +// This is done through the role_pin +// + +// The various roles supported by this sketch +typedef enum { role_ping_out = 1, + role_pong_back } role_e; + +// The debug-friendly names of those roles +const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back" }; + +// The role of the current running sketch +role_e role; + +// +// Payload +// + +const int min_payload_size = 1; +const int max_payload_size = 32; +const int payload_size_increments_by = 1; +int next_payload_size = min_payload_size; + +char receive_payload[max_payload_size + 1]; // +1 to allow room for a terminating NULL char + +void setup(void) { + // + // Multicast + // + pinMode(multicast_pin, INPUT); + digitalWrite(multicast_pin, HIGH); + delay(20); + + // read multicast role, LOW for unicast + if (digitalRead(multicast_pin)) + multicast = true; + else + multicast = false; + + + // + // Role + // + + // set up the role pin + pinMode(role_pin, INPUT); + digitalWrite(role_pin, HIGH); + delay(20); // Just to get a solid reading on the role pin + + // read the address pin, establish our role + if (digitalRead(role_pin)) + role = role_ping_out; + else + role = role_pong_back; + + // + // Print preamble + // + + Serial.begin(115200); + + Serial.println(F("RF24/examples/pingpair_multi_dyn/")); + Serial.print(F("ROLE: ")); + Serial.println(role_friendly_name[role]); + + Serial.print(F("MULTICAST: ")); + Serial.println(multicast ? F("true (unreliable)") : F("false (reliable)")); + + // + // Setup and configure rf radio + // + + radio.begin(); + + // enable dynamic payloads + radio.enableDynamicPayloads(); + radio.setCRCLength(RF24_CRC_16); + + // optionally, increase the delay between retries & # of retries + radio.setRetries(15, 5); + radio.setAutoAck(true); + //radio.setPALevel( RF24_PA_LOW ) ; + + // + // Open pipes to other nodes for communication + // + + // This simple sketch opens two pipes for these two nodes to communicate + // back and forth. + // Open 'our' pipe for writing + // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) + + if (role == role_ping_out) { + radio.openWritingPipe(pipes[0]); + radio.openReadingPipe(1, pipes[1]); + } else { + radio.openWritingPipe(pipes[1]); + radio.openReadingPipe(1, pipes[0]); + } + + // + // Start listening + // + radio.powerUp(); + radio.startListening(); + + // + // Dump the configuration of the rf unit for debugging + // + + radio.printDetails(); +} + +void loop(void) { + // + // Ping out role. Repeatedly send the current time + // + + if (role == role_ping_out) { + // The payload will always be the same, what will change is how much of it we send. + static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012"; + + // First, stop listening so we can talk. + radio.stopListening(); + + // Take the time, and send it. This will block until complete + Serial.print(F("Now sending length ")); + Serial.println(next_payload_size); + radio.write(send_payload, next_payload_size, multicast); + + // Now, continue listening + radio.startListening(); + + // Wait here until we get a response, or timeout + unsigned long started_waiting_at = millis(); + bool timeout = false; + while (!radio.available() && !timeout) + if (millis() - started_waiting_at > 500) + timeout = true; + + // Describe the results + if (timeout) { + Serial.println(F("Failed, response timed out.")); + } else { + // Grab the response, compare, and send to debugging spew + uint8_t len = radio.getDynamicPayloadSize(); + radio.read(receive_payload, len); + + // Put a zero at the end for easy printing + receive_payload[len] = 0; + + // Spew it + Serial.print(F("Got response size=")); + Serial.print(len); + Serial.print(F(" value=")); + Serial.println(receive_payload); + } + + // Update size for next time. + next_payload_size += payload_size_increments_by; + if (next_payload_size > max_payload_size) + next_payload_size = min_payload_size; + + // Try again 1s later + delay(250); + } + + // + // Pong back role. Receive each packet, dump it out, and send it back + // + + if (role == role_pong_back) { + // if there is data ready + if (radio.available()) { + // Dump the payloads until we've gotten everything + uint8_t len; + bool done = false; + while (radio.available()) { + // Fetch the payload, and see if this was the last one. + len = radio.getDynamicPayloadSize(); + radio.read(receive_payload, len); + + // Put a zero at the end for easy printing + receive_payload[len] = 0; + + // Spew it + Serial.print(F("Got response size=")); + Serial.print(len); + Serial.print(F(" value=")); + Serial.println(receive_payload); + } + + // First, stop listening so we can talk + radio.stopListening(); + + // Send the final one back. + radio.write(receive_payload, len, multicast); + Serial.println(F("Sent response.")); + + // Now, resume listening so we catch the next packets. + radio.startListening(); + } + } +} +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/pingpair_sleepy/pingpair_sleepy.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/pingpair_sleepy/pingpair_sleepy.ino new file mode 100644 index 0000000..c3beec8 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/pingpair_sleepy/pingpair_sleepy.ino @@ -0,0 +1,231 @@ +/* + Copyright (C) 2011 J. Coliz <maniacbug@ymail.com> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + + TMRh20 2014 - Updates to the library allow sleeping both in TX and RX modes: + TX Mode: The radio can be powered down (.9uA current) and the Arduino slept using the watchdog timer + RX Mode: The radio can be left in standby mode (22uA current) and the Arduino slept using an interrupt pin +*/ + +/** + Example RF Radio Ping Pair which Sleeps between Sends + + This is an example of how to use the RF24 class to create a battery- + efficient system. It is just like the GettingStarted_CallResponse example, but the + ping node powers down the radio and sleeps the MCU after every + ping/pong cycle, and the receiver sleeps between payloads. + + Write this sketch to two different nodes, + connect the role_pin to ground on one. The ping node sends the current + time to the pong node, which responds by sending the value back. The ping + node can then see how long the whole cycle took. +*/ + +#include <SPI.h> +#include <avr/sleep.h> +#include <avr/power.h> +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + + +// Set up nRF24L01 radio on SPI bus plus pins 7 & 8 +RF24 radio(7, 8); + +// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver +// Leave open to be the 'ping' transmitter +const int role_pin = 5; + +const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; // Radio pipe addresses for the 2 nodes to communicate. + +// Role management +// Set up role. This sketch uses the same software for all the nodes +// in this system. Doing so greatly simplifies testing. The hardware itself specifies +// which node it is. + +// The various roles supported by this sketch +typedef enum { role_ping_out = 1, + role_pong_back } role_e; + +// The debug-friendly names of those roles +const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back" }; + +// The role of the current running sketch +role_e role; + + +// Sleep declarations +typedef enum { wdt_16ms = 0, + wdt_32ms, + wdt_64ms, + wdt_128ms, + wdt_250ms, + wdt_500ms, + wdt_1s, + wdt_2s, + wdt_4s, + wdt_8s } wdt_prescalar_e; + +void setup_watchdog(uint8_t prescalar); +void do_sleep(void); + +const short sleep_cycles_per_transmission = 4; +volatile short sleep_cycles_remaining = sleep_cycles_per_transmission; + + + +void setup() { + + // set up the role pin + pinMode(role_pin, INPUT); + digitalWrite(role_pin, HIGH); + delay(20); // Just to get a solid reading on the role pin + + // read the address pin, establish our role + if (digitalRead(role_pin)) + role = role_ping_out; + else + role = role_pong_back; + + Serial.begin(115200); + printf_begin(); + Serial.print(F("\n\rRF24/examples/pingpair_sleepy/\n\rROLE: ")); + Serial.println(role_friendly_name[role]); + + // Prepare sleep parameters + // Only the ping out role uses WDT. Wake up every 4s to send a ping + //if ( role == role_ping_out ) + setup_watchdog(wdt_4s); + + // Setup and configure rf radio + + radio.begin(); + + // Open pipes to other nodes for communication + + // This simple sketch opens two pipes for these two nodes to communicate + // back and forth. + // Open 'our' pipe for writing + // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) + + if (role == role_ping_out) { + radio.openWritingPipe(pipes[0]); + radio.openReadingPipe(1, pipes[1]); + } else { + radio.openWritingPipe(pipes[1]); + radio.openReadingPipe(1, pipes[0]); + } + + // Start listening + radio.startListening(); + + // Dump the configuration of the rf unit for debugging + //radio.printDetails(); +} + +void loop() { + + + if (role == role_ping_out) { // Ping out role. Repeatedly send the current time + radio.powerUp(); // Power up the radio after sleeping + radio.stopListening(); // First, stop listening so we can talk. + + unsigned long time = millis(); // Take the time, and send it. + Serial.print(F("Now sending... ")); + Serial.println(time); + + radio.write(&time, sizeof(unsigned long)); + + radio.startListening(); // Now, continue listening + + unsigned long started_waiting_at = millis(); // Wait here until we get a response, or timeout (250ms) + bool timeout = false; + while (!radio.available()) { + if (millis() - started_waiting_at > 250) { // Break out of the while loop if nothing available + timeout = true; + break; + } + } + + if (timeout) { // Describe the results + Serial.println(F("Failed, response timed out.")); + } else { + unsigned long got_time; // Grab the response, compare, and send to debugging spew + radio.read(&got_time, sizeof(unsigned long)); + + printf("Got response %lu, round-trip delay: %lu\n\r", got_time, millis() - got_time); + } + + // Shut down the system + delay(500); // Experiment with some delay here to see if it has an effect + // Power down the radio. + radio.powerDown(); // NOTE: The radio MUST be powered back up again manually + + // Sleep the MCU. + do_sleep(); + } + + + // Pong back role. Receive each packet, dump it out, and send it back + if (role == role_pong_back) { + + if (radio.available()) { // if there is data ready + + unsigned long got_time; + while (radio.available()) { // Dump the payloads until we've gotten everything + radio.read(&got_time, sizeof(unsigned long)); // Get the payload, and see if this was the last one. + // Spew it. Include our time, because the ping_out millis counter is unreliable + printf("Got payload %lu @ %lu...", got_time, millis()); // due to it sleeping + } + + radio.stopListening(); // First, stop listening so we can talk + radio.write(&got_time, sizeof(unsigned long)); // Send the final one back. + Serial.println(F("Sent response.")); + radio.startListening(); // Now, resume listening so we catch the next packets. + } else { + Serial.println(F("Sleeping")); + delay(50); // Delay so the serial data can print out + do_sleep(); + } + } +} + +void wakeUp() { + sleep_disable(); +} + +// Sleep helpers + +//Prescaler values +// 0=16ms, 1=32ms,2=64ms,3=125ms,4=250ms,5=500ms +// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec + +void setup_watchdog(uint8_t prescalar) { + + uint8_t wdtcsr = prescalar & 7; + if (prescalar & 8) + wdtcsr |= _BV(WDP3); + MCUSR &= ~_BV(WDRF); // Clear the WD System Reset Flag + WDTCSR = _BV(WDCE) | _BV(WDE); // Write the WD Change enable bit to enable changing the prescaler and enable system reset + WDTCSR = _BV(WDCE) | wdtcsr | _BV(WDIE); // Write the prescalar bits (how long to sleep, enable the interrupt to wake the MCU +} + +ISR(WDT_vect) { + //--sleep_cycles_remaining; + Serial.println(F("WDT")); +} + +void do_sleep(void) { + set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here + sleep_enable(); + attachInterrupt(0, wakeUp, LOW); + WDTCSR |= _BV(WDIE); + sleep_mode(); // System sleeps here + // The WDT_vect interrupt wakes the MCU from here + sleep_disable(); // System continues execution here when watchdog timed out + detachInterrupt(0); + WDTCSR &= ~_BV(WDIE); +} diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/led_remote/led_remote.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/led_remote/led_remote.ino new file mode 100644 index 0000000..6ec865e --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/led_remote/led_remote.ino @@ -0,0 +1,236 @@ +/* + Copyright (C) 2011 J. Coliz <maniacbug@ymail.com> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. +*/ + +/** + Example LED Remote + + This is an example of how to use the RF24 class to control a remote + bank of LED's using buttons on a remote control. + + On the 'remote', connect any number of buttons or switches from + an arduino pin to ground. Update 'button_pins' to reflect the + pins used. + + On the 'led' board, connect the same number of LED's from an + arduino pin to a resistor to ground. Update 'led_pins' to reflect + the pins used. Also connect a separate pin to ground and change + the 'role_pin'. This tells the sketch it's running on the LED board. + + Every time the buttons change on the remote, the entire state of + buttons is send to the led board, which displays the state. +*/ + +#include <SPI.h> +#include "nRF24L01.h" +#include "RF24.h" +#include "printf.h" + +// +// Hardware configuration +// + +// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 (CE & CS) + +RF24 radio(9, 10); + +// sets the role of this unit in hardware. Connect to GND to be the 'led' board receiver +// Leave open to be the 'remote' transmitter +const int role_pin = A4; + +// Pins on the remote for buttons +const uint8_t button_pins[] = { 2, 3, 4, 5, 6, 7 }; +const uint8_t num_button_pins = sizeof(button_pins); + +// Pins on the LED board for LED's +const uint8_t led_pins[] = { 2, 3, 4, 5, 6, 7 }; +const uint8_t num_led_pins = sizeof(led_pins); + +// +// Topology +// + +// Single radio pipe address for the 2 nodes to communicate. +const uint64_t pipe = 0xE8E8F0F0E1LL; + +// +// Role management +// +// Set up role. This sketch uses the same software for all the nodes in this +// system. Doing so greatly simplifies testing. The hardware itself specifies +// which node it is. +// +// This is done through the role_pin +// + +// The various roles supported by this sketch +typedef enum { role_remote = 1, + role_led } role_e; + +// The debug-friendly names of those roles +const char* role_friendly_name[] = { "invalid", "Remote", "LED Board" }; + +// The role of the current running sketch +role_e role; + +// +// Payload +// + +uint8_t button_states[num_button_pins]; +uint8_t led_states[num_led_pins]; + +// +// Setup +// + +void setup(void) { + // + // Role + // + + // set up the role pin + pinMode(role_pin, INPUT); + digitalWrite(role_pin, HIGH); + delay(20); // Just to get a solid reading on the role pin + + // read the address pin, establish our role + if (digitalRead(role_pin)) + role = role_remote; + else + role = role_led; + + // + // Print preamble + // + + Serial.begin(115200); + printf_begin(); + printf("\n\rRF24/examples/led_remote/\n\r"); + printf("ROLE: %s\n\r", role_friendly_name[role]); + + // + // Setup and configure rf radio + // + + radio.begin(); + + // + // Open pipes to other nodes for communication + // + + // This simple sketch opens a single pipes for these two nodes to communicate + // back and forth. One listens on it, the other talks to it. + + if (role == role_remote) { + radio.openWritingPipe(pipe); + } else { + radio.openReadingPipe(1, pipe); + } + + // + // Start listening + // + + if (role == role_led) + radio.startListening(); + + // + // Dump the configuration of the rf unit for debugging + // + + radio.printDetails(); + + // + // Set up buttons / LED's + // + + // Set pull-up resistors for all buttons + if (role == role_remote) { + int i = num_button_pins; + while (i--) { + pinMode(button_pins[i], INPUT); + digitalWrite(button_pins[i], HIGH); + } + } + + // Turn LED's ON until we start getting keys + if (role == role_led) { + int i = num_led_pins; + while (i--) { + pinMode(led_pins[i], OUTPUT); + led_states[i] = HIGH; + digitalWrite(led_pins[i], led_states[i]); + } + } +} + +// +// Loop +// + +void loop(void) { + // + // Remote role. If the state of any button has changed, send the whole state of + // all buttons. + // + + if (role == role_remote) { + // Get the current state of buttons, and + // Test if the current state is different from the last state we sent + int i = num_button_pins; + bool different = false; + while (i--) { + uint8_t state = !digitalRead(button_pins[i]); + if (state != button_states[i]) { + different = true; + button_states[i] = state; + } + } + + // Send the state of the buttons to the LED board + if (different) { + printf("Now sending..."); + bool ok = radio.write(button_states, num_button_pins); + if (ok) + printf("ok\n\r"); + else + printf("failed\n\r"); + } + + // Try again in a short while + delay(20); + } + + // + // LED role. Receive the state of all buttons, and reflect that in the LEDs + // + + if (role == role_led) { + // if there is data ready + if (radio.available()) { + // Dump the payloads until we've gotten everything + while (radio.available()) { + // Fetch the payload, and see if this was the last one. + radio.read(button_states, num_button_pins); + + // Spew it + printf("Got buttons\n\r"); + + // For each button, if the button now on, then toggle the LED + int i = num_led_pins; + while (i--) { + if (button_states[i]) { + led_states[i] ^= HIGH; + digitalWrite(led_pins[i], led_states[i]); + } + } + } + } + } +} +// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/nordic_fob/nordic_fob.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/nordic_fob/nordic_fob.ino new file mode 100644 index 0000000..894d926 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/nordic_fob/nordic_fob.ino @@ -0,0 +1,135 @@ +/* + Copyright (C) 2012 J. Coliz <maniacbug@ymail.com> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. +*/ + +/** + Example Nordic FOB Receiver + + This is an example of how to use the RF24 class to receive signals from the + Sparkfun Nordic FOB. Thanks to Kirk Mower for providing test hardware. + + See blog post at http://maniacbug.wordpress.com/2012/01/08/nordic-fob/ +*/ + +#include <SPI.h> +#include <RF24.h> +#include "nRF24L01.h" +#include "printf.h" + +// +// Hardware configuration +// + +// Set up nRF24L01 radio on SPI bus plus pins 9 & 10 + +RF24 radio(9, 10); + +// +// Payload +// + +struct payload_t { + uint8_t buttons; + uint16_t id; + uint8_t empty; +}; + +const char* button_names[] = { "Up", "Down", "Left", "Right", "Center" }; +const int num_buttons = 5; + +// +// Forward declarations +// + +uint16_t flip_endian(uint16_t in); + +// +// Setup +// + +void setup(void) { + // + // Print preamble + // + + Serial.begin(115200); + printf_begin(); + printf("\r\nRF24/examples/nordic_fob/\r\n"); + + // + // Setup and configure rf radio according to the built-in parameters + // of the FOB. + // + + radio.begin(); + radio.setChannel(2); + radio.setPayloadSize(4); + radio.setAutoAck(false); + radio.setCRCLength(RF24_CRC_8); + radio.openReadingPipe(1, 0xE7E7E7E7E7LL); + + // + // Start listening + // + + radio.startListening(); + + // + // Dump the configuration of the rf unit for debugging + // + + radio.printDetails(); +} + +// +// Loop +// + +void loop(void) { + // + // Receive each packet, dump it out + // + + // if there is data ready + if (radio.available()) { + // Get the packet from the radio + payload_t payload; + radio.read(&payload, sizeof(payload)); + + // Print the ID of this message. Note that the message + // is sent 'big-endian', so we have to flip it. + printf("#%05u Buttons ", flip_endian(payload.id)); + + // Print the name of each button + int i = num_buttons; + while (i--) { + if (!(payload.buttons & _BV(i))) { + printf("%s ", button_names[i]); + } + } + + // If no buttons, print None + if (payload.buttons == _BV(num_buttons) - 1) + printf("None"); + + printf("\r\n"); + } +} + +// +// Helper functions +// + +// Change a big-endian word into a little-endian +uint16_t flip_endian(uint16_t in) { + uint16_t low = in >> 8; + uint16_t high = in << 8; + + return high | low; +} + +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/pingpair_maple/main.cpp b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/pingpair_maple/main.cpp new file mode 100644 index 0000000..be3ea98 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/pingpair_maple/main.cpp @@ -0,0 +1,77 @@ +#ifdef MAPLE_IDE + +#include <stdio.h> +#include "wirish.h" + +extern void setup(void); +extern void loop(void); + +void board_start(const char* program_name) { + // Set up the LED to steady on + pinMode(BOARD_LED_PIN, OUTPUT); + digitalWrite(BOARD_LED_PIN, HIGH); + + // Setup the button as input + pinMode(BOARD_BUTTON_PIN, INPUT); + digitalWrite(BOARD_BUTTON_PIN, HIGH); + + SerialUSB.begin(); + SerialUSB.println("Press BUT"); + + // Wait for button press + while (!isButtonPressed()) { + } + + SerialUSB.println("Welcome!"); + SerialUSB.println(program_name); + + int i = 11; + while (i--) { + toggleLED(); + delay(50); + } +} + +/** + Custom version of _write, which will print to the USB. + In order to use it you MUST ADD __attribute__((weak)) + to _write in libmaple/syscalls.c +*/ +extern "C" int _write(int file, char* ptr, int len) { + if ((file != 1) && (file != 2)) + return 0; + else + SerialUSB.write(ptr, len); + return len; +} + +/** + Re-entrant version of _write. Yagarto and Devkit now use + the re-entrant newlib, so these get called instead of the + non_r versions. +*/ +extern "C" int _write_r(void*, int file, char* ptr, int len) { + return _write(file, ptr, len); +} + +__attribute__((constructor)) __attribute__((weak)) void premain() { + init(); +} + +__attribute__((weak)) void setup(void) { + board_start("No program defined"); +} + +__attribute__((weak)) void loop(void) { +} + +__attribute__((weak)) int main(void) { + setup(); + + while (true) { + loop(); + } + return 0; +} +#endif // ifdef MAPLE_IDE +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/pingpair_maple/pingpair_maple.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/pingpair_maple/pingpair_maple.ino new file mode 100644 index 0000000..e1b0511 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/pingpair_maple/pingpair_maple.ino @@ -0,0 +1,231 @@ +/* + Copyright (C) 2011 J. Coliz <maniacbug@ymail.com> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. +*/ + +/** + Example RF Radio Ping Pair ... for Maple + + This is an example of how to use the RF24 class. Write this sketch to two different nodes, + connect the role_pin to ground on one. The ping node sends the current time to the pong node, + which responds by sending the value back. The ping node can then see how long the whole cycle + took. +*/ + +#include "WProgram.h" +#include <SPI.h> +#include "nRF24L01.h" +#include "RF24.h" + +// +// Maple specific setup. Other than this section, the sketch is the same on Maple as on +// Arduino +// + +#ifdef MAPLE_IDE + +// External startup function +extern void board_start(const char* program_name); + +// Use SPI #2. +HardwareSPI SPI(2); + +#else +#define board_startup printf +#define toggleLED(x) (x) +#endif + +// +// Hardware configuration +// + +// Set up nRF24L01 radio on SPI bus plus pins 7 & 6 +// (This works for the Getting Started board plugged into the +// Maple Native backwards.) + +RF24 radio(7, 6); + +// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver +// Leave open to be the 'ping' transmitter +const int role_pin = 10; + +// +// Topology +// + +// Radio pipe addresses for the 2 nodes to communicate. +const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; + +// +// Role management +// +// Set up role. This sketch uses the same software for all the nodes +// in this system. Doing so greatly simplifies testing. The hardware itself specifies +// which node it is. +// +// This is done through the role_pin +// + +// The various roles supported by this sketch +typedef enum { role_ping_out = 1, + role_pong_back } role_e; + +// The debug-friendly names of those roles +const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back" }; + +// The role of the current running sketch +role_e role; + +void setup(void) { + // + // Role + // + + // set up the role pin + pinMode(role_pin, INPUT); + digitalWrite(role_pin, HIGH); + delay(20); // Just to get a solid reading on the role pin + + // read the address pin, establish our role + if (digitalRead(role_pin)) + role = role_ping_out; + else + role = role_pong_back; + + // + // Print preamble + // + + board_start("\n\rRF24/examples/pingpair/\n\r"); + printf("ROLE: %s\n\r", role_friendly_name[role]); + + // + // Setup and configure rf radio + // + + radio.begin(); + + // optionally, increase the delay between retries & # of retries + radio.setRetries(15, 15); + + // optionally, reduce the payload size. seems to + // improve reliability + radio.setPayloadSize(8); + + // + // Open pipes to other nodes for communication + // + + // This simple sketch opens two pipes for these two nodes to communicate + // back and forth. + // Open 'our' pipe for writing + // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) + + if (role == role_ping_out) { + radio.openWritingPipe(pipes[0]); + radio.openReadingPipe(1, pipes[1]); + } else { + radio.openWritingPipe(pipes[1]); + radio.openReadingPipe(1, pipes[0]); + } + + // + // Start listening + // + + radio.startListening(); + + // + // Dump the configuration of the rf unit for debugging + // + + radio.printDetails(); +} + +void loop(void) { + // + // Ping out role. Repeatedly send the current time + // + + if (role == role_ping_out) { + toggleLED(); + + // First, stop listening so we can talk. + radio.stopListening(); + + // Take the time, and send it. This will block until complete + unsigned long time = millis(); + printf("Now sending %lu...", time); + bool ok = radio.write(&time, sizeof(unsigned long)); + + if (ok) + printf("ok...\r\n"); + else + printf("failed.\r\n"); + + // Now, continue listening + radio.startListening(); + + // Wait here until we get a response, or timeout (250ms) + unsigned long started_waiting_at = millis(); + bool timeout = false; + while (!radio.available() && !timeout) + if (millis() - started_waiting_at > 200) + timeout = true; + + // Describe the results + if (timeout) { + printf("Failed, response timed out.\r\n"); + } else { + // Grab the response, compare, and send to debugging spew + unsigned long got_time; + radio.read(&got_time, sizeof(unsigned long)); + + // Spew it + printf("Got response %lu, round-trip delay: %lu\r\n", got_time, millis() - got_time); + } + + toggleLED(); + + // Try again 1s later + delay(1000); + } + + // + // Pong back role. Receive each packet, dump it out, and send it back + // + + if (role == role_pong_back) { + // if there is data ready + if (radio.available()) { + // Dump the payloads until we've gotten everything + unsigned long got_time; + bool done = false; + while (!done) { + // Fetch the payload, and see if this was the last one. + done = radio.read(&got_time, sizeof(unsigned long)); + + // Spew it + printf("Got payload %lu...", got_time); + + // Delay just a little bit to let the other unit + // make the transition to receiver + delay(20); + } + + // First, stop listening so we can talk + radio.stopListening(); + + // Send the final one back. + radio.write(&got_time, sizeof(unsigned long)); + printf("Sent response.\r\n"); + + // Now, resume listening so we catch the next packets. + radio.startListening(); + } + } +} +// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/readme.md b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/readme.md new file mode 100644 index 0000000..c4b3fbb --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/old_backups/recipes/readme.md @@ -0,0 +1,7 @@ +# Recipes + +> [!note] +> These recipe examples may have not been maintained with library updates, and are provided as-is for reference purposes. + +> [!warning] +> These are recipe examples are intended for specific hardware usage. diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/rf24_ATTiny/rf24ping85/rf24ping85.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/rf24_ATTiny/rf24ping85/rf24ping85.ino new file mode 100644 index 0000000..4c5faf3 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/rf24_ATTiny/rf24ping85/rf24ping85.ino @@ -0,0 +1,204 @@ +/** + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * written in 2014 by tong67 (https://github.com/tong67) + * Updated 2020 by 2bndy5 (http://github.com/2bndy5) for the + * SpenceKonde ATTinyCore (https://github.com/SpenceKonde/ATTinyCore) + */ + +/** + * The RF24 library uses the [ATTinyCore by + * SpenceKonde](https://github.com/SpenceKonde/ATTinyCore) + * + * This sketch is a duplicate of the ManualAcknowledgements.ino example + * (without all the Serial input/output code), and it demonstrates + * a ATTiny25/45/85 or ATTiny24/44/84 driving the nRF24L01 transceiver using + * the RF24 class to communicate with another node. + * + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with manually transmitted (non-automatic) Acknowledgement (ACK) payloads. + * This example still uses ACK packets, but they have no payloads. Instead the + * acknowledging response is sent with `write()`. This tactic allows for more + * updated acknowledgement payload data, where actual ACK payloads' data are + * outdated by 1 transmission because they have to loaded before receiving a + * transmission. + * + * This example was written to be used on 2 devices acting as "nodes". + */ + +/* + * ********** Hardware configuration (& schematics) ******************* + * + * When direct use of 3V does not work (UNO boards tend to have poor 3V supply), + * use 5V with LED (1.8V ~ 2.2V drop) instead. + * For low power consumption solutions floating pins (SCK and MOSI) should be + * pulled HIGH or LOW with 10K resistors. + * + * ATTiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 4 + * ^^ + * +-\/-+ // + * PB5 1|o |8 Vcc --- nRF24L01 VCC --- |<|--- 5V + * nRF24L01 CE --- PB3 2| |7 PB2 --- nRF24L01 SCK LED + * nRF24L01 CSN --- PB4 3| |6 PB1 --- nRF24L01 MOSI + * nRF24L01 GND --- GND 4| |5 PB0 --- nRF24L01 MISO + * +----+ + * + * ATTiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 3 => PB3 and PB4 are + * free to use for other purposes. This "3 pin solution" is from + * Ralph Doncaster (AKA NerdRalph) which is outlined on his blog at + * http://nerdralph.blogspot.ca/2014/01/nrf24l01-control-with-3-attiny85-pins.html + * Original RC combination was 1K/100nF. 22K/10nF combination worked better. + * + * For best settle time delay value to use for RF24::csDelay in RF24::csn(), use + * the examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino sketch. + * + * This configuration is enabled in the RF24 library when CE_PIN and + * CSN_PIN parameters to the constructor are equal. Notice (in the schematic + * below) that these pins aren't directly to the ATTiny85. Because the CE pin + * is always HIGH, the power consumption is higher than it would be for the + * typical 5 pins solution. + * ^^ + * +-\/-+ nRF24L01 CE --------| // + * PB5 1|o |8 Vcc --- nRF24L01 VCC -------x----------x--|<|-- 5V + * PB3 2| |7 PB2 --- nRF24L01 SCK ---|<|---x-[22k]--| LED + * PB4 3| |6 PB1 --- nRF24L01 MOSI 1n4148 | + * nRF24L01 GND -x- GND 4| |5 PB0 --- nRF24L01 MISO | + * | +----+ | + * |-----------------------------------------||----x-- nRF24L01 CSN + * 10nF + * + * ATTiny24/44/84 Pin map with CE_PIN 8 and CSN_PIN 7 & assuming 1.9V to 3V on VCC + * Schematic provided and successfully tested by + * Carmine Pastore (https://github.com/Carminepz) + * + * +-\/-+ + * nRF24L01 VCC ---- VCC 1|o |14 GND --- nRF24L01 GND + * PB0 2| |13 AREF + * PB1 3| |12 PA1 + * PB3 4| |11 PA2 --- nRF24L01 CE + * PB2 5| |10 PA3 --- nRF24L01 CSN + * PA7 6| |9 PA4 --- nRF24L01 SCK + * nRF24L01 MOSI --- PA6 7| |8 PA5 --- nRF24L01 MISO + * +----+ + */ + +#include "SPI.h" +#include "RF24.h" + +// CE and CSN are configurable, specified values for ATTiny85 as connected above +#define CE_PIN 3 +#define CSN_PIN 4 +//#define CSN_PIN 3 // uncomment for ATTiny85 3 pins solution + +// 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 & an integer number that will be incremented +// on every successful transmission. +// Make a data structure to store the entire payload of different datatypes +struct PayloadStruct { + char message[7]; // only using 6 characters for TX & RX payloads + uint8_t counter; +}; +PayloadStruct payload; + +void setup() { + + // append a NULL terminating character for printing as a c-string + payload.message[6] = 0; + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + while (1) {} // hold in infinite loop + } + + // 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. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // char[7] & uint8_t datatypes occupy 8 bytes + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + if (role) { + // setup the TX node + + memcpy(payload.message, "Hello ", 6); // set the outgoing message + radio.stopListening(); // put radio in TX mode + } else { + // setup the RX node + + memcpy(payload.message, "World ", 6); // set the outgoing message + radio.startListening(); // put radio in RX mode + } +} // setup() + +void loop() { + + if (role) { + // This device is a TX node + + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + + if (report) { + // transmission successful; wait for response and print results + + radio.startListening(); // put in RX mode + unsigned long start_timeout = millis(); // timer to detect no response + while (!radio.available()) { // wait for response or timeout + if (millis() - start_timeout > 200) // only wait 200 ms + break; + } + radio.stopListening(); // put back in TX mode + + // print summary of transactions + if (radio.available()) { // is there a payload received? + + PayloadStruct received; + radio.read(&received, sizeof(received)); // get payload from RX FIFO + payload.counter = received.counter; // save incoming counter for next outgoing counter + } + } // report + + // to make this example readable in the serial monitor + delay(1000); // slow transmissions down by 1 second + + } else { + // This device is a RX node + + if (radio.available()) { // is there a payload? + + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming payload + payload.counter = received.counter + 1; // increment incoming counter for next outgoing response + + // transmit response & save result to `report` + radio.stopListening(); // put in TX mode + + radio.writeFast(&payload, sizeof(payload)); // load response to TX FIFO + radio.txStandBy(150); // keep retrying for 150 ms + + radio.startListening(); // put back in RX mode + } + } // role +} // loop diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino new file mode 100644 index 0000000..6a983fa --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/rf24_ATTiny/timingSearch3pin/timingSearch3pin.ino @@ -0,0 +1,207 @@ +/** + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * written by tong67 (https://github.com/tong67) + * edited by 2bndy5 (http://github.com/2bndy5) for compatibility with SpenceKonde's ATTinyCore + */ + +/* + * This sketch can determine the best settle time values to use for + * macros, defined as RF24_CSN_SETTLE_HIGH_DELAY and RF24_CSN_SETTLE_LOW_DELAY, + * in RF24::csn(). + * The settle time values used here are 100/20. However, these values depend + * on the actual used RC combination and voltage drop by LED. The + * intermediate results are written to TX (PB3, pin 2 -- using Serial). + * + * For schematic details, see introductory comment block in the + * examples/rf24_ATTiny/rf24ping85/rf24ping85.ino sketch. + */ + +#include <stdio.h> +#include <SPI.h> +#include <Arduino.h> +#include <nRF24L01.h> + + +#if defined(ARDUINO) && !defined(__arm__) +#if defined(__AVR_ATtinyX5__) || defined(__AVR_ATtinyX4__) +#define RF24_TINY +#endif +#endif + +/****************************************************************************/ + +#if defined(RF24_TINY) + +// when Attiny84 or Attiny85 is detected +#define CE_PIN 3 /** "Chip Enable" pin, activates the RX or TX role */ +#define CSN_PIN 3 /** SPI Chip Select Not */ + +#else +// when not running on an ATTiny84 or ATTiny85 +#define CE_PIN 7 /** "Chip Enable" pin, activates the RX or TX role */ +#define CSN_PIN 8 /** SPI Chip Select Not */ + +#endif + +#define MAX_HIGH 100 +#define MAX_LOW 100 +#define MINIMAL 8 + +// Use these adjustable variables to test for best configuration to be used on +// the ATTiny chips. These variables are defined as macros in the library's +// RF24/utility/ATTiny/RF24_arch_config.h file. To change them, simply define +// the corresponding macro(s) before #include <RF24> in your sketch. +uint8_t csnHighSettle = MAX_HIGH; // defined as RF24_CSN_SETTLE_HIGH_DELAY +uint8_t csnLowSettle = MAX_LOW; // defined as RF24_CSN_SETTLE_LOW_DELAY + +/****************************************************************************/ +void ce(bool level) { + if (CE_PIN != CSN_PIN) digitalWrite(CE_PIN, level); +} + +/****************************************************************************/ +void csn(bool mode) { + if (CE_PIN != CSN_PIN) { + digitalWrite(CSN_PIN, mode); + } else { + // digitalWrite(SCK, mode); + if (mode == HIGH) { + PORTB |= (1 << PINB2); // SCK->CSN HIGH + delayMicroseconds(csnHighSettle); // allow csn to settle + } else { + PORTB &= ~(1 << PINB2); // SCK->CSN LOW + delayMicroseconds(csnLowSettle); // allow csn to settle + } + } +} + +/****************************************************************************/ +uint8_t read_register(uint8_t reg) { + csn(LOW); + SPI.transfer(reg); + uint8_t result = SPI.transfer(0xff); + csn(HIGH); + return result; +} + +/****************************************************************************/ +void write_register(uint8_t reg, uint8_t value) { + csn(LOW); + SPI.transfer(W_REGISTER | reg); + SPI.transfer(value); + csn(HIGH); +} + +/****************************************************************************/ +void setup(void) { + +#ifndef __AVR_ATtinyX313__ + // not enough memory on ATTiny4313 or ATTint2313(a) to use Serial I/O for this sketch + + // start serial port and SPI + Serial.begin(115200); + SPI.begin(); + // configure CE and CSN as output when used + pinMode(CE_PIN, OUTPUT); + if (CSN_PIN != CE_PIN) + pinMode(CSN_PIN, OUTPUT); + + // csn is used in SPI transfers. Set to LOW at start and HIGH after transfer. Set to HIGH to reflect no transfer active + // SPI command are accepted in Power Down state. + // CE pin represent PRX (LOW) or PTX (HIGH) mode apart from register settings. Start in PRX mode. + ce(LOW); + csn(HIGH); + + // nRF24L01 goes from to Power Down state 100ms after Power on Reset ( Vdd > 1.9V) or when PWR_UP is 0 in config register + // Goto Power Down state (Powerup or force) and set in transmit mode + write_register(NRF_CONFIG, read_register(NRF_CONFIG) & ~_BV(PWR_UP) & ~_BV(PRIM_RX)); + delay(100); + + // Goto Standby-I + // Technically we require 4.5ms Tpd2stby+ 14us as a worst case. We'll just call it 5ms for good measure. + // WARNING: Delay is based on P-variant whereby non-P *may* require different timing. + write_register(NRF_CONFIG, read_register(NRF_CONFIG) | _BV(PWR_UP)); + delay(5); + + // Goto Standby-II + ce(HIGH); + Serial.print("Scanning for optimal setting time for csn"); + + + /************************** Main program *********************************/ + + uint8_t result; // used to compare read/write results with read/write cmds + bool success = true; + uint8_t bottom_success; + bool bottom_found; + uint8_t value[] = { 5, 10 }; + uint8_t limit[] = { MAX_HIGH, MAX_LOW }; + uint8_t advice[] = { MAX_HIGH, MAX_LOW }; + + // check max values give correct behavior + for (uint8_t k = 0; k < 2; k++) { + bottom_found = false; + bottom_success = 0; + while (bottom_success < 255) { + csnHighSettle = limit[0]; + csnLowSettle = limit[1]; + // check current values + uint8_t i = 0; + while (i < 255 && success) { + for (uint8_t j = 0; j < 2; j++) { + write_register(EN_AA, value[j]); + result = read_register(EN_AA); + if (value[j] != result) { + success = false; + } + } + i++; + } + // process result of current values + if (!success) { + Serial.print("Settle Not OK. csnHigh="); + Serial.print(limit[0], DEC); + Serial.print(" csnLow="); + Serial.println(limit[1], DEC); + limit[k]++; + bottom_found = true; + bottom_success = 0; + success = true; + } else { + Serial.print("Settle OK. csnHigh="); + Serial.print(limit[0], DEC); + Serial.print(" csnLow="); + Serial.println(limit[1], DEC); + if (!bottom_found) { + limit[k]--; + if (limit[k] == MINIMAL) { + bottom_found = true; + bottom_success = 0; + success = true; + } + } else { + bottom_success++; + } + } + } // while (bottom_success < 255) + Serial.print("Settle value found for "); + if (k == 0) { + Serial.print("csnHigh: "); + } else { + Serial.print("csnLow: "); + } + Serial.println(limit[k], DEC); + advice[k] = limit[k] + (limit[k] / 10); + limit[k] = 100; + } // for (uint8_t k = 0; k < 2; k++) + Serial.print("Advised Settle times are: csnHigh="); + Serial.print(advice[0], DEC); + Serial.print(" csnLow="); + Serial.println(advice[1], DEC); + +#endif // not defined __AVR_ATtinyX313__ +} + + +void loop(void) {} // this program runs only once, thus it resides in setup() diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/scanner/scanner.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/scanner/scanner.ino new file mode 100644 index 0000000..d6c7d44 --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/scanner/scanner.ino @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2011 J. Coliz <maniacbug@ymail.com> + * Updated 2020 TMRh20 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +/** + * Channel scanner and Continuous Carrier Wave Output + * + * Example to detect interference on the various channels available. + * This is a good diagnostic tool to check whether you're picking a + * good channel for your application. + * + * Run this sketch on two devices. On one device, start emitting a constant carrier wave + * by sending a channel number in the Serial Monitor. The other device scanning should + * detect the constant carrier wave from the sending device on the given channel. + * Send a negative number in the Serial Monitor to stop emitting a constant carrier wave + * and resume scanning. + * + * Inspired by cpixip. + * See https://forum.arduino.cc/t/poor-mans-2-4-ghz-scanner/54846 + * + * See documentation at https://nRF24.github.io/RF24 + */ + +/* + * How to read the output: + * - The header is a list of supported channels in decimal written vertically. + * - Each column corresponding to the vertical header is a hexadecimal count of + * detected signals (max is 15 or 'f'). + * + * The following example + * 000 + * 111 + * 789 + * ~~~ <- just a divider between the channel's vertical labels and signal counts + * 1-2 + * can be interpreted as + * - 1 signal detected on channel 17 + * - 0 signals (denoted as '-') detected on channel 18 + * - 2 signals detected on channel 19 + * + * Each line of signal counts represent 100 passes of the supported spectrum. + */ + +#include "RF24.h" +#include "printf.h" + +// +// Hardware configuration +// + +#define CE_PIN 7 +#define CSN_PIN 8 +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// +// Channel info +// + +const uint8_t num_channels = 126; // 0-125 are supported +uint8_t values[num_channels]; // the array to store summary of signal counts per channel + +// To detect noise, we'll use the worst addresses possible (a reverse engineering tactic). +// These addresses are designed to confuse the radio into thinking +// that the RF signal's preamble is part of the packet/payload. +const uint8_t noiseAddress[][2] = { { 0x55, 0x55 }, { 0xAA, 0xAA }, { 0xA0, 0xAA }, { 0xAB, 0xAA }, { 0xAC, 0xAA }, { 0xAD, 0xAA } }; + +const int num_reps = 100; // number of passes for each scan of the entire spectrum +bool constCarrierMode = 0; // this flag controls example behavior (scan mode is default) + +void printHeader(); // prototype function for printing the channels' header + + +void setup(void) { + + // Print preamble + Serial.begin(115200); + while (!Serial) { + // some boards need this to wait for Serial connection + } + Serial.println(F("RF24/examples/scanner/")); + + // Setup and configure rf radio + if (!radio.begin()) { + Serial.println(F("radio hardware not responding!")); + while (true) { + // hold in an infinite loop + } + } + radio.stopConstCarrier(); // in case MCU was reset while radio was emitting carrier wave + radio.setAutoAck(false); // Don't acknowledge arbitrary signals + radio.disableCRC(); // Accept any signal we find + radio.setAddressWidth(2); // A reverse engineering tactic (not typically recommended) + for (uint8_t i = 0; i < 6; ++i) { + radio.openReadingPipe(i, noiseAddress[i]); + } + + // set the data rate + Serial.print(F("Select your Data Rate. ")); + Serial.print(F("Enter '1' for 1 Mbps, '2' for 2 Mbps, '3' for 250 kbps. ")); + Serial.println(F("Defaults to 1Mbps.")); + while (!Serial.available()) { + // wait for user input + } + uint8_t dataRate = Serial.parseInt(); + if (dataRate == 50) { + Serial.println(F("Using 2 Mbps.")); + radio.setDataRate(RF24_2MBPS); + } else if (dataRate == 51) { + Serial.println(F("Using 250 kbps.")); + radio.setDataRate(RF24_250KBPS); + } else { + Serial.println(F("Using 1 Mbps.")); + radio.setDataRate(RF24_1MBPS); + } + Serial.println(F("***Enter a channel number to emit a constant carrier wave.")); + Serial.println(F("***Enter a negative number to switch back to scanner mode.")); + + // Get into standby mode + radio.startListening(); + radio.stopListening(); + radio.flush_rx(); + + // printf_begin(); + // radio.printPrettyDetails(); + // delay(1000); + + // Print out vertical header + printHeader(); +} + +void loop(void) { + /****************************************/ + // Send a number over Serial to begin Constant Carrier Wave output + // Configure the power amplitude level below + if (Serial.available()) { + int8_t c = Serial.parseInt(); + if (c >= 0) { + c = min((int8_t)125, c); // clamp channel to supported range + constCarrierMode = 1; + radio.stopListening(); + delay(2); + Serial.print("\nStarting Carrier Wave Output on channel "); + Serial.println(c); + // for non-plus models, startConstCarrier() changes address on pipe 0 and sets address width to 5 + radio.startConstCarrier(RF24_PA_LOW, c); + } else { + constCarrierMode = 0; + radio.stopConstCarrier(); + radio.setAddressWidth(2); // reset address width + radio.openReadingPipe(0, noiseAddress[0]); // ensure address is looking for noise + Serial.println("\nStopping Carrier Wave Output"); + printHeader(); + } + + // discard any CR and LF sent + while (Serial.peek() != -1) { + if (Serial.peek() == '\r' || Serial.peek() == '\n') { + Serial.read(); + } else { // got a charater that isn't a line feed + break; // handle it on next loop() iteration + } + } + } + + /****************************************/ + + if (constCarrierMode == 0) { + // Clear measurement values + memset(values, 0, sizeof(values)); + + // Scan all channels num_reps times + int rep_counter = num_reps; + while (rep_counter--) { + int i = num_channels; + while (i--) { + // Select this channel + radio.setChannel(i); + + // Listen for a little + radio.startListening(); + delayMicroseconds(128); + bool foundSignal = radio.testRPD(); + radio.stopListening(); + + // Did we get a signal? + if (foundSignal || radio.testRPD() || radio.available()) { + ++values[i]; + radio.flush_rx(); // discard packets of noise + } + } + } + + // Print out channel measurements, clamped to a single hex digit + for (int i = 0; i < num_channels; ++i) { + if (values[i]) + Serial.print(min((uint8_t)0xf, values[i]), HEX); + else + Serial.print(F("-")); + } + Serial.println(); + + } // if constCarrierMode == 0 + else { + // show some output to prove that the program isn't bricked + Serial.print(F(".")); + delay(1000); // delay a second to keep output readable + } +} // end loop() + +void printHeader() { + // Print the hundreds digits + for (uint8_t i = 0; i < num_channels; ++i) + Serial.print(i / 100); + Serial.println(); + + // Print the tens digits + for (uint8_t i = 0; i < num_channels; ++i) + Serial.print((i % 100) / 10); + Serial.println(); + + // Print the singles digits + for (uint8_t i = 0; i < num_channels; ++i) + Serial.print(i % 10); + Serial.println(); + + // Print the header's divider + for (uint8_t i = 0; i < num_channels; ++i) + Serial.print(F("~")); + Serial.println(); +}
\ No newline at end of file diff --git a/.pio/libdeps/esp32-s3-n16r8/RF24/examples/scannerGraphic/scannerGraphic.ino b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/scannerGraphic/scannerGraphic.ino new file mode 100644 index 0000000..ddbed5a --- /dev/null +++ b/.pio/libdeps/esp32-s3-n16r8/RF24/examples/scannerGraphic/scannerGraphic.ino @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2022 Brendan Doherty <2bndy5@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +/* + * This example uses 1 of 2 different popular displays. To control which display to use, + * comment/uncomment the lines below that define + * - `SPI_DISPLAY`: This requires the "Adafruit ST7735 and ST7789 Library" installed + * - `I2C_DISPLAY`: This requires the "Adafruit SSD1306" library installed + * + * Use the Arduino Library manager to ensure the required libraries are installed. + * By default, this sketch uses the SPI_DISPLAY (ST7789). Using both displays at the same + * time is not supported by this sketch. + * + * NOTES: + * The `SCREEN_HEIGHT` and `SCREEN_WIDTH` defines may need to be adjusted according + * to your display module's capability. This example expects the display to be at + * least 128 pixels wide. Otherwise, you would have to reduce the `numChannels` + * constant to fit within your display's width. + * + * The SPI_DISPLAY uses its own pins defined by `TFT_CS`, `TFT_DC`, and the + * optional `TFT_RST` (see below). The SPI bus is shared between radio and display, + * so the display's CS pin must be connected as specified by `TFT_CS`. + * If your ST7789 display does not have a CS pin, then further modification must + * be made so it does not use the same SPI bus that the radio uses. + * + * `DEBUGGING` can be enabled (uncommented) to show Serial output. This is just a + * convenience to set radio data rate or further development. See our other + * RF24/scanner example that only uses the Serial Monitor instead of a graphic + * display. + * + * See documentation at https://nRF24.github.io/RF24 + */ +#include <Adafruit_GFX.h> // dependency of Adafruit display libraries +#include "RF24.h" + +/******************************************************************** + * CHOOSE A DISPLAY INTERFACE + * uncomment/comment only 1 of the following to use the desired display + ********************************************************************/ +// #define I2C_DISPLAY // using the SSD1306 +#define SPI_DISPLAY // using ST7789 + +/******************************************************************** + * Choose a sketch feature + * uncomment any of the following to enable a special feature + ********************************************************************/ +// #define DEBUGGING // uncomment to enable Serial output (optional) +// #define HOLD_PEAKS // uncomment to disable decay of maxPeak pixels (useful for assessing total noise) + +/******************************************************************** + * Instantiate the radio and app-specific attributes + ********************************************************************/ + +#define CE_PIN 7 +#define CSN_PIN 8 +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// To detect noise, we'll use the worst addresses possible (a reverse engineering tactic). +// These addresses are designed to confuse the radio into thinking +// that the RF signal's preamble is part of the packet/payload. +const uint8_t noiseAddress[][2] = { { 0x55, 0x55 }, { 0xAA, 0xAA }, { 0xA0, 0xAA }, { 0xAB, 0xAA }, { 0xAC, 0xAA }, { 0xAD, 0xAA } }; + +const uint8_t numChannels = 126; // 0-125 are supported + +/*********************************************************************** + * Declare caching mechanism to track history of signals for peak decay + **********************************************************************/ + +const uint8_t cacheMax = 4; + +/// A data structure to organize the cache of signals for a certain channel. +struct ChannelHistory { + /// max peak value is (at most) 2 * CACHE_MAX to allow for half-step decays + uint8_t maxPeak = 0; + + /// Push a signal's value into cached history while popping + /// oldest cached value. This also sets the maxPeak value. + /// @returns The sum of signals found in the cached history + uint8_t push(bool value) { + uint8_t sum = value; + for (uint8_t i = 0; i < cacheMax - 1; ++i) { + history[i] = history[i + 1]; + sum += history[i]; + } + history[cacheMax - 1] = value; + maxPeak = max((uint8_t)(sum * 2), maxPeak); // sum * 2 to allow half-step decay + return sum; + } + +private: + bool history[cacheMax] = { 0 }; +}; + +/// An array of caches to use as channels' history +ChannelHistory stored[numChannels]; + +/******************************************************************** + * Instantiate the appropriate display objects according to the + * defines (above near top of file) + ********************************************************************/ + +#ifdef I2C_DISPLAY + +#include <Wire.h> +#include <Adafruit_SSD1306.h> + +#define SCREEN_WIDTH 128 // OLED display width, in pixels +#define SCREEN_HEIGHT 64 // OLED display height, in pixels + +// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) +// The pins for I2C are defined by the Wire-library. +// On an arduino UNO: A4(SDA), A5(SCL) +// On an arduino MEGA 2560: 20(SDA), 21(SCL) +// On an arduino LEONARDO: 2(SDA), 3(SCL), ... +#define OLED_RESET -1 // Or set to -1 and connect to Arduino RESET pin +#define SCREEN_ADDRESS 0x3D // See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); + +#define BLACK SSD1306_BLACK +#define WHITE SSD1306_WHITE +#define REFRESH ({ display.display(); }) +#define CLEAR_DISPLAY ({ display.clearDisplay(); }) + +#elif defined(SPI_DISPLAY) + +#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789 + +#define TFT_CS 9 +#define TFT_RST -1 // Or set to -1 and connect to Arduino RESET pin +#define TFT_DC 6 + +#define SCREEN_WIDTH 135 // TFT display width, in pixels +#define SCREEN_HEIGHT 240 // TFT display height, in pixels + +// For 1.14", 1.3", 1.54", 1.69", and 2.0" TFT with ST7789: +Adafruit_ST7789 display = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST); + +#define BLACK ST77XX_BLACK +#define WHITE ST77XX_WHITE +#define REFRESH +#define CLEAR_DISPLAY ({ display.fillScreen(BLACK); }) + +#endif // if defined(I2C_DISPLAY) || defined(SPI_DISPLAY) + +// constant chart size attributes +const uint16_t margin = 1; // use 1 pixel margin for markers on each side of chart +const uint16_t barWidth = (SCREEN_WIDTH - (margin * 2)) / numChannels; +const uint16_t chartHeight = SCREEN_HEIGHT - 10; +const uint16_t chartWidth = margin * 2 + (numChannels * barWidth); + +/******************************************************************** + * Configure debugging on Serial output + ********************************************************************/ + +#ifdef DEBUGGING +#include "printf.h" +#define SERIAL_DEBUG(x) ({ x; }) +#else +#define SERIAL_DEBUG(x) +#endif + +/******************************************************************** + * Setup the app + ********************************************************************/ +void setup(void) { + +#ifdef DEBUGGING + // Print preamble + Serial.begin(115200); + while (!Serial) { + // some boards need this to wait for Serial connection + } + Serial.println(F("RF24/examples/scannerGraphic")); +#endif + +#ifdef I2C_DISPLAY + // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally + if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { + SERIAL_DEBUG(Serial.println(F("SSD1306 allocation failed"));); + while (true) { + // Don't proceed, loop forever + } + } +#elif defined(SPI_DISPLAY) + // use this initializer for a 1.14" 240x135 TFT: + display.init(SCREEN_WIDTH, SCREEN_HEIGHT); // Init ST7789 240x135 +#endif + + // Clear the buffer + CLEAR_DISPLAY; + + // Setup and configure rf radio + if (!radio.begin()) { + SERIAL_DEBUG(Serial.println(F("radio hardware not responding!"));); + display.setCursor(1, 1); + display.setTextColor(WHITE); + display.print(F("radio hardware\nnot responding!")); + REFRESH; + while (true) { + // hold in an infinite loop + } + } + displayChartAxis(); + + radio.setAutoAck(false); // Don't acknowledge arbitrary signals + radio.disableCRC(); // accept any signal we find + radio.setAddressWidth(2); // a reverse engineering tactic (not typically recommended) + for (uint8_t i = 0; i < 6; ++i) { + radio.openReadingPipe(i, noiseAddress[i]); + } + + // set the data rate +#ifdef DEBUGGING + unsigned long inputTimeout = millis() + 7000; + Serial.print(F("Select your Data Rate. ")); + Serial.println(F("Enter '1' for 1Mbps, '2' for 2Mbps, '3' for 250kbps. Defaults to 1 Mbps.")); + while (!Serial.available() && millis() < inputTimeout) { + // Wait for user input. Timeout after 7 seconds. + } + char dataRate = !Serial.available() ? '1' : Serial.parseInt(); +#else + char dataRate = '1'; +#endif + if (dataRate == '2') { + SERIAL_DEBUG(Serial.println(F("Using 2 Mbps."));); + radio.setDataRate(RF24_2MBPS); + } else if (dataRate == '3') { + SERIAL_DEBUG(Serial.println(F("Using 250 kbps."));); + radio.setDataRate(RF24_250KBPS); + } else { // dataRate == '1' or invalid values + SERIAL_DEBUG(Serial.println(F("Using 1 Mbps."));); + radio.setDataRate(RF24_1MBPS); + } + + // Get into standby mode + radio.startListening(); + radio.stopListening(); + radio.flush_rx(); +} + +/******************************************************************** + * Make the app loop forever + ********************************************************************/ +void loop(void) { + // Print out channel measurements, clamped to a single hex digit + for (uint8_t channel = 0; channel < numChannels; ++channel) { + bool foundSignal = scanChannel(channel); + uint8_t cacheSum = stored[channel].push(foundSignal); + uint8_t x = (barWidth * channel) + 1 + margin - (barWidth * (bool)channel); + // reset bar for current channel to 0 + display.fillRect(x, 0, barWidth, chartHeight, BLACK); + if (stored[channel].maxPeak > cacheSum * 2) { + // draw a peak line only if it is greater than current sum of cached signal counts + uint16_t y = chartHeight - (chartHeight * stored[channel].maxPeak / (cacheMax * 2)); + display.drawLine(x, y, x + barWidth, y, WHITE); +#ifndef HOLD_PEAKS + stored[channel].maxPeak -= 1; // decrement max peak +#endif + } + if (cacheSum) { // draw the cached signal count + uint8_t barHeight = chartHeight * cacheSum / cacheMax; + display.fillRect(x, chartHeight - barHeight, barWidth, barHeight, WHITE); + } + } + REFRESH; +} // end loop() + +/// Scan a specified channel and return the resulting flag +bool scanChannel(uint8_t channel) { + radio.setChannel(channel); + + // Listen for a little + radio.startListening(); + delayMicroseconds(130); + bool foundSignal = radio.testRPD(); + radio.stopListening(); + + // Did we get a signal? + if (foundSignal || radio.testRPD() || radio.available()) { + radio.flush_rx(); // discard packets of noise + return true; + } + return false; +} + +/// Draw the chart axis and labels +void displayChartAxis() { + // draw base line + display.drawLine(0, chartHeight + 1, chartWidth - margin, chartHeight + 1, WHITE); + + // draw base line border + display.drawLine(margin, SCREEN_HEIGHT, margin, chartHeight - 2, WHITE); + display.drawLine(chartWidth - margin, SCREEN_HEIGHT, chartWidth - margin, chartHeight - 2, WHITE); + + // draw scalar marks + for (uint8_t i = 0; i < cacheMax; ++i) { + uint8_t scalarHeight = chartHeight * i / cacheMax; + display.drawLine(0, scalarHeight, chartWidth, scalarHeight, WHITE); + } + + // draw channel range labels + display.setTextSize(1); + display.setTextColor(WHITE); + uint8_t maxChannelDigits = 0; + uint8_t tmp = numChannels; + while (tmp) { + maxChannelDigits += 1; + tmp /= 10; + } + display.setCursor(chartWidth - (7 * maxChannelDigits), chartHeight + 3); + display.print(numChannels - 1); + display.setCursor(margin + 2, chartHeight + 3); + display.print(0); + + // refresh display + REFRESH; +} |
