├── .clang-format ├── .github ├── dependabot.yml ├── doxygen.py └── workflows │ ├── build_arduino.yml │ ├── build_linux.yml │ ├── build_nrf_to_nrf.yml │ ├── build_platformIO.yml │ ├── build_rp2xxx.yml │ ├── clang_format.yml │ └── doxygen.yml ├── .gitignore ├── .readthedocs.yaml ├── CHANGELOG.md ├── CMakeLists.txt ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── RF24Network.cpp ├── RF24Network.h ├── RF24Network_config.h ├── RPi └── pyRF24Network │ ├── README.md │ ├── examples │ ├── helloworld_rx.py │ └── helloworld_tx.py │ ├── pyRF24Network.cpp │ ├── pyproject.toml │ └── setup.py ├── cmake ├── AutoConfig_RF24_DRIVER.cmake ├── CPackInfo.cmake ├── Cache.cmake ├── CompilerWarnings.cmake ├── GetLibInfo.cmake ├── PreventInSourceBuilds.cmake ├── StandardProjectSettings.cmake ├── detectCPU.cmake ├── toolchains │ ├── arm64.cmake │ ├── armhf.cmake │ ├── default.cmake │ ├── i686.cmake │ └── x86_64.cmake └── usePicoSDK.cmake ├── docs ├── Doxyfile ├── README.md ├── addressing.md ├── advanced_config.md ├── doxygen-custom.css ├── images │ ├── Logo large.png │ └── favicon.ico ├── main_page.md ├── tuning.md └── zigabee.md ├── examples ├── .clang-format ├── Network_Ping │ └── Network_Ping.ino ├── Network_Ping_Sleep │ └── Network_Ping_Sleep.ino ├── Network_Priority_RX │ └── Network_Priority_RX.ino ├── Network_Priority_TX │ └── Network_Priority_TX.ino ├── helloworld_rx │ └── helloworld_rx.ino ├── helloworld_rx_advanced │ └── helloworld_rx_advanced.ino ├── helloworld_tx │ └── helloworld_tx.ino ├── helloworld_tx_advanced │ └── helloworld_tx_advanced.ino ├── nrf_to_nrf │ ├── helloworld_rx │ │ └── helloworld_rx.ino │ ├── helloworld_rxEncryption │ │ └── helloworld_rxEncryption.ino │ ├── helloworld_tx │ │ └── helloworld_tx.ino │ └── helloworld_txEncryption │ │ └── helloworld_txEncryption.ino └── sensornet_archived.zip ├── examples_RPi ├── CMakeLists.txt ├── Makefile ├── helloworld_rx.cpp ├── helloworld_tx.cpp ├── rx-test.cpp └── temperature.txt ├── examples_pico ├── CMakeLists.txt ├── defaultPins.h ├── helloworld_rx.cpp └── helloworld_tx.cpp ├── images ├── example_tree.dot ├── example_tree.svg ├── topologyImage.jpg ├── topologyImage_Advanced.jpg ├── topologyImage_Advanced.xcf ├── topologyImage_Advanced_Multicast.jpg └── topologyImage_Advanced_Multicast.xcf ├── library.json ├── library.properties └── nurfile /.clang-format: -------------------------------------------------------------------------------- 1 | # See options listed at https://releases.llvm.org/12.0.1/tools/clang/docs/ClangFormatStyleOptions.html 2 | --- 3 | Language: Cpp 4 | # BasedOnStyle: WebKit 5 | AccessModifierOffset: -4 6 | AlignAfterOpenBracket: Align 7 | AlignConsecutiveMacros: Consecutive 8 | AlignConsecutiveAssignments: None 9 | AlignConsecutiveBitFields: None 10 | AlignConsecutiveDeclarations: None 11 | AlignEscapedNewlines: Left 12 | AlignOperands: DontAlign 13 | AlignTrailingComments: true 14 | AllowAllArgumentsOnNextLine: true 15 | AllowAllConstructorInitializersOnNextLine: true 16 | AllowAllParametersOfDeclarationOnNextLine: true 17 | AllowShortEnumsOnASingleLine: false 18 | AllowShortBlocksOnASingleLine: Empty 19 | AllowShortCaseLabelsOnASingleLine: true 20 | AllowShortFunctionsOnASingleLine: All 21 | AllowShortLambdasOnASingleLine: All 22 | AllowShortIfStatementsOnASingleLine: Never 23 | AllowShortLoopsOnASingleLine: false 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakBeforeMultilineStrings: false 26 | AlwaysBreakTemplateDeclarations: Yes 27 | AttributeMacros: ["__capability", "__output", "__ununsed"] 28 | BinPackArguments: true 29 | BinPackParameters: true 30 | BitFieldColonSpacing: Both 31 | BraceWrapping: 32 | AfterCaseLabel: false 33 | AfterClass: true 34 | AfterControlStatement: MultiLine 35 | AfterEnum: true 36 | AfterFunction: true 37 | AfterNamespace: false 38 | AfterStruct: true 39 | AfterUnion: true 40 | AfterExternBlock: false 41 | BeforeCatch: true 42 | BeforeElse: true 43 | BeforeLambdaBody: false 44 | BeforeWhile: false 45 | IndentBraces: false 46 | SplitEmptyFunction: true 47 | SplitEmptyRecord: true 48 | SplitEmptyNamespace: true 49 | BreakBeforeBinaryOperators: All 50 | BreakBeforeConceptDeclarations: true 51 | BreakBeforeBraces: Custom 52 | BreakBeforeInheritanceComma: false 53 | BreakInheritanceList: BeforeColon 54 | BreakBeforeTernaryOperators: true 55 | BreakConstructorInitializersBeforeComma: false 56 | BreakConstructorInitializers: BeforeColon 57 | BreakStringLiterals: true 58 | ColumnLimit: 0 59 | # CommentPragmas are a regex pattern indicating the comment is not be touched by the formatter 60 | CommentPragmas: "^ Include gaurd .*" 61 | CompactNamespaces: false 62 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 63 | ConstructorInitializerIndentWidth: 4 64 | ContinuationIndentWidth: 4 65 | Cpp11BracedListStyle: true 66 | DeriveLineEnding: false 67 | DerivePointerAlignment: false 68 | DisableFormat: false 69 | EmptyLineBeforeAccessModifier: Always 70 | EmptyLineAfterAccessModifier: Leave 71 | ExperimentalAutoDetectBinPacking: false 72 | FixNamespaceComments: true 73 | IncludeBlocks: Preserve 74 | IncludeCategories: 75 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 76 | Priority: 2 77 | SortPriority: 0 78 | CaseSensitive: false 79 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 80 | Priority: 3 81 | SortPriority: 0 82 | CaseSensitive: false 83 | - Regex: ".*" 84 | Priority: 1 85 | SortPriority: 0 86 | CaseSensitive: false 87 | IncludeIsMainRegex: "(Test)?$" 88 | IncludeIsMainSourceRegex: "" 89 | IndentAccessModifiers: false 90 | IndentCaseLabels: true 91 | IndentCaseBlocks: false 92 | IndentGotoLabels: false 93 | IndentPPDirectives: BeforeHash 94 | IndentExternBlock: AfterExternBlock 95 | IndentRequires: false 96 | IndentWidth: 4 97 | IndentWrappedFunctionNames: false 98 | InsertTrailingCommas: None 99 | KeepEmptyLinesAtTheStartOfBlocks: true 100 | MacroBlockBegin: "" 101 | MacroBlockEnd: "" 102 | MaxEmptyLinesToKeep: 1 103 | NamespaceIndentation: Inner 104 | PenaltyBreakAssignment: 2 105 | PenaltyBreakBeforeFirstCallParameter: 19 106 | PenaltyBreakComment: 300 107 | PenaltyBreakFirstLessLess: 120 108 | PenaltyBreakString: 1000 109 | PenaltyBreakTemplateDeclaration: 10 110 | PenaltyExcessCharacter: 1000000 111 | PenaltyReturnTypeOnItsOwnLine: 60 112 | PenaltyIndentedWhitespace: 0 113 | PointerAlignment: Left 114 | ReferenceAlignment: Pointer 115 | ReflowComments: true 116 | SpacesInLineCommentPrefix: 117 | Maximum: -1 118 | Minimum: 0 119 | ShortNamespaceLines: 0 120 | # Sort**** is about sorting include/using statements alphabetically 121 | SortIncludes: false 122 | SortUsingDeclarations: false 123 | SpaceAfterCStyleCast: false 124 | SpaceAfterLogicalNot: false 125 | SpaceAfterTemplateKeyword: false 126 | SpaceBeforeAssignmentOperators: true 127 | SpaceBeforeCaseColon: false 128 | SpaceBeforeCpp11BracedList: true 129 | SpaceBeforeCtorInitializerColon: true 130 | SpaceBeforeInheritanceColon: true 131 | SpaceBeforeParens: ControlStatements 132 | SpaceAroundPointerQualifiers: Default 133 | SpaceBeforeRangeBasedForLoopColon: true 134 | SpaceInEmptyBlock: false 135 | SpaceInEmptyParentheses: false 136 | SpacesBeforeTrailingComments: 1 137 | SpacesInAngles: false 138 | SpacesInConditionalStatement: false 139 | SpacesInContainerLiterals: false 140 | SpacesInCStyleCastParentheses: false 141 | SpacesInParentheses: false 142 | SpacesInSquareBrackets: false 143 | SpaceBeforeSquareBrackets: false 144 | Standard: c++11 145 | StatementAttributeLikeMacros: [emit] 146 | StatementMacros: [Q_UNUSED, QT_REQUIRE_VERSION] 147 | TabWidth: 4 148 | UseCRLF: false 149 | UseTab: Never 150 | WhitespaceSensitiveMacros: 151 | - PRIPSTR 152 | - STRINGIZE 153 | - PP_STRINGIZE 154 | - BOOST_PP_STRINGIZE 155 | - NS_SWIFT_NAME 156 | - CF_SWIFT_NAME 157 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" 9 | # Workflow files stored in the 10 | # default location of `.github/workflows` 11 | directory: "/" 12 | schedule: 13 | interval: "weekly" 14 | -------------------------------------------------------------------------------- /.github/doxygen.py: -------------------------------------------------------------------------------- 1 | """WARNING -- FOR CI ONLY 2 | 3 | This script is meant to be execute in CI only. 4 | Running this locally will alter the Doxyfile. 5 | Such changes SHOULD NOT be pushed to the remote. 6 | """ 7 | from pathlib import Path 8 | import json 9 | 10 | DOCS_DIR = Path(__file__).parent.parent / "docs" 11 | PROPERTIES = DOCS_DIR.parent / "library.json" 12 | CONFIG = DOCS_DIR / "Doxyfile" 13 | TMP = DOCS_DIR / "doxygenAction" 14 | 15 | 16 | def overwrite_doxygen_value(): 17 | properties = json.loads(PROPERTIES.read_text(encoding="utf-8")) 18 | assert "version" in properties 19 | config = CONFIG.read_text(encoding="utf-8") 20 | TMP.write_text("PROJECT_NUMBER = {}\n".format(properties["version"]), encoding="utf-8") 21 | config += f"\n@INCLUDE = {str(TMP)}\n" 22 | CONFIG.write_text(config, encoding="utf-8") 23 | 24 | if __name__ == "__main__": 25 | overwrite_doxygen_value() 26 | -------------------------------------------------------------------------------- /.github/workflows/build_arduino.yml: -------------------------------------------------------------------------------- 1 | name: Arduino CLI build 2 | 3 | on: 4 | pull_request: 5 | branches: [master, v1.x] 6 | paths: 7 | - ".github/workflows/build_arduino.yml" 8 | - "examples/**" 9 | 10 | push: 11 | branches: [master, v1.x] 12 | paths: 13 | - ".github/workflows/build_arduino.yml" 14 | - "examples/**" 15 | 16 | jobs: 17 | build: 18 | uses: nRF24/.github/.github/workflows/build_arduino.yaml@main 19 | with: 20 | sketch-paths: | 21 | - examples/helloworld_rx 22 | - examples/helloworld_rx_advanced 23 | - examples/helloworld_tx_advanced 24 | - examples/helloworld_tx 25 | - examples/Network_Priority_RX 26 | - examples/Network_Priority_TX 27 | # - examples/Network_Ping 28 | # - examples/Network_Ping_Sleep 29 | libraries: | 30 | - source-url: https://github.com/nRF24/RF24.git 31 | - source-path: ./ 32 | - name: nrf_to_nrf 33 | fqbn: ${{ matrix.fqbn }} 34 | enable-deltas-report: ${{ matrix.enable-deltas-report }} 35 | platforms: | 36 | - name: arduino:avr 37 | - name: arduino:megaavr 38 | - name: arduino:samd 39 | - name: arduino:mbed 40 | # - name: arduino:sam 41 | strategy: 42 | fail-fast: false 43 | matrix: 44 | fqbn: 45 | - "arduino:avr:yun" 46 | - "arduino:avr:uno" 47 | - "arduino:avr:diecimila" 48 | - "arduino:avr:mega" 49 | - "arduino:avr:megaADK" 50 | - "arduino:avr:leonardo" 51 | - "arduino:avr:micro" 52 | - "arduino:avr:esplora" 53 | - "arduino:avr:mini" 54 | - "arduino:avr:ethernet" 55 | - "arduino:avr:fio" 56 | - "arduino:avr:bt" 57 | # - "arduino:avr:LilyPad" # board not found 58 | - "arduino:avr:LilyPadUSB" 59 | - "arduino:avr:pro" 60 | - "arduino:avr:atmegang" 61 | - "arduino:avr:robotControl" 62 | # - "arduino:avr:gemma" # does not support SPI 63 | - "arduino:avr:circuitplay32u4cat" 64 | - "arduino:avr:yunmini" 65 | - "arduino:avr:chiwawa" 66 | - "arduino:avr:one" 67 | - "arduino:avr:unowifi" 68 | - "arduino:mbed:nano33ble" 69 | - "arduino:samd:mkr1000" 70 | - "arduino:samd:mkrwifi1010" 71 | - "arduino:samd:nano_33_iot" 72 | - "arduino:samd:mkrfox1200" 73 | - "arduino:samd:mkrwan1300" 74 | - "arduino:samd:mkrwan1310" 75 | - "arduino:samd:mkrgsm1400" 76 | - "arduino:samd:mkrnb1500" 77 | - "arduino:samd:mkrvidor4000" 78 | - "arduino:samd:adafruit_circuitplayground_m0" 79 | - "arduino:samd:mzero_pro_bl" 80 | - "arduino:samd:mzero_bl" 81 | - "arduino:samd:tian" 82 | - "arduino:megaavr:uno2018" 83 | # - "arduino:megaavr:nano4809" # board not found 84 | # By default, don't generate size deltas data. 85 | enable-deltas-report: 86 | - false 87 | # Generate size deltas data for this board 88 | include: 89 | - fqbn: arduino:avr:nano 90 | enable-deltas-report: true 91 | - fqbn: arduino:samd:mkrzero 92 | enable-deltas-report: true 93 | 94 | # When using a matrix to compile for multiple boards, it's necessary to use a separate job for the deltas report 95 | report: 96 | needs: [build] 97 | if: github.event_name == 'pull_request' 98 | uses: nRF24/.github/.github/workflows/arduino_size_deltas.yaml@main 99 | -------------------------------------------------------------------------------- /.github/workflows/build_linux.yml: -------------------------------------------------------------------------------- 1 | name: Linux build 2 | 3 | on: 4 | pull_request: 5 | branches: [master, v1.x] 6 | paths: 7 | - "*.h" 8 | - "*.cpp" 9 | - "CMakeLists.txt" 10 | - "cmake/**" 11 | - "library.properties" # CMake gets lib info from here 12 | - "examples_RPi/*" 13 | - "!**Makefile" # old build system is not tested in this workflow 14 | - "**pyRF24Network/setup.py" 15 | - "**pyRF24Network/*.cpp" 16 | - ".github/workflows/linux_build.yml" 17 | push: 18 | branches: [master, v1.x] 19 | paths: 20 | - "*.h" 21 | - "*.cpp" 22 | - "CMakeLists.txt" 23 | - "cmake/**" 24 | - "library.properties" # CMake gets lib info from here 25 | - "examples_RPi/**" 26 | - "!**Makefile" # old build system is not tested in this workflow 27 | - "**pyRF24Network/setup.py" 28 | - "**pyRF24Network/*.cpp" 29 | - ".github/workflows/linux_build.yml" 30 | release: 31 | types: [created] 32 | 33 | jobs: 34 | using_cmake: 35 | uses: nRF24/.github/.github/workflows/build_linux_cmake.yaml@main 36 | with: 37 | rf24network-ref: ${{ github.sha }} 38 | compiler: ${{ matrix.toolchain.compiler }} 39 | usr-dir: ${{ matrix.toolchain.usr_dir }} 40 | examples-path: examples_RPi 41 | deploy-release: ${{ github.event_name == 'release' && (matrix.toolchain.compiler == 'armhf' || matrix.toolchain.compiler == 'arm64') }} 42 | py-wrapper-path: RPi/pyRF24Network 43 | strategy: 44 | fail-fast: false 45 | matrix: 46 | toolchain: 47 | - compiler: "armhf" 48 | usr_dir: "arm-linux-gnueabihf" 49 | - compiler: "arm64" 50 | usr_dir: "aarch64-linux-gnu" 51 | # - compiler: "x86_64" 52 | # usr_dir: "x86_64-linux-gnux32" 53 | # - compiler: "i686" 54 | # usr_dir: "i686-linux-gnu" 55 | - compiler: "default" # github runner is hosted on a "amd64" 56 | usr_dir: "local" 57 | -------------------------------------------------------------------------------- /.github/workflows/build_nrf_to_nrf.yml: -------------------------------------------------------------------------------- 1 | name: nRF52840 build 2 | 3 | on: 4 | pull_request: 5 | branches: [master] 6 | push: 7 | branches: [master] 8 | 9 | jobs: 10 | build: 11 | uses: nRF24/.github/.github/workflows/build_platformio.yaml@main 12 | with: 13 | example-path: ${{ matrix.example }} 14 | board-id: ${{ matrix.board }} 15 | lib-deps: -l https://github.com/TMRh20/nrf_to_nrf.git 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | example: 20 | - "examples/nrf_to_nrf/helloworld_rx/helloworld_rx.ino" 21 | - "examples/nrf_to_nrf/helloworld_tx/helloworld_tx.ino" 22 | - "examples/nrf_to_nrf/helloworld_rxEncryption/helloworld_rxEncryption.ino" 23 | - "examples/nrf_to_nrf/helloworld_txEncryption/helloworld_txEncryption.ino" 24 | board: 25 | - "adafruit_feather_nrf52840" 26 | -------------------------------------------------------------------------------- /.github/workflows/build_platformIO.yml: -------------------------------------------------------------------------------- 1 | name: PlatformIO build 2 | 3 | on: 4 | pull_request: 5 | branches: [master, v1.x] 6 | paths: 7 | - ".github/workflows/build_platformIO.yml" 8 | - "library.json" 9 | - "examples/**" 10 | - "!examples/*.zip" 11 | push: 12 | branches: [master, v1.x] 13 | paths: 14 | - ".github/workflows/build_platformIO.yml" 15 | - "library.json" 16 | - "examples/**" 17 | - "!examples/*.zip" 18 | release: 19 | types: [published, edited] 20 | 21 | jobs: 22 | validate_lib_json: 23 | uses: nRF24/.github/.github/workflows/validate_deploy_platformio.yaml@main 24 | secrets: inherit 25 | with: 26 | deploy-release: ${{ github.event_name == 'release' }} 27 | 28 | build: 29 | needs: [validate_lib_json] 30 | uses: nRF24/.github/.github/workflows/build_platformio.yaml@main 31 | with: 32 | example-path: ${{ matrix.example }} 33 | board-id: ${{ matrix.board }} 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | example: 38 | - "examples/helloworld_rx/helloworld_rx.ino" 39 | - "examples/helloworld_rx_advanced/helloworld_rx_advanced.ino" 40 | - "examples/helloworld_tx/helloworld_tx.ino" 41 | - "examples/helloworld_tx_advanced/helloworld_tx_advanced.ino" 42 | - "examples/Network_Priority_RX/Network_Priority_RX.ino" 43 | - "examples/Network_Priority_TX/Network_Priority_TX.ino" 44 | board: 45 | - "teensy31" 46 | - "teensy35" 47 | - "teensy36" 48 | - "teensy40" 49 | - "teensy41" 50 | - "teensylc" 51 | -------------------------------------------------------------------------------- /.github/workflows/build_rp2xxx.yml: -------------------------------------------------------------------------------- 1 | name: Pico SDK build 2 | 3 | on: 4 | push: 5 | branches: [master, v1.x] 6 | paths: 7 | - ".github/workflows/build_rp2xxx.yml" 8 | - "*.h" 9 | - "*.cpp" 10 | - "CMakeLists.txt" 11 | - "cmake/" 12 | - "examples_pico/*" 13 | pull_request: 14 | branches: [master, v1.x] 15 | paths: 16 | - ".github/workflows/build_rp2xxx.yml" 17 | - "*.h" 18 | - "*.cpp" 19 | - "CMakeLists.txt" 20 | - "cmake/**" 21 | - "examples_pico/*" 22 | 23 | jobs: 24 | 25 | build: 26 | uses: nRF24/.github/.github/workflows/build_pico_sdk.yaml@main 27 | with: 28 | board-id: ${{ matrix.board }} 29 | rf24network-ref: ${{ github.sha }} 30 | strategy: 31 | fail-fast: false 32 | matrix: 33 | board: 34 | - "pico" 35 | - "adafruit_feather_rp2040" 36 | - "adafruit_itsybitsy_rp2040" 37 | - "adafruit_qtpy_rp2040" 38 | - "pimoroni_tiny2040" # examples require PicoSDK v1.2.0 39 | - "sparkfun_micromod" # examples require PicoSDK v1.2.0 40 | - "sparkfun_promicro" # examples require PicoSDK v1.2.0 41 | - "sparkfun_thingplus" # examples require PicoSDK v1.2.0 42 | # - "vgaboard" # examples require PicoSDK v1.2.0 (this can be enabled on request) 43 | - "arduino_nano_rp2040_connect" # requires PicoSDK v1.2.0 44 | - "pimoroni_picolipo_4mb" # requires PicoSDK v1.2.0 45 | - "pimoroni_picolipo_16mb" # requires PicoSDK v1.2.0 46 | - "pimoroni_pga2040" # requires PicoSDK v1.2.0 47 | # - "pimoroni_keybow2040" # no SPI bus exposed 48 | # - "pimoroni_picosystem" # SPI is reserved for LCD 49 | -------------------------------------------------------------------------------- /.github/workflows/clang_format.yml: -------------------------------------------------------------------------------- 1 | name: check code formatting 2 | 3 | on: 4 | push: 5 | branches: [master, v1.x] 6 | pull_request: 7 | branches: [master, v1.x] 8 | 9 | jobs: 10 | check_formatting: 11 | uses: nRF24/.github/.github/workflows/cpp_lint.yaml@main 12 | with: 13 | extensions: ino,c,cpp,h -------------------------------------------------------------------------------- /.github/workflows/doxygen.yml: -------------------------------------------------------------------------------- 1 | name: build Docs 2 | 3 | on: 4 | pull_request: 5 | branches: [master, v1.x] 6 | paths: 7 | - "*.h" 8 | - "docs/**" 9 | - "!docs/README.md" 10 | - "*.md" 11 | - "images/**" 12 | - ".github/workflows/doxygen.yml" 13 | - "Doxyfile" 14 | - "library.properties" # get lib version from here 15 | push: 16 | branches: [master, v1.x] 17 | paths: 18 | - "*.h" 19 | - "docs/**" 20 | - "!docs/README.md" 21 | - "*.md" 22 | - "images/**" 23 | - ".github/workflows/doxygen.yml" 24 | - "Doxyfile" 25 | - "library.properties" # get lib version from here 26 | release: 27 | types: [published, edited] 28 | workflow_dispatch: 29 | 30 | jobs: 31 | build-docs: 32 | uses: nRF24/.github/.github/workflows/build_docs.yaml@main 33 | with: 34 | deploy-gh-pages: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master') }} 35 | doxygen-version: '1.11.0' 36 | secrets: inherit 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 16000000/ 2 | 8000000/ 3 | out/ 4 | docs/html/ 5 | docs/sphinx/xml/ 6 | docs/_build/ 7 | .*.swp 8 | .*.swo 9 | Session.vim 10 | *.swp 11 | *.swo 12 | version.h 13 | *.orig 14 | *.bak 15 | PINS_*/ 16 | *.exe 17 | build/ 18 | .vscode/ 19 | *CMakeUserPresets*.json 20 | *.tar.gz 21 | *env/ 22 | *.egg-info/ 23 | 24 | # Cmake build-in-source generated stuff 25 | CMakeCache.txt 26 | CPackConfig.cmake 27 | CPackSourceConfig.cmake 28 | CMakeFiles 29 | DEBIAN 30 | cmake_install.cmake 31 | compile_commands.json 32 | # Makefile is modified when `cmake .` is run 33 | # Makefile # preserve old/traditional build system 34 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | build: 9 | os: "ubuntu-22.04" 10 | apt_packages: 11 | - libclang1-12 12 | - libclang-cpp12 13 | tools: 14 | python: "3" 15 | commands: 16 | # Install doxygen from source distributions (conda forge does not keep up-to-date doxygen releases) 17 | - > 18 | DOXYGEN_VERSION="1.12.0" && 19 | mkdir .doxygen && cd .doxygen && 20 | echo $(pwd) && 21 | echo "https://sourceforge.net/projects/doxygen/files/rel-$DOXYGEN_VERSION/doxygen-$DOXYGEN_VERSION.linux.bin.tar.gz" && 22 | curl -L https://sourceforge.net/projects/doxygen/files/rel-$DOXYGEN_VERSION/doxygen-$DOXYGEN_VERSION.linux.bin.tar.gz > doxygen.tar.gz && 23 | gunzip doxygen.tar.gz && 24 | tar xf doxygen.tar && 25 | mv doxygen-$DOXYGEN_VERSION/bin/doxygen ./ 26 | # get lib version & overwrite Doxyfile values 27 | - python3 .github/doxygen.py 28 | # run doxygen 29 | - cd docs && ../.doxygen/doxygen 30 | # copy output to RTD output path for HTML files 31 | - ls -R docs/html/ 32 | - mkdir -p ${READTHEDOCS_OUTPUT} 33 | - mv docs/html/ "${READTHEDOCS_OUTPUT}" 34 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Check if we are building a pico-sdk based project 2 | # (or more exactly: if we just got included in a pico-sdk based project) 3 | if (PICO_SDK_PATH) 4 | # If so, load the relevant CMakeLists-file but don't do anything else 5 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/usePicoSDK.cmake) 6 | return() 7 | endif() 8 | 9 | 10 | ############################ 11 | # for non-RPi-Pico platforms 12 | ############################ 13 | cmake_minimum_required(VERSION 3.15) 14 | 15 | # Set the project name to your project name 16 | project(RF24Network C CXX) 17 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/StandardProjectSettings.cmake) 18 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/PreventInSourceBuilds.cmake) 19 | 20 | # get library info from Arduino IDE's required library.properties file 21 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/GetLibInfo.cmake) # sets the variable LibTargetName 22 | 23 | # detect any applicable external libs (like pigpio) 24 | include(cmake/AutoConfig_RF24_DRIVER.cmake) 25 | 26 | # Link this 'library' to set the c++ standard / compile-time options requested 27 | add_library(${LibTargetName}_project_options INTERFACE) 28 | target_compile_features(${LibTargetName}_project_options INTERFACE cxx_std_17) 29 | add_compile_options(-Ofast -Wall) 30 | 31 | # allow using CMake options to adjust RF24Network_config.h without modiying source code 32 | option(RF24NETWORK_DEBUG "enable/disable general debugging output" OFF) 33 | option(RF24NETWORK_DEBUG_MINIMAL "enable/disable minimal debugging output" OFF) 34 | option(RF24NETWORK_DEBUG_ROUTING 35 | "enable/disable debugging output related to transmission routing" 36 | OFF 37 | ) 38 | option(RF24NETWORK_DEBUG_FRAGMENTATION 39 | "enable/disable debugging output related to message fragmentation" 40 | OFF 41 | ) 42 | option(RF24NETWORK_DEBUG_FRAGMENTATION_L2 43 | "enable/disable debugging output related to fragmented messages' transmission success" 44 | OFF 45 | ) 46 | option(DISABLE_FRAGMENTATION "disable message fragmentation" OFF) 47 | option(DISABLE_DYNAMIC_PAYLOADS "force usage of static payload size" OFF) 48 | 49 | # detect CPU and add compiler flags accordingly 50 | include(cmake/detectCPU.cmake) 51 | 52 | if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") 53 | option(ENABLE_BUILD_WITH_TIME_TRACE "Enable -ftime-trace to generate time tracing .json files on clang" OFF) 54 | if(ENABLE_BUILD_WITH_TIME_TRACE) 55 | add_compile_definitions(project_options INTERFACE -ftime-trace) 56 | endif() 57 | endif() 58 | 59 | # Link this 'library' to use the warnings specified in CompilerWarnings.cmake 60 | add_library(${LibTargetName}_project_warnings INTERFACE) 61 | 62 | # enable cache system 63 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/Cache.cmake) 64 | 65 | # standard compiler warnings 66 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/CompilerWarnings.cmake) 67 | set_project_warnings(${LibTargetName}_project_warnings) 68 | 69 | # setup CPack options 70 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/CPackInfo.cmake) 71 | 72 | if(NOT DEFINED USE_RF24_LIB_SRC) 73 | find_library(RF24 rf24 REQUIRED) 74 | message(STATUS "using RF24 library: ${RF24}") 75 | endif() 76 | 77 | ########################### 78 | # create target for bulding the RF24Network lib 79 | ########################### 80 | add_library(${LibTargetName} SHARED 81 | RF24Network.cpp 82 | ) 83 | 84 | target_include_directories(${LibTargetName} PUBLIC 85 | ${CMAKE_CURRENT_LIST_DIR} 86 | ) 87 | 88 | if(DEFINED USE_RF24_LIB_SRC OR pybind11_FOUND OR SKBUILD) 89 | message(STATUS "Building lib from RF24 source") 90 | target_compile_definitions(${LibTargetName} PUBLIC USE_RF24_LIB_SRC) 91 | if(NOT DEFINED RF24_LIB_PATH) 92 | target_include_directories(${LibTargetName} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../RF24) 93 | else() 94 | target_include_directories(${LibTargetName} PUBLIC ${RF24_LIB_PATH}) 95 | endif() 96 | target_link_libraries(${LibTargetName} 97 | INTERFACE ${LibTargetName}_project_options 98 | INTERFACE ${LibTargetName}_project_warnings 99 | ) 100 | 101 | else() 102 | target_link_libraries(${LibTargetName} 103 | INTERFACE ${LibTargetName}_project_options 104 | INTERFACE ${LibTargetName}_project_warnings 105 | SHARED ${RF24} 106 | ) 107 | endif() 108 | 109 | set_target_properties( 110 | ${LibTargetName} 111 | PROPERTIES 112 | SOVERSION ${${LibName}_VERSION_MAJOR} 113 | VERSION ${${LibName}_VERSION_STRING} 114 | ) 115 | 116 | # assert the appropriate preprocessor macros for RF24Network_config.h 117 | if(RF24NETWORK_DEBUG) 118 | message(STATUS "RF24NETWORK_DEBUG asserted") 119 | target_compile_definitions(${LibTargetName} PUBLIC RF24NETWORK_DEBUG) 120 | endif() 121 | if(RF24NETWORK_DEBUG_MINIMAL) 122 | message(STATUS "RF24NETWORK_DEBUG_MINIMAL asserted") 123 | target_compile_definitions(${LibTargetName} PUBLIC RF24NETWORK_DEBUG_MINIMAL) 124 | endif() 125 | if(RF24NETWORK_DEBUG_ROUTING) 126 | message(STATUS "RF24NETWORK_DEBUG_ROUTING asserted") 127 | target_compile_definitions(${LibTargetName} PUBLIC RF24NETWORK_DEBUG_ROUTING) 128 | endif() 129 | if(RF24NETWORK_DEBUG_FRAGMENTATION) 130 | message(STATUS "RF24NETWORK_DEBUG_FRAGMENTATION asserted") 131 | target_compile_definitions(${LibTargetName} PUBLIC RF24NETWORK_DEBUG_FRAGMENTATION) 132 | endif() 133 | if(RF24NETWORK_DEBUG_FRAGMENTATION_L2) 134 | message(STATUS "RF24NETWORK_DEBUG_FRAGMENTATION_L2 asserted") 135 | target_compile_definitions(${LibTargetName} PUBLIC RF24NETWORK_DEBUG_FRAGMENTATION_L2) 136 | endif() 137 | if(DISABLE_FRAGMENTATION) 138 | message(STATUS "DISABLE_FRAGMENTATION asserted") 139 | target_compile_definitions(${LibTargetName} PUBLIC DISABLE_FRAGMENTATION) 140 | endif() 141 | if(DISABLE_DYNAMIC_PAYLOADS) 142 | message(STATUS "DISABLE_DYNAMIC_PAYLOADS asserted") 143 | target_compile_definitions(${LibTargetName} PUBLIC DISABLE_DYNAMIC_PAYLOADS) 144 | endif() 145 | # for MAX_PAYLOAD_SIZE, we let the default be configured in source code 146 | if(DEFINED MAX_PAYLOAD_SIZE) # don't use CMake's `option()` for this one 147 | message(STATUS "MAX_PAYLOAD_SIZE set to ${MAX_PAYLOAD_SIZE}") 148 | target_compile_definitions(${LibTargetName} PUBLIC MAX_PAYLOAD_SIZE=${MAX_PAYLOAD_SIZE}) 149 | endif() 150 | if(DEFINED SLOW_ADDR_POLL_RESPONSE) 151 | message(STATUS "SLOW_ADDR_POLL_RESPONSE set to ${SLOW_ADDR_POLL_RESPONSE}") 152 | target_compile_definitions(${LibTargetName} PUBLIC SLOW_ADDR_POLL_RESPONSE=${SLOW_ADDR_POLL_RESPONSE}) 153 | endif() 154 | 155 | ########################### 156 | # target install rules for the RF24Network lib 157 | ########################### 158 | install(TARGETS ${LibTargetName} 159 | DESTINATION lib 160 | ) 161 | 162 | install(FILES 163 | RF24Network.h 164 | RF24Network_config.h 165 | DESTINATION include/RF24Network 166 | ) 167 | 168 | # CMAKE_CROSSCOMPILING is only TRUE when CMAKE_TOOLCHAIN_FILE is specified via CLI 169 | if("${CMAKE_CROSSCOMPILING}" STREQUAL "FALSE") 170 | install(CODE "message(STATUS \"Updating ldconfig\")") 171 | install(CODE "execute_process(COMMAND ldconfig)") 172 | endif() 173 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | These are the current requirements for getting your code included in RF24Network: 2 | 3 | * Try your best to follow the rest of the code, if you're unsure then the NASA C style can help as it's closest to the current style: https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19950022400.pdf 4 | 5 | * Definetly follow [PEP-8](https://www.python.org/dev/peps/pep-0008/) if it's Python code. 6 | 7 | * Follow the [Arduino IDE formatting style](https://www.arduino.cc/en/Reference/StyleGuide) for Arduino examples 8 | 9 | * Add [doxygen-compatible documentation](https://www.doxygen.nl/manual/docblocks.html) to any new functions you add, or update existing documentation if you change behaviour 10 | 11 | * CMake modules and CMakeLists.txt files should also have a uniform syntax. 12 | - Indentation is a mandatory 4 spaces (not a `\t` character). 13 | - Closing parenthesis for multi-line commands should have the same indentation as the line that opened the parenthesis. 14 | - For other useful CMake syntax convention, please see [CMake docs for developers](https://cmake.org/cmake/help/v3.20/manual/cmake-developer.7.html) and [this useful best CMake practices article](https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1). The qiBuild project has some [well-reasoned "Dos & Don'ts" guideline](http://doc.aldebaran.com/qibuild/hacking/contrib/cmake/coding_guide.html), but beware that the nRF24 organization is not related to the qiBuild project in any way. 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # 3 | # Makefile for librf24network-bcm on Raspberry Pi 4 | # 5 | # License: GPL (General Public License) 6 | # Author: Charles-Henri Hallard 7 | # Date: 2013/03/13 8 | # 9 | # Description: 10 | # ------------ 11 | # use make all and mak install to install the library 12 | # You can change the install directory by editing the LIBDIR line 13 | # 14 | PREFIX=/usr/local 15 | 16 | # Library parameters 17 | # where to put the lib 18 | LIBDIR=$(PREFIX)/lib 19 | # lib name 20 | LIB_RFN=librf24network 21 | # shared library name 22 | LIBNAME_RFN=$(LIB_RFN).so.1.0 23 | 24 | HEADER_DIR=${PREFIX}/include/RF24Network 25 | 26 | ARCH=armv6zk 27 | ifeq "$(shell uname -m)" "armv7l" 28 | ARCH=armv7-a 29 | endif 30 | 31 | # Detect the Raspberry Pi from cpuinfo 32 | #Count the matches for BCM2708 or BCM2709 in cpuinfo 33 | RPI=$(shell cat /proc/cpuinfo | grep Hardware | grep -c BCM2708) 34 | ifneq "${RPI}" "1" 35 | RPI=$(shell cat /proc/cpuinfo | grep Hardware | grep -c BCM2709) 36 | endif 37 | 38 | ifeq "$(RPI)" "1" 39 | # The recommended compiler flags for the Raspberry Pi 40 | CCFLAGS=-Ofast -mfpu=vfp -mfloat-abi=hard -march=$(ARCH) -mtune=arm1176jzf-s -std=c++0x 41 | endif 42 | 43 | # make all 44 | # reinstall the library after each recompilation 45 | all: librf24network 46 | 47 | # Make the library 48 | librf24network: RF24Network.o 49 | g++ -shared -Wl,-soname,$@.so.1 ${CCFLAGS} -o ${LIBNAME_RFN} $^ -lrf24-bcm 50 | 51 | # Library parts 52 | RF24Network.o: RF24Network.cpp 53 | g++ -Wall -fPIC ${CCFLAGS} -c $^ 54 | 55 | # clear build files 56 | clean: 57 | rm -rf *.o ${LIB_RFN}.* 58 | 59 | install: all install-libs install-headers 60 | 61 | # Install the library to LIBPATH 62 | 63 | install-libs: 64 | @echo "[Install]" 65 | @if ( test ! -d $(PREFIX)/lib ) ; then mkdir -p $(PREFIX)/lib ; fi 66 | @install -m 0755 ${LIBNAME_RFN} ${LIBDIR} 67 | @ln -sf ${LIBDIR}/${LIBNAME_RFN} ${LIBDIR}/${LIB_RFN}.so.1 68 | @ln -sf ${LIBDIR}/${LIBNAME_RFN} ${LIBDIR}/${LIB_RFN}.so 69 | @ldconfig 70 | 71 | install-headers: 72 | @echo "[Installing Headers]" 73 | @if ( test ! -d ${HEADER_DIR} ) ; then mkdir -p ${HEADER_DIR} ; fi 74 | @install -m 0644 *.h ${HEADER_DIR} 75 | 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![Linux build](https://github.com/nRF24/RF24Network/actions/workflows/build_linux.yml/badge.svg)](https://github.com/nRF24/RF24Network/actions/workflows/build_linux.yml) 3 | [![Arduino CLI build](https://github.com/nRF24/RF24Network/actions/workflows/build_arduino.yml/badge.svg)](https://github.com/nRF24/RF24Network/actions/workflows/build_arduino.yml) 4 | [![PlatformIO build](https://github.com/nRF24/RF24Network/actions/workflows/build_platformIO.yml/badge.svg)](https://github.com/nRF24/RF24Network/actions/workflows/build_platformIO.yml) 5 | [![Pico SDK build](https://github.com/nRF24/RF24Network/actions/workflows/build_rp2xxx.yml/badge.svg)](https://github.com/nRF24/RF24Network/actions/workflows/build_rp2xxx.yml) 6 | [![Documentation Status](https://readthedocs.org/projects/rf24network/badge/?version=latest)](https://rf24network.readthedocs.io/en/latest/?badge=latest) 7 | 8 | # TMRh20 2014-2024 - Optimized Network Layer for nRF24L01(+) & nRF52x radios 9 | Introducing **RF24Network & RF24Mesh v2.0** with some *significant API changes*, adding the use of C++ Templates in order to support a 10 | range of ESB enabled radios, most recently NRF52x radios. 11 | 12 | **Important Notes:** 13 | - Any network layer that uses v2 needs to have RF24Network/RF24Mesh dependencies of v2 or newer. RF24 v1.x is an exception here. 14 | - General usage should remain backward compatible, see the included examples of the related libraries for more info 15 | - Any third party libs that extend the network/mesh layer may also need to be updated to incorporate the new templated class prototypes: 16 | ```cpp 17 | template 18 | class ESBNetwork; 19 | 20 | template 21 | class ESBMesh; 22 | ``` 23 | - Third party libs should also be able to use the backward-compatible typedef in their template: 24 | - ESBGateway.h: 25 | ```cpp 26 | template 27 | class ESBGateway 28 | ``` 29 | and inform the compiler what types they intend to support: 30 | - ESBGateway.cpp: 31 | ```cpp 32 | template class ESBGateway; 33 | ``` 34 | - The auto installers do not perform a version check like package managers, so having the correct versions of the software is important. 35 | - We *will* be maintaining the v1.x versions with bugfixes etc for those who cannot or do not wish to migrate to the newer template approach. 36 | 37 | Please see the full documentation at http://nRF24.github.io/RF24Network/ for more information 38 | 39 | See http://nRF24.github.io/RF24/index.html for general RF24 configuration and setup 40 | 41 | See [Linux Installation](http://nRF24.github.io/RF24/md_docs_linux_install.html) and [General Linux/RPi configuration and setup](http://nRF24.github.io/RF24/md_docs_rpi_general.html) 42 | -------------------------------------------------------------------------------- /RF24Network_config.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright (C) 2011 James Coliz, Jr. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | version 2 as published by the Free Software Foundation. 8 | */ 9 | 10 | #ifndef __RF24NETWORK_CONFIG_H__ 11 | #define __RF24NETWORK_CONFIG_H__ 12 | 13 | /** @brief A reserved valid address for use with RF24Mesh (when a mesh node requests an assigned address) */ 14 | #ifndef NETWORK_DEFAULT_ADDRESS 15 | #define NETWORK_DEFAULT_ADDRESS 04444 16 | #endif // NETWORK_DEFAULT_ADDRESS 17 | 18 | /** @brief A sentinel address value for multicasting purposes */ 19 | #define NETWORK_MULTICAST_ADDRESS 0100 20 | 21 | /** @brief A sentinel value for internally indicating that the frame should be automatically routed as necessary */ 22 | #define NETWORK_AUTO_ROUTING 070 23 | 24 | #ifdef DOXYGEN_FORCED 25 | /** 26 | * @brief Adds a delay to node prior to transmitting @ref NETWORK_ADDR_RESPONSE messages 27 | * 28 | * By default this is undefined for speed. This defined number of milliseconds is 29 | * only applied to the master node when replying to a child trying to connect to the 30 | * mesh network. 31 | * @note It is advised to define this if any child node is running CircuitPython because 32 | * the execution speed in pure python is inherently slower than it is in C++. 33 | */ 34 | #define SLOW_ADDR_POLL_RESPONSE 10 35 | #endif // defined DOXYGEN_FORCED 36 | 37 | /** The number of 'pipes' available for addressing in the current device 38 | * Networks with NRF24L01 devices only have 6 pipes 39 | * NRF52x networks support up to 8 pipes 40 | */ 41 | #define NUM_PIPES 6 42 | 43 | #if !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny84__) 44 | 45 | /********** USER CONFIG - non ATTiny **************/ 46 | 47 | //#define ENABLE_SLEEP_MODE //AVR only 48 | /** @brief When defined, this will allow the use of multicasting messages */ 49 | #define RF24NetworkMulticast 50 | 51 | /* Saves memory by disabling fragmentation */ 52 | //#define DISABLE_FRAGMENTATION 53 | 54 | /* System defines */ 55 | 56 | /** 57 | * @brief Maximum size of fragmented network frames and fragmentation cache. 58 | * @note This buffer can now be any size > 24. Previously this needed to be a multiple of 24 (changed in v1.0.15). 59 | * @note If used with RF24Ethernet, this value is used to set the buffer sizes. 60 | * @note For nodes driven by an ATTiny based chip, this is set to 72. However, defining `DISABLE_FRAGMENTION` truncates 61 | * the actual transmitted payload to 24 bytes (which is also the default behavior on ATTiny devices). 62 | */ 63 | #ifndef MAX_PAYLOAD_SIZE 64 | #if defined linux || defined __linux 65 | #define MAX_PAYLOAD_SIZE 1514 66 | #else 67 | #define MAX_PAYLOAD_SIZE 144 68 | #endif 69 | #endif // MAX_PAYLOAD_SIZE 70 | 71 | /** 72 | * @brief The allocated size of the incoming frame buffer. 73 | * 74 | * This is the user-cache, where incoming data is stored. 75 | * Data is stored using Frames: Header (8 bytes) + Message_Size (2 bytes) + Message_Data (? bytes) 76 | * @note Over-The-Air (OTA) transmissions don't include the message size in the transmitted packet. 77 | */ 78 | #define MAIN_BUFFER_SIZE (MAX_PAYLOAD_SIZE + FRAME_HEADER_SIZE) 79 | 80 | /* Disable user payloads. Saves memory when used with RF24Ethernet or software that uses external data.*/ 81 | //#define DISABLE_USER_PAYLOADS 82 | 83 | /* Enable tracking of success and failures for all transmissions, routed and user initiated */ 84 | //#define ENABLE_NETWORK_STATS 85 | 86 | #ifndef DISABLE_DYNAMIC_PAYLOADS 87 | /** Enable dynamic payloads - If using different types of nRF24L01 modules, some may be incompatible when using this feature **/ 88 | #define ENABLE_DYNAMIC_PAYLOADS 89 | #endif // DISABLE_DYNAMIC_PAYLOADS 90 | 91 | /* Debug Options */ 92 | //#define RF24NETWORK_DEBUG 93 | //#define RF24NETWORK_DEBUG_MINIMAL 94 | //#define RF24NETWORK_DEBUG_ROUTING 95 | //#define RF24NETWORK_DEBUG_FRAGMENTATION 96 | //#define RF24NETWORK_DEBUG_FRAGMENTATION_L2 97 | /*************************************/ 98 | 99 | #else // Different set of defaults for ATTiny - fragmentation is disabled and user payloads are set to 3 max 100 | /********** USER CONFIG - ATTiny **************/ 101 | //#define ENABLE_SLEEP_MODE //AVR only 102 | #define RF24NetworkMulticast 103 | // NOTE: Only 24 bytes of a payload are used when DISABLE_FRAGMENTATION is defined 104 | #define MAX_PAYLOAD_SIZE 72 105 | #define MAIN_BUFFER_SIZE (MAX_PAYLOAD_SIZE + FRAME_HEADER_SIZE) 106 | #define DISABLE_FRAGMENTATION 107 | #define ENABLE_DYNAMIC_PAYLOADS 108 | //#define DISABLE_USER_PAYLOADS 109 | #endif 110 | /*************************************/ 111 | 112 | #endif // RF24_NETWORK_CONFIG_H 113 | 114 | #ifdef __cplusplus 115 | 116 | #if (defined(__linux) || defined(linux)) && !defined(__ARDUINO_X86__) && !defined(USE_RF24_LIB_SRC) 117 | #include 118 | 119 | // ATXMega 120 | #elif defined(XMEGA) 121 | #include "../../rf24lib/rf24lib/RF24_config.h" 122 | #else 123 | #include 124 | #endif 125 | 126 | #if !defined(ARDUINO_ARCH_AVR) 127 | // sprintf is used by RF24NetworkHeader::toString 128 | #ifndef sprintf_P 129 | #define sprintf_P sprintf 130 | #endif 131 | #endif 132 | 133 | #ifdef RF24NETWORK_DEBUG 134 | #define IF_RF24NETWORK_DEBUG(x) ({ x; }) 135 | #else 136 | #define IF_RF24NETWORK_DEBUG(x) 137 | #endif 138 | #if defined(RF24NETWORK_DEBUG_MINIMAL) 139 | #define IF_RF24NETWORK_DEBUG_MINIMAL(x) ({ x; }) 140 | #else 141 | #define IF_RF24NETWORK_DEBUG_MINIMAL(x) 142 | #endif 143 | 144 | #if defined(RF24NETWORK_DEBUG_FRAGMENTATION) 145 | #define IF_RF24NETWORK_DEBUG_FRAGMENTATION(x) ({ x; }) 146 | #else 147 | #define IF_RF24NETWORK_DEBUG_FRAGMENTATION(x) 148 | #endif 149 | 150 | #if defined(RF24NETWORK_DEBUG_FRAGMENTATION_L2) 151 | #define IF_RF24NETWORK_DEBUG_FRAGMENTATION_L2(x) ({ x; }) 152 | #else 153 | #define IF_RF24NETWORK_DEBUG_FRAGMENTATION_L2(x) 154 | #endif 155 | 156 | #if defined(RF24NETWORK_DEBUG_ROUTING) 157 | #define IF_RF24NETWORK_DEBUG_ROUTING(x) ({ x; }) 158 | #else 159 | #define IF_RF24NETWORK_DEBUG_ROUTING(x) 160 | #endif 161 | 162 | #endif // RF24_CONFIG_H 163 | -------------------------------------------------------------------------------- /RPi/pyRF24Network/README.md: -------------------------------------------------------------------------------- 1 | # Individual python wrapper 2 | 3 | > [!warning] 4 | > This python wrapper for the RF24Network C++ library was not intended 5 | > for distribution on pypi.org. Any such attempts to publish this package 6 | > is unauthorized and unofficial. 7 | 8 | ## Use pyRF24 instead 9 | 10 | We recommend using the newer [pyRF24](https://github.com/nRF24/pyRF24) package 11 | [available from pypi](https://pypi.org/project/pyrf24/) because 12 | 13 | 1. it is [practically drop-in compatible](https://nrf24.github.io/pyRF24/#migrating-to-pyrf24) 14 | 2. easier to install or get updates with popular package managers like pip 15 | 3. does not require the C++ libraries to be installed -- it uses its own isolated binaries 16 | 4. includes wrappers for RF24, RF24Network, RF24Mesh libraries 17 | 5. includes a new [fake BLE implementation](https://nrf24.github.io/pyRF24/ble_api.html) 18 | 6. has its own [dedicated documentation](https://nRF24.github.io/pyRF24) 19 | 7. is compatible with python's builtin `help()` 20 | 8. includes typing stub files for type checking tools like mypy 21 | 22 | The only reason that you should need to keep using these older individual python 23 | wrappers is if you must use python v3.6 or older. 24 | 25 | You **cannot** use these individual wrappers in combination with the pyRF24 package. 26 | -------------------------------------------------------------------------------- /RPi/pyRF24Network/examples/helloworld_rx.py: -------------------------------------------------------------------------------- 1 | """Simplest possible example of using RF24Network in RX role. 2 | Listens for messages from the transmitter and prints them out. 3 | """ 4 | import struct 5 | from RF24 import RF24 6 | from RF24Network import RF24Network 7 | 8 | 9 | ########### USER CONFIGURATION ########### 10 | # See https://github.com/TMRh20/RF24/blob/master/pyRF24/readme.md 11 | # Radio CE Pin, CSN Pin, SPI Speed 12 | # CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use 13 | # their own pin numbering 14 | # CS Pin addresses the SPI bus number at /dev/spidev. 15 | # ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. 16 | 17 | # Generic: 18 | radio = RF24(22, 0) 19 | ################## Linux (BBB,x86,etc) ######################### 20 | # See http://nRF24.github.io/RF24/pages.html for more information on usage 21 | # See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA 22 | # See https://www.kernel.org/doc/Documentation/spi/spidev for more 23 | # information on SPIDEV 24 | 25 | # instantiate the network node using `radio` object 26 | network = RF24Network(radio) 27 | 28 | # Address of our node in Octal format (01, 021, etc) 29 | this_node = 0o0 30 | 31 | # Address of the other node 32 | other_node = 0o1 33 | 34 | # initialize the radio 35 | if not radio.begin(): 36 | raise RuntimeError("radio hardware not responding") 37 | 38 | radio.channel = 90 39 | 40 | # initialize the network node 41 | network.begin(this_node) 42 | 43 | # radio.printDetails() 44 | radio.printPrettyDetails() 45 | 46 | radio.startListening() # put radio in RX mode 47 | try: 48 | while True: 49 | network.update() 50 | while network.available(): 51 | header, payload = network.read(8) 52 | print("payload length ", len(payload)) 53 | millis, number = struct.unpack(". 16 | # ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. 17 | 18 | # Generic: 19 | radio = RF24(22, 0) 20 | ################## Linux (BBB,x86,etc) ######################### 21 | # See http://nRF24.github.io/RF24/pages.html for more information on usage 22 | # See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA 23 | # See https://www.kernel.org/doc/Documentation/spi/spidev for more 24 | # information on SPIDEV 25 | 26 | # instantiate the network node using `radio` object 27 | network = RF24Network(radio) 28 | 29 | # Address of our node in Octal format (01,021, etc) 30 | this_node = 0o1 31 | 32 | # Address of the other node 33 | other_node = 0o0 34 | 35 | # How long to wait before sending the next message 36 | interval = 2000 # in milliseconds 37 | 38 | # initialize the radio 39 | if not radio.begin(): 40 | raise RuntimeError("radio hardware not responding") 41 | 42 | radio.channel = 90 43 | 44 | # initialize the network node 45 | network.begin(this_node) 46 | 47 | # radio.printDetails() 48 | radio.printPrettyDetails() 49 | packets_sent = 0 50 | last_sent = 0 51 | 52 | try: 53 | while True: 54 | network.update() 55 | now = int(time.monotonic_ns() / 1000000) 56 | # If it's time to send a message, send it! 57 | if now - last_sent >= interval: 58 | last_sent = now 59 | packets_sent += 1 60 | payload = struct.pack("(PyByteArray_FromStringAndSize(buf, len))); 51 | delete[] buf; 52 | 53 | return bp::make_tuple(header, py_ba); 54 | } 55 | 56 | bp::tuple peek_read_wrap(RF24Network& ref, size_t maxlen) 57 | { 58 | RF24NetworkHeader header; 59 | char* buf = new char[maxlen + 1]; 60 | 61 | uint16_t len = rf24_min(maxlen, ref.peek(header)); 62 | ref.peek(header, buf, len); 63 | bp::object py_ba(bp::handle<>(PyByteArray_FromStringAndSize(buf, len))); 64 | delete[] buf; 65 | 66 | return bp::make_tuple(header, py_ba); 67 | } 68 | 69 | bool write_wrap(RF24Network& ref, RF24NetworkHeader& header, bp::object buf) 70 | { 71 | return ref.write(header, get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf)); 72 | } 73 | 74 | #if defined RF24NetworkMulticast 75 | bool multicast_wrap(RF24Network& ref, RF24NetworkHeader& header, bp::object buf, uint8_t level) 76 | { 77 | return ref.multicast(header, get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf), level); 78 | } 79 | #endif // defined RF24NetworkMulticast 80 | 81 | std::string toString_wrap(RF24NetworkHeader& ref) 82 | { 83 | return std::string(ref.toString()); 84 | } 85 | 86 | // **************** Overload wrappers ******************** 87 | void (RF24Network::*begin1)(uint8_t, uint16_t) = &RF24Network::begin; 88 | void (RF24Network::*begin2)(uint16_t) = &RF24Network::begin; 89 | uint16_t (RF24Network::*peek_header)(RF24NetworkHeader&) = &RF24Network::peek; 90 | 91 | // **************** RF24Network exposed ***************** 92 | 93 | BOOST_PYTHON_MODULE(RF24Network) 94 | { 95 | //::RF24Network 96 | bp::class_("RF24Network", bp::init((bp::arg("_radio")))) 97 | .def("available", &RF24Network::available) 98 | .def("begin", begin1, (bp::arg("_channel"), bp::arg("_node_address"))) 99 | .def("begin", begin2, (bp::arg("_node_address"))) 100 | .def("parent", &RF24Network::parent) 101 | .def("peek", peek_header, (bp::arg("header"))) 102 | .def("peek", &peek_read_wrap, (bp::arg("maxlen") = MAX_PAYLOAD_SIZE)) 103 | .def("read", &read_wrap, (bp::arg("maxlen") = MAX_PAYLOAD_SIZE)) 104 | .def("update", &RF24Network::update) 105 | .def("write", &write_wrap, (bp::arg("header"), bp::arg("buf"))) 106 | 107 | #if defined RF24NetworkMulticast 108 | 109 | .def("multicastLevel", &RF24Network::multicastLevel, (bp::arg("level"))) 110 | .def("multicast", &multicast_wrap, (bp::arg("header"), bp::arg("buf"), bp::arg("level") = 7)) 111 | .def_readwrite("multicastRelay", &RF24Network::multicastRelay) 112 | #endif // defined RF24NetworkMulticast 113 | 114 | .def("is_valid_address", &RF24Network::is_valid_address, (bp::arg("address"))) 115 | .def_readwrite("txTimeout", &RF24Network::txTimeout) 116 | .def_readwrite("routeTimeout", &RF24Network::routeTimeout) 117 | .def_readwrite("networkFlags", &RF24Network::networkFlags) 118 | .add_property("parent", &RF24Network::parent); 119 | 120 | // **************** RF24NetworkHeader exposed ***************** 121 | 122 | bp::class_("RF24NetworkHeader", bp::init<>()) 123 | .def(bp::init>((bp::arg("_to"), bp::arg("_type") = (unsigned char)(0)))) 124 | .def("toString", &toString_wrap) 125 | .def_readwrite("from_node", &RF24NetworkHeader::from_node) 126 | .def_readwrite("id", &RF24NetworkHeader::id) 127 | .def_readwrite("next_id", RF24NetworkHeader::next_id) 128 | .def_readwrite("reserved", &RF24NetworkHeader::reserved) 129 | .def_readwrite("to_node", &RF24NetworkHeader::to_node) 130 | .def_readwrite("type", &RF24NetworkHeader::type); 131 | } 132 | -------------------------------------------------------------------------------- /RPi/pyRF24Network/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "RF24Network" 7 | classifiers = [ 8 | "Programming Language :: Python :: 2", 9 | "Programming Language :: Python :: 3", 10 | "Programming Language :: C++", 11 | "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", 12 | ] 13 | license = {text = "GNU General Public License v2 (GPLv2)"} 14 | readme = {file = "README.md", content-type = "text/markdown"} 15 | dynamic = ["version"] # version is set in setup.py 16 | -------------------------------------------------------------------------------- /RPi/pyRF24Network/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | from setuptools import setup, Extension 4 | from sys import version_info 5 | 6 | BOOST_LIB = "boost_python" + ( 7 | "" if version_info < (3,) else "%d%d" % (version_info.major, version_info.minor) 8 | ) 9 | 10 | # NOTE can't access "../../library.properties" from working dir because 11 | # it's relative. Brute force absolute path dynamically. 12 | git_dir = os.path.split(os.path.abspath(os.getcwd()))[0] 13 | git_dir = os.path.split(git_dir)[0] # remove the "RPi" dir from working path 14 | 15 | # get LIB_VERSION from library.properties file for Arduino IDE 16 | version = "1.0" 17 | with open(os.path.join(git_dir, "library.properties"), "r") as f: 18 | for line in f.read().splitlines(): 19 | if line.startswith("version"): 20 | version = line.split("=")[1] 21 | 22 | setup( 23 | version=version, 24 | ext_modules=[ 25 | Extension( 26 | "RF24Network", 27 | sources=["pyRF24Network.cpp"], 28 | libraries=["rf24network", "rf24", BOOST_LIB], 29 | ) 30 | ], 31 | ) 32 | -------------------------------------------------------------------------------- /cmake/AutoConfig_RF24_DRIVER.cmake: -------------------------------------------------------------------------------- 1 | set(RF24_LINKED_DRIVER "") 2 | set(RF24_DRIVER "UNKNOWN" CACHE STRING "override automatic configuration of RF24's utility driver. 3 | Specify 1 of the following supported drivers (ie -DRF24_DRIVER=SPIDEV): 4 | wiringPi 5 | RPi 6 | SPIDEV 7 | MRAA 8 | LittleWire 9 | pigpio" 10 | ) 11 | 12 | ########################### 13 | # detect pre-existing (locally installed) 3rd party libraries 14 | ########################### 15 | 16 | # detect installed libraries despite what RF24_DRIVER is set to 17 | # this is always done for cross-compiling purposes 18 | find_library(LibMRAA mraa) 19 | find_library(LibWiringPi wiringPi) 20 | find_library(LibLittleWire littlewire-spi) 21 | find_library(LibPIGPIO pigpio) 22 | if(EXISTS /dev/spidev0.0) 23 | set(SPIDEV_EXISTS TRUE) 24 | else() 25 | set(SPIDEV_EXISTS FALSE) 26 | endif() 27 | 28 | 29 | # if(${RF24_DRIVER} STREQUAL "UNKNOWN") # invokes automatic configuration 30 | # if("${SOC}" STREQUAL "BCM2708" OR "${SOC}" STREQUAL "BCM2709" OR "${SOC}" STREQUAL "BCM2835") 31 | # set(RF24_DRIVER RPi CACHE STRING "using folder /utility/RPi" FORCE) 32 | # elseif(NOT "${LibPIGPIO}" STREQUAL "LibPIGPIO-NOTFOUND") 33 | # message(STATUS "Found pigpio library: ${LibPIGPIO}") 34 | # set(RF24_DRIVER pigpio CACHE STRING "using folder /utility/pigpio" FORCE) 35 | # elseif(NOT "${LibWiringPi}" STREQUAL "LibWiringPi-NOTFOUND") 36 | # message(STATUS "Found wiringPi library: ${LibWiringPi}") 37 | # set(RF24_DRIVER wiringPi CACHE STRING "using folder /utility/wiringPi" FORCE) 38 | # elseif(NOT "${LibLittleWire}" STREQUAL "LibLittleWire-NOTFOUND") 39 | # message(STATUS "Found LittleWire library: ${LibLittleWire}") 40 | # set(RF24_DRIVER LittleWire CACHE STRING "using folder /utility/LittleWire" FORCE) 41 | # elseif(NOT "${LibMRAA}" STREQUAL "LibMRAA-NOTFOUND") 42 | # message(STATUS "Found MRAA library: ${LibMRAA}") 43 | # set(RF24_DRIVER MRAA CACHE STRING "using folder /utility/MRAA" FORCE) 44 | # elseif(SPIDEV_EXISTS) # should be a non-empty string if SPI is enabled 45 | # message(STATUS "detected that SPIDEV is enabled: ${SPIDEV_EXISTS}") 46 | # set(RF24_DRIVER SPIDEV CACHE STRING "using folder /utility/SPIDEV" FORCE) 47 | # endif() 48 | # endif() 49 | 50 | # override the auto-detect if RF24_DRIVER is defined in an env var 51 | if(DEFINED ENV{RF24_DRIVER}) 52 | message(STATUS "RF24_DRIVER (set from env var) = $ENV{RF24_DRIVER}") 53 | set(RF24_DRIVER $ENV{RF24_DRIVER} CACHE STRING "" FORCE) 54 | elseif(${RF24_DRIVER} STREQUAL "UNKNOWN") 55 | set(RF24_DRIVER SPIDEV CACHE STRING "using folder RF24/utility/SPIDEV" FORCE) 56 | endif() 57 | 58 | message(STATUS "Using driver: ${RF24_DRIVER}") 59 | -------------------------------------------------------------------------------- /cmake/CPackInfo.cmake: -------------------------------------------------------------------------------- 1 | # This module will build a debian compatible package to install - handy for cross-compiling 2 | 3 | if(NOT PKG_REV) 4 | set(PKG_REV "1") 5 | endif() 6 | 7 | # get target arch if not cross-compiling 8 | if(NOT TARGET_ARCH) # TARGET_ARCH is defined only in the toolchain_.cmake files 9 | if(WIN32) 10 | set(TARGET_ARCH $ENV{PROCESSOR_ARCHITECTURE}) 11 | else() 12 | execute_process(COMMAND dpkg --print-architecture 13 | OUTPUT_VARIABLE TARGET_ARCH 14 | ) 15 | endif() 16 | string(STRIP "${TARGET_ARCH}" TARGET_ARCH) 17 | endif() 18 | 19 | # set the Cpack generators (specific to types of packages to create) 20 | if(NOT WIN32) 21 | set(CPACK_GENERATOR DEB RPM) # RPM requires rpmbuild executable 22 | else() 23 | set(CPACK_GENERATOR "") # should find out how to build vcpkg packages 24 | endif() 25 | 26 | # assemble a debian package filename from known info 27 | include(InstallRequiredSystemLibraries) 28 | set(CPACK_PACKAGE_FILE_NAME "lib${LibTargetName}_${${LibName}_VERSION_STRING}-${PKG_REV}_${TARGET_ARCH}") 29 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") 30 | set(CPACK_PACKAGE_VERSION_MAJOR "${${LibName}_VERSION_MAJOR}") 31 | set(CPACK_PACKAGE_VERSION_MINOR "${${LibName}_VERSION_MINOR}") 32 | set(CPACK_PACKAGE_VERSION_PATCH "${${LibName}_VERSION_PATCH}") 33 | set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/pkgs") # for easy uploading to github releases 34 | 35 | if(NOT WIN32) 36 | ############################### 37 | # info specific debian packages 38 | ############################### 39 | set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${TARGET_ARCH}) 40 | set(CPACK_DEBIAN_PACKAGE_SECTION libs) 41 | set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE) 42 | set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS ON) 43 | 44 | ############################### 45 | # info specific rpm (fedora) packages 46 | ############################### 47 | set(CPACK_RPM_FILE_NAME "lib${LibTargetName}-${${LibName}_VERSION_STRING}-${PKG_REV}.${TARGET_ARCH}.rpm") 48 | set(CPACK_RPM_PACKAGE_ARCHITECTURE ${TARGET_ARCH}) 49 | set(CPACK_RPM_PACKAGE_LICENSE "GPLv2.0") 50 | set(CPACK_RPM_PACKAGE_VENDOR "Humanity") 51 | 52 | # create a post-install & post-removal scripts to update linker 53 | set(POST_SCRIPTS 54 | ${CMAKE_BINARY_DIR}/DEBIAN/postrm 55 | ${CMAKE_BINARY_DIR}/DEBIAN/postinst 56 | ) 57 | foreach(script ${POST_SCRIPTS}) 58 | file(WRITE ${script} /sbin/ldconfig) 59 | execute_process(COMMAND chmod +x ${script}) 60 | execute_process(COMMAND chmod 775 ${script}) 61 | endforeach() 62 | # declare scripts for deb pkgs 63 | list(JOIN POST_SCRIPTS ";" EXTRA_CTRL_FILES) 64 | set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA EXTRA_CTRL_FILES) 65 | # declare scripts for rpm pkgs 66 | list(POP_FRONT POST_SCRIPTS CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE) 67 | list(POP_FRONT POST_SCRIPTS CPACK_RPM_POST_INSTALL_SCRIPT_FILE) 68 | 69 | message(STATUS "ready to package: ${CPACK_PACKAGE_FILE_NAME}.deb") 70 | message(STATUS "ready to package: ${CPACK_RPM_FILE_NAME}") 71 | endif() 72 | 73 | include(CPack) 74 | -------------------------------------------------------------------------------- /cmake/Cache.cmake: -------------------------------------------------------------------------------- 1 | option(ENABLE_CACHE "Enable cache if available" ON) 2 | if(NOT ENABLE_CACHE) 3 | return() 4 | endif() 5 | 6 | set(CACHE_OPTION "ccache" CACHE STRING "Compiler cache to be used") 7 | set(CACHE_OPTION_VALUES "ccache" "sccache") 8 | set_property(CACHE CACHE_OPTION PROPERTY STRINGS ${CACHE_OPTION_VALUES}) 9 | list(FIND CACHE_OPTION_VALUES ${CACHE_OPTION} CACHE_OPTION_INDEX) 10 | 11 | if(${CACHE_OPTION_INDEX} EQUAL -1) 12 | message(STATUS 13 | "Using custom compiler cache system: '${CACHE_OPTION}', explicitly supported entries are ${CACHE_OPTION_VALUES}" 14 | ) 15 | endif() 16 | 17 | find_program(CACHE_BINARY ${CACHE_OPTION}) 18 | if(CACHE_BINARY) 19 | message(STATUS "${CACHE_OPTION} found and enabled") 20 | set(CMAKE_CXX_COMPILER_LAUNCHER ${CACHE_BINARY}) 21 | else() 22 | message(WARNING "${CACHE_OPTION} is enabled but was not found. Not using it") 23 | endif() 24 | -------------------------------------------------------------------------------- /cmake/CompilerWarnings.cmake: -------------------------------------------------------------------------------- 1 | # from here: 2 | # 3 | # https://github.com/lefticus/cppbestpractices/blob/master/02-Use_the_Tools_Available.md 4 | 5 | function(set_project_warnings project_name) 6 | option(WARNINGS_AS_ERRORS "Treat compiler warnings as errors" TRUE) 7 | 8 | set(MSVC_WARNINGS 9 | /W4 # Baseline reasonable warnings 10 | /w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss of data 11 | /w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data 12 | /w14263 # 'function': member function does not override any base class virtual member function 13 | /w14265 # 'classname': class has virtual functions, but destructor is not virtual instances of this class may not 14 | # be destructed correctly 15 | /w14287 # 'operator': unsigned/negative constant mismatch 16 | /we4289 # nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside 17 | # the for-loop scope 18 | /w14296 # 'operator': expression is always 'boolean_value' 19 | /w14311 # 'variable': pointer truncation from 'type1' to 'type2' 20 | /w14545 # expression before comma evaluates to a function which is missing an argument list 21 | /w14546 # function call before comma missing argument list 22 | /w14547 # 'operator': operator before comma has no effect; expected operator with side-effect 23 | /w14549 # 'operator': operator before comma has no effect; did you intend 'operator'? 24 | /w14555 # expression has no effect; expected expression with side- effect 25 | /w14619 # pragma warning: there is no warning number 'number' 26 | /w14640 # Enable warning on thread un-safe static member initialization 27 | /w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior. 28 | /w14905 # wide string literal cast to 'LPSTR' 29 | /w14906 # string literal cast to 'LPWSTR' 30 | /w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied 31 | /permissive- # standards conformance mode for MSVC compiler. 32 | ) 33 | 34 | set(CLANG_WARNINGS 35 | -Wall 36 | -Wextra # reasonable and standard 37 | -Wshadow # warn the user if a variable declaration shadows one from a parent context 38 | -Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor. This helps 39 | # catch hard to track down memory errors 40 | -Wold-style-cast # warn for c-style casts 41 | -Wcast-align # warn for potential performance problem casts 42 | -Wunused # warn on anything being unused 43 | -Woverloaded-virtual # warn if you overload (not override) a virtual function 44 | -Wpedantic # warn if non-standard C++ is used 45 | -Wconversion # warn on type conversions that may lose data 46 | -Wsign-conversion # warn on sign conversions 47 | -Wnull-dereference # warn if a null dereference is detected 48 | -Wdouble-promotion # warn if float is implicit promoted to double 49 | -Wformat=2 # warn on security issues around functions that format output (ie printf) 50 | ) 51 | 52 | if(WARNINGS_AS_ERRORS) 53 | set(CLANG_WARNINGS ${CLANG_WARNINGS} -Werror) 54 | set(MSVC_WARNINGS ${MSVC_WARNINGS} /WX) 55 | endif() 56 | 57 | set(GCC_WARNINGS 58 | ${CLANG_WARNINGS} 59 | -Wmisleading-indentation # warn if indentation implies blocks where blocks do not exist 60 | -Wduplicated-cond # warn if if / else chain has duplicated conditions 61 | -Wduplicated-branches # warn if if / else branches have duplicated code 62 | -Wlogical-op # warn about logical operations being used where bitwise were probably wanted 63 | -Wuseless-cast # warn if you perform a cast to the same type 64 | ) 65 | 66 | if(MSVC) 67 | set(PROJECT_WARNINGS ${MSVC_WARNINGS}) 68 | elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") 69 | set(PROJECT_WARNINGS ${CLANG_WARNINGS}) 70 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 71 | set(PROJECT_WARNINGS ${GCC_WARNINGS}) 72 | else() 73 | message(AUTHOR_WARNING "No compiler warnings set for '${CMAKE_CXX_COMPILER_ID}' compiler.") 74 | endif() 75 | 76 | target_compile_options(${project_name} INTERFACE ${PROJECT_WARNINGS}) 77 | 78 | endfunction() 79 | -------------------------------------------------------------------------------- /cmake/GetLibInfo.cmake: -------------------------------------------------------------------------------- 1 | # get lib info from the maintained library.properties required by the Arduino IDE 2 | file(STRINGS ${CMAKE_CURRENT_LIST_DIR}/../library.properties LibInfo) 3 | foreach(line ${LibInfo}) 4 | string(FIND ${line} "=" label_delimiter) 5 | if(${label_delimiter} GREATER 0) 6 | math(EXPR label_delimiter "${label_delimiter} + 1") 7 | string(FIND ${line} "version" has_version) 8 | string(FIND ${line} "name" has_name) 9 | string(FIND ${line} "maintainer" has_maintainer) 10 | string(FIND ${line} "sentence" has_sentence) 11 | string(FIND ${line} "url" has_url) 12 | string(FIND ${line} "paragraph" has_paragraph) 13 | if(${has_version} EQUAL 0) 14 | string(SUBSTRING ${line} ${label_delimiter} "-1" VERSION) 15 | elseif(${has_name} EQUAL 0) 16 | string(SUBSTRING ${line} ${label_delimiter} "-1" LibName) 17 | elseif(${has_maintainer} EQUAL 0) 18 | string(SUBSTRING ${line} ${label_delimiter} "-1" CPACK_PACKAGE_CONTACT) 19 | elseif(${has_sentence} EQUAL 0) 20 | string(SUBSTRING ${line} ${label_delimiter} "-1" CPACK_PACKAGE_DESCRIPTION_SUMMARY) 21 | elseif(${has_url} EQUAL 0) 22 | string(SUBSTRING ${line} ${label_delimiter} "-1" CMAKE_PROJECT_HOMEPAGE_URL) 23 | elseif(${has_paragraph} EQUAL 0) 24 | string(SUBSTRING ${line} ${label_delimiter} "-1" CPACK_PACKAGE_DESCRIPTION) 25 | endif() 26 | endif() 27 | endforeach() 28 | 29 | # convert the LibName to lower case 30 | string(TOLOWER ${LibName} LibTargetName) 31 | 32 | #parse the version information into pieces. 33 | string(REGEX REPLACE "^([0-9]+)\\..*" "\\1" VERSION_MAJOR "${VERSION}") 34 | string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${VERSION}") 35 | string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_PATCH "${VERSION}") 36 | 37 | # this is the library version 38 | set(${LibName}_VERSION_MAJOR ${VERSION_MAJOR}) 39 | set(${LibName}_VERSION_MINOR ${VERSION_MINOR}) 40 | set(${LibName}_VERSION_PATCH ${VERSION_PATCH}) 41 | set(${LibName}_VERSION_STRING ${${LibName}_VERSION_MAJOR}.${${LibName}_VERSION_MINOR}.${${LibName}_VERSION_PATCH}) 42 | 43 | message(STATUS "${LibName} library version: ${${LibName}_VERSION_STRING}") 44 | -------------------------------------------------------------------------------- /cmake/PreventInSourceBuilds.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # This function will prevent in-source builds 3 | function(AssureOutOfSourceBuilds) 4 | # make sure the user doesn't play dirty with symlinks 5 | get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) 6 | get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) 7 | 8 | # disallow in-source builds 9 | if("${srcdir}" STREQUAL "${bindir}") 10 | message("######################################################") 11 | message("Warning: in-source builds are disabled") 12 | message("Please create a separate build directory and run cmake from there") 13 | message("######################################################") 14 | message(FATAL_ERROR "Quitting configuration") 15 | endif() 16 | endfunction() 17 | 18 | assureoutofsourcebuilds() 19 | -------------------------------------------------------------------------------- /cmake/StandardProjectSettings.cmake: -------------------------------------------------------------------------------- 1 | # Set a default build type if none was specified 2 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 3 | message(STATUS "Setting build type to 'Release' as none was specified.") 4 | set(CMAKE_BUILD_TYPE 5 | Release 6 | CACHE STRING "Choose the type of build." FORCE 7 | ) 8 | # Set the possible values of build type for cmake-gui, ccmake 9 | set_property( 10 | CACHE CMAKE_BUILD_TYPE 11 | PROPERTY STRINGS 12 | "Debug" 13 | "Release" 14 | "MinSizeRel" 15 | "RelWithDebInfo" 16 | ) 17 | endif() 18 | 19 | # Generate compile_commands.json to make it easier to work with clang based tools 20 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 21 | 22 | option(ENABLE_IPO "Enable Interprocedural Optimization, aka Link Time Optimization (LTO)" OFF) 23 | 24 | if(ENABLE_IPO) 25 | include(CheckIPOSupported) 26 | check_ipo_supported( 27 | RESULT result 28 | OUTPUT output 29 | ) 30 | if(result) 31 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) 32 | else() 33 | message(SEND_ERROR "IPO is not supported: ${output}") 34 | endif() 35 | endif() 36 | -------------------------------------------------------------------------------- /cmake/detectCPU.cmake: -------------------------------------------------------------------------------- 1 | # try to get the CPU model using a Linux bash command 2 | if(NOT SOC) # if SOC variable not defined by user at CLI 3 | if(EXISTS "/sys/class/sunxi_info/sys_info") 4 | execute_process(COMMAND grep sunxi_platform /sys/class/sunxi_info/sys_info 5 | OUTPUT_VARIABLE CPU_MODEL 6 | OUTPUT_STRIP_TRAILING_WHITESPACE 7 | ) 8 | else() 9 | execute_process(COMMAND grep Hardware /proc/cpuinfo 10 | OUTPUT_VARIABLE CPU_MODEL 11 | OUTPUT_STRIP_TRAILING_WHITESPACE 12 | ) 13 | endif() 14 | 15 | string(FIND "${CPU_MODEL}" ":" cpu_is_described) 16 | if(${cpu_is_described} GREATER 0) # Hardware field does exist 17 | math(EXPR cpu_is_described "${cpu_is_described} + 1") 18 | string(SUBSTRING "${CPU_MODEL}" ${cpu_is_described} -1 SOC) 19 | string(STRIP "${SOC}" SOC) 20 | else() # Hardware field does not exist 21 | set(SOC "UNKNOWN") # use this string as a sentinel 22 | endif() 23 | message(STATUS "detected SoC: ${SOC}") 24 | else() 25 | message(STATUS "SOC set to ${SOC}") 26 | endif() 27 | 28 | string(FIND "${SOC}" "Generic AM33XX" is_AM33XX) 29 | 30 | #[[ detect machine hardware name 31 | This CPU_TYPE variable is not used anywhere. 32 | It remains as useful prompt info & to be consistent with old build system ]] 33 | execute_process(COMMAND uname -m 34 | OUTPUT_VARIABLE CPU_TYPE 35 | OUTPUT_STRIP_TRAILING_WHITESPACE 36 | ) 37 | message(STATUS "detected CPU type: ${CPU_TYPE}") 38 | 39 | # identify the compiler base name for customizing flags 40 | # THIS ONLY WORKS/TESTED FOR GNU COMPILERS 41 | if(NOT CMAKE_CROSSCOMPILING) # need to use /usr/lib/gcc soft symlink 42 | # NOTE the following command doesn't work with " | tail -1" appended 43 | execute_process(COMMAND ls /usr/lib/gcc 44 | OUTPUT_VARIABLE tool_name 45 | OUTPUT_STRIP_TRAILING_WHITESPACE 46 | ) 47 | 48 | # use only last entry if multiple entries are returned 49 | string(FIND "${tool_name}" "\n" last_list_delimiter REVERSE) 50 | if(last_list_delimiter GREATER -1) 51 | math(EXPR last_list_delimiter "${last_list_delimiter} + 1") 52 | string(SUBSTRING "${tool_name}" ${last_list_delimiter} -1 tool_name) 53 | endif() 54 | 55 | else() # we can use the compiler's name of the path set in the toolchain file 56 | string(REGEX REPLACE "^\/usr\/bin\/(.*)-gcc.*" "\\1" tool_name "${CMAKE_C_COMPILER}") 57 | endif() 58 | 59 | message(STATUS "tool name being used is ${tool_name}") 60 | 61 | # add compiler flags to optomize builds with arm-linux-gnueabihf-g* compilers 62 | if("${tool_name}" STREQUAL "arm-linux-gnueabihf") 63 | if("${SOC}" STREQUAL "BCM2835" OR "${SOC}" STREQUAL "BCM2708") 64 | add_compile_options(-marm -march=armv6zk -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard) 65 | elseif("$SOC" STREQUAL "BCM2836" OR "${SOC}" STREQUAL "BCM2709") 66 | add_compile_options(-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard) 67 | elseif(${is_AM33XX} GREATER -1) 68 | add_compile_options(-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard) 69 | elseif("$SOC" STREQUAL "sun4i" OR "${SOC}" STREQUAL "Sun4iw1p1") # A10 70 | add_compile_options(-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard) 71 | elseif("$SOC" STREQUAL "sun5i" OR "${SOC}" STREQUAL "Sun4iw2p1") # A13 72 | add_compile_options(-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard) 73 | elseif("$SOC" STREQUAL "sun7i" OR "${SOC}" STREQUAL "Sun8iw2p1") # A20 74 | add_compile_options(-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard) 75 | elseif("$SOC" STREQUAL "sun8i" OR "${SOC}" STREQUAL "Sun8iw7p1") # H3 76 | add_compile_options(-march=armv8-a -mtune=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard) 77 | endif() 78 | endif() 79 | -------------------------------------------------------------------------------- /cmake/toolchains/arm64.cmake: -------------------------------------------------------------------------------- 1 | ###################### FOR CROSS-COMPILING using the aarch64-linux-gnu-g** compiler 2 | # invoke this toolchain file using `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/.cmake` 3 | # this file is meant to be used generically, but will not work for all CMake projects 4 | # this toolchain file's cmds was copied from the CMake docs then modified for better explanation and re-use 5 | 6 | set(CMAKE_SYSTEM_NAME Linux) 7 | set(CMAKE_SYSTEM_PROCESSOR arm64) 8 | set(TARGET_ARCH arm64) # only used in cmake/createDebianPkg.cmake 9 | set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc) 10 | set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++) 11 | 12 | # CMAKE_SYSROOT can only be set in a toolchain file 13 | # set(CMAKE_SYSROOT /usr/aarch64-linux-gnu) # useful when a target machine's files are available 14 | 15 | # set the directory for searching installed headers 16 | # add_compile_options(-I /usr/aarch64-linux-gnu/include) # this may not be best practice 17 | 18 | #[[ 19 | # CMAKE_STAGING_PREFIX is only useful for transfering a built CMake project to a target machine 20 | set(CMAKE_STAGING_PREFIX /home/devel/stage) # use CMAKE_INSTALL_PREFIX instead (see below comments) 21 | 22 | CMAKE_FIND_ROOT_PATH is an empty list by default (this list can be modified where applicable) 23 | if cross-compiling a dependent lib (like MRAA - which is optional), then 24 | set the lib's CMAKE_INSTALL_PREFIX to a value that is appended to RF24 lib's CMAKE_FIND_ROOT_PATH 25 | example using MRAA: 26 | (for MRAA/build dir) `cmake .. -D CMAKE_TOOLCHAIN_FILE=path/to/RF24/repo/cmake/toolchains/arm64.cmake -D CMAKE_INSTALL_PREFIX:PATH=/usr/aarch64-linux-gnu 27 | (for RF24/build dir) `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/arm64.cmake 28 | ]] 29 | list(APPEND CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu) 30 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # search CMAKE_SYSROOT when find_program() is called 31 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_library() is called 32 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_file() is called 33 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_package() is called 34 | -------------------------------------------------------------------------------- /cmake/toolchains/armhf.cmake: -------------------------------------------------------------------------------- 1 | ###################### FOR CROSS-COMPILING using the arm-linux-gnueabihf-g** compiler 2 | # invoke this toolchain file using `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/.cmake` 3 | # this file is meant to be used generically, but will not work for all CMake projects 4 | # this toolchain file's cmds was copied from the CMake docs then modified for better explanation and re-use 5 | 6 | set(CMAKE_SYSTEM_NAME Linux) 7 | set(CMAKE_SYSTEM_PROCESSOR armhf) 8 | set(TARGET_ARCH armhf) # only used in cmake/CPackInfo.cmake 9 | set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabihf-gcc) 10 | set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabihf-g++) 11 | 12 | # CMAKE_SYSROOT can only be set in a toolchain file 13 | # set(CMAKE_SYSROOT /usr/arm-linux-gnueabihf) # useful when a target machine's files are available 14 | 15 | # set the directory for searching installed headers 16 | # add_compile_options(-I /usr/arm-linux-gnueabihf/include) # this may not be best practice 17 | 18 | #[[ 19 | # CMAKE_STAGING_PREFIX is only useful for transfering a built CMake project to a target machine 20 | set(CMAKE_STAGING_PREFIX /home/devel/stage) # use CMAKE_INSTALL_PREFIX instead (see below comments) 21 | 22 | CMAKE_FIND_ROOT_PATH is an empty list by default (this list can be modified where applicable) 23 | if cross-compiling a dependent lib (like MRAA - which is optional), then 24 | set the lib's CMAKE_INSTALL_PREFIX to a value that is appended to RF24 lib's CMAKE_FIND_ROOT_PATH 25 | example using MRAA: 26 | (for MRAA/build dir) `cmake .. -D CMAKE_TOOLCHAIN_FILE=path/to/RF24/repo/cmake/toolchains/arm.cmake -D CMAKE_INSTALL_PREFIX:PATH=/usr/arm-linux-gnueabihf 27 | (for RF24/build dir) `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/arm.cmake 28 | ]] 29 | list(APPEND CMAKE_FIND_ROOT_PATH /usr/arm-linux-gnueabihf) 30 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # search CMAKE_SYSROOT when find_program() is called 31 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_library() is called 32 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_file() is called 33 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_package() is called 34 | -------------------------------------------------------------------------------- /cmake/toolchains/default.cmake: -------------------------------------------------------------------------------- 1 | # empty toolchain file to allow CI scripts to still use system default toolchains -------------------------------------------------------------------------------- /cmake/toolchains/i686.cmake: -------------------------------------------------------------------------------- 1 | ###################### FOR CROSS-COMPILING using the i686-linux-gnu-g** compiler 2 | # invoke this toolchain file using `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/.cmake` 3 | # this file is meant to be used generically, but will not work for all CMake projects 4 | # this toolchain file's cmds was copied from the CMake docs then modified for better explanation and re-use 5 | 6 | set(CMAKE_SYSTEM_NAME Linux) 7 | set(CMAKE_SYSTEM_PROCESSOR i686) 8 | set(TARGET_ARCH i686) # only used in cmake/createDebianPkg.cmake 9 | set(CMAKE_C_COMPILER /usr/bin/i686-linux-gnu-gcc) 10 | set(CMAKE_CXX_COMPILER /usr/bin/i686-linux-gnu-g++) 11 | 12 | # CMAKE_SYSROOT can only be set in a toolchain file 13 | # set(CMAKE_SYSROOT /usr/i686-linux-gnu) # useful when a target machine's files are available 14 | 15 | # set the directory for searching installed headers 16 | # add_compile_options(-I /usr/i686-linux-gnu/include) # this may not be best practice 17 | 18 | #[[ 19 | # CMAKE_STAGING_PREFIX is only useful for transfering a built CMake project to a target machine 20 | set(CMAKE_STAGING_PREFIX /home/devel/stage) # use CMAKE_INSTALL_PREFIX instead (see below comments) 21 | 22 | CMAKE_FIND_ROOT_PATH is an empty list by default (this list can be modified where applicable) 23 | if cross-compiling a dependent lib (like MRAA - which is optional), then 24 | set the lib's CMAKE_INSTALL_PREFIX to a value that is appended to RF24 lib's CMAKE_FIND_ROOT_PATH 25 | example using MRAA: 26 | (for MRAA/build dir) `cmake .. -D CMAKE_TOOLCHAIN_FILE=path/to/RF24/repo/cmake/toolchains/i686.cmake -D CMAKE_INSTALL_PREFIX:PATH=/usr/i686-linux-gnu 27 | (for RF24/build dir) `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/i686.cmake 28 | ]] 29 | list(APPEND CMAKE_FIND_ROOT_PATH /usr/i686-linux-gnu) 30 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # search CMAKE_SYSROOT when find_program() is called 31 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_library() is called 32 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_file() is called 33 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_package() is called 34 | -------------------------------------------------------------------------------- /cmake/toolchains/x86_64.cmake: -------------------------------------------------------------------------------- 1 | ###################### FOR CROSS-COMPILING using the x86_64-linux-gnux32-g** compiler 2 | # invoke this toolchain file using `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/.cmake` 3 | # this file is meant to be used generically, but will not work for all CMake projects 4 | # this toolchain file's cmds was copied from the CMake docs then modified for better explanation and re-use 5 | 6 | set(CMAKE_SYSTEM_NAME Linux) 7 | set(CMAKE_SYSTEM_PROCESSOR x86_64) 8 | set(TARGET_ARCH x86_64) # only used in cmake/createDebianPkg.cmake 9 | set(CMAKE_C_COMPILER /usr/bin/x86_64-linux-gnux32-gcc) 10 | set(CMAKE_CXX_COMPILER /usr/bin/x86_64-linux-gnux32-g++) 11 | 12 | # CMAKE_SYSROOT can only be set in a toolchain file 13 | # set(CMAKE_SYSROOT /usr/x86_64-linux-gnux32) # useful when a target machine's files are available 14 | 15 | # set the directory for searching installed headers 16 | # add_compile_options(-I /usr/x86_64-linux-gnux32/include) # this may not be best practice 17 | 18 | #[[ 19 | # CMAKE_STAGING_PREFIX is only useful for transfering a built CMake project to a target machine 20 | set(CMAKE_STAGING_PREFIX /home/devel/stage) # use CMAKE_INSTALL_PREFIX instead (see below comments) 21 | 22 | CMAKE_FIND_ROOT_PATH is an empty list by default (this list can be modified where applicable) 23 | if cross-compiling a dependent lib (like MRAA - which is optional), then 24 | set the lib's CMAKE_INSTALL_PREFIX to a value that is appended to RF24 lib's CMAKE_FIND_ROOT_PATH 25 | example using MRAA: 26 | (for MRAA/build dir) `cmake .. -D CMAKE_TOOLCHAIN_FILE=path/to/RF24/repo/cmake/toolchains/x86_64.cmake -D CMAKE_INSTALL_PREFIX:PATH=/usr/x86_64-linux-gnux32 27 | (for RF24/build dir) `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/x86_64.cmake 28 | ]] 29 | list(APPEND CMAKE_FIND_ROOT_PATH /usr/x86_64-linux-gnux32) 30 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # search CMAKE_SYSROOT when find_program() is called 31 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_library() is called 32 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_file() is called 33 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_package() is called 34 | -------------------------------------------------------------------------------- /cmake/usePicoSDK.cmake: -------------------------------------------------------------------------------- 1 | ## Include this file if you want to use the RF24Network library 2 | ## in YOUR (pico-sdk based) project. 3 | 4 | cmake_minimum_required(VERSION 3.12) 5 | 6 | set(CMAKE_C_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD 17) 8 | 9 | # Define the RF24Network library 10 | add_library(RF24Network INTERFACE) 11 | 12 | target_sources(RF24Network INTERFACE 13 | ${CMAKE_CURRENT_LIST_DIR}/../RF24Network.cpp 14 | ) 15 | 16 | target_include_directories(RF24Network INTERFACE 17 | ${CMAKE_CURRENT_LIST_DIR}/../ 18 | ) 19 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Please browse the docs from either http://nrf24.github.io/RF24Network or https://rf24network.rtfd.io 2 | 3 | ## Intended for use in Doxygen 4 | 5 | The markdown files (\*.md) in this docs folder contain relative hyperlinks. Any relative hyperlinks will not work when viewing these markdown files in github. 6 | 7 | ---- 8 | 9 | ## Building the docs 10 | 11 | Navigate to the repo's docs folder: 12 | 13 | ```shell 14 | cd docs 15 | ``` 16 | 17 | Install Doxygen (v1.9.5 or newer) and run the following command from the repo's docs folder: 18 | 19 | ```shell 20 | doxygen 21 | ``` 22 | 23 | The Doxygen HTML output is now in docs/html. The Doxygen XML output in docs/sphinx/xml can be optionally used to generate Sphinx output. 24 | 25 | ### Generating Sphinx docs (optional) 26 | 27 | To build the Sphinx docs based on Doxygen's XML output, first install the necessary python dependencies. 28 | 29 | ``` shell 30 | python -m pip install docs/sphinx/requirements.txt 31 | ``` 32 | 33 | Now build the Sphinx docs (after building the Doxygen output) from the repo's docs folder: 34 | 35 | ```shell 36 | sphinx-build sphinx _build/html 37 | ``` 38 | 39 | The Sphinx HTML output now exists in docs/_build/html. 40 | -------------------------------------------------------------------------------- /docs/addressing.md: -------------------------------------------------------------------------------- 1 | # Addressing Format: Understanding Addressing and Topology 2 | 3 | @tableofcontents 4 | 5 | 6 | An overview of addressing in RF24Network 7 | 8 | ## Overview 9 | 10 | The nrf24 radio modules typically use a 40-bit address format, requiring 5-bytes of storage space per address, and allowing a wide 11 | array of addresses to be utilized. In addition, the radios are limited to direct communication with 6 other nodes while using the 12 | Enhanced-Shock-Burst (ESB) functionality of the radios. 13 | 14 | The NRF52x modules use a similar format for addressing, but can communicate directly with 8 other nodes while using the 15 | Enhanced-Shock-Burst (ESB) functionality of the radios. 16 | 17 | RF24Network uses a simple method of data compression to store the addresses using only 2 bytes, in a format designed to represent the 18 | network topology in an intuitive way. 19 | See the [Topology and Overview](tuning.md) page for more info regarding topology. 20 | 21 | ## Decimal, Octal and Binary formats 22 | 23 | Say we want to designate a logical address to a node, using a tree topology as defined by the 24 | manufacturer. In the simplest format, we could assign the first node the address of 1, the second 25 | 2, and so on. Since a single node can only connect to 6 other nodes (1 parent and 5 children) 26 | subnets need to be created if using more than 6 nodes. In this case, the 27 | 28 | - children of node 1 could simply be designated as 11, 21, 31, 41, and 51 29 | - children of node 2 could be designated as 12, 22, 32, 42, and 52 30 | 31 | The above example is exactly how RF24Network manages the addresses, but they are represented in Octal format. 32 | 33 | ## Available Addresses 34 | 35 | RF24Network supports various configurations, but by default has multicast enabled. This means one additional pipe is taken up on each 36 | node for multicasting. The master node will support 5 nodes (01 through 05) and 1 multicast address, while the nodes themselves will 37 | support 4 nodes (01n to 04n etc), 1 multicast address and 1 parent pipe. Users can edit RF24Network_config.h and comment out 38 | `#define RF24NetworkMulticast` as well. This allows the master to support 5 children, with nodes supporting 5 children also. 39 | See the [Topology and Overview](md_docs_tuning.html) page for more info regarding topology. 40 | 41 | With the newer NRF52x devices, the master node will support 7 nodes (01 through 07) and 1 multicast address, while the nodes 42 | themselves support 6 nodes (01n to 06n etc), 1 multicast address and 1 parent pipe. 43 | 44 | ### Decimal, Octal and Binary 45 | 46 | | Decimal | Octal | Binary | 47 | | :-----: | :---: | :------: | 48 | | 1 | 01 | 00000001 | 49 | | 11 | 013 | 00001011 | 50 | | 9 | 011 | 00001001 | 51 | | 73 | 0111 | 01001001 | 52 | | 111 | 0157 | 01101111 | 53 | 54 | Since the numbers 0-7 can be represented in exactly three bits, each digit is represented by 55 | exactly 3 bits when viewed in octal format. This allows a very simple method of managing addresses 56 | via masking and bit shifting. 57 | 58 | ## Displaying Addresses 59 | 60 | When using Arduino devices, octal addresses can be printed in the following manner: 61 | 62 | ```cpp 63 | uint16_t address = 0111; 64 | Serial.println(address, OCT); 65 | ``` 66 | 67 | Printf can also be used, if enabled, or if using linux/RPi 68 | 69 | ```cpp 70 | uint16_t address = 0111; 71 | printf("0%o\n", address); 72 | ``` 73 | 74 | @see 75 | - [This cplusplus.com tutorial](http://www.cplusplus.com/doc/hex/) for more information number bases. 76 | - The [Topology and Overview page](tuning.md) for more information regarding network topology. 77 | -------------------------------------------------------------------------------- /docs/advanced_config.md: -------------------------------------------------------------------------------- 1 | # Advanced Configuration 2 | 3 | @tableofcontents 4 | 5 | 6 | RF24Network offers many features, some of which can be configured by editing the RF24Network_config.h file 7 | 8 | | Configuration Option | Description | 9 | | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 10 | | `#define RF24NetworkMulticast` | This option allows nodes to send and receive multicast payloads.
Nodes with multicast enabled can also be configured to relay multicast payloads on to further multicast levels.
See ESBNetwork::multicastRelay | 11 | | `#define DISABLE_FRAGMENTATION` | Fragmentation is enabled by default, and uses an additional 144 bytes of memory. | 12 | | `#define MAX_PAYLOAD_SIZE 144` | The maximum size of payloads defaults to 144 bytes. If used with RF24toTUN and two Raspberry Pi, set this to 1500 | 13 | | `#define DISABLE_USER_PAYLOADS` | This option will disable user-caching of payloads entirely. Use with RF24Ethernet to reduce memory usage. (TCP/IP is an external data type, and not cached) | 14 | | `#define ENABLE_SLEEP_MODE` | Uncomment this option to enable sleep mode for AVR devices. (ATTiny,Uno, etc) | 15 | | `#define ENABLE_NETWORK_STATS` | Enable counting of all successful or failed transmissions, routed or sent directly | 16 | | `#define NUM_PIPES` | Define the number of pipes for addressing. The max value is generally hardware dependant. NRF24 supports 6 pipes, NRF52x supports 8 pipes | 17 | | `#define MAX_FRAME_SIZE` | Found in RF24Network.h, this allows users to set the maximum frame size used internally. NRF24 supports 32-bytes, NRF52x supports 123-bytes, or 111 if encryption is enabled | 18 | -------------------------------------------------------------------------------- /docs/doxygen-custom.css: -------------------------------------------------------------------------------- 1 | table.markdownTable th { 2 | color: unset; 3 | } 4 | 5 | /* overrides from default CSS for some admonitions */ 6 | dl.note, 7 | dl.remark, 8 | dl.warning, 9 | dl.attention, 10 | dl.important, 11 | dl.deprecated, 12 | dl.see { 13 | color: unset; 14 | box-shadow: 5px 5px 5px hsla(0, 0%, 19.2%, 0.5); 15 | } 16 | 17 | dl.remark { 18 | background: var(--remark-color-bg); 19 | border-left: 8px solid var(--remark-color-hl); 20 | } 21 | 22 | dl.remark dt { 23 | color: var(--remark-color-hl); 24 | } 25 | 26 | dl.important dt { 27 | color: var(--important-color-hl); 28 | } 29 | 30 | dl.important { 31 | background: var(--important-color-bg); 32 | border-left: 8px solid var(--important-color-hl); 33 | } 34 | 35 | dl.attention dt { 36 | color: var(--attention-color-hl); 37 | } 38 | 39 | dl.attention { 40 | background: var(--attention-color-bg); 41 | border-left: 8px solid var(--attention-color-hl); 42 | } 43 | 44 | dl.deprecated dt { 45 | color: var(--deprecated-color-hl); 46 | } 47 | 48 | dl.deprecated { 49 | background: var(--deprecated-color-bg); 50 | border-left: 8px solid var(--deprecated-color-hl); 51 | } 52 | 53 | /* special rules to accent `/see` or `/sa` command output */ 54 | dl.see { 55 | background: var(--seealso-color-bg); 56 | border-left: 8px solid var(--seealso-color-hl); 57 | } 58 | 59 | dl.see dt { 60 | color: var(--seealso-color-hl); 61 | } 62 | 63 | dl.see { 64 | padding: 10px; 65 | margin: 10px 0px; 66 | overflow: hidden; 67 | margin-left: 0; 68 | border-radius: 4px; 69 | } 70 | 71 | dl.see dd { 72 | margin-left: 0; 73 | } 74 | 75 | /* admonition icons */ 76 | dl.note dt::before { 77 | background-color: var(--note-color-hl); 78 | mask-image: var(--note-icon); 79 | } 80 | 81 | dl.see dt::before { 82 | background-color: var(--seealso-color-hl); 83 | mask-image: var(--seealso-icon); 84 | } 85 | 86 | dl.remark dt::before { 87 | background-color: var(--remark-color-hl); 88 | mask-image: var(--remark-icon); 89 | } 90 | 91 | dl.warning dt::before { 92 | background-color: var(--warning-color-hl); 93 | mask-image: var(--warning-icon); 94 | } 95 | 96 | dl.deprecated dt::before { 97 | background-color: var(--deprecated-color-hl); 98 | mask-image: var(--deprecated-icon); 99 | } 100 | 101 | dl.important dt::before { 102 | background-color: var(--important-color-hl); 103 | mask-image: var(--important-icon); 104 | } 105 | 106 | dl.attention dt::before { 107 | background-color: var(--attention-color-hl); 108 | mask-image: var(--attention-icon); 109 | } 110 | 111 | dl.note dt::before, 112 | dl.see dt::before, 113 | dl.warning dt::before, 114 | dl.remark dt::before, 115 | dl.deprecated dt::before, 116 | dl.important dt::before, 117 | dl.attention dt::before { 118 | vertical-align: middle; 119 | background-repeat: no-repeat; 120 | content: ""; 121 | display: inline-block; 122 | height: 2em; 123 | width: 2em; 124 | margin-right: 0.25rem; 125 | } 126 | 127 | dl.note dt, 128 | dl.see dt, 129 | dl.warning dt, 130 | dl.remark dt, 131 | dl.deprecated dt, 132 | dl.important dt, 133 | dl.attention dt { 134 | margin-top: -0.35em; 135 | margin-bottom: 0.5em; 136 | } 137 | 138 | /* icon SVG data */ 139 | *:root { 140 | --note-icon: url('data:image/svg+xml;utf8,'); 141 | --warning-icon: url('data:image/svg+xml;utf8,'); 142 | --remark-icon: url('data:image/svg+xml;utf8,'); 143 | --attention-icon: url('data:image/svg+xml;utf8,'); 144 | --important-icon: url('data:image/svg+xml;utf8,'); 145 | --seealso-icon: url('data:image/svg+xml;utf8,'); 146 | --deprecated-icon: url('data:image/svg+xml;utf8,'); 147 | } 148 | 149 | /* color overrides */ 150 | html, 151 | html.dark-mode { 152 | --note-color-hl: hsl(213.7, 92.8%, 62%); 153 | --note-color-bg: hsla(213.7, 92.8%, 62%, 12.5%); 154 | --warning-color-hl: hsl(40.6, 72.1%, 47.8%); 155 | --warning-color-bg: hsla(40.6, 72.1%, 47.8%, 12.5%); 156 | --attention-color-hl: hsl(2.7, 92.6%, 62.9%); 157 | --attention-color-bg: hsla(2.7, 92.6%, 62.9%, 12.5%); 158 | --deprecated-color-hl: hsl(0, 0%, 47%); 159 | --deprecated-color-bg: hsla(0, 0%, 47%, 12.5%); 160 | --seealso-color-hl: hsl(323, 72%, 52%); 161 | --seealso-color-bg: hsla(323, 72%, 52%, 12.5%); 162 | --remark-color-hl: hsl(128.4, 49.2%, 48.6%); 163 | --remark-color-bg: hsla(128.4, 49.2%, 48.6%, 12.5%); 164 | --important-color-hl: hsl(262.4, 89.8%, 73.1%); 165 | --important-color-bg: hsla(262.4, 89.8%, 73.1%, 12.5%); 166 | } -------------------------------------------------------------------------------- /docs/images/Logo large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nRF24/RF24Network/0b19dd59b742c87dd1d1b5b1a17182162b48e8d0/docs/images/Logo large.png -------------------------------------------------------------------------------- /docs/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nRF24/RF24Network/0b19dd59b742c87dd1d1b5b1a17182162b48e8d0/docs/images/favicon.ico -------------------------------------------------------------------------------- /docs/main_page.md: -------------------------------------------------------------------------------- 1 | # Network Layer for RF24 Radios 2 | 3 | @tableofcontents 4 | 5 | This class implements an [OSI Network Layer](http://en.wikipedia.org/wiki/Network_layer) using nRF24L01(+) radios driven 6 | by the newly optimized [RF24 library fork](http://nRF24.github.com/RF24/) or using nRF52x radios with the newly created 7 | [nrf_to_nrf library](https://github.com/TMRh20/nrf_to_nrf). 8 | 9 | @see 10 | [RF24 Library docs](http://nRF24.github.io/RF24/) for general RF24 configuration and setup. 11 | - [Linux Installation](https://nrf24.github.io/RF24/md_docs_2linux__install.html) and [General Linux/RPi configuration and setup](https://nrf24.github.io/RF24/md_docs_2rpi__general.html) documentation 12 | 13 | ## Purpose/Goal 14 | 15 | Original: Create an alternative to ZigBee radios for Arduino communication. 16 | 17 | New: Enhance the current functionality for maximum efficiency, reliability, and speed 18 | 19 | Xbees are excellent little radios, backed up by a mature and robust standard 20 | protocol stack. They are also expensive. 21 | 22 | For many Arduino uses, they seem like overkill. So I am working to improve the current 23 | standard for nRF24L01 radios. The best RF24 modules are available for less than 24 | $6 from many sources. With the RF24Network layer, I hope to cover many 25 | common communication scenarios. 26 | 27 | Please see [TMRh20's blog post](https://tmrh20.blogspot.com/2019/05/comparative-performance-analysis.html) 28 | for a comparison against the ZigBee protocols 29 | 30 | ## News - 2023 API Changes 31 | Introducing **RF24Network & RF24Mesh v2.0** with some *significant API changes*, adding the use of [C++ Templates](https://cplusplus.com/doc/oldtutorial/templates/) 32 | in order to support a range of ESB enabled radios, most recently NRF52x radios. 33 | 34 | **Important Notes:** 35 | - Any network layer that uses v2 needs to have RF24Network/RF24Mesh dependencies of v2 or newer. RF24 v1.x is an exception here. 36 | - General usage should remain backward compatible, see the included examples of the related libraries for more info 37 | - Any third party libs that extend the network/mesh layer may also need to be updated to incorporate the new templated class prototypes: 38 | ```cpp 39 | template 40 | class ESBNetwork; 41 | 42 | template 43 | class ESBMesh; 44 | ``` 45 | - Third party libs should also be able to use the backward-compatible typedef in their template: 46 | - ESBGateway.h: 47 | ```cpp 48 | template 49 | class ESBGateway 50 | ``` 51 | and inform the compiler what types they intend to support: 52 | - ESBGateway.cpp: 53 | ```cpp 54 | template class ESBGateway; 55 | ``` 56 | - The auto installers do not perform a version check like package managers, so having the correct versions of the software is important. 57 | - We *will* be maintaining the v1.x versions with bugfixes etc for those who cannot or do not wish to migrate to the newer template approach. 58 | 59 | Please see the recent changes listed in [the github releases page](https://github.com/nRF24/RF24Network/releases) 60 | 61 | ## Features 62 | 63 | ### The layer provides 64 | 65 | - Network ACKs: Efficient acknowledgement of network-wide transmissions, via dynamic radio acks and network protocol acks. 66 | - Updated addressing standard for optimal radio transmission. 67 | - Extended timeouts and staggered timeout intervals. The new txTimeout variable allows fully automated extended timeout periods via auto-retry/auto-reUse of payloads. 68 | - Optimization to the core library provides improvements to reliability, speed and efficiency. See [RF24 library documentation](https://nRF24.github.io/RF24) for more info. 69 | - Built in sleep mode using interrupts. (Still under development -- enable via RF24Network_config.h) 70 | - Host Addressing. Each node has a logical address on the local network. 71 | - Message Forwarding. Messages can be sent from one node to any other, and 72 | this layer will get them there no matter how many hops it takes. 73 | - Ad-hoc Joining. A node can join a network without any changes to any 74 | existing nodes. 75 | 76 | ### The layer does not provide 77 | 78 | - Dynamic address assignment (See [RF24Mesh](https://github.com/nRF24/RF24Mesh)) 79 | - Layer 4 protocols (TCP/IP - See [RF24Ethernet](https://github.com/nRF24/RF24Ethernet) and [RF24Gateway](https://github.com/nRF24/RF24Gateway)) 80 | 81 | ## How to learn more 82 | 83 | - [RF24Network Class Documentation](classRF24Network.html) 84 | - [Advanced Configuration Options](advanced_config.md) 85 | - [Addressing format](addressing.md) 86 | - [Topology and Overview](tuning.md) 87 | - [Examples Page](examples.html). Start with `helloworld_*` examples. 88 | 89 | ### Additional Information & Add-ons 90 | 91 | - [RF24Mesh: Dynamic Mesh Layer for RF24Network](https://github.com/nRF24/RF24Mesh) 92 | - [RF24Ethernet: TCP/IP over RF24Network](https://github.com/nRF24/RF24Ethernet) 93 | - [TMRh20's Blog: RF24 Optimization Overview](http://tmrh20.blogspot.com/2014/03/high-speed-data-transfers-and-wireless.html) 94 | - [TMRh20's Blog: RF24 Wireless Audio](http://tmrh20.blogspot.com/2014/03/arduino-radiointercomwireless-audio.html) 95 | - [RF24: Original Author](http://maniacbug.github.com/RF24/) 96 | 97 | ## Topology for Mesh Networks using nRF24L01(+) 98 | 99 | This network layer takes advantage of the fundamental capability of the nRF24L01(+) radio to 100 | listen actively to up to 6 other radios at once (8 with NRF52x). The network is arranged in a 101 | [Tree Topology](http://en.wikipedia.org/wiki/Network_Topology#Tree), where 102 | one node is the base, and all other nodes are children either of that node, or of another. 103 | Unlike a true mesh network, multiple nodes are not connected together, so there is only one 104 | path to any given node. 105 | 106 | ## Octal Addressing and Topology 107 | 108 | Each node must be assigned an 15-bit address by the administrator. This address exactly 109 | describes the position of the node within the tree. The address is an octal number. Each 110 | digit in the address represents a position in the tree further from the base. 111 | 112 | - Node 00 is the base node. 113 | - Nodes 01-05 are nodes whose parent is the base. 114 | - Node 021 is the second child of node 01. 115 | - Node 0321 is the third child of node 021, an so on. 116 | - The largest node address is 05555, so up to 781 nodes are allowed on a single channel. 117 | An example topology is shown below, with 5 nodes in direct communication with the master node, 118 | and multiple leaf nodes spread out at a distance, using intermediate nodes to reach other nodes. 119 | - With the newer NRF52x devices, up to 3200 nodes are allowed on a single channel 120 | 121 | @image html example_tree.svg 122 | 123 | ## How routing is handled 124 | 125 | When sending a message using ESBNetwork::write(), you fill in the header with the logical 126 | node address. The network layer figures out the right path to find that node, and sends 127 | it through the system until it gets to the right place. This works even if the two nodes 128 | are far separated, as it will send the message down to the base node, and then back out 129 | to the final destination. 130 | 131 | All of this work is handled by the ESBNetwork::update() method, so be sure to call it 132 | regularly or your network will miss packets. 133 | 134 | ## Starting up a node 135 | 136 | When a node starts up, it only has to contact its parent to establish communication. 137 | No direct connection to the Base node is needed. This is useful in situations where 138 | relay nodes are being used to bridge the distance to the base, so leaf nodes are out 139 | of range of the base. 140 | 141 | ## Directionality 142 | 143 | By default all nodes are always listening, so messages will quickly reach 144 | their destination. 145 | 146 | You may choose to sleep any nodes on the network if using interrupts. This is useful in a 147 | case where the nodes are operating on batteries and need to sleep. This greatly decreases 148 | the power requirements for a sensor network. The leaf nodes can sleep most of the time, 149 | and wake every few minutes to send in a reading. Routing nodes can be triggered to wake up 150 | whenever a payload is received See ESBNetwork::sleepNode() in the class documentation, and RF24Network_config.h 151 | to enable sleep mode. 152 | -------------------------------------------------------------------------------- /docs/tuning.md: -------------------------------------------------------------------------------- 1 | # Performance and Data Loss: Tuning the Network 2 | 3 | @tableofcontents 4 | 5 | 6 | Tips and examples for tuning the network and general operation. 7 | 8 | Observe: 9 | 10 | ![@image html images/topologyImage.jpg width=70% height=70%](https://github.com/nRF24/RF24Network/raw/master/images/topologyImage.jpg) 11 | 12 | ## Understanding Radio Communication and Topology 13 | 14 | When a transmission takes place from one radio module to another, the receiving radio will communicate 15 | back to the sender with an acknowledgement (ACK) packet, to indicate success. If the sender does not 16 | receive an ACK, the radio automatically engages in a series of timed retries, at set intervals. The 17 | radios use techniques like addressing and numbering of payloads to manage this, but it is all done 18 | automatically by the nrf chip, out of sight from the user. 19 | 20 | When working over a radio network, some of these automated techniques can actually hinder data transmission to a degree. 21 | Retrying failed payloads over and over on a radio network can hinder communication for nearby nodes, or 22 | reduce throughput and errors on routing nodes. 23 | 24 | Radios in this network are linked by **addresses** assigned to **pipes**. Each radio can listen 25 | to 6 addresses on 6 pipes, (8 pipes on NRF52x) therefore each radio has a parent pipe and 4-5 child pipes, which are 26 | used to form a tree structure. Nodes communicate directly with their parent and children nodes. Any other 27 | traffic to or from a node must be routed through the network. 28 | 29 | ## Topology of RF24Network 30 | 31 | Anybody who is familiar at all with IP networking should be able to easily understand RF24Network topology. The 32 | master node can be seen as the gateway, with (by default) up to 5 directly connected nodes. Each of those nodes 33 | creates a subnet below it, with up to 4 additional child nodes. The numbering scheme can also be related to IP 34 | addresses, for purposes of understanding the topology via subnetting. Nodes can have 5 children if multicast is 35 | disabled. 36 | 37 | ### Expressing RF24Network addresses in IP format 38 | 39 | As an example, we could designate the master node in theory, as Address `10.10.10.10` 40 | 41 | - The children nodes of the master would be `10.10.10.1`, `10.10.10.2`, `10.10.10.3`, `10.10.10.4` and `10.10.10.5` 42 | - The children nodes of `10.10.10.1` would be `10.10.1.1`, `10.10.2.1`, `10.10.3.1`, `10.10.4.1` and `10.10.5.1` 43 | 44 | In RF24Network, the master is just `00` 45 | 46 | - Children of master are `01`, `02`, `03`, `04`, `05` 47 | - Children of `01` are `011`, `021`, `031`, `041`, `051` 48 | 49 | ## Multicast 50 | 51 | Multicast is enabled by default, which limits the master node to 5 child pipes and other nodes to 4 when using RF24 52 | modules. Nodes are arranged in multicast 'levels' with the master node being level 0, nodes 01-05 are level 1, nodes 53 | n1-n5 are level 2, and so on. The multicast level of each node can be configured as desired by the user, or 54 | multicast can be disabled by editing RF24Network_config.h. For example, if all nodes are in range of the master node, 55 | all nodes can be configured to use multicast level 1, allowing the master node to contact all of them by sending a 56 | single payload. Multicasting is also used by the RF24Mesh layer for dynamic addressing requests. 57 | 58 | ## Routing 59 | 60 | Routing of traffic is handled invisibly to the user, by the network layer. If the network addresses are 61 | assigned in accordance with the physical layout of the network, nodes will route traffic automatically 62 | as required. Users simply construct a header containing the appropriate destination address, and the network 63 | will forward it through to the correct node. Individual nodes only route individual fragments, so if using 64 | fragmentation, routing nodes do not need it enabled, unless sending or receiving fragmented payloads themselves. 65 | 66 | If routing data between parent and child nodes (marked by direct links on the topology image above) the network 67 | uses built-in acknowledgement and retry functions of the chip to prevent data loss. When payloads are sent to 68 | other nodes, they need to be routed. Routing is managed using a combination of built in ACK requests, and 69 | software driven network ACKs. This allows all routing nodes to forward data very quickly, with only the final 70 | routing node confirming delivery and sending back an 71 | acknowledgement. 72 | 73 | Example: Node 00 sends to node 01. The nodes will use the built in auto-retry and auto-ack functions. 74 | 75 | Example: Node 00 sends to node 011. Node 00 will send to node 01 as before. Node 01 will forward the message 76 | to 011. If delivery was successful, node 01 will also forward a message back to node 00, indicating success. 77 | 78 | Old Functionality: Node 00 sends to node 011 using auto-ack. Node 00 first sends to 01, 01 acknowledges. 79 | Node 01 forwards the payload to 011 using auto-ack. If the payload fails between 01 and 011, node 00 has 80 | no way of knowing. 81 | 82 | @note When retrying failed payloads that have been routed, there is a chance of duplicate payloads if the network-ack 83 | is not successful. In this case, it is left up to the user to manage retries and filtering of duplicate payloads. 84 | 85 | Acknowledgements can and should be managed by the application or user. If requesting a response from another node, 86 | an acknowledgement is not required, so a user defined type of 0-64 should be used, to prevent the network from 87 | responding with an acknowledgement. If not requesting a response, and wanting to know if the payload was successful 88 | or not, users can utilize header types 65-127. 89 | 90 | ## Tuning Overview 91 | 92 | The RF24 radio modules are generally only capable of either sending or receiving data at any given 93 | time, but have built-in auto-retry mechanisms to prevent the loss of data. These values are adjusted 94 | automatically by the library on startup, but can be further adjusted to reduce data loss, and 95 | thus increase throughput of the network. This page is intended to provide a general overview of its 96 | operation within the context of the network library, and provide guidance for adjusting these values. 97 | 98 | ## Auto-Retry Timing 99 | 100 | The core radio library provides the functionality of adjusting the internal auto-retry interval of the 101 | radio modules. In the network configuration, the radios can be set to automatically retry failed 102 | transmissions at intervals ranging anywhere from 500us (0.5ms) up to 4000us (4ms). When operating any 103 | number of radios larger than two, it is important to stagger the assigned intervals, to prevent the 104 | radios from interfering with each other at the radio frequency (RF) layer. 105 | 106 | The library should provide fairly good working values, as it simply staggers the assigned values within 107 | groups of radios in direct communication. This value can be set manually by calling `radio.setRetries(X, 15);` 108 | and adjusting the value of X from 1 to 15 (steps of 250us). 109 | 110 | ## Auto-Retry Count and Extended Timeouts 111 | 112 | The core radio library also provides the ability to adjust the internal auto-retry count of the radio 113 | modules. The default setting is 15 automatic retries per payload, and can be extended by configuring 114 | the network.txTimeout variable. This default retry count should generally be left at 15, as per the 115 | example in the above section. An interval/retry setting of (15,15) will provide 15 retries at intervals of 116 | 4ms, taking up to 60ms per payload. The library now provides staggered timeout periods by default, but 117 | they can also be adjusted on a per-node basis. 118 | 119 | The txTimeout variable is used to extend the retry count to a defined duration in milliseconds. See the 120 | network.txTimeout variable. Timeout periods of extended duration (500+) will generally not help when payloads 121 | are failing due to data collisions, it will only extend the duration of the errors. Extended duration timeouts 122 | should generally only be configured on leaf nodes that do not receive data. 123 | 124 | ## Usage with NRF52x devices 125 | 126 | 1. Users can utilize large payloads by calling `radio.begin();` then `radio.enableDynamicPayloads(123);` 127 | prior to calling `network.begin();`. Users would also need to edit RF24Network.h and set 128 | MAX_FRAME_SIZE to a maximum of 111 if encryption is enabled, 123 without encryption. 129 | 2. Users can allow more nodes by modifying RF24Network_config.h and setting NUM_PIPES to 8 (Allows 130 | master to have 7 child nodes, other nodes can have 6 children by default) 131 | 3. The MAX_PAYLOAD_SIZE is also defined in RF24Network_config.h. Raise to a multiple of 123 to allow 132 | multiple large payloads to be cached in memory. 133 | 134 | @see 135 | - [RX example using encryption](https://github.com/TMRh20/nrf_to_nrf/blob/main/examples/RF24Network/helloworld_rxEncryption/helloworld_rxEncryption.ino) 136 | - [TX example using encryption](https://github.com/TMRh20/nrf_to_nrf/blob/main/examples/RF24Network/helloworld_txEncryption/helloworld_txEncryption.ino) 137 | 138 | ## Scenarios 139 | 140 | ### Example 1 141 | 142 | Network with master node and three leaf nodes that send data to the master node. None of the leaf 143 | nodes need to receive data. 144 | 145 | 1. Master node uses default configuration 146 | 2. Leaf nodes can be configured with extended timeout periods to ensure reception by the master. 147 | 3. The following configuration will provide a reduction in errors, as the timeouts have been extended and are staggered 148 | between devices. 149 | ```text 150 | Leaf 01: network.txTimeout = 500; 151 | Leaf 02: network.txTimeout = 573; 152 | Leaf 03: network.txTimeout = 653; 153 | ``` 154 | 155 | ### Example 2 156 | 157 | Network with master node and three leaf nodes that send data to the master node. The second leaf 158 | node needs to receive configuration data from the master at set intervals of 1 second, and send data back to the 159 | master node. The other leaf nodes will send basic sensor information every few seconds, and a few dropped payloads 160 | will not affect the operation greatly. 161 | 162 | 1. Master node configured with extended timeouts of 0.5 seconds, and increased retry delay: 163 | ```cpp 164 | radio.setRetries(11, 15); 165 | network.txTimeout = 500; 166 | ``` 167 | 2. Second leaf node configured with a similar timeout period and retry delay: 168 | ```cpp 169 | radio.setRetries(8, 15); 170 | network.txTimeout = 553; 171 | ``` 172 | 3. First and third leaf nodes configured with default timeout periods or slightly increased timeout periods. 173 | -------------------------------------------------------------------------------- /docs/zigabee.md: -------------------------------------------------------------------------------- 1 | # Comparison to ZigBee 2 | 3 | @tableofcontents 4 | 5 | This network layer is influenced by the design of ZigBee, but does not implement it 6 | directly. 7 | 8 | ## Which is better? 9 | 10 | ZigBee is a much more robust, feature-rich set of protocols, with many different vendors 11 | providing compatible chips. 12 | 13 | RF24Network is cheap. While ZigBee radios are well over $20, nRF24L01 modules can be found 14 | for under $2. 15 | 16 | ## Similiarities & Differences 17 | 18 | Here are some comparisons between RF24Network and ZigBee. 19 | 20 | - Both networks support Star and Tree topologies. Only Zigbee supports a true mesh. 21 | - In ZigBee networks, only leaf nodes can sleep 22 | - ZigBee nodes are configured using AT commands, or a separate Windows application. 23 | RF24 nodes are configured by recompiliing the firmware or writing to EEPROM. 24 | - A paper was written comparing the performance of Zigbee vs nRF24l01+, see [TMRh20s Blog](https://tmrh20.blogspot.com/2019/05/comparative-performance-analysis.html) for a detailed overview. 25 | 26 | ## Node Naming 27 | 28 | - Leaf node: A node at the outer edge of the network with no children. ZigBee calls it 29 | an End Device node. 30 | - Relay node: A node which has both parents and children, and relays messages from one 31 | to the other. ZigBee calls it a Router. 32 | - Base node. The top of the tree node with no parents, only children. Typically this node 33 | will bridge to another kind of network like Ethernet. ZigBee calls it a Co-ordinator node. 34 | -------------------------------------------------------------------------------- /examples/.clang-format: -------------------------------------------------------------------------------- 1 | # See: https://releases.llvm.org/11.0.1/tools/clang/docs/ClangFormatStyleOptions.html 2 | --- 3 | Language: Cpp 4 | # LLVM is the default style setting, used when a configuration option is not set here 5 | BasedOnStyle: LLVM 6 | AccessModifierOffset: -2 7 | AlignAfterOpenBracket: Align 8 | AlignConsecutiveAssignments: false 9 | AlignConsecutiveBitFields: false 10 | AlignConsecutiveDeclarations: false 11 | AlignConsecutiveMacros: false 12 | AlignEscapedNewlines: DontAlign 13 | AlignOperands: Align 14 | AlignTrailingComments: true 15 | AllowAllArgumentsOnNextLine: true 16 | AllowAllConstructorInitializersOnNextLine: true 17 | AllowAllParametersOfDeclarationOnNextLine: true 18 | AllowShortBlocksOnASingleLine: Always 19 | AllowShortCaseLabelsOnASingleLine: true 20 | AllowShortEnumsOnASingleLine: true 21 | AllowShortFunctionsOnASingleLine: Empty 22 | AllowShortIfStatementsOnASingleLine: Always 23 | AllowShortLambdasOnASingleLine: Empty 24 | AllowShortLoopsOnASingleLine: true 25 | AlwaysBreakAfterDefinitionReturnType: None 26 | AlwaysBreakAfterReturnType: None 27 | AlwaysBreakBeforeMultilineStrings: false 28 | AlwaysBreakTemplateDeclarations: No 29 | BinPackArguments: true 30 | BinPackParameters: true 31 | # Only used when "BreakBeforeBraces" set to "Custom" 32 | BraceWrapping: 33 | AfterCaseLabel: false 34 | AfterClass: false 35 | AfterControlStatement: Never 36 | AfterEnum: false 37 | AfterFunction: false 38 | AfterNamespace: false 39 | #AfterObjCDeclaration: 40 | AfterStruct: false 41 | AfterUnion: false 42 | AfterExternBlock: false 43 | BeforeCatch: false 44 | BeforeElse: false 45 | BeforeLambdaBody: false 46 | BeforeWhile: false 47 | IndentBraces: false 48 | SplitEmptyFunction: false 49 | SplitEmptyRecord: false 50 | SplitEmptyNamespace: false 51 | # Java-specific 52 | #BreakAfterJavaFieldAnnotations: 53 | BreakBeforeBinaryOperators: NonAssignment 54 | BreakBeforeBraces: Attach 55 | BreakBeforeTernaryOperators: true 56 | BreakConstructorInitializers: BeforeColon 57 | BreakInheritanceList: BeforeColon 58 | BreakStringLiterals: false 59 | ColumnLimit: 0 60 | # "" matches none 61 | CommentPragmas: "" 62 | CompactNamespaces: false 63 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 64 | ConstructorInitializerIndentWidth: 2 65 | ContinuationIndentWidth: 2 66 | Cpp11BracedListStyle: false 67 | DeriveLineEnding: true 68 | DerivePointerAlignment: true 69 | DisableFormat: false 70 | # Docs say "Do not use this in config files". The default (LLVM 11.0.1) is "false". 71 | #ExperimentalAutoDetectBinPacking: 72 | FixNamespaceComments: false 73 | ForEachMacros: [] 74 | IncludeBlocks: Preserve 75 | IncludeCategories: [] 76 | # "" matches none 77 | IncludeIsMainRegex: "" 78 | IncludeIsMainSourceRegex: "" 79 | IndentCaseBlocks: true 80 | IndentCaseLabels: true 81 | IndentExternBlock: Indent 82 | IndentGotoLabels: false 83 | IndentPPDirectives: None 84 | IndentWidth: 2 85 | IndentWrappedFunctionNames: false 86 | InsertTrailingCommas: None 87 | # Java-specific 88 | #JavaImportGroups: 89 | # JavaScript-specific 90 | #JavaScriptQuotes: 91 | #JavaScriptWrapImports 92 | KeepEmptyLinesAtTheStartOfBlocks: true 93 | MacroBlockBegin: "" 94 | MacroBlockEnd: "" 95 | # Set to a large number to effectively disable 96 | MaxEmptyLinesToKeep: 100000 97 | NamespaceIndentation: None 98 | NamespaceMacros: [] 99 | # Objective C-specific 100 | #ObjCBinPackProtocolList: 101 | #ObjCBlockIndentWidth: 102 | #ObjCBreakBeforeNestedBlockParam: 103 | #ObjCSpaceAfterProperty: 104 | #ObjCSpaceBeforeProtocolList 105 | PenaltyBreakAssignment: 1 106 | PenaltyBreakBeforeFirstCallParameter: 1 107 | PenaltyBreakComment: 1 108 | PenaltyBreakFirstLessLess: 1 109 | PenaltyBreakString: 1 110 | PenaltyBreakTemplateDeclaration: 1 111 | PenaltyExcessCharacter: 1 112 | PenaltyReturnTypeOnItsOwnLine: 1 113 | # Used as a fallback if alignment style can't be detected from code (DerivePointerAlignment: true) 114 | PointerAlignment: Right 115 | RawStringFormats: [] 116 | ReflowComments: false 117 | SortIncludes: false 118 | SortUsingDeclarations: false 119 | SpaceAfterCStyleCast: false 120 | SpaceAfterLogicalNot: false 121 | SpaceAfterTemplateKeyword: false 122 | SpaceBeforeAssignmentOperators: true 123 | SpaceBeforeCpp11BracedList: false 124 | SpaceBeforeCtorInitializerColon: true 125 | SpaceBeforeInheritanceColon: true 126 | SpaceBeforeParens: ControlStatements 127 | SpaceBeforeRangeBasedForLoopColon: true 128 | SpaceBeforeSquareBrackets: false 129 | SpaceInEmptyBlock: false 130 | SpaceInEmptyParentheses: false 131 | SpacesBeforeTrailingComments: 2 132 | SpacesInAngles: false 133 | SpacesInCStyleCastParentheses: false 134 | SpacesInConditionalStatement: false 135 | SpacesInContainerLiterals: false 136 | SpacesInParentheses: false 137 | SpacesInSquareBrackets: false 138 | Standard: Auto 139 | StatementMacros: [] 140 | TabWidth: 2 141 | TypenameMacros: [] 142 | # Default to LF if line endings can't be detected from the content (DeriveLineEnding). 143 | UseCRLF: false 144 | UseTab: Never 145 | WhitespaceSensitiveMacros: [] 146 | -------------------------------------------------------------------------------- /examples/Network_Ping/Network_Ping.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2011 James Coliz, Jr. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | */ 8 | 9 | /** 10 | * Example: Network topology, and pinging across a tree/mesh network 11 | * 12 | * Using this sketch, each node will send a ping to every other node in the network every few seconds. 13 | * The RF24Network library will route the message across the mesh to the correct node. 14 | * 15 | * This sketch is greatly complicated by the fact that at startup time, each 16 | * node (including the base) has no clue what nodes are alive. So, 17 | * each node builds an array of nodes it has heard about. The base 18 | * periodically sends out its whole known list of nodes to everyone. 19 | * 20 | * To see the underlying frames being relayed, compile RF24Network with 21 | * #define RF24NETWORK_DEBUG. 22 | * 23 | * Update: The logical node address of each node is set below, and are grouped in twos for demonstration. 24 | * Number 0 is the master node. Numbers 1-2 represent the 2nd layer in the tree (02,05). 25 | * Number 3 (012) is the first child of number 1 (02). Number 4 (015) is the first child of number 2. 26 | * Below that are children 5 (022) and 6 (025), and so on as shown below 27 | * The tree below represents the possible network topology with the addresses defined lower down 28 | * 29 | * Addresses/Topology Node Numbers (To simplify address assignment in this demonstration) 30 | * 00 - Master Node ( 0 ) 31 | * 02 05 - 1st Level children ( 1,2 ) 32 | * 32 22 12 15 25 35 45 - 2nd Level children (7,5,3-4,6,8) 33 | * 34 | * eg: 35 | * For node 4 (Address 015) to contact node 1 (address 02), it will send through node 2 (address 05) which relays the payload 36 | * through the master (00), which sends it through to node 1 (02). This seems complicated, however, node 4 (015) can be a very 37 | * long way away from node 1 (02), with node 2 (05) bridging the gap between it and the master node. 38 | * 39 | * To use the sketch, upload it to two or more units and set the NODE_ADDRESS below. If configuring only a few 40 | * units, set the addresses to 0,1,3,5... to configure all nodes as children to each other. If using many nodes, 41 | * it is easiest just to increment the NODE_ADDRESS by 1 as the sketch is uploaded to each device. 42 | */ 43 | 44 | #include 45 | #include "printf.h" 46 | #include 47 | #include 48 | #include 49 | 50 | /*********************************************************************** 51 | ************* Set the Node Address ************************************* 52 | /***********************************************************************/ 53 | 54 | // These are the Octal addresses that will be assigned 55 | const uint16_t node_address_set[10] = { 00, 02, 05, 012, 015, 022, 025, 032, 035, 045 }; 56 | 57 | // 0 = Master 58 | // 1-2 (02, 05) = Children of Master(00) 59 | // 3,5 (012, 022) = Children of (02) 60 | // 4,6 (015, 025) = Children of (05) 61 | // 7 (032) = Child of (02) 62 | // 8,9 (035, 045) = Children of (05) 63 | 64 | uint8_t NODE_ADDRESS = 0; // Use numbers 0 through to select an address from the array 65 | 66 | /***********************************************************************/ 67 | /***********************************************************************/ 68 | 69 | 70 | RF24 radio(7, 8); // CE & CS pins to use (Using 7,8 on Uno,Nano) 71 | RF24Network network(radio); 72 | 73 | uint16_t this_node; // Our node address 74 | 75 | const unsigned long interval = 1000; // ms // Delay manager to send pings regularly. 76 | unsigned long last_time_sent; 77 | 78 | 79 | const short max_active_nodes = 10; // Array of nodes we are aware of 80 | uint16_t active_nodes[max_active_nodes]; 81 | short num_active_nodes = 0; 82 | short next_ping_node_index = 0; 83 | 84 | 85 | bool send_T(uint16_t to); // Prototypes for functions to send & handle messages 86 | bool send_N(uint16_t to); 87 | void handle_T(RF24NetworkHeader& header); 88 | void handle_N(RF24NetworkHeader& header); 89 | void add_node(uint16_t node); 90 | 91 | 92 | void setup() { 93 | 94 | Serial.begin(115200); 95 | printf_begin(); // needed for RF24* libs' internal printf() calls 96 | while (!Serial) { 97 | // some boards need this because of native USB capability 98 | } 99 | Serial.println(F("RF24Network/examples/meshping/")); 100 | 101 | this_node = node_address_set[NODE_ADDRESS]; // Which node are we? 102 | 103 | if (!radio.begin()) { 104 | Serial.println(F("Radio hardware not responding!")); 105 | while (1) { 106 | // hold in infinite loop 107 | } 108 | } 109 | radio.setPALevel(RF24_PA_HIGH); 110 | radio.setChannel(100); 111 | network.begin(/*node address*/ this_node); 112 | } 113 | 114 | void loop() { 115 | 116 | network.update(); // Pump the network regularly 117 | 118 | while (network.available()) { // Is there anything ready for us? 119 | 120 | RF24NetworkHeader header; // If so, take a look at it 121 | network.peek(header); 122 | 123 | 124 | switch (header.type) { // Dispatch the message to the correct handler. 125 | case 'T': 126 | handle_T(header); 127 | break; 128 | case 'N': 129 | handle_N(header); 130 | break; 131 | default: 132 | Serial.print(F("*** WARNING *** Unknown message type ")); 133 | Serial.println(header.type); 134 | network.read(header, 0, 0); 135 | break; 136 | }; 137 | } 138 | 139 | 140 | unsigned long now = millis(); // Send a ping to the next node every 'interval' ms 141 | if (now - last_time_sent >= interval) { 142 | last_time_sent = now; 143 | 144 | 145 | uint16_t to = 00; // Who should we send to? By default, send to base 146 | 147 | 148 | if (num_active_nodes) { // Or if we have active nodes, 149 | to = active_nodes[next_ping_node_index++]; // Send to the next active node 150 | if (next_ping_node_index > num_active_nodes) { // Have we rolled over? 151 | next_ping_node_index = 0; // Next time start at the beginning 152 | to = 00; // This time, send to node 00. 153 | } 154 | } 155 | 156 | bool ok; 157 | 158 | if (this_node > 00 || to == 00) { // Normal nodes send a 'T' ping 159 | ok = send_T(to); 160 | } else { // Base node sends the current active nodes out 161 | ok = send_N(to); 162 | } 163 | 164 | if (ok) { // Notify us of the result 165 | Serial.print(millis()); 166 | Serial.println(F(": APP Send ok")); 167 | } else { 168 | Serial.print(millis()); 169 | Serial.println(F(": APP Send failed")); 170 | last_time_sent -= 100; // Try sending at a different time next time 171 | } 172 | } 173 | 174 | 175 | // delay(50); // Delay to allow completion of any serial printing 176 | // if(!network.available()){ 177 | // network.sleepNode(2,0); // Sleep this node for 2 seconds or a payload is received (interrupt 0 triggered), whichever comes first 178 | // } 179 | } 180 | 181 | /** 182 | * Send a 'T' message, the current time 183 | */ 184 | bool send_T(uint16_t to) { 185 | RF24NetworkHeader header(/*to node*/ to, /*type*/ 'T' /*Time*/); 186 | 187 | // The 'T' message that we send is just a ulong, containing the time 188 | unsigned long message = millis(); 189 | Serial.println(F("---------------------------------")); 190 | Serial.print(millis()); 191 | Serial.print(F(": APP Sending ")); 192 | Serial.print(message); 193 | Serial.print(F(" to ")); 194 | Serial.print(to); 195 | Serial.println(F("...")); 196 | return network.write(header, &message, sizeof(unsigned long)); 197 | } 198 | 199 | /** 200 | * Send an 'N' message, the active node list 201 | */ 202 | bool send_N(uint16_t to) { 203 | RF24NetworkHeader header(/*to node*/ to, /*type*/ 'N' /*Time*/); 204 | 205 | Serial.println(F("---------------------------------")); 206 | Serial.print(millis()); 207 | Serial.print(F(": APP Sending active nodes to ")); 208 | Serial.print(to); 209 | Serial.println(F("...")); 210 | return network.write(header, active_nodes, sizeof(active_nodes)); 211 | } 212 | 213 | /** 214 | * Handle a 'T' message 215 | * Add the node to the list of active nodes 216 | */ 217 | void handle_T(RF24NetworkHeader& header) { 218 | 219 | unsigned long message; // The 'T' message is just a ulong, containing the time 220 | network.read(header, &message, sizeof(unsigned long)); 221 | Serial.print(millis()); 222 | Serial.print(F(": APP Received ")); 223 | Serial.print(message); 224 | Serial.print(F(" from ")); 225 | Serial.println(header.from_node); 226 | 227 | if (header.from_node != this_node || header.from_node > 00) // If this message is from ourselves or the base, don't bother adding it to the active nodes. 228 | add_node(header.from_node); 229 | } 230 | 231 | /** 232 | * Handle an 'N' message, the active node list 233 | */ 234 | void handle_N(RF24NetworkHeader& header) { 235 | static uint16_t incoming_nodes[max_active_nodes]; 236 | 237 | network.read(header, &incoming_nodes, sizeof(incoming_nodes)); 238 | Serial.print(millis()); 239 | Serial.print(F(": APP Received nodes from ")); 240 | Serial.println(header.from_node); 241 | 242 | int i = 0; 243 | while (i < max_active_nodes && incoming_nodes[i] > 00) 244 | add_node(incoming_nodes[i++]); 245 | } 246 | 247 | /** 248 | * Add a particular node to the current list of active nodes 249 | */ 250 | void add_node(uint16_t node) { 251 | 252 | short i = num_active_nodes; // Do we already know about this node? 253 | while (i--) { 254 | if (active_nodes[i] == node) 255 | break; 256 | } 257 | 258 | if (i == -1 && num_active_nodes < max_active_nodes) { // If not, add it to the table 259 | active_nodes[num_active_nodes++] = node; 260 | Serial.print(millis()); 261 | Serial.print(F(": APP Added ")); 262 | Serial.print(node); 263 | Serial.println(F(" to list of active nodes.")); 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /examples/Network_Ping_Sleep/Network_Ping_Sleep.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2011 James Coliz, Jr. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | * 8 | * 2014 - TMRh20: New sketch included with updated library 9 | */ 10 | 11 | /** 12 | * Example: Network topology, and pinging across a tree/mesh network with sleeping nodes 13 | * 14 | * Using this sketch, each node will send a ping to every other node in the network every few seconds. 15 | * The RF24Network library will route the message across the mesh to the correct node. 16 | * 17 | * This sketch demonstrates the new functionality of nodes sleeping in STANDBY-I mode. In receive mode, 18 | * the radio will draw about 13.5 mA. In STANDBY-I mode, the radio draws .000022mA, and is able to awake 19 | * when payloads are received. 20 | * 21 | * How it Works: 22 | * The enhanced sleep mode utilizes the ACK payload functionality, as radios that are in Primary Transmitter 23 | * mode (PTX) are able to receive ACK payloads while in STANDBY-I mode. 24 | * 1. The radio is configured to use Dynamic Payloads and ACK payloads with Auto-Ack enabled 25 | * 2. The radio enters PTX mode and attaches an interrupt handler to the radio interrupt input pin (pin 2) 26 | * 3. The radio uses the Watchdog Timer to awake at set 1 second intervals in this example 27 | * 4. Every interval, it sends out a 'sleep' payload and goes back to sleep. Incoming payloads will then be treated as ACK payloads, while the radio remains in STANDBY-I mode. 28 | * 5. If an interrupt is triggered, the radio wakes up 29 | * 6. When a message is sent to the sleeping node, the interrupt triggers a wake up, the MCU 30 | * grabs the payload, and switches back to receive mode in case more data is on its way. 31 | * 32 | * The node (Arduino) power use can be reduced further by disabling unnessessary systems via the Power Reduction Register(s) (PRR). 33 | */ 34 | 35 | #include 36 | #include 37 | #include 38 | #include "printf.h" 39 | #include 40 | #include 41 | #include 42 | 43 | 44 | /*********************************************************************** 45 | ************* Set the Node Address ************************************* 46 | ************************************************************************/ 47 | 48 | // These are the Octal addresses that will be assigned 49 | const uint16_t node_address_set[10] = { 00, 02, 05, 012, 015, 022, 025, 032, 035, 045 }; 50 | 51 | // 0 = Master 52 | // 1-2 (02, 05) = Children of Master(00) 53 | // 3, 5 (012, 022) = Children of (02) 54 | // 4, 6 (015, 025) = Children of (05) 55 | // 7 (032) = Child of (02) 56 | // 8, 9 (035, 045) = Children of (05) 57 | 58 | uint8_t NODE_ADDRESS = 1; // Use numbers 0 through 9 to select an address from the array 59 | 60 | /***********************************************************************/ 61 | /***********************************************************************/ 62 | 63 | 64 | RF24 radio(7, 8); // CE & CS pins to use (Using 7,8 on Uno,Nano) 65 | RF24Network network(radio); 66 | 67 | uint16_t this_node; // Our node address 68 | 69 | const unsigned long interval = 1000; // Delay manager to send pings regularly (in ms). Because of sleepNode(), this is largely irrelevant. 70 | unsigned long last_time_sent; 71 | 72 | const short max_active_nodes = 10; // Array of nodes we are aware of 73 | uint16_t active_nodes[max_active_nodes]; 74 | short num_active_nodes = 0; 75 | short next_ping_node_index = 0; 76 | 77 | 78 | bool send_T(uint16_t to); // Prototypes for functions to send & handle messages 79 | bool send_N(uint16_t to); 80 | void handle_T(RF24NetworkHeader& header); 81 | void handle_N(RF24NetworkHeader& header); 82 | void add_node(uint16_t node); 83 | 84 | 85 | //This is for sleep mode. It is not really required, as users could just use the number 0 through 10 86 | typedef enum { wdt_16ms = 0, 87 | wdt_32ms, 88 | wdt_64ms, 89 | wdt_128ms, 90 | wdt_250ms, 91 | wdt_500ms, 92 | wdt_1s, 93 | wdt_2s, 94 | wdt_4s, 95 | wdt_8s } wdt_prescalar_e; 96 | 97 | unsigned long awakeTime = 500; // How long in ms the radio will stay awake after leaving sleep mode 98 | unsigned long sleepTimer = 0; // Used to keep track of how long the system has been awake 99 | 100 | void setup() { 101 | 102 | Serial.begin(115200); 103 | printf_begin(); // needed for RF24* libs' internal printf() calls 104 | while (!Serial) { 105 | // some boards need this because of native USB capability 106 | } 107 | Serial.println(F("RF24Network/examples/meshping/")); 108 | 109 | this_node = node_address_set[NODE_ADDRESS]; // Which node are we? 110 | 111 | if (!radio.begin()) { 112 | Serial.println(F("Radio hardware not responding!")); 113 | while (1) { 114 | // hold in infinite loop 115 | } 116 | } 117 | radio.setPALevel(RF24_PA_HIGH); 118 | radio.setChannel(100); 119 | network.begin(/*node address*/ this_node); 120 | 121 | /******************************** This is the configuration for sleep mode ***********************/ 122 | network.setup_watchdog(wdt_1s); //The watchdog timer will wake the MCU and radio every second to send a sleep payload, then go back to sleep 123 | } 124 | 125 | void loop() { 126 | 127 | network.update(); // Pump the network regularly 128 | 129 | while (network.available()) { // Is there anything ready for us? 130 | 131 | RF24NetworkHeader header; // If so, take a look at it 132 | network.peek(header); 133 | 134 | 135 | switch (header.type) { // Dispatch the message to the correct handler. 136 | case 'T': 137 | handle_T(header); 138 | break; 139 | case 'N': 140 | handle_N(header); 141 | break; 142 | 143 | /************* SLEEP MODE *********/ 144 | // Note: A 'sleep' header has been defined, and should only need to be ignored if a node is routing traffic to itself 145 | // The header is defined as: RF24NetworkHeader sleepHeader(/*to node*/ 00, /*type*/ 'S' /*Sleep*/); 146 | case 'S': 147 | /*This is a sleep payload, do nothing*/ 148 | break; 149 | 150 | default: 151 | Serial.print(F("*** WARNING *** Unknown message type ")); 152 | Serial.println(header.type); 153 | network.read(header, 0, 0); 154 | break; 155 | }; 156 | } 157 | 158 | /***************************** CALLING THE NEW SLEEP FUNCTION ************************/ 159 | 160 | if (millis() - sleepTimer > awakeTime && NODE_ADDRESS) { 161 | // Want to make sure the Arduino stays awake for a little while when data comes in. 162 | // Do NOT sleep if master node. 163 | Serial.println(F("Sleep")); 164 | sleepTimer = millis(); // Reset the timer value 165 | delay(100); // Give the Serial print some time to finish up 166 | radio.stopListening(); // Switch to PTX mode. Payloads will be seen as ACK payloads, and the radio will wake up 167 | network.sleepNode(8, 0); // Sleep the node for 8 cycles of 1second intervals 168 | Serial.println(F("Awake")); 169 | } 170 | 171 | //Examples: 172 | // network.sleepNode(cycles, interrupt-pin); 173 | // network.sleepNode(0, 0); // The WDT is configured in this example to sleep in cycles of 1 second. This will sleep 1 second, or until a payload is received 174 | // network.sleepNode(1, 255); // Sleep this node for 1 second. Do not wake up until then, even if a payload is received ( no interrupt ) Payloads will be lost. 175 | 176 | /**** end sleep section ***/ 177 | 178 | 179 | unsigned long now = millis(); // Send a ping to the next node every 'interval' ms 180 | if (now - last_time_sent >= interval) { 181 | last_time_sent = now; 182 | 183 | uint16_t to = 00; // Who should we send to? By default, send to base 184 | 185 | if (num_active_nodes) { // Or if we have active nodes, 186 | to = active_nodes[next_ping_node_index++]; // Send to the next active node 187 | if (next_ping_node_index > num_active_nodes) { // Have we rolled over? 188 | next_ping_node_index = 0; // Next time start at the beginning 189 | to = 00; // This time, send to node 00. 190 | } 191 | } 192 | 193 | bool ok; 194 | 195 | if (this_node > 00 || to == 00) { // Normal nodes send a 'T' ping 196 | ok = send_T(to); 197 | } else { // Base node sends the current active nodes out 198 | ok = send_N(to); 199 | } 200 | 201 | if (ok) { // Notify us of the result 202 | Serial.print(millis()); 203 | Serial.println(F(": APP Send ok")); 204 | } else { 205 | Serial.print(millis()); 206 | Serial.println(F(": APP Send failed")); 207 | last_time_sent -= 100; // Try sending at a different time next time 208 | } 209 | } 210 | } 211 | 212 | /** 213 | * Send a 'T' message, the current time 214 | */ 215 | bool send_T(uint16_t to) { 216 | RF24NetworkHeader header(/*to node*/ to, /*type*/ 'T' /*Time*/); 217 | 218 | // The 'T' message that we send is just a ulong, containing the time 219 | unsigned long message = millis(); 220 | Serial.println(F("---------------------------------")); 221 | Serial.print(millis()); 222 | Serial.print(F(": APP Sending ")); 223 | Serial.print(message); 224 | Serial.print(F(" to ")); 225 | Serial.print(to); 226 | Serial.println(F("...")); 227 | return network.write(header, &message, sizeof(unsigned long)); 228 | } 229 | 230 | /** 231 | * Send an 'N' message, the active node list 232 | */ 233 | bool send_N(uint16_t to) { 234 | RF24NetworkHeader header(/*to node*/ to, /*type*/ 'N' /*Time*/); 235 | 236 | Serial.println(F("---------------------------------")); 237 | Serial.print(millis()); 238 | Serial.print(F(": APP Sending active nodes to ")); 239 | Serial.print(to); 240 | Serial.println(F("...")); 241 | return network.write(header, active_nodes, sizeof(active_nodes)); 242 | } 243 | 244 | /** 245 | * Handle a 'T' message 246 | * Add the node to the list of active nodes 247 | */ 248 | void handle_T(RF24NetworkHeader& header) { 249 | 250 | unsigned long message; // The 'T' message is just a ulong, containing the time 251 | network.read(header, &message, sizeof(unsigned long)); 252 | Serial.print(millis()); 253 | Serial.print(F(": APP Received ")); 254 | Serial.print(message); 255 | Serial.print(F(" from ")); 256 | Serial.print(header.from_node); 257 | 258 | if (header.from_node != this_node || header.from_node > 00) // If this message is from ourselves or the base, don't bother adding it to the active nodes. 259 | add_node(header.from_node); 260 | } 261 | 262 | /** 263 | * Handle an 'N' message, the active node list 264 | */ 265 | void handle_N(RF24NetworkHeader& header) { 266 | static uint16_t incoming_nodes[max_active_nodes]; 267 | 268 | network.read(header, &incoming_nodes, sizeof(incoming_nodes)); 269 | Serial.print(millis()); 270 | Serial.print(F(": APP Received nodes from ")); 271 | Serial.println(header.from_node); 272 | 273 | int i = 0; 274 | while (i < max_active_nodes && incoming_nodes[i] > 00) 275 | add_node(incoming_nodes[i++]); 276 | } 277 | 278 | /** 279 | * Add a particular node to the current list of active nodes 280 | */ 281 | void add_node(uint16_t node) { 282 | 283 | short i = num_active_nodes; // Do we already know about this node? 284 | while (i--) { 285 | if (active_nodes[i] == node) 286 | break; 287 | } 288 | 289 | if (i == -1 && num_active_nodes < max_active_nodes) { // If not, add it to the table 290 | active_nodes[num_active_nodes++] = node; 291 | Serial.print(millis()); 292 | Serial.print(F(": APP Added ")); 293 | Serial.print(node); 294 | Serial.print(F(" to list of active nodes.")); 295 | } 296 | } 297 | -------------------------------------------------------------------------------- /examples/Network_Priority_RX/Network_Priority_RX.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2020 TMRh20(tmrh20@gmail.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | */ 8 | 9 | /** 10 | * This sketch demonstrates handling of external data 11 | * 12 | * RF24Network contains a buffer for storing user payloads that have been received via the network.update() 13 | * function. If using protocols like TCP/IP over RF24Network, the memory on small devices is very limited. 14 | * Instead of using the user-payload buffer for such large payloads, they can be designated as an 15 | * EXTERNAL_DATA_TYPE in the header.type field. This allows users to prioritize these payloads, as they are 16 | * often very large, and would take up most or all of the user data buffer. 17 | * 18 | * The network.update function will return immediately upon receiving a payload marked as EXTERNAL_DATA_TYPE 19 | * Users can then process the data immediately. 20 | * All other payload types are handled via the network.available() and network.read() functionality. 21 | * 22 | * Functionality: 23 | * The TX node will send normal user data designated with header.type = 33, along with additional data 24 | * marked as header.type = EXTERNAL_DATA_TYPE. 25 | * The RX node demonstrates how to handle such data, allowing separation of standard data that is processed 26 | * normally vs data that needs to be passed elsewhere, like network interface for TCP/IP packets. 27 | * These methods are used in RF24Gateway & RF24Ethernet TCP/IP libraries for nrf24l01+. 28 | */ 29 | 30 | #include "printf.h" 31 | #include 32 | #include 33 | 34 | RF24 radio(7, 8); // nRF24L01(+) radio attached using Getting Started board 35 | 36 | RF24Network network(radio); // Network uses that radio 37 | 38 | const uint16_t this_node = 00; // Address of our node in Octal format 39 | const uint16_t other_node = 01; // Address of the other node in Octal format 40 | 41 | uint32_t myVariable = 0; 42 | 43 | void setup() { 44 | 45 | Serial.begin(115200); 46 | printf_begin(); // needed for RF24* libs' internal printf() calls 47 | while (!Serial) { 48 | // some boards need this because of native USB capability 49 | } 50 | Serial.println(F("RF24Network/examples/Network_Separation_RX/")); 51 | 52 | if (!radio.begin()) { 53 | Serial.println(F("Radio hardware not responding!")); 54 | while (1) { 55 | // hold in infinite loop 56 | } 57 | } 58 | radio.setChannel(90); 59 | network.begin(/*node address*/ this_node); 60 | radio.printDetails(); 61 | 62 | } //setup 63 | 64 | 65 | uint32_t sendTimer = 0; 66 | 67 | /* **** Create a large array for data to be received **** 68 | * MAX_PAYLOAD_SIZE is defined in RF24Network_config.h 69 | * Payload sizes of ~1-2 KBytes or more are practical when radio conditions are good 70 | */ 71 | #define EXTERNAL_DATA_MAX_SIZE MAX_PAYLOAD_SIZE 72 | 73 | uint8_t dataBuffer[EXTERNAL_DATA_MAX_SIZE]; 74 | 75 | uint32_t userDataTimer = 0; 76 | 77 | 78 | /* 79 | * The main loop behaviour demonstrates the different prioritization of handling data 80 | * External data is handled immediately upon reception, with the network.update() function being 81 | * called very regularly to handle incoming/outgoing radio traffic. 82 | * 83 | * The network.available() function is only called every 5 seconds, to simulate a busy microcontroller, 84 | * so the user payloads will only print out every 5 seconds 85 | * 86 | * The radio has 3, 32-byte FIFO buffers operating independantly of the MCU, and RF24Network will buffer 87 | * up to MAX_PAYLOAD_SIZE (see RF24Network_config.h) of user data. 88 | */ 89 | void loop() { 90 | 91 | // Immediate handling of data with header type EXTERNAL_DATA_TYPE 92 | 93 | if (network.update() == EXTERNAL_DATA_TYPE) { 94 | uint16_t size = network.frag_ptr->message_size; 95 | memcpy(&dataBuffer, network.frag_ptr->message_buffer, network.frag_ptr->message_size); 96 | 97 | // Handle the external data however... 98 | Serial.print(F("External Data RX, size: ")); 99 | Serial.println(network.frag_ptr->message_size); 100 | 101 | for (uint16_t i = 0; i < network.frag_ptr->message_size; i++) { 102 | Serial.print(dataBuffer[i]); 103 | Serial.print(F(":")); 104 | } 105 | Serial.println(); 106 | } 107 | 108 | 109 | // Use a timer to simulate a busy MCU where normal network data cannot be processed in a timely manner 110 | if (millis() - userDataTimer > 5000) { 111 | userDataTimer = millis(); 112 | 113 | // Handling of standard RF24Network User Data 114 | while (network.available()) { 115 | 116 | RF24NetworkHeader header; // Create an empty header 117 | uint16_t dataSize = network.peek(header); // Peek to get the size of the data 118 | uint32_t someVariable; 119 | if (header.type == 32) { // If a certain header type is recieved 120 | network.read(header, &someVariable, sizeof(someVariable)); // Handle the data a specific way 121 | Serial.print(F("RX User Data:\nHeader Type ")); 122 | Serial.print(header.type); 123 | Serial.print(F(" Value ")); 124 | Serial.println(someVariable); 125 | } else { 126 | // Clear the user data from the buffer if some other header type is received 127 | network.read(header, &someVariable, 0); 128 | } 129 | } 130 | } 131 | } //loop 132 | -------------------------------------------------------------------------------- /examples/Network_Priority_TX/Network_Priority_TX.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2020 TMRh20(tmrh20@gmail.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | */ 8 | 9 | /** 10 | * This sketch demonstrates handling of external data 11 | * 12 | * RF24Network contains a buffer for storing user payloads that have been received via the network.update() 13 | * function. If using protocols like TCP/IP over RF24Network, the memory on small devices is very limited. 14 | * Instead of using the user-payload buffer for such large payloads, they can be designated as an 15 | * EXTERNAL_DATA_TYPE in the header.type field. This allows users to prioritize these payloads, as they are 16 | * often very large, and would take up most or all of the user data buffer. 17 | * 18 | * The network.update function will return immediately upon receiving a payload marked as EXTERNAL_DATA_TYPE 19 | * Users can then process the data immediately. 20 | * All other payload types are handled via the network.available() and network.read() functionality. 21 | * 22 | * Functionality: 23 | * The TX node will send normal user data designated with header.type = 33, along with additional data 24 | * marked as header.type = EXTERNAL_DATA_TYPE. 25 | * The RX node demonstrates how to handle such data, allowing separation of standard data that is processed 26 | * normally vs data that needs to be passed elsewhere, like network interface for TCP/IP packets. 27 | * These methods are used in RF24Gateway & RF24Ethernet TCP/IP libraries for nrf24l01+. 28 | */ 29 | 30 | #include 31 | #include 32 | #include "printf.h" 33 | 34 | RF24 radio(7, 8); // nRF24L01(+) radio attached using Getting Started board 35 | 36 | RF24Network network(radio); // Network uses that radio 37 | 38 | const uint16_t this_node = 01; // Address of our node in Octal format 39 | const uint16_t other_node = 00; // Address of the other node in Octal format 40 | 41 | uint8_t dataBuffer[33]; 42 | 43 | void setup() { 44 | 45 | Serial.begin(115200); 46 | printf_begin(); // needed for RF24* libs' internal printf() calls 47 | while (!Serial) { 48 | // some boards need this because of native USB capability 49 | } 50 | Serial.println(F("RF24Network/examples/Network_Separation_TX/")); 51 | 52 | if (!radio.begin()) { 53 | Serial.println(F("Radio hardware not responding!")); 54 | while (1) { 55 | // hold in infinite loop 56 | } 57 | } 58 | radio.setChannel(90); 59 | network.begin(/*node address*/ this_node); 60 | radio.printDetails(); 61 | 62 | // Load our data buffer with numbered data 63 | for (uint16_t i = 0; i < 33; i++) { 64 | dataBuffer[i] = i; 65 | } 66 | 67 | } //setup 68 | 69 | 70 | uint32_t sendTimer = 0; 71 | 72 | /* 73 | * The main loop sends two types of data to be processed with different priority per the RX 74 | * example 75 | */ 76 | 77 | void loop() { 78 | 79 | network.update(); 80 | 81 | if (millis() - sendTimer > 1000) { 82 | sendTimer = millis(); 83 | 84 | Serial.println(F("Sending data...")); 85 | 86 | // Sending of External data, which will be handled immediately 87 | RF24NetworkHeader header(other_node, EXTERNAL_DATA_TYPE); 88 | bool ok = network.write(header, &dataBuffer, 33); 89 | Serial.println(ok ? F("OK 1") : F("Fail 1")); 90 | 91 | // Sending normal user data, which may be buffered and handled later 92 | RF24NetworkHeader header2(other_node, 32); 93 | uint32_t someVariable = 1234; 94 | ok = network.write(header2, &someVariable, sizeof(someVariable)); 95 | Serial.println(ok ? F("OK 2") : F("Fail 2")); 96 | } 97 | 98 | // Dummy operation to read 0 bytes from all incoming user payloads 99 | // Ensures the buffer doesnt fill up 100 | if (network.available()) { 101 | RF24NetworkHeader header; 102 | network.read(header, &dataBuffer, 0); 103 | } 104 | 105 | } //loop 106 | -------------------------------------------------------------------------------- /examples/helloworld_rx/helloworld_rx.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2012 James Coliz, Jr. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | * 8 | * Update 2014 - TMRh20 9 | */ 10 | 11 | /** 12 | * Simplest possible example of using RF24Network, 13 | * 14 | * RECEIVER NODE 15 | * Listens for messages from the transmitter and prints them out. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | RF24 radio(7, 8); // nRF24L01(+) radio attached using Getting Started board 24 | 25 | RF24Network network(radio); // Network uses that radio 26 | const uint16_t this_node = 00; // Address of our node in Octal format (04, 031, etc) 27 | const uint16_t other_node = 01; // Address of the other node in Octal format 28 | 29 | struct payload_t { // Structure of our payload 30 | unsigned long ms; 31 | unsigned long counter; 32 | }; 33 | 34 | 35 | void setup(void) { 36 | Serial.begin(115200); 37 | while (!Serial) { 38 | // some boards need this because of native USB capability 39 | } 40 | Serial.println(F("RF24Network/examples/helloworld_rx/")); 41 | 42 | if (!radio.begin()) { 43 | Serial.println(F("Radio hardware not responding!")); 44 | while (1) { 45 | // hold in infinite loop 46 | } 47 | } 48 | radio.setChannel(90); 49 | network.begin(/*node address*/ this_node); 50 | } 51 | 52 | void loop(void) { 53 | 54 | network.update(); // Check the network regularly 55 | 56 | while (network.available()) { // Is there anything ready for us? 57 | 58 | RF24NetworkHeader header; // If so, grab it and print it out 59 | payload_t payload; 60 | network.read(header, &payload, sizeof(payload)); 61 | Serial.print(F("Received packet: counter=")); 62 | Serial.print(payload.counter); 63 | Serial.print(F(", origin timestamp=")); 64 | Serial.println(payload.ms); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /examples/helloworld_rx_advanced/helloworld_rx_advanced.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2020 TMRh20(tmrh20@gmail.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | */ 8 | 9 | /** 10 | * More advanced example of using RF24Network: 11 | * Fragmentation and Reassembly: 12 | * - nrf24l01+ radios can tx/rx 32 bytes of data per transmission 13 | * - RF24Network will fragment and re-assemble payloads of any size 14 | * Demonstrates use of differing sized payloads using peek() function 15 | * 16 | * RECEIVER NODE 17 | * Every X milliseconds, send a payload to the receiver node. 18 | */ 19 | 20 | #include "printf.h" 21 | #include 22 | #include 23 | 24 | RF24 radio(7, 8); // nRF24L01(+) radio attached using Getting Started board 25 | 26 | RF24Network network(radio); // Network uses that radio 27 | const uint16_t this_node = 00; // Address of our node in Octal format ( 04,031, etc) 28 | const uint16_t other_node = 01; // Address of the other node in Octal format 29 | 30 | /**** Create a large array for data to be received **** 31 | * MAX_PAYLOAD_SIZE is defined in RF24Network_config.h 32 | * Payload sizes of ~1-2 KBytes or more are practical when radio conditions are good 33 | */ 34 | uint8_t dataBuffer[MAX_PAYLOAD_SIZE]; //MAX_PAYLOAD_SIZE is defined in RF24Network_config.h 35 | 36 | 37 | void setup(void) { 38 | 39 | Serial.begin(115200); 40 | while (!Serial) { 41 | // some boards need this because of native USB capability 42 | } 43 | Serial.println(F("RF24Network/examples/helloworld_rx_advanced/")); 44 | 45 | if (!radio.begin()) { 46 | Serial.println(F("Radio hardware not responding!")); 47 | while (1) { 48 | // hold in infinite loop 49 | } 50 | } 51 | radio.setChannel(90); 52 | network.begin(/*node address*/ this_node); 53 | 54 | printf_begin(); // needed for RF24* libs' internal printf() calls 55 | radio.printDetails(); // requires printf support 56 | } 57 | 58 | // Variable for calculating how long between RX 59 | uint32_t timeBetweenPackets = 0; 60 | 61 | void loop(void) { 62 | 63 | network.update(); // Check the network regularly 64 | 65 | while (network.available()) { // Is there anything ready for us? 66 | 67 | RF24NetworkHeader header; // If so, grab it and print it out 68 | uint16_t payloadSize = network.peek(header); // Use peek() to get the size of the payload 69 | network.read(header, &dataBuffer, payloadSize); // Get the data 70 | Serial.print("Received packet, size "); // Print info about received data 71 | Serial.print(payloadSize); 72 | Serial.print("("); 73 | Serial.print(millis() - timeBetweenPackets); 74 | Serial.println("ms since last)"); 75 | timeBetweenPackets = millis(); 76 | 77 | // Uncomment below to print the entire payload 78 | /* 79 | for(uint32_t i = 0; i < payloadSize; i++) { 80 | Serial.print(dataBuffer[i]); 81 | Serial.print(F(": ")); 82 | if(i % 50 == 49) { 83 | //Add a line break every 50 characters 84 | Serial.println(); 85 | } 86 | } 87 | Serial.println(); 88 | */ 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /examples/helloworld_tx/helloworld_tx.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2012 James Coliz, Jr. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | * 8 | * Update 2014 - TMRh20 9 | */ 10 | 11 | /** 12 | * Simplest possible example of using RF24Network 13 | * 14 | * TRANSMITTER NODE 15 | * Every 2 seconds, send a payload to the receiver node. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | RF24 radio(7, 8); // nRF24L01(+) radio attached using Getting Started board 23 | 24 | RF24Network network(radio); // Network uses that radio 25 | 26 | const uint16_t this_node = 01; // Address of our node in Octal format 27 | const uint16_t other_node = 00; // Address of the other node in Octal format 28 | 29 | const unsigned long interval = 2000; // How often (in ms) to send 'hello world' to the other unit 30 | 31 | unsigned long last_sent; // When did we last send? 32 | unsigned long packets_sent; // How many have we sent already 33 | 34 | 35 | struct payload_t { // Structure of our payload 36 | unsigned long ms; 37 | unsigned long counter; 38 | }; 39 | 40 | void setup(void) { 41 | Serial.begin(115200); 42 | while (!Serial) { 43 | // some boards need this because of native USB capability 44 | } 45 | Serial.println(F("RF24Network/examples/helloworld_tx/")); 46 | 47 | if (!radio.begin()) { 48 | Serial.println(F("Radio hardware not responding!")); 49 | while (1) { 50 | // hold in infinite loop 51 | } 52 | } 53 | radio.setChannel(90); 54 | network.begin(/*node address*/ this_node); 55 | } 56 | 57 | void loop() { 58 | 59 | network.update(); // Check the network regularly 60 | 61 | unsigned long now = millis(); 62 | 63 | // If it's time to send a message, send it! 64 | if (now - last_sent >= interval) { 65 | last_sent = now; 66 | 67 | Serial.print(F("Sending... ")); 68 | payload_t payload = { millis(), packets_sent++ }; 69 | RF24NetworkHeader header(/*to node*/ other_node); 70 | bool ok = network.write(header, &payload, sizeof(payload)); 71 | Serial.println(ok ? F("ok.") : F("failed.")); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /examples/helloworld_tx_advanced/helloworld_tx_advanced.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2020 TMRh20(tmrh20@gmail.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | */ 8 | 9 | /** 10 | * More advanced example of using RF24Network: 11 | * Fragmentation and Reassembly: 12 | * - nrf24l01+ radios can tx/rx 32 bytes of data per transmission 13 | * - RF24Network will fragment and re-assemble payloads of any size 14 | * Demonstrates use of differing sized payloads using peek() function 15 | * 16 | * TRANSMITTER NODE 17 | * Every X milliseconds, send a payload to the receiver node. 18 | */ 19 | 20 | #include "printf.h" 21 | #include 22 | #include 23 | 24 | RF24 radio(7, 8); // nRF24L01(+) radio attached using Getting Started board 25 | 26 | RF24Network network(radio); // Network uses that radio 27 | 28 | const uint16_t this_node = 01; // Address of our node in Octal format 29 | const uint16_t other_node = 00; // Address of the other node in Octal format 30 | 31 | const unsigned long interval = 500; //ms // How often to send 'hello world to the other unit 32 | 33 | unsigned long last_sent; // When did we last send? 34 | 35 | /**** Create a large array for data to be sent **** 36 | * MAX_PAYLOAD_SIZE is defined in RF24Network_config.h 37 | * Payload sizes of ~1-2 KBytes or more are practical when radio conditions are good 38 | */ 39 | uint8_t dataBuffer[MAX_PAYLOAD_SIZE]; 40 | 41 | void setup(void) { 42 | Serial.begin(115200); 43 | while (!Serial) { 44 | // some boards need this because of native USB capability 45 | } 46 | Serial.println(F("RF24Network/examples/helloworld_tx_advanced/")); 47 | printf_begin(); // needed for RF24* libs' internal printf() calls 48 | 49 | if (!radio.begin()) { 50 | Serial.println(F("Radio hardware not responding!")); 51 | while (1) { 52 | // hold in infinite loop 53 | } 54 | } 55 | radio.setChannel(90); 56 | network.begin(/*node address*/ this_node); 57 | radio.printDetails(); 58 | 59 | // Load our data buffer with numbered data 60 | for (uint16_t i = 0; i < MAX_PAYLOAD_SIZE; i++) { 61 | dataBuffer[i] = i % 256; //Ensure the max value is 255 62 | } 63 | } 64 | 65 | uint16_t sizeofSend = 0; //Variable to indicate how much data to send 66 | bool stopSending = 0; //Used to stop/start sending of data 67 | 68 | void loop() { 69 | 70 | //User input anything via Serial to stop/start data transmission 71 | if (Serial.available()) { 72 | Serial.read(); 73 | stopSending = !stopSending; 74 | } 75 | 76 | network.update(); // Check the network regularly 77 | 78 | unsigned long now = millis(); // If it's time to send a message, send it! 79 | if (now - last_sent >= interval && !stopSending) { 80 | last_sent = now; 81 | Serial.print(F("Sending size ")); 82 | Serial.print(sizeofSend); 83 | 84 | // Fragmentation/reassembly is transparent. Just send payloads as usual. 85 | RF24NetworkHeader header(/*to node*/ other_node); 86 | bool ok = network.write(header, &dataBuffer, sizeofSend++); 87 | 88 | // If the size of data to be sent is larger than max payload size, reset at 0 89 | if (sizeofSend > MAX_PAYLOAD_SIZE) { 90 | sizeofSend = 0; 91 | } 92 | 93 | Serial.println(ok ? F(" ok.") : F(" failed.")); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /examples/nrf_to_nrf/helloworld_rx/helloworld_rx.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2012 James Coliz, Jr. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | * 8 | * Update 2014 - TMRh20 9 | */ 10 | 11 | /** 12 | * Simplest possible example of using RF24Network, 13 | * 14 | * RECEIVER NODE 15 | * Listens for messages from the transmitter and prints them out. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | 22 | nrf_to_nrf radio; // nRF24L01(+) radio attached using Getting Started board 23 | 24 | RF52Network network(radio); // Network uses that radio 25 | const uint16_t this_node = 00; // Address of our node in Octal format (04, 031, etc) 26 | const uint16_t other_node = 01; // Address of the other node in Octal format 27 | 28 | struct payload_t { // Structure of our payload 29 | unsigned long ms; 30 | unsigned long counter; 31 | }; 32 | 33 | 34 | void setup(void) { 35 | Serial.begin(115200); 36 | while (!Serial) { 37 | // some boards need this because of native USB capability 38 | } 39 | Serial.println(F("RF24Network/examples/helloworld_rx/")); 40 | 41 | if (!radio.begin()) { 42 | Serial.println(F("Radio hardware not responding!")); 43 | while (1) { 44 | // hold in infinite loop 45 | } 46 | } 47 | radio.setChannel(90); 48 | network.begin(/*node address*/ this_node); 49 | } 50 | 51 | void loop(void) { 52 | 53 | network.update(); // Check the network regularly 54 | 55 | while (network.available()) { // Is there anything ready for us? 56 | 57 | RF24NetworkHeader header; // If so, grab it and print it out 58 | payload_t payload; 59 | network.read(header, &payload, sizeof(payload)); 60 | Serial.print(F("Received packet: counter=")); 61 | Serial.print(payload.counter); 62 | Serial.print(F(", origin timestamp=")); 63 | Serial.println(payload.ms); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /examples/nrf_to_nrf/helloworld_rxEncryption/helloworld_rxEncryption.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2012 James Coliz, Jr. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | * 8 | * Update 2014 - TMRh20 9 | */ 10 | 11 | /** 12 | * Simplest possible example of using RF24Network, 13 | * 14 | * RECEIVER NODE 15 | * Listens for messages from the transmitter and prints them out. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | //Set up our encryption key 22 | uint8_t myKey[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 }; 23 | 24 | nrf_to_nrf radio; // nRF24L01(+) radio attached using Getting Started board 25 | 26 | RF52Network network(radio); // Network uses that radio 27 | const uint16_t this_node = 00; // Address of our node in Octal format (04, 031, etc) 28 | const uint16_t other_node = 01; // Address of the other node in Octal format 29 | 30 | struct payload_t { // Structure of our payload 31 | unsigned long ms; 32 | unsigned long counter; 33 | }; 34 | 35 | 36 | void setup(void) { 37 | Serial.begin(115200); 38 | while (!Serial) { 39 | // some boards need this because of native USB capability 40 | } 41 | Serial.println(F("RF24Network/examples/helloworld_rx/")); 42 | 43 | if (!radio.begin()) { 44 | Serial.println(F("Radio hardware not responding!")); 45 | while (1) { 46 | // hold in infinite loop 47 | } 48 | } 49 | 50 | radio.setKey(myKey); // Set our key and IV 51 | radio.enableEncryption = true; // Enable encryption 52 | radio.enableDynamicPayloads(123); //This is important to call so the encryption overhead will not be included in the 32-byte limit 53 | //To overcome the 32-byte limit, edit RF24Network.h and set MAX_FRAME_SIZE to 111 54 | radio.setChannel(90); 55 | network.begin(/*node address*/ this_node); 56 | } 57 | 58 | void loop(void) { 59 | 60 | network.update(); // Check the network regularly 61 | 62 | while (network.available()) { // Is there anything ready for us? 63 | 64 | RF24NetworkHeader header; // If so, grab it and print it out 65 | payload_t payload; 66 | network.read(header, &payload, sizeof(payload)); 67 | Serial.print(F("Received packet: counter=")); 68 | Serial.print(payload.counter); 69 | Serial.print(F(", origin timestamp=")); 70 | Serial.println(payload.ms); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /examples/nrf_to_nrf/helloworld_tx/helloworld_tx.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2012 James Coliz, Jr. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | * 8 | * Update 2014 - TMRh20 9 | */ 10 | 11 | /** 12 | * Simplest possible example of using RF24Network 13 | * 14 | * TRANSMITTER NODE 15 | * Every 2 seconds, send a payload to the receiver node. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | nrf_to_nrf radio; // nRF24L01(+) radio attached using Getting Started board 22 | 23 | RF52Network network(radio); // Network uses that radio 24 | 25 | const uint16_t this_node = 01; // Address of our node in Octal format 26 | const uint16_t other_node = 00; // Address of the other node in Octal format 27 | 28 | const unsigned long interval = 2000; // How often (in ms) to send 'hello world' to the other unit 29 | 30 | unsigned long last_sent; // When did we last send? 31 | unsigned long packets_sent; // How many have we sent already 32 | 33 | 34 | struct payload_t { // Structure of our payload 35 | unsigned long ms; 36 | unsigned long counter; 37 | }; 38 | 39 | void setup(void) { 40 | Serial.begin(115200); 41 | while (!Serial) { 42 | // some boards need this because of native USB capability 43 | } 44 | Serial.println(F("RF24Network/examples/helloworld_tx/")); 45 | 46 | if (!radio.begin()) { 47 | Serial.println(F("Radio hardware not responding!")); 48 | while (1) { 49 | // hold in infinite loop 50 | } 51 | } 52 | radio.setChannel(90); 53 | network.begin(/*node address*/ this_node); 54 | } 55 | 56 | void loop() { 57 | 58 | network.update(); // Check the network regularly 59 | 60 | unsigned long now = millis(); 61 | 62 | // If it's time to send a message, send it! 63 | if (now - last_sent >= interval) { 64 | last_sent = now; 65 | 66 | Serial.print(F("Sending... ")); 67 | payload_t payload = { millis(), packets_sent++ }; 68 | RF24NetworkHeader header(/*to node*/ other_node); 69 | bool ok = network.write(header, &payload, sizeof(payload)); 70 | Serial.println(ok ? F("ok.") : F("failed.")); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /examples/nrf_to_nrf/helloworld_txEncryption/helloworld_txEncryption.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2012 James Coliz, Jr. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | * 8 | * Update 2014 - TMRh20 9 | */ 10 | 11 | /** 12 | * Simplest possible example of using RF24Network 13 | * 14 | * TRANSMITTER NODE 15 | * Every 2 seconds, send a payload to the receiver node. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | //Set up our encryption key 22 | uint8_t myKey[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 }; 23 | 24 | nrf_to_nrf radio; // nRF24L01(+) radio attached using Getting Started board 25 | 26 | RF52Network network(radio); // Network uses that radio 27 | 28 | const uint16_t this_node = 01; // Address of our node in Octal format 29 | const uint16_t other_node = 00; // Address of the other node in Octal format 30 | 31 | const unsigned long interval = 2000; // How often (in ms) to send 'hello world' to the other unit 32 | 33 | unsigned long last_sent; // When did we last send? 34 | unsigned long packets_sent; // How many have we sent already 35 | 36 | 37 | struct payload_t { // Structure of our payload 38 | unsigned long ms; 39 | unsigned long counter; 40 | }; 41 | 42 | void setup(void) { 43 | Serial.begin(115200); 44 | while (!Serial) { 45 | // some boards need this because of native USB capability 46 | } 47 | Serial.println(F("RF24Network/examples/helloworld_tx/")); 48 | 49 | if (!radio.begin()) { 50 | Serial.println(F("Radio hardware not responding!")); 51 | while (1) { 52 | // hold in infinite loop 53 | } 54 | } 55 | 56 | radio.setKey(myKey); // Set our key and IV 57 | radio.enableEncryption = true; // Enable encryption 58 | radio.enableDynamicPayloads(123); //This is important to call so the encryption overhead will not be included in the 32-byte limit 59 | //To overcome the 32-byte limit, edit RF24Network.h and set MAX_FRAME_SIZE to 111 60 | radio.setChannel(90); 61 | network.begin(/*node address*/ this_node); 62 | } 63 | 64 | void loop() { 65 | 66 | network.update(); // Check the network regularly 67 | 68 | unsigned long now = millis(); 69 | 70 | // If it's time to send a message, send it! 71 | if (now - last_sent >= interval) { 72 | last_sent = now; 73 | 74 | Serial.print(F("Sending... ")); 75 | payload_t payload = { millis(), packets_sent++ }; 76 | RF24NetworkHeader header(/*to node*/ other_node); 77 | bool ok = network.write(header, &payload, sizeof(payload)); 78 | Serial.println(ok ? F("ok.") : F("failed.")); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/sensornet_archived.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nRF24/RF24Network/0b19dd59b742c87dd1d1b5b1a17182162b48e8d0/examples/sensornet_archived.zip -------------------------------------------------------------------------------- /examples_RPi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | # iterate over a list of examples by filename 4 | set(EXAMPLES_LIST 5 | helloworld_rx 6 | helloworld_tx 7 | rx-test 8 | ) 9 | 10 | project(RF24NetworkExamples) 11 | add_compile_options(-Ofast -Wall) # passing the compiler a `-pthread` flag doesn't work here 12 | 13 | # detect the CPU make and type 14 | include(../cmake/detectCPU.cmake) # sets the variable SOC accordingly 15 | 16 | # detect if any additional libs need be linked to executable (ei RF24_DRIVER) 17 | include(../cmake/AutoConfig_RF24_DRIVER.cmake) 18 | 19 | find_library(RF24 rf24 REQUIRED) 20 | message(STATUS "using RF24 library: ${RF24}") 21 | 22 | find_library(RF24Network rf24network REQUIRED) 23 | message(STATUS "using RF24Network library: ${RF24Network}") 24 | 25 | set(linked_libs 26 | ${RF24} 27 | pthread # Notice we specify pthread as a linked lib here 28 | ${RF24Network} 29 | ) 30 | 31 | # append additional libs for linking to the executable 32 | if("${RF24_DRIVER}" STREQUAL "MRAA") 33 | if(NOT "${LibMRAA}" STREQUAL "LibMRAA-NOTFOUND") 34 | message(STATUS "linking to ${LibMRAA}") 35 | list(APPEND linked_libs ${LibMRAA}) 36 | else() 37 | message(FATAL "Lib ${RF24_DRIVER} not found.") 38 | endif() 39 | elseif("${RF24_DRIVER}" STREQUAL "wiringPi") 40 | if(NOT "${LibWiringPi}" STREQUAL "LibWiringPi-NOTFOUND") 41 | message(STATUS "linking to ${LibWiringPi}") 42 | list(APPEND linked_libs ${LibWiringPi}) 43 | else() 44 | message(FATAL "Lib ${RF24_DRIVER} not found.") 45 | endif() 46 | elseif("${RF24_DRIVER}" STREQUAL "pigpio") 47 | if(NOT "${LibPIGPIO}" STREQUAL "LibPIGPIO-NOTFOUND") 48 | message(STATUS "linking to ${LibPIGPIO}") 49 | list(APPEND linked_libs ${LibPIGPIO}) 50 | else() 51 | message(FATAL "Lib ${RF24_DRIVER} not found.") 52 | endif() 53 | endif() 54 | 55 | foreach(example ${EXAMPLES_LIST}) 56 | # make a target 57 | add_executable(${example} ${example}.cpp) 58 | # link the RF24 lib to the target. 59 | target_link_libraries(${example} PUBLIC ${linked_libs}) 60 | endforeach() 61 | -------------------------------------------------------------------------------- /examples_RPi/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # 3 | # Makefile for librf24 examples on Raspberry Pi 4 | # 5 | # License: GPL (General Public License) 6 | # Author: gnulnulf 7 | # Date: 2013/02/07 (version 1.0) 8 | # 9 | # Description: 10 | # ------------ 11 | # use make all and make install to install the examples 12 | # You can change the install directory by editing the prefix line 13 | # 14 | prefix := /usr/local 15 | 16 | ARCH=armv6zk 17 | ifeq "$(shell uname -m)" "armv7l" 18 | ARCH=armv7-a 19 | endif 20 | 21 | # Detect the Raspberry Pi from cpuinfo 22 | #Count the matches for BCM2708 or BCM2709 in cpuinfo 23 | RPI=$(shell cat /proc/cpuinfo | grep Hardware | grep -c BCM2708) 24 | ifneq "${RPI}" "1" 25 | RPI=$(shell cat /proc/cpuinfo | grep Hardware | grep -c BCM2709) 26 | endif 27 | 28 | ifeq "$(RPI)" "1" 29 | # The recommended compiler flags for the Raspberry Pi 30 | CCFLAGS=-Ofast -mfpu=vfp -mfloat-abi=hard -march=$(ARCH) -mtune=arm1176jzf-s -std=c++0x 31 | endif 32 | 33 | # define all programs 34 | PROGRAMS = rx-test helloworld_rx helloworld_tx 35 | SOURCES = ${PROGRAMS:=.cpp} 36 | 37 | all: ${PROGRAMS} 38 | 39 | ${PROGRAMS}: ${SOURCES} 40 | g++ ${CCFLAGS} -Wall -I../ $@.cpp -lrf24-bcm -lrf24network -o $@ 41 | 42 | clean: 43 | rm -rf $(PROGRAMS) 44 | 45 | install: all 46 | test -d $(prefix) || mkdir $(prefix) 47 | test -d $(prefix)/bin || mkdir $(prefix)/bin 48 | for prog in $(PROGRAMS); do \ 49 | install -m 0755 $$prog $(prefix)/bin; \ 50 | done 51 | 52 | .PHONY: install 53 | -------------------------------------------------------------------------------- /examples_RPi/helloworld_rx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Update 2014 - TMRh20 3 | */ 4 | 5 | /** 6 | * Simplest possible example of using RF24Network, 7 | * 8 | * RECEIVER NODE 9 | * Listens for messages from the transmitter and prints them out. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | // CE Pin, CSN Pin, SPI Speed (Hz) 20 | RF24 radio(22, 0); 21 | 22 | RF24Network network(radio); 23 | 24 | // Address of our node in Octal format 25 | const uint16_t this_node = 00; 26 | 27 | // Address of the other node in Octal format (01, 021, etc) 28 | const uint16_t other_node = 01; 29 | 30 | struct payload_t 31 | { // Structure of our payload 32 | uint32_t ms; 33 | uint32_t counter; 34 | }; 35 | 36 | int main(int argc, char** argv) 37 | { 38 | // Refer to RF24 docs or nRF24L01 Datasheet for settings 39 | 40 | if (!radio.begin()) { 41 | printf("Radio hardware not responding!\n"); 42 | return 0; 43 | } 44 | 45 | delay(5); 46 | radio.setChannel(90); 47 | network.begin(/*node address*/ this_node); 48 | radio.printDetails(); 49 | 50 | while (1) { 51 | 52 | network.update(); 53 | while (network.available()) { // Is there anything ready for us? 54 | 55 | RF24NetworkHeader header; // If so, grab it and print it out 56 | payload_t payload; 57 | network.read(header, &payload, sizeof(payload)); 58 | 59 | printf("Received payload: counter=%u, origin timestamp=%u\n", payload.counter, payload.ms); 60 | } 61 | //sleep(2); 62 | delay(2000); 63 | } 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /examples_RPi/helloworld_tx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Update 2014 - TMRh20 3 | */ 4 | 5 | /** 6 | * Simplest possible example of using RF24Network, 7 | * 8 | * RECEIVER NODE 9 | * Listens for messages from the transmitter and prints them out. 10 | */ 11 | 12 | //#include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | using namespace std; 21 | 22 | RF24 radio(22, 0); // (CE Pin, CSN Pin, [SPI Speed (in Hz)]) 23 | 24 | RF24Network network(radio); 25 | 26 | // Address of our node in Octal format (01,021, etc) 27 | const uint16_t this_node = 01; 28 | 29 | // Address of the other node 30 | const uint16_t other_node = 00; 31 | 32 | // How often (in milliseconds) to send a message to the `other_node` 33 | const unsigned long interval = 2000; 34 | 35 | uint32_t last_sent; // When did we last send? 36 | uint32_t packets_sent; // How many have we sent already 37 | 38 | struct payload_t 39 | { // Structure of our payload 40 | uint32_t ms; 41 | uint32_t counter; 42 | }; 43 | 44 | int main(int argc, char** argv) 45 | { 46 | // Refer to RF24 docs or nRF24L01 Datasheet for settings 47 | 48 | if (!radio.begin()) { 49 | printf("Radio hardware not responding!\n"); 50 | return 0; 51 | } 52 | 53 | delay(5); 54 | radio.setChannel(90); 55 | network.begin(/*node address*/ this_node); 56 | radio.printDetails(); 57 | 58 | while (1) { 59 | 60 | network.update(); 61 | uint32_t now = millis(); // If it's time to send a message, send it! 62 | if (now - last_sent >= interval) { 63 | last_sent = now; 64 | 65 | printf("Sending ..\n"); 66 | payload_t payload = {millis(), packets_sent++}; 67 | RF24NetworkHeader header(/*to node*/ other_node); 68 | bool ok = network.write(header, &payload, sizeof(payload)); 69 | printf("%s.\n", ok ? "ok" : "failed"); 70 | } 71 | } 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /examples_RPi/rx-test.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | /*#include */ 9 | #include 10 | 11 | /** 12 | * g++ -L/usr/lib main.cc -I/usr/include -o main -lrrd 13 | **/ 14 | //using namespace std; 15 | 16 | // CE Pin, CSN Pin, SPI Speed (Hz) 17 | 18 | RF24 radio(22, 0); 19 | 20 | RF24Network network(radio); 21 | 22 | // Address of our node 23 | const uint16_t this_node = 00; 24 | 25 | // Address of the other node 26 | const uint16_t other_node = 01; 27 | 28 | struct payload_power_t 29 | { // Structure of our payload 30 | uint32_t nodeId; 31 | float power; 32 | float current; 33 | }; 34 | 35 | struct payload_weather_t 36 | { 37 | uint32_t nodeId; 38 | float temperature; 39 | float humidity; 40 | uint32_t lux; 41 | }; 42 | 43 | int main(int argc, char** argv) 44 | { 45 | // Refer to RF24.h or nRF24L01 DS for settings 46 | 47 | //char filenameTemp[] = "/root/weather/weather_sensor.rrd"; 48 | //char filenameCurrent[] = "/home/pi/temperature.txt"; 49 | //char command[] = "update"; 50 | //char values[100]; 51 | 52 | char temperatureFile[] = "temperature.txt"; 53 | 54 | if (!radio.begin()) { 55 | printf("Radio hardware not responding!\n"); 56 | return 0; 57 | } 58 | //radio.setDataRate(RF24_250KBPS); 59 | radio.setRetries(7, 7); 60 | 61 | delay(5); 62 | radio.setChannel(100); 63 | network.begin(/*node address*/ this_node); 64 | radio.printDetails(); 65 | 66 | while (1) { 67 | //FILE * pFile; 68 | //pFile = fopen ("/root/temp-exterior.txt","a"); 69 | network.update(); 70 | while (network.available()) { 71 | // If so, grab it and print it out 72 | RF24NetworkHeader header; 73 | network.peek(header); 74 | 75 | if (header.type == 'T') { 76 | float message; 77 | network.read(header, &message, sizeof(float)); 78 | printf("RCVD: %.3f \n\r", message); 79 | FILE* myFile; 80 | myFile = fopen(temperatureFile, "a+"); //Append, new EOF 81 | 82 | if (!myFile) { 83 | printf("File not opened\n\r"); 84 | } 85 | else { 86 | //fwrite(msg,sizeof(float),1,myFile); 87 | fprintf(myFile, "%.3f\n\r", message); 88 | //putc('\n',myFile); 89 | //putc('\r',myFile); 90 | fclose(myFile); 91 | } 92 | } 93 | // temperature & humidity sensor 94 | /* 95 | if (header.from_node == 1) { 96 | payload_weather_t payload; 97 | network.read(header, &payload, sizeof(payload)); 98 | rrd_argv[0] = command; 99 | rrd_argv[1] = filenameTemp; 100 | rrd_argv[3] = NULL; 101 | rrd_argc = 3; 102 | printf("N:%.2f:%.2f:%lu\n", payload.temperature, payload.humidity, payload.lux); 103 | sprintf(values, "N:%.2f:%.2f:%lu", payload.temperature, payload.humidity, payload.lux); 104 | rrd_argv[2] = values; 105 | rrd_update(rrd_argc, rrd_argv); 106 | } 107 | 108 | if (header.from_node == 2) { 109 | payload_power_t payload; 110 | network.read(header, &payload, sizeof(payload)); 111 | rrd_argv[0] = command; 112 | rrd_argv[1] = filenameCurrent; 113 | rrd_argv[3] = NULL; 114 | rrd_argc = 3; 115 | printf("N:%.2f:%.2f\n", payload.power, payload.current); 116 | sprintf(values, "N:%.2f:%.2f", payload.power, payload.current); 117 | rrd_argv[2] = values; 118 | rrd_update(rrd_argc, rrd_argv); 119 | } 120 | */ 121 | 122 | //time_t timer; 123 | //char timeBuffer[25]; 124 | //struct tm* tm_info; 125 | //time(&timer); 126 | //tm_info = localtime(&timer); 127 | //strftime(timeBuffer, 25, "%Y/%m/%d %H:%M:%S", tm_info); 128 | //fprintf(pFile, "%s;%lu;%.2f;%.2f\n", timeBuffer, payload.nodeId, payload.data1, payload.data2); 129 | } 130 | delay(2000); 131 | //fclose(pFile); 132 | } 133 | 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /examples_RPi/temperature.txt: -------------------------------------------------------------------------------- 1 | 25.382 2 | 21.027 3 | 21.091 4 | 22.628 5 | 23.332 6 | 23.345 7 | 23.320 8 | 23.358 9 | 23.345 10 | 23.358 11 | 23.384 12 | 23.397 13 | 23.409 14 | 23.435 15 | 23.435 16 | 23.435 17 | 23.461 18 | 23.473 19 | 23.486 20 | 23.486 21 | 23.499 22 | 23.499 23 | 23.486 24 | 23.499 25 | 23.512 26 | 24.319 27 | 24.780 28 | 24.921 29 | 25.061 30 | 25.151 31 | 25.151 32 | 25.151 33 | 25.177 34 | 25.215 35 | 25.190 36 | 25.202 37 | 25.228 38 | 25.266 39 | 25.292 40 | 25.330 41 | 25.356 42 | 25.382 43 | 25.433 44 | -------------------------------------------------------------------------------- /examples_pico/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | #[[ 4 | for these examples we are assuming the following structure: 5 | path/to/github/repos/ 6 | RF24/ 7 | RF24Network/ 8 | examples_pico/ <-- you are here 9 | pico-sdk/ 10 | 11 | Be sure to set the PICO_SDK_PATH environment variable 12 | `export PICO_SDK_PATH=/path/to/github/repos/pico-sdk/` 13 | ]] 14 | 15 | # Pull in SDK (must be before project) 16 | include(../../RF24/cmake/pico_sdk_import.cmake) 17 | 18 | project(pico_examples C CXX ASM) 19 | 20 | # Initialize the Pico SDK 21 | pico_sdk_init() 22 | 23 | # In YOUR project, include RF24's CMakeLists.txt 24 | # giving the path depending on where the library 25 | # is cloned to in your project 26 | include(../../RF24/CMakeLists.txt) # for RF24 lib 27 | include(../CMakeLists.txt) # for RF24Network lib 28 | 29 | # iterate over a list of examples by name 30 | set(EXAMPLES_LIST 31 | helloworld_rx 32 | helloworld_tx 33 | ) 34 | 35 | foreach(example ${EXAMPLES_LIST}) 36 | # make a target 37 | add_executable(${example} ${example}.cpp defaultPins.h) 38 | 39 | # link the necessary libs to the target 40 | target_link_libraries(${example} PUBLIC 41 | RF24 42 | RF24Network 43 | pico_stdlib 44 | hardware_spi 45 | hardware_gpio 46 | ) 47 | 48 | # specify USB port as default serial communication's interface (not UART RX/TX pins) 49 | pico_enable_stdio_usb(${example} 1) 50 | pico_enable_stdio_uart(${example} 0) 51 | 52 | # create map/bin/hex file etc. 53 | pico_add_extra_outputs(${example}) 54 | endforeach() 55 | -------------------------------------------------------------------------------- /examples_pico/defaultPins.h: -------------------------------------------------------------------------------- 1 | // pre-chossen pins for different boards 2 | #ifndef DEFAULTPINS_H 3 | #define DEFAULTPINS_H 4 | 5 | #if defined(ADAFRUIT_QTPY_RP2040) 6 | // for this board, you can still use the Stemma QT connector as a separate I2C bus (`i2c1`) 7 | #define CE_PIN PICO_DEFAULT_I2C_SDA_PIN // the pin labeled SDA 8 | #define CSN_PIN PICO_DEFAULT_I2C_SCL_PIN // the pin labeled SCL 9 | 10 | #elif defined(PIMORONI_TINY2040) 11 | // default SPI_SCK_PIN = 6 12 | // default SPI_TX_PIN = 7 13 | // default SPI_RX_PIN = 4 14 | #define CE_PIN PICO_DEFAULT_I2C_SCL_PIN // pin 3 15 | #define CSN_PIN PICO_DEFAULT_SPI_CSN_PIN // pin 5 16 | 17 | #elif defined(SPARFUN_THINGPLUS) 18 | #define CSN_PIN 16 // the pin labeled 16 19 | #define CE_PIN 7 // the pin labeled SCL 20 | 21 | #else 22 | // pins available on (ADAFRUIT_ITSYBITSY_RP2040 || ADAFRUIT_FEATHER_RP2040 || Pico_board || Sparkfun_ProMicro || SparkFun MicroMod) 23 | 24 | #define CE_PIN 7 25 | #define CSN_PIN 8 26 | #endif // board detection macro defs 27 | 28 | #endif // DEFAULTPINS_H 29 | -------------------------------------------------------------------------------- /examples_pico/helloworld_rx.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Simplest possible example of using RF24Network, 3 | * 4 | * RECEIVER NODE 5 | * Listens for messages from the transmitter and prints them out. 6 | */ 7 | #include "pico/stdlib.h" // printf(), sleep_ms(), to_ms_since_boot(), get_absolute_time() 8 | #include // tud_cdc_connected() 9 | #include // RF24 radio object 10 | #include // RF24Network network object 11 | #include "defaultPins.h" // board presumptive default pin numbers for CE_PIN and CSN_PIN 12 | 13 | // instantiate an object for the nRF24L01 transceiver 14 | RF24 radio(CE_PIN, CSN_PIN); 15 | 16 | RF24Network network(radio); 17 | 18 | // Address of our node in Octal format 19 | const uint16_t this_node = 00; 20 | 21 | // Address of the other node in Octal format (01, 021, etc) 22 | const uint16_t other_node = 01; 23 | 24 | struct payload_t 25 | { // Structure of our payload 26 | unsigned long ms; 27 | unsigned long counter; 28 | }; 29 | 30 | bool setup() 31 | { 32 | // wait here until the CDC ACM (serial port emulation) is connected 33 | while (!tud_cdc_connected()) { 34 | sleep_ms(10); 35 | } 36 | 37 | // initialize the transceiver on the SPI bus 38 | if (!radio.begin()) { 39 | printf("radio hardware is not responding!!\n"); 40 | return false; 41 | } 42 | 43 | radio.setChannel(90); 44 | network.begin(/*node address*/ this_node); 45 | 46 | // print example's introductory prompt 47 | printf("RF24Network/examples_pico/helloworld_rx\n"); 48 | 49 | // For debugging info 50 | // radio.printDetails(); // (smaller) function that prints raw register values 51 | // radio.printPrettyDetails(); // (larger) function that prints human readable data 52 | 53 | return true; 54 | } // setup 55 | 56 | void loop() 57 | { 58 | network.update(); 59 | while (network.available()) { // Is there anything ready for us? 60 | // If so, grab it and print it out 61 | RF24NetworkHeader header; 62 | payload_t payload; 63 | network.read(header, &payload, sizeof(payload)); 64 | 65 | printf("Received payload: counter=%lu, origin timestamp=%lu\n", payload.counter, payload.ms); 66 | } 67 | } 68 | 69 | int main() 70 | { 71 | stdio_init_all(); // init necessary IO for the RP2040 72 | 73 | while (!setup()) { // if radio.begin() failed 74 | // hold program in infinite attempts to initialize radio 75 | } 76 | while (true) { 77 | loop(); 78 | } 79 | return 0; // we will never reach this 80 | } 81 | -------------------------------------------------------------------------------- /examples_pico/helloworld_tx.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Simplest possible example of using RF24Network, 3 | * 4 | * TRANSMITTER NODE 5 | * Transmits messages to the reciever every 2 seconds. 6 | */ 7 | #include "pico/stdlib.h" // printf(), sleep_ms(), to_ms_since_boot(), get_absolute_time() 8 | #include // tud_cdc_connected() 9 | #include // RF24 radio object 10 | #include // RF24Network network object 11 | #include "defaultPins.h" // board presumptive default pin numbers for CE_PIN and CSN_PIN 12 | 13 | // instantiate an object for the nRF24L01 transceiver 14 | RF24 radio(CE_PIN, CSN_PIN); 15 | 16 | RF24Network network(radio); 17 | 18 | // Address of our node in Octal format (01,021, etc) 19 | const uint16_t this_node = 01; 20 | 21 | // Address of the other node 22 | const uint16_t other_node = 00; 23 | 24 | // How often (in milliseconds) to send a message to the `other_node` 25 | const unsigned long interval = 2000; 26 | 27 | unsigned long last_sent; // When did we last send? 28 | unsigned long packets_sent; // How many have we sent already 29 | 30 | struct payload_t 31 | { // Structure of our payload 32 | unsigned long ms; 33 | unsigned long counter; 34 | }; 35 | 36 | bool setup() 37 | { 38 | // wait here until the CDC ACM (serial port emulation) is connected 39 | while (!tud_cdc_connected()) { 40 | sleep_ms(10); 41 | } 42 | 43 | // initialize the transceiver on the SPI bus 44 | if (!radio.begin()) { 45 | printf("radio hardware is not responding!!\n"); 46 | return false; 47 | } 48 | 49 | radio.setChannel(90); 50 | network.begin(/*node address*/ this_node); 51 | 52 | // print example's introductory prompt 53 | printf("RF24Network/examples_pico/helloworld_tx\n"); 54 | 55 | // For debugging info 56 | // radio.printDetails(); // (smaller) function that prints raw register values 57 | // radio.printPrettyDetails(); // (larger) function that prints human readable data 58 | 59 | return true; 60 | } // setup 61 | 62 | void loop() 63 | { 64 | network.update(); 65 | unsigned long now = to_ms_since_boot(get_absolute_time()); 66 | if (now - last_sent >= interval) { // If it's time to send a message, send it! 67 | last_sent = now; 68 | 69 | printf("Sending ..\n"); 70 | payload_t payload = {now, packets_sent++}; 71 | RF24NetworkHeader header(/*to node*/ other_node); 72 | bool ok = network.write(header, &payload, sizeof(payload)); 73 | printf("%s.\n", ok ? "ok" : "failed"); 74 | } 75 | } 76 | 77 | int main() 78 | { 79 | stdio_init_all(); // init necessary IO for the RP2040 80 | 81 | while (!setup()) { // if radio.begin() failed 82 | // hold program in infinite attempts to initialize radio 83 | } 84 | while (true) { 85 | loop(); 86 | } 87 | return 0; // we will never reach this 88 | } 89 | -------------------------------------------------------------------------------- /images/example_tree.dot: -------------------------------------------------------------------------------- 1 | graph network_hierarchy { 2 | bgcolor="#323232A1" 3 | node [ 4 | fontcolor="#FEFEFE" 5 | fontsize=14 6 | fontname=Arial 7 | ] 8 | subgraph cluster_hierarchy { 9 | style = rounded 10 | bgcolor="#24242400" 11 | color="#24242400" 12 | fontcolor = "#FEF9A9" 13 | node [ 14 | style="filled" 15 | color="#FEFEFE7f" 16 | ] 17 | edge [color="#FEFEFE" style="setlinewidth(2)"] 18 | subgraph cluster_lvl_0 { 19 | label = "Network Level 0 (master node)" 20 | bgcolor = "#383838" 21 | 00 [ 22 | shape="circle" 23 | style="radial" 24 | fillcolor="#000000;0:#018268;0.85" 25 | ] 26 | } 27 | subgraph cluster_lvl_1 { 28 | label = "Network Level 1 " 29 | labeljust="l" 30 | pad="15" 31 | bgcolor = "#383838" 32 | node [fillcolor="#3E0180"] 33 | 01 04 34 | } 35 | subgraph cluster_lvl_2 { 36 | label = "Network Level 2 " 37 | bgcolor = "#383838" 38 | node [fillcolor="#014B80"] 39 | 014 021 011 40 | } 41 | subgraph cluster_lvl_3 { 42 | label = "Network Level 3 " 43 | bgcolor = "#383838" 44 | node [fillcolor="#0E6902"] 45 | 0111 0121 0221 0114 46 | } 47 | subgraph cluster_lvl_4 { 48 | label = "Network Level 4 (highest)" 49 | labelloc="b" 50 | // labeljust="l" 51 | style = rounded 52 | bgcolor = "#383838" 53 | node [fillcolor="#80010B"] 54 | 01221 01114 02114 03114 55 | } 56 | 00 -- 04 -- 014 -- 0114 -- 01114 57 | 00 -- 01 -- 011 -- 0111 58 | 01 -- 021 -- 0121 59 | 021 -- 0221 -- 01221 60 | 0114 -- 02114 61 | 0114 --03114 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /images/example_tree.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | network_hierarchy 11 | 12 | 13 | cluster_hierarchy 14 | 15 | 16 | 17 | cluster_lvl_4 18 | 19 | Network Level 4 (highest) 20 | 21 | 22 | cluster_lvl_1 23 | 24 | Network Level 1                                                                                     25 | 26 | 27 | cluster_lvl_2 28 | 29 | Network Level 2                                                                                     30 | 31 | 32 | cluster_lvl_0 33 | 34 | Network Level 0 (master node) 35 | 36 | 37 | cluster_lvl_3 38 | 39 | Network Level 3                                                                                     40 | 41 | 42 | 43 | 00 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 00 52 | 53 | 54 | 55 | 01 56 | 57 | 01 58 | 59 | 60 | 61 | 00--01 62 | 63 | 64 | 65 | 66 | 04 67 | 68 | 04 69 | 70 | 71 | 72 | 00--04 73 | 74 | 75 | 76 | 77 | 021 78 | 79 | 021 80 | 81 | 82 | 83 | 01--021 84 | 85 | 86 | 87 | 88 | 011 89 | 90 | 011 91 | 92 | 93 | 94 | 01--011 95 | 96 | 97 | 98 | 99 | 014 100 | 101 | 014 102 | 103 | 104 | 105 | 04--014 106 | 107 | 108 | 109 | 110 | 0114 111 | 112 | 0114 113 | 114 | 115 | 116 | 014--0114 117 | 118 | 119 | 120 | 121 | 0121 122 | 123 | 0121 124 | 125 | 126 | 127 | 021--0121 128 | 129 | 130 | 131 | 132 | 0221 133 | 134 | 0221 135 | 136 | 137 | 138 | 021--0221 139 | 140 | 141 | 142 | 143 | 0111 144 | 145 | 0111 146 | 147 | 148 | 149 | 011--0111 150 | 151 | 152 | 153 | 154 | 01221 155 | 156 | 01221 157 | 158 | 159 | 160 | 0221--01221 161 | 162 | 163 | 164 | 165 | 01114 166 | 167 | 01114 168 | 169 | 170 | 171 | 0114--01114 172 | 173 | 174 | 175 | 176 | 02114 177 | 178 | 02114 179 | 180 | 181 | 182 | 0114--02114 183 | 184 | 185 | 186 | 187 | 03114 188 | 189 | 03114 190 | 191 | 192 | 193 | 0114--03114 194 | 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /images/topologyImage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nRF24/RF24Network/0b19dd59b742c87dd1d1b5b1a17182162b48e8d0/images/topologyImage.jpg -------------------------------------------------------------------------------- /images/topologyImage_Advanced.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nRF24/RF24Network/0b19dd59b742c87dd1d1b5b1a17182162b48e8d0/images/topologyImage_Advanced.jpg -------------------------------------------------------------------------------- /images/topologyImage_Advanced.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nRF24/RF24Network/0b19dd59b742c87dd1d1b5b1a17182162b48e8d0/images/topologyImage_Advanced.xcf -------------------------------------------------------------------------------- /images/topologyImage_Advanced_Multicast.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nRF24/RF24Network/0b19dd59b742c87dd1d1b5b1a17182162b48e8d0/images/topologyImage_Advanced_Multicast.jpg -------------------------------------------------------------------------------- /images/topologyImage_Advanced_Multicast.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nRF24/RF24Network/0b19dd59b742c87dd1d1b5b1a17182162b48e8d0/images/topologyImage_Advanced_Multicast.xcf -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RF24Network", 3 | "version": "2.0.5", 4 | "keywords": "rf, radio, wireless, spi", 5 | "description": "OSI Layer 3 Networking for nrf24L01(+) & nrf52x devices.", 6 | "license": "GPL-2.0-only", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/nRF24/RF24Network.git" 10 | }, 11 | "dependencies": [ 12 | { 13 | "name": "RF24", 14 | "authors": "nRF24", 15 | "frameworks": "arduino", 16 | "version": ">=1.5" 17 | }, 18 | { 19 | "name": "nrf_to_nrf", 20 | "authors": "TMRh20", 21 | "frameworks": "arduino", 22 | "platforms": [ 23 | "nordicnrf52" 24 | ], 25 | "version": ">=1.2.16" 26 | } 27 | ], 28 | "export": { 29 | "exclude": [ 30 | ".github/*", 31 | "keywords.txt", 32 | "examples_RPi/*", 33 | "RPi/*", 34 | "cmake/*", 35 | "CMakeLists.txt", 36 | "Makefile" 37 | ] 38 | }, 39 | "frameworks": "arduino", 40 | "platforms": [ 41 | "atmelavr", 42 | "atmelsam", 43 | "teensy", 44 | "atmelmegaavr", 45 | "espressif32", 46 | "espressif8266", 47 | "ststm32", 48 | "nordicnrf52" 49 | ] 50 | } -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=RF24Network 2 | version=2.0.5 3 | author=TMRh20 4 | maintainer=TMRh20,Avamander 5 | sentence=OSI Layer 3 Networking for nrf24L01(+) & nrf52x devices. 6 | paragraph=Provides a simple and seamless network layer for sensor/IoT networks, including routing, addressing and fragmentation/reassembly. 7 | category=Communication 8 | url=https://nRF24.github.io/RF24Network/ 9 | architectures=* 10 | depends=RF24,nrf_to_nrf 11 | -------------------------------------------------------------------------------- /nurfile: -------------------------------------------------------------------------------- 1 | 2 | 3 | def is-windows [] { 4 | $nu.os-info | get "family" | str starts-with "windows" 5 | } 6 | 7 | 8 | def --wrapped run-cmd [...cmd: string] { 9 | print $"\n(ansi blue)Running(ansi reset) ($cmd | str join ' ')" 10 | let elapsed = timeit {|| ^($cmd | first) ...($cmd | skip 1)} 11 | print $"(ansi magenta)($cmd | first) took ($elapsed)(ansi reset)" 12 | } 13 | 14 | 15 | def flush-artifacts [ 16 | build_dir: string, dirty: bool 17 | ] { 18 | if ($build_dir | path exists) { 19 | if $dirty == false { 20 | print $"(ansi yellow)Removing artifacts(ansi reset) ($build_dir)" 21 | rm -r $build_dir 22 | } 23 | } 24 | } 25 | 26 | 27 | # Build the docs. 28 | # 29 | # Note, there is no check against what 30 | # version of doxygen is used. 31 | def "nur docs" [ 32 | --dirty (-d) # Do not flush previous build artifacts 33 | --open (-o) # Open the built docs in your default browser 34 | ] { 35 | let build_dir = "docs/html" 36 | flush-artifacts $build_dir $dirty 37 | cd docs 38 | run-cmd doxygen 39 | if $open { 40 | let root_pg = $nur.project-path | path join $"($build_dir)/index.html" 41 | start $root_pg 42 | } 43 | } 44 | 45 | 46 | def find-built-examples [path: string] { 47 | let len = $nur.project-path | str length 48 | let example_path_len = ($path | str length) + 2 49 | let sources = ( 50 | glob $"($path)/**/*.cpp" --exclude [ 51 | "**/build/**" 52 | ] 53 | | each {$in | str substring ($len + $example_path_len)..-5} 54 | ) 55 | let binaries = ( 56 | glob $"($path)/build/**/*" --exclude [ 57 | "**/CMakeFiles/**" 58 | ] 59 | | each {$in | str substring ($len + $example_path_len + 6)..} 60 | | filter {$in in $sources} 61 | ) 62 | $binaries 63 | } 64 | 65 | 66 | # Build the Linux examples. 67 | # 68 | # This task expects the library to be installed. 69 | # CMake will build any ncurses examples if 70 | # the libncurses5-dev package is installed 71 | def "nur examples" [ 72 | --dirty (-d) # Reuse previous build env 73 | ...cmake_opts: string # additional args passed to cmake when configuring the build env 74 | ] { 75 | let src_dir = "examples_RPi" 76 | let build_dir = $"($src_dir)/build" 77 | 78 | flush-artifacts $build_dir $dirty 79 | 80 | if $dirty == false { 81 | run-cmd cmake -B $build_dir $src_dir ...$cmake_opts 82 | } else if ($build_dir | path exists) == false { 83 | run-cmd cmake -B $build_dir $src_dir ...$cmake_opts 84 | } 85 | run-cmd cmake --build $build_dir 86 | 87 | print $"(ansi green)Built the following examples:(ansi reset)" 88 | let binaries = ( 89 | find-built-examples $src_dir 90 | | each {$"($build_dir)/($in)"} 91 | ) 92 | print $binaries 93 | } 94 | 95 | 96 | # Build/install the library. 97 | # 98 | # Note, this may ask for the password to 99 | # install the library with super-user privileges. 100 | def --wrapped "nur lib" [ 101 | --dirty (-d) # Reuse previous build env 102 | --no-install # Do not install the library (useful for testing compilation) 103 | ...cmake_opts: string # additional args passed to cmake when configuring the build env 104 | ] { 105 | let build_dir = "build" 106 | flush-artifacts $build_dir $dirty 107 | 108 | if $dirty == false { 109 | run-cmd cmake -B build -S . ...$cmake_opts 110 | } 111 | run-cmd cmake --build $build_dir 112 | if $no_install == false { 113 | run-cmd sudo cmake --install $build_dir 114 | } 115 | } 116 | 117 | 118 | # Build the Pico SDK examples. 119 | # 120 | # If building on Windows, then `-G Ninja` is 121 | # automatically passed to CMake when configuring the 122 | # build environment. 123 | def --wrapped "nur pico" [ 124 | --dirty (-d) # Reuse previous build env 125 | ...cmake_opts: string # additional args passed to cmake when configuring the build env 126 | ] { 127 | let src_dir = "examples_pico" 128 | let build_dir = $"($src_dir)/build" 129 | flush-artifacts $build_dir $dirty 130 | 131 | let use_ninja = '-G Ninja' 132 | let opts = if (is-windows) { 133 | $cmake_opts | append $use_ninja 134 | } else { $cmake_opts } 135 | 136 | if $dirty == false { 137 | run-cmd cmake -B $build_dir $src_dir ...$opts 138 | } else if ($build_dir | path exists) == false { 139 | run-cmd cmake -B $build_dir $src_dir ...$opts 140 | } 141 | run-cmd cmake --build $build_dir 142 | } 143 | 144 | 145 | # Install the python wrapper. 146 | # 147 | # Note, this task requires the library 148 | # (& boost.python) to be installed. 149 | def "nur py" [ 150 | --dirty (-d) # Reuse previous build env 151 | ] { 152 | let src_dir = "RPi/pyRF24Network" 153 | let artifacts = glob $"($src_dir)/{build,*.egg-info}" 154 | if ($artifacts | length) > 0 { 155 | if $dirty == false { 156 | print $"(ansi yellow)Removing artifacts(ansi reset) ($artifacts | str join ' ')" 157 | rm -r ...$artifacts 158 | } 159 | } 160 | run-cmd pip install -v $"./($src_dir)" 161 | } 162 | 163 | 164 | def changed-files [] { 165 | let status = git status --short | lines 166 | if ($status | length) == 0 { 167 | print $"(ansi red)No file changes detected via (ansi cyan)`git status`(ansi reset)" 168 | print $"Perhaps you want to format all files? (ansi cyan)`nur fmt -a`" 169 | return [] 170 | } 171 | let changed = ( 172 | $status 173 | | each {$in | str trim | split column --regex '\s+' -n 2} 174 | | flatten 175 | | rename "state" "name" 176 | ) 177 | # print $changed 178 | let result = ( 179 | $changed 180 | | where {$in.state | split chars | each {$in in ['A' 'M' 'R']} | any {$in}} 181 | | get "name" 182 | | each { 183 | if ($in | str contains " -> ") { 184 | $in | parse "{a} -> {b}" | get "b" | $in.0 185 | } else { $in } 186 | } 187 | ) 188 | # print $result 189 | $result 190 | } 191 | 192 | 193 | def get-clang-format-version [bin_name: string] { 194 | if (which $bin_name | is-empty) { 195 | null 196 | } else { 197 | let version = ( 198 | ^$bin_name --version 199 | | split column ' ' 200 | | values 201 | | flatten 202 | | last 203 | ) 204 | print $"($bin_name) --version: ($version)" 205 | $version | parse "{major}.{minor}.{patch}" 206 | } 207 | } 208 | 209 | 210 | def match-version [ 211 | bin_name: string, 212 | expected: string = "14", 213 | --throw 214 | ] { 215 | let version = get-clang-format-version $bin_name 216 | if ($version | is-empty) { 217 | if $throw { 218 | error make { 219 | msg: $"($bin_name) not found. Ensure it is installed and added to your PATH." 220 | } 221 | } 222 | false 223 | } else { 224 | if ($version.major.0 == $expected) { 225 | true 226 | } else if $throw { 227 | error make { 228 | msg: $"Failed to find clang-format v($expected).x" 229 | } 230 | } else { 231 | false 232 | } 233 | } 234 | } 235 | 236 | 237 | # Run clang-format on C++ files. 238 | # 239 | # By default, only changed C++ sources are formatted (uses `git status`). 240 | # The clang-format version is expected to be v14. 241 | # If v14 is not found, then an error is thrown. 242 | def "nur fmt" [ 243 | --all (-a) # Format all C++ sources 244 | ] { 245 | let all_files = glob "**/*.{h,cpp,c,ino}" --exclude [ 246 | "**/build/**" 247 | ] | path relative-to $nur.project-path 248 | let files = if $all { 249 | $all_files 250 | } else { 251 | let changes = changed-files 252 | ( 253 | $all_files 254 | | where { 255 | ($in | path split) in ( 256 | $changes | each {$in | path split} 257 | ) 258 | } 259 | ) 260 | } 261 | 262 | let bin_name = if (is-windows) { 263 | let bin_name = "clang-format" 264 | let is_expected = match-version $bin_name --throw 265 | "clang-format" 266 | } else { 267 | let bin_name = "clang-format-14" 268 | let is_expected = match-version $bin_name 269 | if ($is_expected == false) { 270 | let bin_name = "clang-format" 271 | let is_expected = match-version $bin_name --throw 272 | $bin_name 273 | } else { 274 | $bin_name 275 | } 276 | } 277 | 278 | if ($files | length) > 0 { 279 | print $files 280 | let elapsed = timeit {|| $files | par-each {|f| ^$bin_name "-i" "--style" "file" $f}} 281 | print $"clang-format took ($elapsed) using parallelism!" 282 | } 283 | print $"(ansi blue)Applied clang-format to ($files | length) files(ansi reset)" 284 | } 285 | --------------------------------------------------------------------------------