├── .clang-format ├── .github ├── dependabot.yml ├── doxygen.py └── workflows │ ├── build_arduino.yml │ ├── build_linux.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 ├── RF24Mesh.cpp ├── RF24Mesh.h ├── RF24Mesh_config.h ├── cmake ├── AutoConfig_RF24_DRIVER.cmake ├── CPackInfo.cmake ├── Cache.cmake ├── CompilerWarnings.cmake ├── GetLibInfo.cmake ├── PreventInSourceBuilds.cmake ├── StandardProjectSettings.cmake ├── detectCPU.cmake ├── enableNcursesExample.cmake ├── toolchains │ ├── arm64.cmake │ ├── armhf.cmake │ ├── default.cmake │ ├── i686.cmake │ └── x86_64.cmake └── usePicoSDK.cmake ├── docs ├── Doxyfile ├── README.md ├── doxygen-custom.css ├── general_usage.md ├── images │ ├── Logo large.png │ └── favicon.ico ├── main_page.md └── setup_config.md ├── examples ├── .clang-format ├── RF24Mesh_Example │ └── RF24Mesh_Example.ino ├── RF24Mesh_Example_Master │ └── RF24Mesh_Example_Master.ino ├── RF24Mesh_Example_Master_Statics │ └── RF24Mesh_Example_Master_Statics.ino ├── RF24Mesh_Example_Master_To_Nodes │ └── RF24Mesh_Example_Master_To_Nodes.ino ├── RF24Mesh_Example_Node2Node │ └── RF24Mesh_Example_Node2Node.ino ├── RF24Mesh_Example_Node2NodeExtra │ └── RF24Mesh_Example_Node2NodeExtra.ino └── RF24Mesh_SerialConfig │ └── RF24Mesh_SerialConfig.ino ├── examples_RPi ├── CMakeLists.txt ├── Makefile ├── RF24Mesh_Example.cpp ├── RF24Mesh_Example.py ├── RF24Mesh_Example_Master.cpp ├── RF24Mesh_Example_Master.py └── ncurses │ ├── CMakeLists.txt │ ├── Makefile │ └── RF24Mesh_Ncurses_Master.cpp ├── examples_pico ├── CMakeLists.txt ├── RF24Mesh_Example.cpp ├── RF24Mesh_Example_Master.cpp └── defaultPins.h ├── images └── RF24Mesh_Ncurses.JPG ├── library.json ├── library.properties ├── nurfile └── pyRF24Mesh ├── README.md ├── pyRF24Mesh.cpp ├── pyproject.toml └── setup.py /.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: true 18 | AllowShortBlocksOnASingleLine: Always 19 | AllowShortCaseLabelsOnASingleLine: true 20 | AllowShortFunctionsOnASingleLine: All 21 | AllowShortLambdasOnASingleLine: All 22 | AllowShortIfStatementsOnASingleLine: WithoutElse 23 | AllowShortLoopsOnASingleLine: true 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 | - "RF24Mesh.*" 10 | - "RF24Mesh_config.h" 11 | 12 | push: 13 | branches: [master, v1.x] 14 | paths: 15 | - ".github/workflows/build_arduino.yml" 16 | - "examples/**" 17 | 18 | jobs: 19 | 20 | build: 21 | uses: nRF24/.github/.github/workflows/build_arduino.yaml@main 22 | with: 23 | sketch-paths: | 24 | - examples/RF24Mesh_Example 25 | - examples/RF24Mesh_Example_Master_Statics 26 | - examples/RF24Mesh_Example_Master_To_Nodes 27 | - examples/RF24Mesh_Example_Node2Node 28 | - examples/RF24Mesh_Example_Node2NodeExtra 29 | - examples/RF24Mesh_SerialConfig 30 | - examples/RF24Mesh_Example_Master 31 | libraries: | 32 | - source-url: https://github.com/nRF24/RF24.git 33 | - source-url: https://github.com/nRF24/RF24Network.git 34 | - source-path: ./ 35 | - name: nrf_to_nrf 36 | fqbn: ${{ matrix.fqbn }} 37 | enable-deltas-report: ${{ matrix.enable-deltas-report }} 38 | platforms: | 39 | - name: arduino:avr 40 | - name: arduino:megaavr 41 | - name: arduino:samd 42 | - name: arduino:mbed 43 | # - name: arduino:sam 44 | strategy: 45 | fail-fast: false 46 | matrix: 47 | fqbn: 48 | - "arduino:avr:yun" 49 | - "arduino:avr:uno" 50 | - "arduino:avr:diecimila" 51 | - "arduino:avr:mega" 52 | - "arduino:avr:megaADK" 53 | - "arduino:avr:leonardo" 54 | - "arduino:avr:micro" 55 | - "arduino:avr:esplora" 56 | - "arduino:avr:mini" 57 | - "arduino:avr:ethernet" 58 | - "arduino:avr:fio" 59 | - "arduino:avr:bt" 60 | # - "arduino:avr:LilyPad" # board not found 61 | - "arduino:avr:LilyPadUSB" 62 | - "arduino:avr:pro" 63 | - "arduino:avr:atmegang" 64 | - "arduino:avr:robotControl" 65 | # - "arduino:avr:gemma" # does not support SPI 66 | - "arduino:avr:circuitplay32u4cat" 67 | - "arduino:avr:yunmini" 68 | - "arduino:avr:chiwawa" 69 | - "arduino:avr:one" 70 | - "arduino:avr:unowifi" 71 | - "arduino:mbed:nano33ble" 72 | - "arduino:samd:mkr1000" 73 | - "arduino:samd:mkrwifi1010" 74 | - "arduino:samd:nano_33_iot" 75 | - "arduino:samd:mkrfox1200" 76 | - "arduino:samd:mkrwan1300" 77 | - "arduino:samd:mkrwan1310" 78 | - "arduino:samd:mkrgsm1400" 79 | - "arduino:samd:mkrnb1500" 80 | - "arduino:samd:mkrvidor4000" 81 | - "arduino:samd:adafruit_circuitplayground_m0" 82 | - "arduino:samd:mzero_pro_bl" 83 | - "arduino:samd:mzero_bl" 84 | - "arduino:samd:tian" 85 | - "arduino:megaavr:uno2018" 86 | # - "arduino:megaavr:nano4809" # board not found 87 | # By default, don't generate size deltas data. 88 | enable-deltas-report: 89 | - false 90 | # Generate size deltas data for this board 91 | include: 92 | - fqbn: arduino:avr:nano 93 | enable-deltas-report: true 94 | - fqbn: arduino:samd:mkrzero 95 | enable-deltas-report: true 96 | 97 | # When using a matrix to compile for multiple boards, it's necessary to use a separate job for the deltas report 98 | report: 99 | needs: [build] 100 | if: github.event_name == 'pull_request' 101 | uses: nRF24/.github/.github/workflows/arduino_size_deltas.yaml@main 102 | -------------------------------------------------------------------------------- /.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 | - "!examples_RPi/*.py" 14 | - "!**Makefile" # old build system is not tested in this workflow 15 | - "pyRF24Mesh/*" 16 | - ".github/workflows/build_linux.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 | - "!examples_RPi/*.py" 27 | - "!**Makefile" # old build system is not tested in this workflow 28 | - "pyRF24Mesh/*" 29 | - ".github/workflows/build_linux.yml" 30 | release: 31 | types: [created] 32 | 33 | env: 34 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 35 | BUILD_TYPE: Release 36 | 37 | jobs: 38 | 39 | using_cmake: 40 | uses: nRF24/.github/.github/workflows/build_linux_cmake.yaml@main 41 | with: 42 | rf24mesh-ref: ${{ github.sha }} 43 | compiler: ${{ matrix.toolchain.compiler }} 44 | usr-dir: ${{ matrix.toolchain.usr_dir }} 45 | examples-path: examples_RPi 46 | deploy-release: ${{ github.event_name == 'release' && (matrix.toolchain.compiler == 'armhf' || matrix.toolchain.compiler == 'arm64') }} 47 | py-wrapper-path: pyRF24Mesh 48 | strategy: 49 | fail-fast: false 50 | matrix: 51 | toolchain: 52 | - compiler: "armhf" 53 | usr_dir: "arm-linux-gnueabihf" 54 | - compiler: "arm64" 55 | usr_dir: "aarch64-linux-gnu" 56 | # - compiler: "x86_64" 57 | # usr_dir: "x86_64-linux-gnux32" 58 | # - compiler: "i686" 59 | # usr_dir: "i686-linux-gnu" 60 | - compiler: "default" # github runner is hosted on a "amd64" 61 | usr_dir: "local" 62 | -------------------------------------------------------------------------------- /.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/old_backups/**" 11 | - "!examples/rf24_ATTiny/**" 12 | push: 13 | branches: [master, v1.x] 14 | paths: 15 | - ".github/workflows/build_platformIO.yml" 16 | - "library.json" 17 | - "examples/**" 18 | - "!examples/old_backups/**" 19 | - "!examples/rf24_ATTiny/**" 20 | release: 21 | types: [published, edited] 22 | 23 | jobs: 24 | validate_lib_json: 25 | uses: nRF24/.github/.github/workflows/validate_deploy_platformio.yaml@main 26 | secrets: inherit 27 | with: 28 | deploy-release: ${{ github.event_name == 'release' }} 29 | 30 | build: 31 | needs: [validate_lib_json] 32 | uses: nRF24/.github/.github/workflows/build_platformio.yaml@main 33 | with: 34 | example-path: ${{ matrix.example }} 35 | board-id: ${{ matrix.board }} 36 | strategy: 37 | fail-fast: false 38 | matrix: 39 | example: 40 | - "examples/RF24Mesh_Example/RF24Mesh_Example.ino" 41 | - "examples/RF24Mesh_Example_Master_Statics/RF24Mesh_Example_Master_Statics.ino" 42 | - "examples/RF24Mesh_Example_Master_To_Nodes/RF24Mesh_Example_Master_To_Nodes.ino" 43 | - "examples/RF24Mesh_Example_Node2Node/RF24Mesh_Example_Node2Node.ino" 44 | - "examples/RF24Mesh_Example_Node2NodeExtra/RF24Mesh_Example_Node2NodeExtra.ino" 45 | - "examples/RF24Mesh_SerialConfig/RF24Mesh_SerialConfig.ino" 46 | - "examples/RF24Mesh_Example_Master/RF24Mesh_Example_Master.ino" 47 | board: 48 | - "teensy31" 49 | - "teensy35" 50 | - "teensy36" 51 | - "teensy40" 52 | - "teensy41" 53 | - "teensylc" 54 | -------------------------------------------------------------------------------- /.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 | rf24mesh-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 | ignore: examples/old_backups|utility/RPi/bcm2835.h|utility/RPi/bcm2835.c 14 | extensions: ino,c,cpp,h 15 | -------------------------------------------------------------------------------- /.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 | - "examples**.cpp" 12 | - "examples**.ino" 13 | - "images/**" 14 | - ".github/workflows/doxygen.yml" 15 | - "Doxyfile" 16 | - "library.properties" # get lib version from here 17 | push: 18 | branches: [master, v1.x] 19 | paths: 20 | - "*.h" 21 | - "docs/**" 22 | - "!docs/README.md" 23 | - "*.md" 24 | - "examples**.cpp" 25 | - "examples**.ino" 26 | - "images/**" 27 | - ".github/workflows/doxygen.yml" 28 | - "Doxyfile" 29 | - "library.properties" # get lib version from here 30 | release: 31 | types: [published, edited] 32 | workflow_dispatch: 33 | 34 | jobs: 35 | build-docs: 36 | uses: nRF24/.github/.github/workflows/build_docs.yaml@main 37 | with: 38 | doxygen-version: '1.13.2' 39 | deploy-gh-pages: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master') }} 40 | secrets: inherit 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Executables from examples 2 | */bin/* 3 | *.exe 4 | 5 | # Generated library files 6 | *.so 7 | *.so.1 8 | 9 | # ignore docs folder 10 | docs/html/ 11 | docs/sphinx/xml/ 12 | docs/_build 13 | 14 | # ignore CMake stuff 15 | build/ 16 | *CMakeUserPresets.json 17 | 18 | # ignore local vscode folder 19 | .vscode/ 20 | 21 | # ignore PlatformIO packages 22 | *.tar.gz 23 | 24 | # ignore python venv 25 | .env/ 26 | .venv/ 27 | 28 | # ignore python build artifacts 29 | *.egg-info/ 30 | 31 | # Cmake build-in-source generated stuff 32 | CMakeCache.txt 33 | CPackConfig.cmake 34 | CPackSourceConfig.cmake 35 | CMakeFiles 36 | DEBIAN 37 | cmake_install.cmake 38 | compile_commands.json 39 | # Makefile is modified when `cmake .` is run 40 | # Makefile # preserve old/traditional build system 41 | -------------------------------------------------------------------------------- /.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.13.2" && 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 | # for non-RPi-Pico platforms 11 | ############################ 12 | cmake_minimum_required(VERSION 3.15) 13 | 14 | # Set the project name to your project name 15 | project(RF24Mesh C CXX) 16 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/StandardProjectSettings.cmake) 17 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/PreventInSourceBuilds.cmake) 18 | 19 | # get library info from Arduino IDE's required library.properties file 20 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/GetLibInfo.cmake) # sets the variable LibTargetName 21 | 22 | # allow using CMake options to adjust RF24Network_config.h without modiying source code 23 | option(MESH_NOMASTER "exclude compiling code that is strictly for master nodes" OFF) 24 | option(RF24MESH_DEBUG "enable/disable debugging output" OFF) 25 | option(RF24MESH_DEBUG_MINIMAL "enable/disable minimal debugging output" OFF) 26 | 27 | # Link this 'library' to set the c++ standard / compile-time options requested 28 | add_library(${LibTargetName}_project_options INTERFACE) 29 | target_compile_features(${LibTargetName}_project_options INTERFACE cxx_std_17) 30 | add_compile_options(-Ofast -Wall) 31 | 32 | # detect CPU and add compiler flags accordingly 33 | include(cmake/detectCPU.cmake) 34 | 35 | # detect any applicable external libs (like pigpio) 36 | include(cmake/AutoConfig_RF24_DRIVER.cmake) 37 | 38 | if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") 39 | option(ENABLE_BUILD_WITH_TIME_TRACE "Enable -ftime-trace to generate time tracing .json files on clang" OFF) 40 | if(ENABLE_BUILD_WITH_TIME_TRACE) 41 | add_compile_definitions(${LibTargetName}_project_options INTERFACE -ftime-trace) 42 | endif() 43 | endif() 44 | 45 | # Link this 'library' to use the warnings specified in CompilerWarnings.cmake 46 | add_library(${LibTargetName}_project_warnings INTERFACE) 47 | 48 | # enable cache system 49 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/Cache.cmake) 50 | 51 | # standard compiler warnings 52 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/CompilerWarnings.cmake) 53 | set_project_warnings(${LibTargetName}_project_warnings) 54 | 55 | # setup CPack options 56 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/CPackInfo.cmake) 57 | if(NOT DEFINED USE_RF24_LIB_SRC) 58 | find_library(RF24 rf24 REQUIRED) 59 | message(STATUS "using RF24 library: ${RF24}") 60 | 61 | find_library(RF24Network rf24network REQUIRED) 62 | message(STATUS "using RF24Network library: ${RF24Network}") 63 | endif() 64 | 65 | ########################### 66 | # create target for bulding the RF24Mesh lib 67 | ########################### 68 | add_library(${LibTargetName} SHARED RF24Mesh.cpp) 69 | target_include_directories(${LibTargetName} PUBLIC ${CMAKE_CURRENT_LIST_DIR}) 70 | 71 | # python wrapper builds from source 72 | if(DEFINED USE_RF24_LIB_SRC OR pybind11_FOUND OR SKBUILD) 73 | message(STATUS "Building lib from RF24 source") 74 | target_compile_definitions(${LibTargetName} PUBLIC USE_RF24_LIB_SRC) 75 | 76 | if(NOT DEFINED RF24_LIB_PATH) 77 | target_include_directories(${LibTargetName} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../RF24) 78 | else() 79 | target_include_directories(${LibTargetName} PUBLIC ${RF24_LIB_PATH}) 80 | endif() 81 | 82 | if(NOT DEFINED RF24NETWORK_LIB_PATH) 83 | target_include_directories(${LibTargetName} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../RF24) 84 | else() 85 | target_include_directories(${LibTargetName} PUBLIC ${RF24NETWORK_LIB_PATH}) 86 | endif() 87 | 88 | target_link_libraries(${LibTargetName} 89 | INTERFACE ${LibTargetName}_project_options 90 | INTERFACE ${LibTargetName}_project_warnings 91 | ) 92 | else() 93 | 94 | target_link_libraries(${LibTargetName} 95 | INTERFACE ${LibTargetName}_project_options 96 | INTERFACE ${LibTargetName}_project_warnings 97 | SHARED ${RF24} 98 | SHARED ${RF24Network} 99 | ) 100 | endif() 101 | 102 | set_target_properties( 103 | ${LibTargetName} 104 | PROPERTIES 105 | SOVERSION ${${LibName}_VERSION_MAJOR} 106 | VERSION ${${LibName}_VERSION_STRING} 107 | ) 108 | # assert the appropriate preprocessor macros for RF24Network_config.h 109 | if(MESH_NOMASTER) 110 | message(STATUS "MESH_NOMASTER asserted") 111 | target_compile_definitions(${LibTargetName} PUBLIC MESH_NOMASTER) 112 | endif() 113 | if(RF24MESH_DEBUG) 114 | message(STATUS "RF24MESH_DEBUG asserted") 115 | target_compile_definitions(${LibTargetName} PUBLIC RF24MESH_DEBUG) 116 | endif() 117 | if(RF24MESH_DEBUG_MINIMAL) 118 | message(STATUS "RF24MESH_DEBUG_MINIMAL asserted") 119 | target_compile_definitions(${LibTargetName} PUBLIC RF24MESH_DEBUG_MINIMAL) 120 | endif() 121 | # for the following, we let the default be configured in source code 122 | if(DEFINED MESH_MAX_CHILDREN) 123 | message(STATUS "MESH_MAX_CHILDREN set to ${MESH_MAX_CHILDREN}") 124 | target_compile_definitions(${LibTargetName} PUBLIC MESH_MAX_CHILDREN=${MESH_MAX_CHILDREN}) 125 | endif() 126 | if(DEFINED MESH_DEFAULT_CHANNEL) 127 | message(STATUS "MESH_DEFAULT_CHANNEL set to ${MESH_DEFAULT_CHANNEL}") 128 | target_compile_definitions(${LibTargetName} PUBLIC MESH_DEFAULT_CHANNEL=${MESH_DEFAULT_CHANNEL}) 129 | endif() 130 | if(DEFINED MESH_RENEWAL_TIMEOUT) 131 | message(STATUS "MESH_RENEWAL_TIMEOUT set to ${MESH_RENEWAL_TIMEOUT}") 132 | target_compile_definitions(${LibTargetName} PUBLIC MESH_RENEWAL_TIMEOUT=${MESH_RENEWAL_TIMEOUT}) 133 | endif() 134 | if(DEFINED MESH_MEM_ALLOC_SIZE) 135 | message(STATUS "MESH_MEM_ALLOC_SIZE set to ${MESH_MEM_ALLOC_SIZE}") 136 | target_compile_definitions(${LibTargetName} PUBLIC MESH_MEM_ALLOC_SIZE=${MESH_MEM_ALLOC_SIZE}) 137 | endif() 138 | if(DEFINED MESH_LOOKUP_TIMEOUT) 139 | message(STATUS "MESH_LOOKUP_TIMEOUT set to ${MESH_LOOKUP_TIMEOUT}") 140 | target_compile_definitions(${LibTargetName} PUBLIC MESH_LOOKUP_TIMEOUT=${MESH_LOOKUP_TIMEOUT}) 141 | endif() 142 | if(DEFINED MESH_WRITE_TIMEOUT) 143 | message(STATUS "MESH_WRITE_TIMEOUT set to ${MESH_WRITE_TIMEOUT}") 144 | target_compile_definitions(${LibTargetName} PUBLIC MESH_WRITE_TIMEOUT=${MESH_WRITE_TIMEOUT}) 145 | endif() 146 | if(DEFINED RF24MESH_CONN_CHECK_TYPE) 147 | message(STATUS "RF24MESH_CONN_CHECK_TYPE set to ${RF24MESH_CONN_CHECK_TYPE}") 148 | target_compile_definitions(${LibTargetName} PUBLIC RF24MESH_CONN_CHECK_TYPE=${RF24MESH_CONN_CHECK_TYPE}) 149 | endif() 150 | 151 | 152 | ########################### 153 | # target install rules for the RF24Mesh lib 154 | ########################### 155 | install(TARGETS ${LibTargetName} 156 | DESTINATION lib 157 | ) 158 | 159 | install(FILES 160 | RF24Mesh.h 161 | RF24Mesh_config.h 162 | DESTINATION include/RF24Mesh 163 | ) 164 | 165 | # CMAKE_CROSSCOMPILING is only TRUE when CMAKE_TOOLCHAIN_FILE is specified via CLI 166 | if(CMAKE_HOST_UNIX AND "${CMAKE_CROSSCOMPILING}" STREQUAL "FALSE") 167 | install(CODE "message(STATUS \"Updating ldconfig\")") 168 | install(CODE "execute_process(COMMAND ldconfig)") 169 | endif() 170 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | These are the current requirements for getting your code included in RF24Mesh: 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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # 3 | # Makefile for RF24Mesh on Raspberry Pi 4 | # 5 | # Author: TMRh20 6 | # Date: 2014/09 7 | # 8 | # Description: 9 | # ------------ 10 | # use make all and make install to install the library 11 | # You can change the install directory by editing the LIBDIR line 12 | # 13 | PREFIX=/usr/local 14 | 15 | # Library parameters 16 | # where to put the lib 17 | LIBDIR=$(PREFIX)/lib 18 | # lib name 19 | LIB_RFN=librf24mesh 20 | # shared library name 21 | LIBNAME_RFN=$(LIB_RFN).so.1.0 22 | 23 | HEADER_DIR=${PREFIX}/include/RF24Mesh 24 | 25 | # Which compiler to use 26 | CC=g++ 27 | 28 | ARCH=armv6zk 29 | ifeq "$(shell uname -m)" "armv7l" 30 | ARCH=armv7-a 31 | endif 32 | 33 | # Detect the Raspberry Pi from cpuinfo 34 | #Count the matches for BCM2708 or BCM2709 in cpuinfo 35 | RPI=$(shell cat /proc/cpuinfo | grep Hardware | grep -c BCM2708) 36 | ifneq "${RPI}" "1" 37 | RPI=$(shell cat /proc/cpuinfo | grep Hardware | grep -c BCM2709) 38 | endif 39 | 40 | ifeq "$(RPI)" "1" 41 | # The recommended compiler flags for the Raspberry Pi 42 | CCFLAGS=-Ofast -mfpu=vfp -mfloat-abi=hard -march=$(ARCH) -mtune=arm1176jzf-s -std=c++0x 43 | endif 44 | 45 | # make all 46 | # reinstall the library after each recompilation 47 | all: librf24mesh 48 | 49 | # Make the library 50 | librf24mesh: RF24Mesh.o 51 | $(CC) -shared -Wl,-soname,$@.so.1 ${CCFLAGS} -o ${LIBNAME_RFN} $^ 52 | 53 | # Library parts 54 | RF24Mesh.o: RF24Mesh.cpp 55 | $(CC) -Wall -fPIC ${CCFLAGS} -c $^ 56 | 57 | # clear build files 58 | clean: 59 | rm -rf *.o ${LIB_RFN}.* 60 | 61 | install: all install-libs install-headers 62 | 63 | # Install the library to LIBPATH 64 | 65 | install-libs: 66 | @echo "[Install]" 67 | @if ( test ! -d $(PREFIX)/lib ) ; then mkdir -p $(PREFIX)/lib ; fi 68 | @install -m 0755 ${LIBNAME_RFN} ${LIBDIR} 69 | @ln -sf ${LIBDIR}/${LIBNAME_RFN} ${LIBDIR}/${LIB_RFN}.so.1 70 | @ln -sf ${LIBDIR}/${LIBNAME_RFN} ${LIBDIR}/${LIB_RFN}.so 71 | @ldconfig 72 | 73 | install-headers: 74 | @echo "[Installing Headers]" 75 | @if ( test ! -d ${HEADER_DIR} ) ; then mkdir -p ${HEADER_DIR} ; fi 76 | @install -m 0644 *.h ${HEADER_DIR} 77 | 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![Linux build](https://github.com/nRF24/RF24Mesh/actions/workflows/build_linux.yml/badge.svg)](https://github.com/nRF24/RF24Mesh/actions/workflows/build_linux.yml) 3 | [![Arduino CLI build](https://github.com/nRF24/RF24Mesh/actions/workflows/build_arduino.yml/badge.svg)](https://github.com/nRF24/RF24Mesh/actions/workflows/build_arduino.yml) 4 | [![PlatformIO build](https://github.com/nRF24/RF24Mesh/actions/workflows/build_platformIO.yml/badge.svg)](https://github.com/nRF24/RF24Mesh/actions/workflows/build_platformIO.yml) 5 | [![Pico SDK build](https://github.com/nRF24/RF24Mesh/actions/workflows/build_rp2xxx.yml/badge.svg)](https://github.com/nRF24/RF24Mesh/actions/workflows/build_rp2xxx.yml) 6 | [![Documentation Status](https://readthedocs.org/projects/rf24mesh/badge/?version=latest)](https://rf24mesh.readthedocs.io/en/latest/?badge=latest) 7 | 8 | # RF24Mesh 9 | 10 | Mesh Networking for RF24Network 11 | 12 | Introducing **RF24Network & RF24Mesh v2.0** with some *significant API changes*, adding the use of [C++ Templates](https://cplusplus.com/doc/oldtutorial/templates/) 13 | in order to support a range of ESB enabled radios, most recently NRF52x radios. 14 | 15 | **Important Notes:** 16 | - Any network layer that uses v2 needs to have RF24Network/RF24Mesh dependencies of v2 or newer. RF24 v1.x is an exception here. 17 | - General usage should remain backward compatible, see the included examples of the related libraries for more info 18 | - Any third party libs that extend the network/mesh layer may also need to be updated to incorporate the new templated class prototypes: 19 | ```cpp 20 | template 21 | class ESBNetwork; 22 | 23 | template 24 | class ESBMesh; 25 | ``` 26 | - Third party libs should also be able to use the backward-compatible typedef in their template: 27 | - ESBGateway.h: 28 | ```cpp 29 | template 30 | class ESBGateway 31 | ``` 32 | and inform the compiler what types they intend to support: 33 | - ESBGateway.cpp: 34 | ```cpp 35 | template class ESBGateway; 36 | ``` 37 | - The auto installers do not perform a version check like package managers, so having the correct versions of the software is important. 38 | - 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. 39 | 40 | https://nRF24.github.io/RF24Mesh 41 | -------------------------------------------------------------------------------- /RF24Mesh.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @file RF24Mesh.h 4 | * 5 | * Class declaration for RF24Mesh 6 | */ 7 | 8 | #ifndef __RF24MESH_H__ 9 | #define __RF24MESH_H__ 10 | 11 | #include 12 | #include 13 | 14 | /** 15 | * Network/Mesh Response Types 16 | * The network will determine whether to automatically acknowledge payloads based on their type 17 | * RF24Mesh uses pre-defined system types for interacting with RF24Network at the system level 18 | * 19 | */ 20 | 21 | // Network ACK types 22 | // None defined 23 | 24 | // No Network ACK types 25 | #define MESH_ADDR_LOOKUP 196 26 | #define MESH_ADDR_RELEASE 197 27 | #define MESH_ID_LOOKUP 198 28 | 29 | #define MESH_BLANK_ID 65535 30 | 31 | #if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny84__) 32 | #define RF24_TINY 33 | #endif 34 | 35 | #include "RF24Mesh_config.h" 36 | 37 | #if defined(__linux) && !defined(__ARDUINO_X86__) && !defined(USE_RF24_LIB_SRC) 38 | #include 39 | #include 40 | #define RF24_LINUX 41 | #else 42 | #include 43 | #include 44 | #if defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_NRF52840) 45 | #include 46 | #endif 47 | #endif 48 | 49 | #include 50 | #include 51 | 52 | class RF24; 53 | #if defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52833) 54 | class nrf_to_nrf; 55 | #endif 56 | 57 | template 58 | class ESBNetwork; 59 | 60 | /** 61 | * @tparam network_t The `network` object's type. Defaults to `RF24Network` for legacy behavior. 62 | * This new abstraction is really meant for using the nRF52840 SoC as a drop-in replacement 63 | * for the nRF24L01 radio. For more detail, see the 64 | * [nrf_to_nrf Arduino library](https://github.com/TMRh20/nrf_to_nrf). 65 | * @tparam radio_t The `radio` object's type. Defaults to `RF24` for legacy behavior. 66 | * This new abstraction is really meant for using the nRF52840 SoC as a drop-in replacement 67 | * for the nRF24L01 radio. For more detail, see the 68 | * [nrf_to_nrf Arduino library](https://github.com/TMRh20/nrf_to_nrf). 69 | */ 70 | template, class radio_t = RF24> 71 | class ESBMesh 72 | { 73 | /** 74 | * @name RF24Mesh 75 | * 76 | * The mesh library and class documentation is currently in active development and usage may change. 77 | */ 78 | /**@{*/ 79 | 80 | public: 81 | /** 82 | * Construct the mesh. 83 | * 84 | * v2.0 supports a backward compatible constructor: 85 | * @code 86 | * RF24 radio(7, 8); 87 | * RF24Network network(radio); 88 | * RF24Mesh mesh(radio, network); // for nRF24L01 89 | * 90 | * nrf_to_nrf radio1; 91 | * RF52Network network1(radio1); 92 | * RF52Mesh mesh1(network1, radio1); // for nRF52xxx family 93 | * @endcode 94 | * 95 | * @see v2.0 supports [nrf_to_nrf Arduino library](https://github.com/TMRh20/nrf_to_nrf) 96 | * for nrf52 chips' internal radio. 97 | * @param _radio The underlying radio driver instance 98 | * @param _network The underlying network instance 99 | */ 100 | ESBMesh(radio_t& _radio, network_t& _network); 101 | 102 | /** 103 | * Call this in setup() to configure the mesh and request an address.
104 | * 105 | * @code mesh.begin(); @endcode 106 | * This may take a few moments to complete. 107 | * 108 | * The following parameters are optional: 109 | * @param channel The radio channel (0 - 125). Default is 97. 110 | * @param data_rate The data rate (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS). Default is RF24_1MBPS. 111 | * @param timeout How long to attempt address renewal in milliseconds. Default is 7500. 112 | */ 113 | bool begin(uint8_t channel = MESH_DEFAULT_CHANNEL, rf24_datarate_e data_rate = RF24_1MBPS, uint32_t timeout = MESH_RENEWAL_TIMEOUT); 114 | 115 | /** 116 | * Very similar to network.update(), it needs to be called regularly to keep the network 117 | * and the mesh going. 118 | */ 119 | uint8_t update(); 120 | 121 | /** 122 | * Automatically construct a header and send a payload. 123 | * Very similar to the standard network.write() function, which can be used directly. 124 | * 125 | * @note Including the @ref _nodeID "nodeID" parameter will result in an automatic address lookup being performed. 126 | * @note Message types 1 - 64 (decimal) will NOT be acknowledged by the network, types 65 - 127 will be. Use as appropriate to manage traffic: 127 | * if expecting a response, no ack is needed. 128 | * 129 | * @param data Send any type of data of any length (maximum length determined by RF24Network layer). 130 | * @param msg_type The user-defined (1 - 127) message header_type to send. Used to distinguish between different types of data being transmitted. 131 | * @param size The size of the data being sent 132 | * @param nodeID **Optional**: The @ref _nodeID "nodeID" of the recipient if not sending to master. 133 | * @return True if success; false if failed 134 | */ 135 | bool write(const void* data, uint8_t msg_type, size_t size, uint8_t nodeID = 0); 136 | 137 | /** 138 | * Set a unique @ref _nodeID "nodeID" for this node. 139 | * 140 | * This needs to be called before ESBMesh::begin(). The parameter value passed can be fetched 141 | * via serial connection, EEPROM, etc when configuring a large number of nodes. 142 | * @note If using RF24Gateway and/or RF24Ethernet, nodeIDs 0 & 1 are used by the master node. 143 | * @param nodeID Can be any unique value ranging from 1 to 255 (reserving 0 for the master node). 144 | */ 145 | void setNodeID(uint8_t nodeID); 146 | 147 | /** 148 | * @brief Reconnect to the mesh and renew the current RF24Network address. 149 | * 150 | * This is used to re-establish a connection to the mesh network if physical location of a node 151 | * or surrounding nodes has changed (or a routing node becomes unavailable). 152 | * 153 | * @note If all nodes are set to verify connectivity and reconnect at a specified period, then 154 | * restarting the master (and deleting dhcplist.txt on Linux) will result in complete 155 | * network/mesh re-convergence. 156 | * @param timeout How long to attempt address renewal in milliseconds. Default is 7500 157 | * @return The newly assigned RF24Network address. If the connecting process fails, then 158 | * MESH_DEFAULT_ADDRESS is returned because all consciously unconnected nodes use that address. 159 | */ 160 | uint16_t renewAddress(uint32_t timeout = MESH_RENEWAL_TIMEOUT); 161 | 162 | #if !defined(MESH_NOMASTER) 163 | /** 164 | * This is only to be used on the master node because it manages allocation of network addresses 165 | * for any requesting (non-master) node's ID, similar to DHCP. 166 | * 167 | * @warning On master nodes, It is required to call this function immediately after calling 168 | * ESBMesh::update() to ensure address requests are handled appropriately. 169 | */ 170 | void DHCP(); 171 | 172 | #endif 173 | 174 | /**@}*/ 175 | /** 176 | * @name Advanced Operation 177 | * 178 | * For advanced configuration and usage of the mesh 179 | */ 180 | /**@{*/ 181 | 182 | /** 183 | * Convert an RF24Network address into a nodeId. 184 | * @param address If no address is provided, returns the local @ref _nodeID "nodeID", 185 | * otherwise a lookup request is sent to the master node 186 | * @return The unique identifier of the node in the range [1, 255] or -1 if node was not found. 187 | */ 188 | int16_t getNodeID(uint16_t address = MESH_BLANK_ID); 189 | 190 | /** 191 | * Tests connectivity of this node to the mesh. 192 | * @note If this function fails, address renewal should typically be done. 193 | * 194 | * The current behavior will only ping this node's parent to validate connection to mesh. 195 | * Previously, this function would validate connection by looking up this node's assigned address with 196 | * the master node's `RF24Mesh::addrList`. 197 | * The old behavior can be mandated by changing @ref RF24MESH_CONN_CHECK_TYPE in RF24Mesh_config.h, 198 | * although a large mesh network might suffer a performance cost using the old behavior. 199 | * 200 | * @return 201 | * - True if connected. 202 | * - False if not connected, mesh is not responding, or this node is the master node. 203 | */ 204 | bool checkConnection(); 205 | 206 | /** 207 | * Releases the currently assigned address lease. Useful for nodes that will be sleeping etc. 208 | * @note Nodes should ensure that addresses are released successfully prior to going offline. 209 | * @return True if successfully released, otherwise false. 210 | */ 211 | bool releaseAddress(); 212 | 213 | /** 214 | * The assigned RF24Network (Octal) address of this node 215 | * @return An unsigned 16-bit integer containing the RF24Network address in octal format. 216 | */ 217 | uint16_t mesh_address; 218 | 219 | /** 220 | * @brief Convert a @ref _nodeID "nodeID" into an RF24Network address 221 | * @note If printing or displaying the address, it needs to be converted to octal format: 222 | * @code{.ino} Serial.println(address, OCT); @endcode 223 | * 224 | * Results in a lookup request being sent to the master node. 225 | * @param nodeID The unique identifier of the node in the range [1, 255]. 226 | * @return The RF24Network address of the node, -2 if successful but not in list, -1 if failed. 227 | */ 228 | int16_t getAddress(uint8_t nodeID); 229 | 230 | /** @brief Write to a specific node by RF24Network address. */ 231 | bool write(uint16_t to_node, const void* data, uint8_t msg_type, size_t size); 232 | 233 | /** 234 | * Change the active radio channel after the mesh has been started. 235 | * @param _channel The value passed to `RF24::setChannel()` 236 | */ 237 | void setChannel(uint8_t _channel); 238 | 239 | /** 240 | * Allow child nodes to discover and attach to this node. 241 | * @param allow True to allow children, False to prevent children from attaching automatically. 242 | */ 243 | void setChild(bool allow); 244 | 245 | /** 246 | * RF24Mesh ID and Address lookups as well as address renewal can take some time. 247 | * Set a callback function to enable additional processing while the mesh is working 248 | * 249 | * @code 250 | * void myCallbackFunction(){ 251 | * someValue = someOtherValue; 252 | * } 253 | * mesh.setCallback(myCallbackFunction); 254 | * @endcode 255 | * 256 | * @param meshCallback The name of a function to call. This function should consume no required input parameters. 257 | */ 258 | void setCallback(void (*meshCallback)(void)); 259 | 260 | #define MESH_CALLBACK \ 261 | if (meshCallback) meshCallback(); 262 | 263 | /** 264 | * Set or change a @ref _nodeID "nodeID" : node address (key : value) pair manually. 265 | * This function is for use on the master node only. 266 | * 267 | * @code 268 | * // Set a static address for node 02, with nodeID 23, since it will just be 269 | * // a static routing node for example running on an ATTiny chip. 270 | * mesh.setAddress(23, 02); 271 | * @endcode 272 | * @code 273 | * // Change or set the nodeID for an existing address 274 | * uint16_t address = 012; 275 | * mesh.setAddress(3, address, true); 276 | * @endcode 277 | * 278 | * @param nodeID The @ref _nodeID "nodeID" to assign 279 | * @param address The octal RF24Network address to assign 280 | * @param searchBy Optional parameter. Default is search by @ref _nodeID "nodeID" and 281 | * set the address. True allows searching by address and setting @ref _nodeID "nodeID". 282 | */ 283 | void setAddress(uint8_t nodeID, uint16_t address, bool searchBy = false); 284 | 285 | #if !defined(MESH_NOMASTER) 286 | /** 287 | * Save the @ref addrList to a binary file named "dhcplist.txt". 288 | * @note This function is for use on the master node only and only on Linux or x86 platforms. 289 | */ 290 | void saveDHCP(); 291 | 292 | /** 293 | * Load the @ref addrList from a binary file named "dhcplist.txt". 294 | * @note This function is for use on the master node only and only on Linux or x86 platforms. 295 | */ 296 | void loadDHCP(); 297 | 298 | /** 299 | * @name Deprecated 300 | * 301 | * Methods provided for backwards compatibility with old/testing code. 302 | */ 303 | /**@{*/ 304 | 305 | /** @deprecated For backward compatibility with older code. Use the synonymous setAddress() instead. */ 306 | void setStaticAddress(uint8_t nodeID, uint16_t address); 307 | 308 | #endif // !defined(MESH_NOMASTER) 309 | /**@}*/ 310 | 311 | /** 312 | * The unique identifying number used to differentiate mesh nodes' from their assigned network 313 | * address. Ideally, this is set before calling begin() or renewAddress(). It is up to the 314 | * network administrator to make sure that this number is unique to each mesh/network node. 315 | * 316 | * This nodeID number is typically in the range [0, 255], but remember that `0` is reserved for 317 | * the master node. Other external systems may reserve other node ID numbers, for instance 318 | * RF24Gateway/RF24Ethernet reserves the node ID number `1` in addition to the master node ID 319 | * `0`. 320 | */ 321 | uint8_t _nodeID; 322 | 323 | #if !defined(MESH_NOMASTER) 324 | /** 325 | * @brief A struct for storing a @ref _nodeID "nodeID" and an address in a single element of 326 | * the ESBMesh::addrList array. 327 | * 328 | * @note This array only exists on the mesh network's master node. 329 | */ 330 | typedef struct 331 | { 332 | /** @brief The @ref _nodeID "nodeID" of an network node (child) */ 333 | uint8_t nodeID; 334 | /** @brief The logical address of an network node (child) */ 335 | uint16_t address; 336 | } addrListStruct; 337 | 338 | /** 339 | * @name Address list struct 340 | * @brief helping members for managing the list of assigned addresses 341 | * @see the addrListStruct struct reference 342 | */ 343 | /**@{*/ 344 | 345 | // Pointer used for dynamic memory allocation of address list 346 | /** 347 | * @brief A array of addrListStruct elements for assigned addresses. 348 | * @see addrListStruct class reference 349 | */ 350 | addrListStruct* addrList; 351 | /** @brief The number of entries in the addrListStruct of assigned addresses. */ 352 | uint8_t addrListTop; 353 | 354 | /** 355 | * Releases the specified address if leased to a mesh node's ID. 356 | * 357 | * This is specific to master nodes, so network administrators can 358 | * manage assigned addresses without notifying the nodes that 359 | * might be appropriating them. 360 | * 361 | * @param address The address to release from any mesh node. 362 | * @return True if successfully released, otherwise false. 363 | */ 364 | bool releaseAddress(uint16_t address); 365 | #endif 366 | /**@}*/ 367 | 368 | private: 369 | radio_t& radio; 370 | network_t& network; 371 | 372 | /** Function pointer for customized callback usage in long running algorithms. */ 373 | void (*meshCallback)(void); 374 | 375 | /** Actual requesting of the address once a contact node is discovered or supplied **/ 376 | bool requestAddress(uint8_t level); 377 | 378 | #if !defined(MESH_NOMASTER) 379 | /** Indicator that an address request is available. */ 380 | bool doDHCP; 381 | /** Just ensures we don't re-allocate the memory buffer if restarting the mesh on master. **/ 382 | bool addrMemAllocated; 383 | #endif 384 | 385 | /** Starts up the network layer with default address. */ 386 | void beginDefault(); 387 | /** A flag asserted in begin() after putting the radio in TX mode. */ 388 | bool meshStarted; 389 | /** Returns the number of octal digits in the specified address. */ 390 | uint8_t getLevel(uint16_t address); 391 | }; 392 | 393 | /** 394 | * A type definition of the template class `ESBMesh` to maintain backward compatibility. 395 | * 396 | * ```.cpp 397 | * RF24 radio(7, 8); 398 | * RF24Network network(radio); 399 | * 400 | * RF24Mesh mesh(radio, network); 401 | * // is equivalent to 402 | * ESBMesh, RF24> mesh(radio, network); 403 | * ``` 404 | */ 405 | typedef ESBMesh, RF24> RF24Mesh; 406 | #if defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52833) 407 | typedef ESBMesh, nrf_to_nrf> RF52Mesh; 408 | #endif 409 | 410 | /** 411 | * @example RF24Mesh_Example.ino 412 | * Arduino Example Sketch
413 | * This example sketch shows how to manually configure a node via RF24Mesh, and send data to the 414 | * master node. 415 | * The nodes will refresh their network address as soon as a single write fails. This allows the 416 | * nodes to change position in relation to each other and the master node. 417 | */ 418 | 419 | /** 420 | * @example RF24Mesh_Example_Master.ino 421 | * Arduino Example Sketch
422 | * @note This sketch only functions on -Arduino Due- 423 | * 424 | * This example sketch shows how to manually configure a node via RF24Mesh as a master node, which 425 | * will receive all data from sensor nodes. 426 | * 427 | * The nodes can change physical or logical position in the network, and reconnect through different 428 | * routing nodes as required. The master node manages the address assignments for the individual nodes 429 | * in a manner similar to DHCP. 430 | * 431 | */ 432 | 433 | /** 434 | * @example RF24Mesh_Example_Node2Node.ino 435 | * Example of node to node communication using RF24Mesh 436 | */ 437 | 438 | /** 439 | * @example RF24Mesh_Example_Node2NodeExtra.ino 440 | * Extended Example of node to node communication using RF24Mesh 441 | */ 442 | 443 | /** 444 | * @example RF24Mesh_SerialConfig.ino 445 | * 446 | * This example sketch shows how the same sketch can be written to a large number of devices, which are 447 | * configured later via Serial input. 448 | * 449 | */ 450 | 451 | /** 452 | * @example RF24Mesh_Example.cpp 453 | * 454 | * Raspberry Pi Example Sketch
455 | * This example sketch shows how to manually configure a node via RF24Mesh, and send data to the 456 | * master node. 457 | * The nodes will refresh their network address as soon as a single write fails. This allows the 458 | * nodes to change position in relation to each other and the master node. 459 | */ 460 | 461 | /** 462 | * @example RF24Mesh_Example_Master.cpp 463 | * 464 | * Raspberry Pi Example Sketch
465 | * 466 | * This example sketch shows how to manually configure a node via RF24Mesh as a master node, which 467 | * will receive all data from sensor nodes. 468 | * 469 | * The nodes can change physical or logical position in the network, and reconnect through different 470 | * routing nodes as required. The master node manages the address assignments for the individual nodes 471 | * in a manner similar to DHCP. 472 | * 473 | */ 474 | 475 | /** 476 | * @example RF24Mesh_Ncurses_Master.cpp 477 | * A very limited ncurses interface used for initial monitoring/testing of RF24Mesh 478 | * @image html "images/RF24Mesh_Ncurses.JPG" 479 | */ 480 | 481 | #endif // define __RF24MESH_H__ 482 | -------------------------------------------------------------------------------- /RF24Mesh_config.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file RF24Mesh_config.h 3 | * 4 | * macro definitions for configuring RF24Mesh 5 | */ 6 | 7 | #ifndef __RF24MESH_CONFIG_H__ 8 | #define __RF24MESH_CONFIG_H__ 9 | 10 | /*** User Configuration ***/ 11 | /** 12 | * @brief Set 1 to 4 (Default: 4) Restricts the maximum children per node. 13 | * 14 | * The master node supports MESH_MAX_CHILDREN + 1 nodes 15 | */ 16 | #ifndef MESH_MAX_CHILDREN 17 | #define MESH_MAX_CHILDREN 4 18 | #endif // MESH_MAX_CHILDREN 19 | #if defined(RF24_TINY) 20 | #define MESH_NOMASTER 21 | #endif 22 | 23 | // un-comment for non-master nodes not running on ATTiny MCUs 24 | //#define MESH_NOMASTER 25 | 26 | /***Advanced User Config***/ 27 | /** 28 | * @brief Radio channel to operate on 1-127. 29 | * 30 | * This is normally modified by calling RF24Mesh::setChannel() 31 | */ 32 | #ifndef MESH_DEFAULT_CHANNEL 33 | #define MESH_DEFAULT_CHANNEL 97 34 | #endif // MESH_DEFAULT_CHANNEL 35 | 36 | /** 37 | * @brief How long to attempt address renewal in milliseconds 38 | * @see RF24Mesh::renewAddress() 39 | */ 40 | #ifndef MESH_RENEWAL_TIMEOUT 41 | #define MESH_RENEWAL_TIMEOUT 7500 42 | #endif // MESH_RENEWAL_TIMEOUT 43 | 44 | /** 45 | * @brief master node memory allocation 46 | * 47 | * On the master node memory for the address list (nodeIDs + RF24Network Addresses) is allocated dynamically and re-allocated using this value 48 | * 49 | * Example: With a value of 10, space for 10 nodes is allocated on startup. Adding an 11th node will re-allocate the memory space to support 10 more nodes. 50 | * 51 | * On 8-bit AVRs (Arduino Uno, Nano etc) each entry uses 3-bytes of memory space. Minimize this value to save memory. Allocate enough to prevent memory fragmentation. 52 | */ 53 | #ifndef MESH_MEM_ALLOC_SIZE 54 | #define MESH_MEM_ALLOC_SIZE 10 55 | #endif // MESH_MEM_ALLOC_SIZE 56 | 57 | /** 58 | * @brief Number of attempts to verify a connection 59 | * 60 | * On child nodes, when calling `mesh.checkConnection();`, configure how many attempts will be made to contact the master node to verify connectivity 61 | * Raising this number can result in a more stable mesh, since nodes can more easily verify that a connection is active 62 | */ 63 | #ifndef MESH_CONNECTION_CHECK_ATTEMPTS 64 | #define MESH_CONNECTION_CHECK_ATTEMPTS 3 65 | #endif 66 | 67 | #define RF24MESH_CONN_CHECK_PARENT 1 68 | #define RF24MESH_CONN_CHECK_MASTER 0 69 | /** 70 | * @brief How to verify a connection 71 | * 72 | * On child nodes, determine how they verify/check their connection periodically, or when writes start to fail via the `RF24Mesh::checkConnection();` 73 | * function. 74 | * Set RF24MESH_CONN_CHECK_TYPE to @ref RF24MESH_CONN_CHECK_PARENT for the new behaviour of verifying connectivity only with their parent node. 75 | * Set RF24MESH_CONN_CHECK_TYPE to @ref RF24MESH_CONN_CHECK_MASTER for the old behaviour of verifying connectivity with the master node. 76 | * The old behaviour typically results in more network congestion, more load on the master node, and less reliable networks, 77 | * but it can work well when radio conditions are good and/or when there are only a small number of nodes on the network and/or in close proximity 78 | * to the master node. 79 | */ 80 | #ifndef RF24MESH_CONN_CHECK_TYPE 81 | #define RF24MESH_CONN_CHECK_TYPE RF24MESH_CONN_CHECK_PARENT 82 | // To use old behavior: 83 | // #define RF24MESH_CONN_CHECK_TYPE RF24MESH_CONN_CHECK_MASTER 84 | #endif 85 | 86 | /**************************/ 87 | /*** Debug ***/ 88 | //#define RF24MESH_DEBUG_MINIMAL /** Uncomment for the Master Node to print out address assignments as they are assigned */ 89 | //#define RF24MESH_DEBUG /** Uncomment to enable debug output to serial **/ 90 | /**************************/ 91 | 92 | /*** Other Configuration ***/ 93 | //#define MESH_MIN_SAVE_TIME 30000 /** UNUSED Minimum time required before changing nodeID. Prevents excessive writing to EEPROM */ 94 | 95 | /** 96 | * @brief How long to wait in ms for a response during individual address lookups 97 | * @see RF24Mesh::getNodeID and RF24Mesh::getAddress 98 | * If using distant nodes or a large number of nodes this value can be increased in general or for specific nodes. 99 | * For Level 1 nodes a response typically takes 2-3ms in good conditions. 100 | * For Level 2 nodes: 4-5ms, Level 3: 6-15ms, Level 4: 10-25ms 101 | **/ 102 | #ifndef MESH_LOOKUP_TIMEOUT 103 | #define MESH_LOOKUP_TIMEOUT 135 104 | #endif // MESH_LOOKUP_TIMEOUT 105 | 106 | /** @brief How long RF24Mesh::write() retries address lookups before timing out. Allows multiple attempts */ 107 | #ifndef MESH_WRITE_TIMEOUT 108 | #define MESH_WRITE_TIMEOUT 115 109 | #endif // MESH_WRITE_TIMEOUT 110 | 111 | #ifndef MESH_DEFAULT_ADDRESS 112 | #define MESH_DEFAULT_ADDRESS NETWORK_DEFAULT_ADDRESS 113 | #endif // MESH_DEFAULT_ADDRESS 114 | 115 | #define MESH_MULTICAST_ADDRESS NETWORK_MULTICAST_ADDRESS 116 | 117 | //#define MESH_MAX_ADDRESSES 255 /* UNUSED Determines the max size of the array used for storing addresses on the Master Node */ 118 | //#define MESH_ADDRESS_HOLD_TIME 30000 /* UNUSED How long before a released address becomes available */ 119 | 120 | #if (defined(__linux) || defined(linux)) && !defined(__ARDUINO_X86__) && !defined(USE_RF24_LIB_SRC) 121 | #include 122 | 123 | //ATXMega 124 | #elif defined(XMEGA) 125 | #include "../../rf24lib/rf24lib/RF24_config.h" 126 | #else 127 | #include 128 | #endif 129 | 130 | #if defined(RF24MESH_DEBUG_MINIMAL) 131 | #define IF_RF24MESH_DEBUG_MINIMAL(x) ({ x; }) 132 | #else 133 | #define IF_RF24MESH_DEBUG_MINIMAL(x) 134 | #endif 135 | 136 | #if defined(RF24MESH_DEBUG) 137 | #define IF_RF24MESH_DEBUG(x) ({ x; }) 138 | #else 139 | #define IF_RF24MESH_DEBUG(x) 140 | #endif 141 | 142 | #endif // __RF24MESH_CONFIG_H__ 143 | -------------------------------------------------------------------------------- /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 7 | "ccache" 8 | CACHE STRING "Compiler cache to be used" 9 | ) 10 | set(CACHE_OPTION_VALUES "ccache" "sccache") 11 | set_property(CACHE CACHE_OPTION PROPERTY STRINGS ${CACHE_OPTION_VALUES}) 12 | list( 13 | FIND 14 | CACHE_OPTION_VALUES 15 | ${CACHE_OPTION} 16 | CACHE_OPTION_INDEX 17 | ) 18 | 19 | if(${CACHE_OPTION_INDEX} EQUAL -1) 20 | message(STATUS 21 | "Using custom compiler cache system: '${CACHE_OPTION}', explicitly supported entries are ${CACHE_OPTION_VALUES}" 22 | ) 23 | endif() 24 | 25 | find_program(CACHE_BINARY ${CACHE_OPTION}) 26 | if(CACHE_BINARY) 27 | message(STATUS "${CACHE_OPTION} found and enabled") 28 | set(CMAKE_CXX_COMPILER_LAUNCHER ${CACHE_BINARY}) 29 | else() 30 | message(WARNING "${CACHE_OPTION} is enabled but was not found. Not using it") 31 | endif() 32 | -------------------------------------------------------------------------------- /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/enableNcursesExample.cmake: -------------------------------------------------------------------------------- 1 | find_package(Curses) 2 | if(Curses_FOUND) 3 | include_directories(${CURSES_INCLUDE_DIR}) 4 | option(BUILD_NCURSES_EXAMPLE 5 | "Enable/Disable building the ncurses example (requires libncurses5-dev installed)" 6 | ON 7 | ) 8 | else() 9 | message(STATUS "libncurses5-dev not found. Skipping ncurses example") 10 | option(BUILD_NCURSES_EXAMPLE 11 | "Enable/Disable building the ncurses example (requires libncurses5-dev installed)" 12 | OFF 13 | ) 14 | endif() 15 | message(STATUS "BUILD_NCURSES_EXAMPLE set to ${BUILD_NCURSES_EXAMPLE}") 16 | -------------------------------------------------------------------------------- /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 RF24Mesh library 2 | ## in YOUR (Pico) 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 RF24Mesh library 10 | add_library(RF24Mesh INTERFACE) 11 | 12 | target_sources(RF24Mesh INTERFACE 13 | ${CMAKE_CURRENT_LIST_DIR}/../RF24Mesh.cpp 14 | ) 15 | 16 | target_include_directories(RF24Mesh INTERFACE 17 | ${CMAKE_CURRENT_LIST_DIR}/../ 18 | ) 19 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Please browse the docs from either http://nrf24.github.io/RF24Mesh or https://rf24mesh.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/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/general_usage.md: -------------------------------------------------------------------------------- 1 | # General Usage 2 | 3 | @tableofcontents 4 | 5 | ## Network Design Options 6 | 7 | 1. **Static Network** (No Mesh) 8 | 9 | RF24Network can be configured manually, with a static design. RF24Mesh is not used at all. See [Network addressing](http://nRF24.github.io/RF24Network/md_docs_2addressing.html) 10 | 2. **Static Network w/Dynamic Assignment** 11 | 12 | RF24Mesh is only used to acquire an address on startup. Nodes are generally expected to remain stationary. Changes to 13 | the network would be addressed manually, by adding, removing, or resetting nodes. Users can choose to use RF24Network functions directly, or use RF24Mesh. 14 | 3. **Dynamic Network & Assignment** 15 | 16 | Nodes join the mesh automatically and re-attach as required. This is the default and how the examples work. 17 | 4. **Hybrid Network** 18 | 19 | Utilizes a combination of static & dynamic nodes. Requires initial planning and deployment, but can result in a more stable network, easing 20 | the use of sleeping nodes. 21 | 22 | ## Network Management 23 | 24 | RF24Network addresses can be viewed as MAC addresses, and RF24Mesh nodeIDs 25 | viewed as static IP addresses. When joining or re-attaching to the network, 26 | nodes will request a RF24Network address, and are identified via nodeID. 27 | 28 | ### Raspberry Pi/Linux 29 | 30 | On Linux devices, the RF24Gateway will save address assignments to file 31 | (dhcplist.txt) so they will be restored, even if the gateway is restarted. 32 | To force network re-convergence, delete the dhcplist.txt file and restart the 33 | gateway. If nodes are configured to verify their connection at a set interval, 34 | they will come back online in time. 35 | 36 | ### Arduino/AVR 37 | 38 | On all other devices, the address list is not saved. To force network re-convergence, 39 | restart the gateway. If nodes are configured to verify their connection at a set 40 | interval, they will come back online in time. 41 | 42 | If a node/nodeID is removed from the network permanently, the address should be 43 | released prior to removal. If it is not, the assigned RF24Network address can be 44 | written to 0 in the RF24Mesh address list. 45 | 46 | ## Mesh Communication 47 | 48 | RF24Mesh nodeIDs are unique identifiers, while RF24Network addresses change 49 | dynamically within a statically defined structure. Due to this structure, it is 50 | simple for any node to communicate with the master node, since the RF24Network 51 | address is always known (00). Conversely, the master node maintains a list of 52 | every node on the network, so address 'lookups' return immediately. 53 | 54 | Communication from node-to-node requires address queries to be sent to the master 55 | node, since individual nodes may change RF24Network & radio address at any time. 56 | Due to the extra data transmissions, node-to-node communication is less efficient. 57 | 58 | ## Tricks of Trade 59 | 60 | One thing to keep in mind is the dynamic nature of RF24Mesh, and the need to 61 | verify connectivity to the network. For nodes that are constantly transmitting, 62 | (every few seconds at most) it is suitable to check the connection, and/or renew 63 | the address when connectivity fails. Since data is not saved by the master 64 | node, if the master node goes down, all child nodes must renew their address. 65 | In this case, as long as the master node is down for a few seconds, the nodes 66 | will all begin requesting an address. 67 | 68 | Nodes that are not actively transmitting, should be configured to test their 69 | connection at predefined intervals, to allow them to reconnect as necessary. 70 | 71 | In the case of sleeping nodes, or nodes that will only be online temporarily, 72 | it is generally suitable to release the address prior to going offline, and 73 | requesting an address upon waking. Keep in mind, address requests can generally 74 | take anywhere from 10 - 15ms, up to few seconds in most cases. 75 | 76 | One of the recently introduced features is the ability to transmit payloads without the network returning a network-ack response. If solely using this method 77 | of transmission, the node should also be configured to verify its connection via `RF24Mesh::checkConnection()` periodically, to ensure connectivity. 78 | 79 | ## RF24Network 80 | 81 | Beyond requesting and releasing addresses, usage is outlined in the RF24Mesh class documentation, and further information regarding RF24Network is available at 82 | [RF24Network documentation](http://nRF24.github.io/RF24Network). 83 | -------------------------------------------------------------------------------- /docs/images/Logo large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nRF24/RF24Mesh/525facce480eb44224e8b5d73ebde48bc146d668/docs/images/Logo large.png -------------------------------------------------------------------------------- /docs/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nRF24/RF24Mesh/525facce480eb44224e8b5d73ebde48bc146d668/docs/images/favicon.ico -------------------------------------------------------------------------------- /docs/main_page.md: -------------------------------------------------------------------------------- 1 | # Mesh Networking Layer for RF24 Radios 2 | 3 | @tableofcontents 4 | 5 | This class intends to provide a simple and seamless 'mesh' layer for sensor networks, 6 | allowing automatic and dynamic configuration that can be customized to suit many scenarios. 7 | It is currently designed to interface directly with with the 8 | [RF24Network library](http://nRF24.github.io/RF24Network), an 9 | [OSI Network Layer](http://en.wikipedia.org/wiki/Network_layer) using nRF24L01(+) or NRF52x radios 10 | driven by the [RF24 library](http://nRF24.github.io/RF24) or [nrf_to_nrf library](https://github.com/TMRh20/nrf_to_nrf). 11 | 12 | ## Purpose/Goals 13 | 14 | - Provide a simple user interface for creating dynamic sensor networks with the RF24 and RF24Network libraries. 15 | - Create stable, fully automated/self-managed networks 16 | 17 | ## News - 2023 API Changes 18 | 19 | Introducing **RF24Network & RF24Mesh v2.0** with some *significant API changes*, adding the use of [C++ Templates](https://cplusplus.com/doc/oldtutorial/templates/) 20 | in order to support a range of ESB enabled radios, most recently NRF52x radios. 21 | 22 | **Important Notes:** 23 | - Any network layer that uses v2 needs to have RF24Network/RF24Mesh dependencies of v2 or newer. RF24 v1.x is an exception here. 24 | - General usage should remain backward compatible, see the included examples of the related libraries for more info 25 | - Any third party libs that extend the network/mesh layer may also need to be updated to incorporate the new templated class prototypes: 26 | ```cpp 27 | template 28 | class ESBNetwork; 29 | 30 | template 31 | class ESBMesh; 32 | ``` 33 | - Third party libs should also be able to use the backward-compatible typedef in their template: 34 | - ESBGateway.h: 35 | ```cpp 36 | template 37 | class ESBGateway 38 | ``` 39 | and inform the compiler what types they intend to support: 40 | - ESBGateway.cpp: 41 | ```cpp 42 | template class ESBGateway; 43 | ``` 44 | - The auto installers do not perform a version check like package managers, so having the correct versions of the software is important. 45 | - 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. 46 | 47 | See a the list of changes on [the Github releases page](https://github.com/nRF24/RF24Mesh/releases/) 48 | 49 | ## RF24Mesh Overview 50 | 51 | The RF24Network library provides a system of addressing and routing for RF24 radio modules 52 | that allows large wireless sensor networks to be constructed. 53 | 54 | RF24Mesh provides extended features, including automatic addressing and dynamic configuration 55 | of wireless sensors. 56 | 57 | ### How does it work? 58 | 59 | Nodes are assigned a unique number ranging from 1 to 255, and just about everything else, addressing, routing, etc. is managed by the library. 60 | 61 | The unique identifier is like an IP address, used to communicate at a high level within the 62 | RF24 communication stack and will generally remain static. At the network layer, the physical 63 | radio addresses, similar to MAC addresses, are allocated as nodes move around and establish 64 | connections within the network. 65 | 66 | The 'master' node keeps track of the unique nodeIDs and the assigned RF24Network addresses. 67 | When a node is moved physically, or just loses its connection to the network, 68 | it can automatically re-join the mesh and reconfigure itself within the network. 69 | 70 | In the mesh configuration sensors/nodes can move around physically, far from the 'master 71 | node' using other nodes to route traffic over extended distances. Addressing and 72 | topology is reconfigured as connections are broken and re-established within different areas 73 | of the network. 74 | 75 | RF24Mesh takes advantage of functionality and features within the RF24 and RF24Network 76 | libraries, so everything from addressing, routing, fragmentation/re-assembly 77 | (very large payloads) are handled automatically with processes designed to support a 78 | multi-node radio network. 79 | 80 | ## How to learn more 81 | 82 | - Try it out! 83 | - [Setup and Configuration](setup_config.md) 84 | - [Usage & Overview](general_usage.md) 85 | - [RF24Mesh Class Documentation](classRF24Mesh.html) 86 | - [RF24 Network Class Documentation](http://nRF24.github.io/RF24Network/) 87 | - [RF24Ethernet: TCP/IP based Mesh over RF24](http://nRF24.github.io/RF24Ethernet/) 88 | - [RF24Gateway: A TCP/IP and RF24 Gateway for RF24 nodes](http://nRF24.github.io/RF24Gateway/) 89 | - [All Documentation and Downloads](https://tmrh20.github.io) 90 | - [Source Code](https://github.com/nRF24/RF24Mesh) 91 | -------------------------------------------------------------------------------- /docs/setup_config.md: -------------------------------------------------------------------------------- 1 | # Setup And Config 2 | 3 | @tableofcontents 4 | 5 | The initial testing version of RF24Mesh is built as a simple overlay for RF24Network. Users 6 | currently need to be familiar with the basics of sending and receiving data via 7 | RF24Network, but do not need to understand the topology, routing or addressing systems. 8 | RF24Mesh will attempt to construct and maintain a mesh network, keeping all nodes 9 | connected together. 10 | 11 | ## Requirements 12 | 13 | ### Hardware Requirements 14 | 15 | - 1 Raspberry Pi or Arduino to act as the Master Node 16 | - 1 or more Arduino, Raspberry Pi, etc. (Sensor Nodes) 17 | - 2 or more NRF24L01+ or the above with NRF52x radio modules 18 | - 1 or more various sensors for your sensor nodes 19 | 20 | ### Software Requirements 21 | 22 | - [Download RF24 Core Radio Library](https://github.com/TMRh20/RF24/archive/master.zip) 23 | - [Download RF24Network Library](https://github.com/TMRh20/RF24Network/archive/master.zip) 24 | - [Download RF24Mesh - Dynamic Mesh Library](https://github.com/TMRh20/RF24Mesh/archive/master.zip) 25 | 26 | ## Installation 27 | 28 | 1. Use the Arduino Library Manager. Selecting RF24Mesh should also install RF24Network and RF24 Core libraries 29 | 2. Configure and test the hardware using examples from RF24 and RF24Network prior to attempting to use RF24Mesh 30 | - In Arduino IDE 31 | - File > Examples > RF24 > GettingStarted 32 | @see [Arduino Support page](http://nRF24.github.io/RF24/md_docs_2arduino.html) 33 | - For a Raspberry Pi 34 | - An installer is provided: [Linux Installation](http://nRF24.github.io/RF24/md_docs_2linux__install.html) 35 | @see [General Linux/RPi setup and configuration page](http://nRF24.github.io/RF24/md_docs_2rpi__general.html) 36 | 3. Once testing is complete: 37 | - In Arduino IDE 38 | - File > Examples > RF24Mesh > RF24Mesh_Example 39 | - For a Raspberry Pi 40 | - Run `make` from the examples directory. Then `sudo ./RF24Mesh_Example_Master` to begin an example as the master node 41 | 4. Once configured and running, the Master Node will begin to assign addresses to the sensor nodes, which will find their way onto the network, and 42 | display incoming data from the sensor examples. Usage is very much the same as RF24Network, except for address assignment and network management. 43 | 44 | ## Configuration 45 | 46 | As per the examples, nodes are configured with a unique value between 1 and 253. This allows 47 | them to change positions on the network while still being identified. 48 | 49 | For pre-configuration of the mesh, some options are available by editing RF24Mesh_config.h 50 | prior to compiling: 51 | 52 | ### Restrict number of children 53 | 54 | ```cpp 55 | #define MESH_MAX_CHILDREN 4 56 | ``` 57 | 58 | The @ref MESH_MAX_CHILDREN option restricts the maximum number of child nodes/node and limits the number of available addresses on the network. Max: 4 59 | 60 | ### Reduce resource consumption 61 | 62 | ```cpp 63 | #define MESH_NOMASTER 64 | ``` 65 | 66 | The MESH_NOMASTER macro optionally reduces program space and memory usage. Can be used on any node except for the master (nodeID 0) 67 | 68 | @see [General Usage](general_usage.md) for information on how to work with the mesh once connected 69 | -------------------------------------------------------------------------------- /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/RF24Mesh_Example/RF24Mesh_Example.ino: -------------------------------------------------------------------------------- 1 | /** RF24Mesh_Example.ino by TMRh20 2 | 3 | This example sketch shows how to manually configure a node via RF24Mesh, and send data to the 4 | master node. 5 | The nodes will refresh their network address as soon as a single write fails. This allows the 6 | nodes to change position in relation to each other and the master node. 7 | */ 8 | 9 | 10 | #include "RF24.h" 11 | #include "RF24Network.h" 12 | #include "RF24Mesh.h" 13 | #include 14 | //#include 15 | 16 | 17 | /**** Configure the nrf24l01 CE and CS pins ****/ 18 | RF24 radio(7, 8); 19 | RF24Network network(radio); 20 | RF24Mesh mesh(radio, network); 21 | 22 | /* 23 | * User Configuration: nodeID - A unique identifier for each radio. Allows addressing 24 | * to change dynamically with physical changes to the mesh. 25 | * 26 | * In this example, configuration takes place below, prior to uploading the sketch to the device 27 | * A unique value from 1-255 must be configured for each node. 28 | */ 29 | #define nodeID 1 30 | 31 | 32 | uint32_t displayTimer = 0; 33 | 34 | struct payload_t { 35 | unsigned long ms; 36 | unsigned long counter; 37 | }; 38 | 39 | void setup() { 40 | 41 | Serial.begin(115200); 42 | while (!Serial) { 43 | // some boards need this because of native USB capability 44 | } 45 | 46 | // Set the nodeID manually 47 | mesh.setNodeID(nodeID); 48 | 49 | // Set the PA Level to MIN and disable LNA for testing & power supply related issues 50 | radio.begin(); 51 | radio.setPALevel(RF24_PA_MIN, 0); 52 | 53 | // Connect to the mesh 54 | Serial.println(F("Connecting to the mesh...")); 55 | if (!mesh.begin()) { 56 | if (radio.isChipConnected()) { 57 | do { 58 | // mesh.renewAddress() will return MESH_DEFAULT_ADDRESS on failure to connect 59 | Serial.println(F("Could not connect to network.\nConnecting to the mesh...")); 60 | } while (mesh.renewAddress() == MESH_DEFAULT_ADDRESS); 61 | } else { 62 | Serial.println(F("Radio hardware not responding.")); 63 | while (1) { 64 | // hold in an infinite loop 65 | } 66 | } 67 | } 68 | } 69 | 70 | 71 | 72 | void loop() { 73 | 74 | mesh.update(); 75 | 76 | // Send to the master node every second 77 | if (millis() - displayTimer >= 1000) { 78 | displayTimer = millis(); 79 | 80 | // Send an 'M' type message containing the current millis() 81 | if (!mesh.write(&displayTimer, 'M', sizeof(displayTimer))) { 82 | 83 | // If a write fails, check connectivity to the mesh network 84 | if (!mesh.checkConnection()) { 85 | //refresh the network address 86 | Serial.println("Renewing Address"); 87 | if (mesh.renewAddress() == MESH_DEFAULT_ADDRESS) { 88 | //If address renewal fails, reconfigure the radio and restart the mesh 89 | //This allows recovery from most if not all radio errors 90 | mesh.begin(); 91 | } 92 | } else { 93 | Serial.println("Send fail, Test OK"); 94 | } 95 | } else { 96 | Serial.print("Send OK: "); 97 | Serial.println(displayTimer); 98 | } 99 | } 100 | 101 | while (network.available()) { 102 | RF24NetworkHeader header; 103 | payload_t payload; 104 | network.read(header, &payload, sizeof(payload)); 105 | Serial.print("Received packet #"); 106 | Serial.print(payload.counter); 107 | Serial.print(" at "); 108 | Serial.println(payload.ms); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /examples/RF24Mesh_Example_Master/RF24Mesh_Example_Master.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** RF24Mesh_Example_Master.ino by TMRh20 4 | * 5 | * 6 | * This example sketch shows how to manually configure a node via RF24Mesh as a master node, which 7 | * will receive all data from sensor nodes. 8 | * 9 | * The nodes can change physical or logical position in the network, and reconnect through different 10 | * routing nodes as required. The master node manages the address assignments for the individual nodes 11 | * in a manner similar to DHCP. 12 | * 13 | */ 14 | 15 | 16 | #include "RF24Network.h" 17 | #include "RF24.h" 18 | #include "RF24Mesh.h" 19 | #include 20 | 21 | /***** Configure the chosen CE,CS pins *****/ 22 | RF24 radio(7, 8); 23 | RF24Network network(radio); 24 | RF24Mesh mesh(radio, network); 25 | 26 | uint32_t displayTimer = 0; 27 | 28 | void setup() { 29 | Serial.begin(115200); 30 | while (!Serial) { 31 | // some boards need this because of native USB capability 32 | } 33 | 34 | // Set the nodeID to 0 for the master node 35 | mesh.setNodeID(0); 36 | Serial.println(mesh.getNodeID()); 37 | 38 | // Set the PA Level to MIN and disable LNA for testing & power supply related issues 39 | radio.begin(); 40 | radio.setPALevel(RF24_PA_MIN, 0); 41 | 42 | // Connect to the mesh 43 | if (!mesh.begin()) { 44 | // if mesh.begin() returns false for a master node, then radio.begin() returned false. 45 | Serial.println(F("Radio hardware not responding.")); 46 | while (1) { 47 | // hold in an infinite loop 48 | } 49 | } 50 | } 51 | 52 | 53 | void loop() { 54 | 55 | // Call mesh.update to keep the network updated 56 | mesh.update(); 57 | 58 | // In addition, keep the 'DHCP service' running on the master node so addresses will 59 | // be assigned to the sensor nodes 60 | mesh.DHCP(); 61 | 62 | 63 | // Check for incoming data from the sensors 64 | if (network.available()) { 65 | RF24NetworkHeader header; 66 | network.peek(header); 67 | 68 | uint32_t dat = 0; 69 | switch (header.type) { 70 | // Display the incoming millis() values from the sensor nodes 71 | case 'M': 72 | network.read(header, &dat, sizeof(dat)); 73 | Serial.println(dat); 74 | break; 75 | default: 76 | network.read(header, 0, 0); 77 | Serial.println(header.type); 78 | break; 79 | } 80 | } 81 | 82 | if (millis() - displayTimer > 5000) { 83 | displayTimer = millis(); 84 | Serial.println(" "); 85 | Serial.println(F("********Assigned Addresses********")); 86 | for (int i = 0; i < mesh.addrListTop; i++) { 87 | Serial.print("NodeID: "); 88 | Serial.print(mesh.addrList[i].nodeID); 89 | Serial.print(" RF24Network Address: 0"); 90 | Serial.println(mesh.addrList[i].address, OCT); 91 | } 92 | Serial.println(F("**********************************")); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /examples/RF24Mesh_Example_Master_Statics/RF24Mesh_Example_Master_Statics.ino: -------------------------------------------------------------------------------- 1 | 2 | /** RF24Mesh_Example_Master.ino by TMRh20 3 | 4 | 5 | This example sketch shows how to manually configure a node via RF24Mesh as a master node, which 6 | will receive all data from sensor nodes. In addition, this sketch demonstrates how to reserve 7 | addresses for static nodes, that will not be using RF24Mesh, or are not using the dynamic addressing 8 | functionality of RF24Mesh. 9 | 10 | The nodes can change physical or logical position in the network, and reconnect through different 11 | routing nodes as required. The master node manages the address assignments for the individual nodes 12 | in a manner similar to DHCP. 13 | 14 | **/ 15 | 16 | 17 | #include "RF24Network.h" 18 | #include "RF24.h" 19 | #include "RF24Mesh.h" 20 | #include 21 | 22 | /***** Configure the chosen CE,CS pins *****/ 23 | RF24 radio(7, 8); 24 | RF24Network network(radio); 25 | RF24Mesh mesh(radio, network); 26 | 27 | 28 | void setup() { 29 | Serial.begin(115200); 30 | while (!Serial) { 31 | // some boards need this because of native USB capability 32 | } 33 | 34 | // Set the nodeID to 0 for the master node 35 | mesh.setNodeID(0); 36 | Serial.println(mesh.getNodeID()); 37 | // Connect to the mesh 38 | if (!mesh.begin()) { 39 | // if mesh.begin() returns false for a master node, then radio.begin() returned false. 40 | Serial.println(F("Radio hardware not responding.")); 41 | while (1) { 42 | // hold in an infinite loop 43 | } 44 | } 45 | 46 | // In this case, assign a static address to nodeIDs 23,24 at RF24Network address 02 && 03 47 | // This will prevent this master node from assigning the address to another node 48 | // This allows a set of static nodes to remain in place as routing nodes, while 49 | // other nodes can move around physically, using the static nodes to join or re-join 50 | // the network. 51 | // With this example, assign nodes 02 and 03 statically. This allows child nodes to join 52 | // the network as children of 00(master), node 02, or node 03, or as children of other 53 | // mesh nodes. If nodes 02 and 03 are placed in proximity to a group of mesh nodes, the 54 | // mesh nodes can attatch to the network via the static nodes, and route traffic through 55 | // either node, to the master node. 56 | mesh.setStaticAddress(23, 02); 57 | mesh.setStaticAddress(24, 03); 58 | } 59 | 60 | uint32_t displayTimer = 0; 61 | 62 | void loop() { 63 | 64 | // Call mesh.update to keep the network updated 65 | mesh.update(); 66 | 67 | // In addition, keep the 'DHCP service' running on the master node so addresses will 68 | // be assigned to the sensor nodes 69 | mesh.DHCP(); 70 | 71 | 72 | // Check for incoming data from the sensors 73 | if (network.available()) { 74 | RF24NetworkHeader header; 75 | network.peek(header); 76 | Serial.print("Got "); 77 | uint32_t dat = 0; 78 | switch (header.type) { 79 | // Display the incoming millis() values from the sensor nodes 80 | case 'M': 81 | network.read(header, &dat, sizeof(dat)); 82 | Serial.print(dat); 83 | Serial.print(" from RF24Network address 0"); 84 | Serial.println(header.from_node, OCT); 85 | break; 86 | default: 87 | network.read(header, 0, 0); 88 | Serial.println(header.type); 89 | break; 90 | } 91 | } 92 | 93 | // Display the currently assigned addresses and nodeIDs 94 | if (millis() - displayTimer > 5000) { 95 | displayTimer = millis(); 96 | Serial.println(" "); 97 | Serial.println(F("********Assigned Addresses********")); 98 | for (int i = 0; i < mesh.addrListTop; i++) { 99 | Serial.print("NodeID: "); 100 | Serial.print(mesh.addrList[i].nodeID); 101 | Serial.print(" RF24Network Address: 0"); 102 | Serial.println(mesh.addrList[i].address, OCT); 103 | } 104 | Serial.println(F("**********************************")); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /examples/RF24Mesh_Example_Master_To_Nodes/RF24Mesh_Example_Master_To_Nodes.ino: -------------------------------------------------------------------------------- 1 | /** Modification of RF24Mesh_Example_Master.ino by TMRh20 and RF24Mesh_Example_Master_Statics by TMRh20 2 | 3 | 4 | This example sketch shows how to send data to nodes bassed on their ID. 5 | 6 | The nodes can change physical or logical position in the network, and reconnect through different 7 | routing nodes as required. The master node manages the address assignments for the individual nodes 8 | in a manner similar to DHCP. 9 | 10 | **/ 11 | 12 | 13 | #include "RF24Network.h" 14 | #include "RF24.h" 15 | #include "RF24Mesh.h" 16 | #include 17 | 18 | /***** Configure the chosen CE,CS pins *****/ 19 | RF24 radio(7, 8); 20 | RF24Network network(radio); 21 | RF24Mesh mesh(radio, network); 22 | 23 | struct payload_t { 24 | unsigned long ms; 25 | unsigned long counter; 26 | }; 27 | 28 | uint32_t ctr = 0; 29 | 30 | 31 | 32 | void setup() { 33 | Serial.begin(115200); 34 | while (!Serial) { 35 | // some boards need this because of native USB capability 36 | } 37 | 38 | // Set the nodeID to 0 for the master node 39 | mesh.setNodeID(0); 40 | Serial.println(mesh.getNodeID()); 41 | // Connect to the mesh 42 | if (!mesh.begin()) { 43 | // if mesh.begin() returns false for a master node, then radio.begin() returned false. 44 | Serial.println(F("Radio hardware not responding.")); 45 | while (1) { 46 | // hold in an infinite loop 47 | } 48 | } 49 | } 50 | 51 | uint32_t displayTimer = 0; 52 | 53 | void loop() { 54 | 55 | // Call mesh.update to keep the network updated 56 | mesh.update(); 57 | 58 | // In addition, keep the 'DHCP service' running on the master node so addresses will 59 | // be assigned to the sensor nodes 60 | mesh.DHCP(); 61 | 62 | 63 | // Check for incoming data from the sensors 64 | if (network.available()) { 65 | RF24NetworkHeader header; 66 | network.peek(header); 67 | Serial.print("Got "); 68 | uint32_t dat = 0; 69 | switch (header.type) { 70 | // Display the incoming millis() values from the sensor nodes 71 | case 'M': 72 | network.read(header, &dat, sizeof(dat)); 73 | Serial.print(dat); 74 | Serial.print(" from RF24Network address 0"); 75 | Serial.println(header.from_node, OCT); 76 | break; 77 | default: 78 | network.read(header, 0, 0); 79 | Serial.println(header.type); 80 | break; 81 | } 82 | } 83 | 84 | 85 | // Send each node a message every five seconds 86 | // Send a different message to node 1, containing another counter instead of millis() 87 | if (millis() - displayTimer > 5000) { 88 | ctr++; 89 | for (int i = 0; i < mesh.addrListTop; i++) { 90 | payload_t payload = { millis(), ctr }; 91 | if (mesh.addrList[i].nodeID == 1) { //Searching for node one from address list 92 | payload = { ctr % 3, ctr }; 93 | } 94 | RF24NetworkHeader header(mesh.addrList[i].address, OCT); //Constructing a header 95 | Serial.println(network.write(header, &payload, sizeof(payload)) == 1 ? F("Send OK") : F("Send Fail")); //Sending an message 96 | } 97 | displayTimer = millis(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /examples/RF24Mesh_Example_Node2Node/RF24Mesh_Example_Node2Node.ino: -------------------------------------------------------------------------------- 1 | 2 | /** RF24Mesh_Example_Node2NodeExtra.ino by TMRh20 3 | * 4 | * This example sketch shows how to communicate between two (non-master) nodes using 5 | * RF24Mesh & RF24Network 6 | */ 7 | 8 | 9 | #include "RF24.h" 10 | #include "RF24Network.h" 11 | #include "RF24Mesh.h" 12 | #include 13 | //#include 14 | 15 | 16 | /**** Configure the nrf24l01 CE and CS pins ****/ 17 | RF24 radio(7, 8); 18 | RF24Network network(radio); 19 | RF24Mesh mesh(radio, network); 20 | 21 | /** 22 | * User Configuration: 23 | * nodeID - A unique identifier for each radio. Allows addressing to change dynamically 24 | * with physical changes to the mesh. (numbers 1-255 allowed) 25 | * 26 | * otherNodeID - A unique identifier for the 'other' radio 27 | * 28 | **/ 29 | #define nodeID 1 30 | #define otherNodeID 2 31 | 32 | 33 | uint32_t millisTimer = 0; 34 | 35 | void setup() { 36 | 37 | Serial.begin(115200); 38 | while (!Serial) { 39 | // some boards need this because of native USB capability 40 | } 41 | 42 | // Set the nodeID 43 | mesh.setNodeID(nodeID); 44 | 45 | // Connect to the mesh 46 | Serial.println(F("Connecting to the mesh...")); 47 | if (!mesh.begin()) { 48 | if (radio.isChipConnected()) { 49 | do { 50 | // mesh.renewAddress() will return MESH_DEFAULT_ADDRESS on failure to connect 51 | Serial.println(F("Could not connect to network.\nConnecting to the mesh...")); 52 | } while (mesh.renewAddress() == MESH_DEFAULT_ADDRESS); 53 | } else { 54 | Serial.println(F("Radio hardware not responding.")); 55 | while (1) { 56 | // hold in an infinite loop 57 | } 58 | } 59 | } 60 | } 61 | 62 | 63 | void loop() { 64 | 65 | mesh.update(); 66 | 67 | if (network.available()) { 68 | RF24NetworkHeader header; 69 | uint32_t mills; 70 | network.read(header, &mills, sizeof(mills)); 71 | Serial.print(F("Rcv ")); 72 | Serial.print(mills); 73 | Serial.print(F(" from nodeID ")); 74 | int _ID = mesh.getNodeID(header.from_node); 75 | if (_ID > 0) { 76 | Serial.println(_ID); 77 | } else { 78 | Serial.println(F("Mesh ID Lookup Failed")); 79 | } 80 | } 81 | 82 | 83 | // Send to the other node every second 84 | if (millis() - millisTimer >= 1000) { 85 | millisTimer = millis(); 86 | 87 | // Send an 'M' type to other Node containing the current millis() 88 | if (!mesh.write(&millisTimer, 'M', sizeof(millisTimer), otherNodeID)) { 89 | if (!mesh.checkConnection()) { 90 | do { 91 | Serial.println(F("Reconnecting to mesh network...")); 92 | } while (mesh.renewAddress() == MESH_DEFAULT_ADDRESS); 93 | } else { 94 | Serial.println(F("Send fail, Test OK")); 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /examples/RF24Mesh_Example_Node2NodeExtra/RF24Mesh_Example_Node2NodeExtra.ino: -------------------------------------------------------------------------------- 1 | 2 | /** RF24Mesh_Example_Node2Node.ino by TMRh20 3 | * 4 | * This example sketch shows how to communicate between two (non-master) nodes using 5 | * RF24Mesh & RF24Network 6 | **/ 7 | 8 | 9 | #include "RF24.h" 10 | #include "RF24Network.h" 11 | #include "RF24Mesh.h" 12 | #include 13 | //#include 14 | 15 | 16 | //########### USER CONFIG ########### 17 | 18 | /**** Configure the nrf24l01 CE and CS pins ****/ 19 | RF24 radio(7, 8); 20 | RF24Network network(radio); 21 | RF24Mesh mesh(radio, network); 22 | 23 | /** 24 | * User Configuration: 25 | * nodeID - A unique identifier for each radio. Allows addressing to change dynamically 26 | * with physical changes to the mesh. (numbers 1-255 allowed) 27 | * 28 | * otherNodeID - A unique identifier for the 'other' radio 29 | * 30 | **/ 31 | #define nodeID 3 32 | #define otherNodeID 2 33 | 34 | //################################# 35 | 36 | uint32_t millisTimer = 0; 37 | uint32_t stringTimer = 0; 38 | char dataStr[] = { "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" }; 39 | char tmpStr[sizeof(dataStr) + 1]; 40 | uint8_t strCtr = 1; 41 | 42 | uint32_t delayTime = 120; 43 | 44 | void setup() { 45 | 46 | Serial.begin(115200); 47 | while (!Serial) { 48 | // some boards need this because of native USB capability 49 | } 50 | 51 | // Set the nodeID manually 52 | mesh.setNodeID(nodeID); 53 | 54 | // Connect to the mesh 55 | Serial.println(F("Connecting to the mesh...")); 56 | if (!mesh.begin()) { 57 | if (radio.isChipConnected()) { 58 | while (mesh.renewAddress() == MESH_DEFAULT_ADDRESS) { 59 | // mesh.renewAddress() will return MESH_DEFAULT_ADDRESS on failure to connect 60 | Serial.println(F("Connecting to the mesh...")); 61 | } 62 | } else { 63 | Serial.println(F("Radio hardware not responding.")); 64 | while (1) { 65 | // hold in an infinite loop 66 | } 67 | } 68 | } 69 | } 70 | 71 | unsigned int sizeCtr = 2; 72 | 73 | uint32_t errorCount = 0; 74 | uint32_t duplicates = 0; 75 | uint32_t totalData = 0; 76 | 77 | void loop() { 78 | 79 | mesh.update(); 80 | 81 | while (network.available()) { 82 | RF24NetworkHeader hdr; 83 | size_t dataSize = network.peek(hdr); 84 | totalData += dataSize; 85 | 86 | if (hdr.type == 'S') { 87 | if (dataSize != sizeCtr) { 88 | if (dataSize == sizeCtr + 1) { 89 | duplicates++; 90 | } 91 | sizeCtr = dataSize + 1; 92 | errorCount++; 93 | } else { 94 | sizeCtr++; 95 | if (sizeCtr > sizeof(dataStr)) { 96 | sizeCtr = 2; 97 | } 98 | //if(sizeCtr > 12){ sizeCtr = 2; } 99 | } 100 | network.read(hdr, &tmpStr, dataSize); 101 | //Serial.println(tmpStr); 102 | } else if (hdr.type == 'M') { 103 | uint32_t mills; 104 | network.read(hdr, &mills, sizeof(mills)); 105 | Serial.print(F("Received ")); 106 | Serial.print(mills); 107 | int _ID = 0; 108 | _ID = mesh.getNodeID(hdr.from_node); 109 | if (_ID > 0) { 110 | if (_ID == nodeID) { 111 | Serial.println(F(" from master.")); 112 | } else { 113 | Serial.print(F(" from node(ID) ")); 114 | Serial.print(_ID); 115 | Serial.println('.'); 116 | } 117 | } else { 118 | Serial.println(F("Mesh ID Lookup Failed")); 119 | } 120 | Serial.print(F("Total Data Received: ")); 121 | Serial.print(totalData); 122 | Serial.println(" bytes"); 123 | Serial.print(F("Detected Errors in data received (Including Duplicates): ")); 124 | Serial.println(errorCount); 125 | Serial.print(F("Duplicates: ")); 126 | Serial.println(duplicates); 127 | Serial.println(F("-------------------------------------")); 128 | } 129 | } 130 | 131 | 132 | // Send to the master node every second 133 | if (millis() - millisTimer >= 1000) { 134 | millisTimer = millis(); 135 | 136 | // Send an 'M' type to other Node containing the current millis() 137 | if (!mesh.write(&millisTimer, 'M', sizeof(millisTimer), otherNodeID)) { 138 | Serial.println(F("Send fail")); 139 | if (!mesh.checkConnection()) { 140 | do { 141 | Serial.println(F("Reconnecting to mesh network...")); 142 | } while (mesh.renewAddress() == MESH_DEFAULT_ADDRESS); 143 | } else { 144 | Serial.println(F("Send fail, Test OK")); 145 | } 146 | } else { 147 | Serial.print(F("Send OK: ")); 148 | Serial.println(millisTimer); 149 | } 150 | } 151 | 152 | if (millis() - stringTimer >= delayTime) { 153 | stringTimer = millis(); 154 | //Copy the current number of characters to the temporary array 155 | memcpy(tmpStr, dataStr, strCtr); 156 | //Set the last character to NULL 157 | tmpStr[strCtr] = '\0'; 158 | 159 | // Send the temp string as an 'S' type message 160 | // Send it to otherNodeID (An RF24Mesh address lookup will be performed) 161 | //bool ok = mesh.write(tmpStr,'S',strCtr+1,otherNodeID); 162 | if (mesh.write(tmpStr, 'S', strCtr + 1, otherNodeID)) { 163 | strCtr++; 164 | delayTime = 333; 165 | //Set the sending length back to 1 once max size is reached 166 | if (strCtr == sizeof(dataStr)) { 167 | strCtr = 1; 168 | } 169 | //if(strCtr == 12){ strCtr=1; } 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /examples/RF24Mesh_SerialConfig/RF24Mesh_SerialConfig.ino: -------------------------------------------------------------------------------- 1 | 2 | /** RF24Mesh_SerialConfig.ino by TMRh20 3 | 4 | This example sketch shows how the same sketch can be written to a large number of devices, which are 5 | configured later via Serial input. 6 | 7 | **/ 8 | 9 | #include "RF24Network.h" 10 | #include "RF24.h" 11 | #include "RF24Mesh.h" 12 | #include 13 | #include 14 | 15 | /** Configure the nrf24l01 CE and CS pins */ 16 | RF24 radio(7, 8); 17 | RF24Network network(radio); 18 | RF24Mesh mesh(radio, network); 19 | 20 | /** 21 | User Configuration: NodeID - A unique identifier for each radio. Allows addressing 22 | to change dynamically with physical changes to the mesh. 23 | 24 | In this example, user configuration of the node takes place via Serial input. 25 | Input a unique decimal value from 1-255 OR simply use characters 0-9, a-z, A-Z etc. 26 | The nodeID will be set/changed and saved in EEPROM upon user input via Serial, and stored 27 | between power loss, etc. Configuration only needs to be done once. 28 | 29 | **/ 30 | 31 | 32 | void setup() { 33 | 34 | Serial.begin(115200); 35 | while (!Serial) { 36 | // some boards need this because of native USB capability 37 | } 38 | 39 | // If this is a new node, the nodeID will return 0. Once the node is configured with an ID other than 0, this 40 | // bit will no longer run. 41 | while (!mesh.getNodeID()) { 42 | // Wait for the nodeID to be set via Serial 43 | if (Serial.available()) { 44 | mesh.setNodeID(Serial.read()); 45 | Serial.print("Set NodeID: "); 46 | Serial.println(mesh.getNodeID()); 47 | } 48 | } 49 | 50 | // Now that this node has a unique ID, connect to the mesh 51 | Serial.println(F("Connecting to the mesh...")); 52 | if (!mesh.begin()) { 53 | if (radio.isChipConnected()) { 54 | do { 55 | // mesh.renewAddress() will return MESH_DEFAULT_ADDRESS on failure to connect 56 | Serial.println(F("Could not connect to network.\nConnecting to the mesh...")); 57 | } while (mesh.renewAddress() == MESH_DEFAULT_ADDRESS); 58 | } else { 59 | Serial.println(F("Radio hardware not responding.")); 60 | while (1) { 61 | // hold in an infinite loop 62 | } 63 | } 64 | } 65 | } 66 | 67 | unsigned long displayTimer = 0; 68 | 69 | void loop() { 70 | 71 | mesh.update(); 72 | 73 | // Send an update in every second 74 | if (millis() - displayTimer >= 1000) { 75 | displayTimer = millis(); 76 | // Send the current millis() value to the master node as an 'M' type message 77 | mesh.write(&displayTimer, 'M', sizeof(displayTimer)); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /examples_RPi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | project(RF24LogExamples) 4 | add_compile_options(-Ofast -Wall) # passing the compiler a `-pthread` flag doesn't work here 5 | 6 | # detect the CPU make and type 7 | include(../cmake/detectCPU.cmake) # sets the variable SOC accordingly 8 | 9 | # detect if any additional libs need be linked to executable (ei RF24_DRIVER) 10 | include(../cmake/AutoConfig_RF24_DRIVER.cmake) 11 | 12 | find_library(RF24 rf24 REQUIRED) 13 | message(STATUS "using RF24 library: ${RF24}") 14 | 15 | find_library(RF24Network rf24network REQUIRED) 16 | message(STATUS "using RF24Network library: ${RF24Network}") 17 | 18 | find_library(RF24Mesh rf24mesh REQUIRED) 19 | message(STATUS "using RF24Mesh library: ${RF24Mesh}") 20 | 21 | 22 | # iterate over a list of examples by filename 23 | set(EXAMPLES_LIST 24 | RF24Mesh_Example 25 | RF24Mesh_Example_Master 26 | ) 27 | 28 | set(linked_libs 29 | ${RF24} 30 | pthread # Notice we specify pthread as a linked lib here 31 | ${RF24Network} 32 | ${RF24Mesh} 33 | ) 34 | 35 | # append additional libs for linking to the executable 36 | if("${RF24_DRIVER}" STREQUAL "MRAA") 37 | if(NOT "${LibMRAA}" STREQUAL "LibMRAA-NOTFOUND") 38 | message(STATUS "linking to ${LibMRAA}") 39 | list(APPEND linked_libs ${LibMRAA}) 40 | else() 41 | message(FATAL "Lib ${RF24_DRIVER} not found.") 42 | endif() 43 | elseif("${RF24_DRIVER}" STREQUAL "wiringPi") 44 | if(NOT "${LibWiringPi}" STREQUAL "LibWiringPi-NOTFOUND") 45 | message(STATUS "linking to ${LibWiringPi}") 46 | list(APPEND linked_libs ${LibWiringPi}) 47 | else() 48 | message(FATAL "Lib ${RF24_DRIVER} not found.") 49 | endif() 50 | elseif("${RF24_DRIVER}" STREQUAL "pigpio") 51 | if(NOT "${LibPIGPIO}" STREQUAL "LibPIGPIO-NOTFOUND") 52 | message(STATUS "linking to ${LibPIGPIO}") 53 | list(APPEND linked_libs ${LibPIGPIO}) 54 | else() 55 | message(FATAL "Lib ${RF24_DRIVER} not found.") 56 | endif() 57 | endif() 58 | 59 | foreach(example ${EXAMPLES_LIST}) 60 | # make a target 61 | add_executable(${example} ${example}.cpp) 62 | # link the RF24 lib to the target. 63 | target_link_libraries(${example} PUBLIC ${linked_libs}) 64 | endforeach() 65 | 66 | include(../cmake/enableNcursesExample.cmake) 67 | if(BUILD_NCURSES_EXAMPLE) 68 | add_subdirectory(ncurses) 69 | endif() 70 | -------------------------------------------------------------------------------- /examples_RPi/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # 3 | # Makefile for librf24mesh examples on Raspberry Pi 4 | # 5 | # By: TMRh20 6 | # Date: 2013/09 7 | # 8 | # Description: 9 | # ------------ 10 | # use make all and make install to install the examples 11 | # You can change the install directory by editing the prefix line 12 | # 13 | prefix := /usr/local 14 | 15 | # Which compiler to use 16 | CC=g++ 17 | 18 | ARCH=armv6zk 19 | ifeq "$(shell uname -m)" "armv7l" 20 | ARCH=armv7-a 21 | endif 22 | 23 | # Detect the Raspberry Pi from cpuinfo 24 | #Count the matches for BCM2708 or BCM2709 in cpuinfo 25 | RPI=$(shell cat /proc/cpuinfo | grep Hardware | grep -c BCM2708) 26 | ifneq "${RPI}" "1" 27 | RPI=$(shell cat /proc/cpuinfo | grep Hardware | grep -c BCM2709) 28 | endif 29 | 30 | ifeq "$(RPI)" "1" 31 | # The recommended compiler flags for the Raspberry Pi 32 | CCFLAGS=-Ofast -mfpu=vfp -mfloat-abi=hard -march=$(ARCH) -mtune=arm1176jzf-s -std=c++0x 33 | endif 34 | 35 | # define all programs 36 | PROGRAMS = RF24Mesh_Example_Master RF24Mesh_Example 37 | SOURCES = ${PROGRAMS:=.cpp} 38 | 39 | all: ${PROGRAMS} 40 | 41 | ${PROGRAMS}: ${SOURCES} 42 | mkdir -p bin 43 | $(CC) ${CCFLAGS} -Wall -I../ $@.cpp -lrf24-bcm -lrf24network -lrf24mesh -o bin/$@ 44 | 45 | clean: 46 | rm -rf $(PROGRAMS) 47 | 48 | install: all 49 | test -d $(prefix) || mkdir $(prefix) 50 | test -d $(prefix)/bin || mkdir $(prefix)/bin 51 | for prog in $(PROGRAMS); do \ 52 | install -m 0755 $$prog $(prefix)/bin; \ 53 | done 54 | 55 | .PHONY: install 56 | -------------------------------------------------------------------------------- /examples_RPi/RF24Mesh_Example.cpp: -------------------------------------------------------------------------------- 1 | /** RF24Mesh_Example.cpp by TMRh20 2 | * 3 | * Note: This sketch only functions on -RPi- 4 | * 5 | * This example sketch shows how to manually configure a node via RF24Mesh, and send data to the 6 | * master node. 7 | * In this sketch, the nodes will refresh their network address as soon as a single write fails. This allows the 8 | * nodes to change position in relation to each other and the master node. 9 | * 10 | */ 11 | #include "RF24Mesh/RF24Mesh.h" 12 | #include 13 | #include 14 | 15 | RF24 radio(22, 0); 16 | RF24Network network(radio); 17 | RF24Mesh mesh(radio, network); 18 | 19 | uint32_t displayTimer = 0; 20 | 21 | int main(int argc, char** argv) 22 | { 23 | 24 | // Set the nodeID to 0 for the master node 25 | mesh.setNodeID(4); 26 | 27 | // Set the PA Level to MIN and disable LNA for testing & power supply related issues 28 | radio.begin(); 29 | radio.setPALevel(RF24_PA_MIN, 0); 30 | 31 | // Connect to the mesh 32 | printf("start nodeID %d\n", mesh.getNodeID()); 33 | if (!mesh.begin()) { 34 | if (radio.isChipConnected()) { 35 | do { 36 | // mesh.renewAddress() will return MESH_DEFAULT_ADDRESS on failure to connect 37 | printf("Could not connect to network.\nConnecting to the mesh...\n"); 38 | } while (mesh.renewAddress() == MESH_DEFAULT_ADDRESS); 39 | } 40 | else { 41 | printf("Radio hardware not responding.\n"); 42 | return 0; 43 | } 44 | } 45 | radio.printDetails(); 46 | 47 | while (1) 48 | { 49 | // Call mesh.update to keep the network updated 50 | mesh.update(); 51 | 52 | // Send the current millis() to the master node every second 53 | if (millis() - displayTimer >= 1000) 54 | { 55 | displayTimer = millis(); 56 | 57 | if (!mesh.write(&displayTimer, 'M', sizeof(displayTimer))) 58 | { 59 | // If a write fails, check connectivity to the mesh network 60 | if (!mesh.checkConnection()) 61 | { 62 | // The address could be refreshed per a specified timeframe or only when sequential writes fail, etc. 63 | printf("Renewing Address\n"); 64 | mesh.renewAddress(); 65 | } 66 | else 67 | { 68 | printf("Send fail, Test OK\n"); 69 | } 70 | } 71 | else 72 | { 73 | printf("Send OK: %u\n", displayTimer); 74 | } 75 | } 76 | delay(1); 77 | } 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /examples_RPi/RF24Mesh_Example.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simplest RF24Mesh example that transmits a time stamp (in milliseconds) 1 per second. 3 | """ 4 | import sys 5 | import time 6 | import struct 7 | from RF24 import RF24, RF24_PA_MIN 8 | from RF24Network import RF24Network 9 | from RF24Mesh import RF24Mesh 10 | 11 | start = time.monotonic() 12 | 13 | 14 | def millis(): 15 | """:Returns: Delta time since started example in milliseconds. Wraps value around 16 | the width of a ``long`` integer.""" 17 | return int((time.monotonic() - start) * 1000) % (2**32) 18 | 19 | 20 | # radio setup for RPi B Rev2: CS0=Pin 24 21 | radio = RF24(22, 0) 22 | network = RF24Network(radio) 23 | mesh = RF24Mesh(radio, network) 24 | 25 | mesh.setNodeID(4) 26 | 27 | # Set the PA Level to MIN and disable LNA for testing & power supply related issues 28 | radio.begin() 29 | radio.setPALevel(RF24_PA_MIN, 0) 30 | 31 | print("starting nodeID", mesh.getNodeID()) 32 | if not mesh.begin(): 33 | if radio.isChipConnected(): 34 | try: 35 | print("Could not connect to network.\nConnecting to mesh...") 36 | while mesh.renewAddress() == 0o4444: 37 | print("Could not connect to network.\nConnecting to mesh...") 38 | except KeyboardInterrupt: 39 | radio.powerDown() 40 | sys.exit() 41 | else: 42 | raise OSError("Radio hardware not responding or could not connect to mesh.") 43 | radio.printDetails() 44 | 45 | TIMER = 0 46 | 47 | try: 48 | while True: 49 | # Call mesh.update to keep the network updated 50 | mesh.update() 51 | 52 | if (millis() - TIMER) >= 1000: 53 | TIMER = millis() 54 | 55 | if not mesh.write(struct.pack("L", TIMER), ord("M")): 56 | # If a write fails, check connectivity to the mesh network 57 | if not mesh.checkConnection(): 58 | # The address could be refreshed per a specified time frame 59 | # or only when sequential writes fail, etc. 60 | print("Send fail. Renewing Address...") 61 | while mesh.renewAddress() == 0o4444: 62 | print("Renewing Address...") 63 | else: 64 | print("Send fail, Test OK") 65 | else: 66 | print("Send OK:", TIMER) 67 | time.sleep(0.001) # delay 1 ms 68 | except KeyboardInterrupt: 69 | print("powering down radio and exiting.") 70 | radio.powerDown() 71 | -------------------------------------------------------------------------------- /examples_RPi/RF24Mesh_Example_Master.cpp: -------------------------------------------------------------------------------- 1 | /** RF24Mesh_Example_Master.ino by TMRh20 2 | * 3 | * Note: This sketch only functions on -Arduino Due- 4 | * 5 | * This example sketch shows how to manually configure a node via RF24Mesh as a master node, which 6 | * will receive all data from sensor nodes. 7 | * 8 | * The nodes can change physical or logical position in the network, and reconnect through different 9 | * routing nodes as required. The master node manages the address assignments for the individual nodes 10 | * in a manner similar to DHCP. 11 | * 12 | */ 13 | #include "RF24Mesh/RF24Mesh.h" 14 | #include 15 | #include 16 | 17 | RF24 radio(22, 0); 18 | RF24Network network(radio); 19 | RF24Mesh mesh(radio, network); 20 | 21 | int main(int argc, char** argv) 22 | { 23 | // Set the nodeID to 0 for the master node 24 | mesh.setNodeID(0); 25 | 26 | // Set the PA Level to MIN and disable LNA for testing & power supply related issues 27 | radio.begin(); 28 | radio.setPALevel(RF24_PA_MIN, 0); 29 | 30 | // Connect to the mesh 31 | printf("start\n"); 32 | if (!mesh.begin()) { 33 | // if mesh.begin() returns false for a master node, then radio.begin() returned false. 34 | printf("Radio hardware not responding.\n"); 35 | return 0; 36 | } 37 | radio.printDetails(); 38 | 39 | while (1) 40 | { 41 | // Call network.update as usual to keep the network updated 42 | mesh.update(); 43 | 44 | // In addition, keep the 'DHCP service' running on the master node so addresses will 45 | // be assigned to the sensor nodes 46 | mesh.DHCP(); 47 | 48 | // Check for incoming data from the sensors 49 | while (network.available()) 50 | { 51 | // printf("rcv\n"); 52 | RF24NetworkHeader header; 53 | network.peek(header); 54 | 55 | uint32_t dat = 0; 56 | switch (header.type) 57 | { // Display the incoming millis() values from the sensor nodes 58 | case 'M': 59 | network.read(header, &dat, sizeof(dat)); 60 | printf("Rcv %u from 0%o\n", dat, header.from_node); 61 | break; 62 | default: 63 | network.read(header, 0, 0); 64 | printf("Rcv bad type %d from 0%o\n", header.type, header.from_node); 65 | break; 66 | } 67 | } 68 | delay(2); 69 | } 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /examples_RPi/RF24Mesh_Example_Master.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example of using the rf24_mesh module to operate the nRF24L01 transceiver as 3 | a Mesh network master node. 4 | """ 5 | import struct 6 | from RF24 import RF24, RF24_PA_MIN 7 | from RF24Network import RF24Network 8 | from RF24Mesh import RF24Mesh 9 | 10 | 11 | # radio setup for RPi B Rev2: CS0=Pin 24 12 | radio = RF24(22, 0) 13 | network = RF24Network(radio) 14 | mesh = RF24Mesh(radio, network) 15 | mesh.setNodeID(0) 16 | 17 | # Set the PA Level to MIN and disable LNA for testing & power supply related issues 18 | radio.begin() 19 | radio.setPALevel(RF24_PA_MIN, 0) 20 | 21 | if not mesh.begin(): 22 | # if mesh.begin() returns false for a master node, 23 | # then radio.begin() returned false. 24 | raise OSError("Radio hardware not responding.") 25 | radio.printDetails() 26 | 27 | try: 28 | while True: 29 | mesh.update() 30 | mesh.DHCP() 31 | 32 | while network.available(): 33 | header, payload = network.read(struct.calcsize("L")) 34 | print(f"Received message {header.toString()}") 35 | except KeyboardInterrupt: 36 | print("powering down radio and exiting.") 37 | radio.powerDown() 38 | -------------------------------------------------------------------------------- /examples_RPi/ncurses/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # this example needs the ncurses package installed 2 | find_package(Curses REQUIRED) 3 | include_directories(${CURSES_INCLUDE_DIR}) 4 | 5 | set(example RF24Mesh_Ncurses_Master) 6 | 7 | # make a target 8 | add_executable(${example} ${example}.cpp) 9 | 10 | # link the RF24 lib to the target. Notice we specify pthread as a linked lib here 11 | target_link_libraries(${example} PUBLIC 12 | ${linked_libs} 13 | ${CURSES_LIBRARIES} 14 | ) 15 | if("${LibPIGPIO}" STREQUAL "LibPIGPIO-NOTFOUND" OR DEFINED RF24_NO_INTERRUPT) 16 | target_compile_definitions(${example} PUBLIC RF24_NO_INTERRUPT) 17 | endif() 18 | -------------------------------------------------------------------------------- /examples_RPi/ncurses/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # 3 | # Makefile for librf24mesh examples on Raspberry Pi 4 | # 5 | # By: TMRh20 6 | # Date: 2013/09 7 | # 8 | # Description: 9 | # ------------ 10 | # use make all and make install to install the examples 11 | # You can change the install directory by editing the prefix line 12 | # 13 | prefix := /usr/local 14 | 15 | # Which compiler to use 16 | CC=g++ 17 | 18 | ARCH=armv6zk 19 | ifeq "$(shell uname -m)" "armv7l" 20 | ARCH=armv7-a 21 | endif 22 | 23 | # Detect the Raspberry Pi from cpuinfo 24 | #Count the matches for BCM2708 or BCM2709 in cpuinfo 25 | RPI=$(shell cat /proc/cpuinfo | grep Hardware | grep -c BCM2708) 26 | ifneq "${RPI}" "1" 27 | RPI=$(shell cat /proc/cpuinfo | grep Hardware | grep -c BCM2709) 28 | endif 29 | 30 | ifeq "$(RPI)" "1" 31 | # The recommended compiler flags for the Raspberry Pi 32 | CCFLAGS+=-Ofast -mfpu=vfp -mfloat-abi=hard -march=$(ARCH) -mtune=arm1176jzf-s 33 | endif 34 | 35 | # define all programs 36 | PROGRAMS = RF24Mesh_Ncurses_Master 37 | SOURCES = ${PROGRAMS2:=.cpp} 38 | 39 | all: ${PROGRAMS} 40 | 41 | ${PROGRAMS}: ${SOURCES} 42 | mkdir -p bin 43 | $(CC) ${CCFLAGS} -Wall -I../ $@.cpp -lncurses -lrf24-bcm -lrf24network -lrf24mesh -o bin/$@ 44 | 45 | clean: 46 | rm -rf $(PROGRAMS) 47 | 48 | install: all 49 | test -d $(prefix) || mkdir $(prefix) 50 | test -d $(prefix)/bin || mkdir $(prefix)/bin 51 | for prog in $(PROGRAMS); do \ 52 | install -m 0755 $$prog $(prefix)/bin; \ 53 | done 54 | 55 | .PHONY: install 56 | -------------------------------------------------------------------------------- /examples_RPi/ncurses/RF24Mesh_Ncurses_Master.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * RF24Mesh Master Node Monitoring Tool 4 | * This is a generic tool for master nodes running RF24Mesh that will display address 5 | * assignments, and information regarding incoming data, regardless of the specific 6 | * configuration details. 7 | * 8 | * Requirements: NCurses 9 | * Install NCurses: apt-get install libncurses5-dev 10 | * Setup: 11 | * 1. cd ~/RF24Mesh/examples_RPi 12 | * 2. mkdir build && cd build 13 | * 3. cmake .. 14 | * 4. make 15 | * 5. ./ncurses/RF24Mesh_Ncurses_Master 16 | * 17 | * NOTE: RF24MESH_DEBUG MUST BE DISABLED IN RF24Mesh_config.h 18 | * 19 | * Once configured and running, the interface will display the header information, data rate, 20 | * and address assignments for all connected nodes.* 21 | * The master node will also continuously ping each of the child nodes, one per second, while indicating 22 | * the results. 23 | * 24 | */ 25 | 26 | #include 27 | #include "RF24Mesh/RF24Mesh.h" 28 | #include 29 | #include 30 | 31 | RF24 radio(22, 0); 32 | 33 | RF24Network network(radio); 34 | RF24Mesh mesh(radio, network); 35 | 36 | void printNodes(uint8_t boldID); 37 | void pingNode(uint8_t listNo); 38 | 39 | uint8_t nodeCounter; 40 | 41 | uint16_t failID = 0; 42 | WINDOW* win; 43 | WINDOW* topoPad; 44 | void drawTopology(); 45 | int nodeY, nodeX = 0; 46 | int maxY, maxX = 0; 47 | 48 | int main() 49 | { 50 | 51 | printf("Establishing mesh...\n"); 52 | mesh.setNodeID(0); 53 | if (!mesh.begin()) { 54 | // if mesh.begin() returns false for a master node, then radio.begin() returned false. 55 | printf("Radio hardware not responding.\n"); 56 | return 0; 57 | } 58 | radio.printDetails(); 59 | win = initscr(); /* Start curses mode */ 60 | getmaxyx(win, maxX, maxY); 61 | start_color(); 62 | curs_set(0); 63 | //keypad(stdscr, TRUE); //Enable user interaction 64 | init_pair(1, COLOR_GREEN, COLOR_BLACK); 65 | init_pair(2, COLOR_BLUE, COLOR_GREEN); 66 | init_pair(3, COLOR_MAGENTA, COLOR_BLACK); 67 | init_pair(4, COLOR_YELLOW, COLOR_BLACK); 68 | init_pair(5, COLOR_CYAN, COLOR_BLACK); 69 | topoPad = newpad(31, 75); 70 | attron(COLOR_PAIR(1)); 71 | printw("RF24Mesh Master Node Monitoring Interface by TMRh20 - 2014-2022\n"); 72 | attroff(COLOR_PAIR(1)); 73 | refresh(); /* Print it on to the real screen */ 74 | 75 | uint32_t kbTimer = 0, kbCount = 0, pingTimer = millis(); 76 | unsigned long totalPayloads = 0; 77 | uint8_t boldID = 0; 78 | 79 | while (1) 80 | { 81 | 82 | // Call mesh.update to keep the network updated 83 | mesh.update(); 84 | // In addition, keep the 'DHCP service' running on the master node so addresses will 85 | // be assigned to the sensor nodes 86 | mesh.DHCP(); 87 | 88 | attron(A_BOLD | COLOR_PAIR(1)); 89 | mvprintw(2, 0, "[Last Payload Info]\n"); 90 | attroff(A_BOLD | COLOR_PAIR(1)); 91 | 92 | // Check for incoming data from the sensors 93 | while (network.available()) { 94 | RF24NetworkHeader header; 95 | network.peek(header); 96 | 97 | // Print the total number of received payloads 98 | mvprintw(9, 0, " Total: %lu\n", totalPayloads++); 99 | 100 | kbCount++; 101 | 102 | // Read the network payload 103 | network.read(header, 0, 0); 104 | 105 | // Display the header info 106 | mvprintw(3, 0, " HeaderID: %u \n Type: %d \n From: 0%o \n ", header.id, header.type, header.from_node); 107 | 108 | for (uint8_t i = 0; i < mesh.addrListTop; i++) { 109 | if (header.from_node == mesh.addrList[i].address) { 110 | boldID = mesh.addrList[i].nodeID; 111 | } 112 | } 113 | } 114 | printNodes(boldID); 115 | 116 | if (millis() - kbTimer > 1000) { 117 | kbTimer = millis(); 118 | attron(A_BOLD | COLOR_PAIR(1)); 119 | mvprintw(7, 0, "[Data Rate (In)]"); 120 | attroff(A_BOLD | COLOR_PAIR(1)); 121 | mvprintw(8, 0, " Kbps: %.2f", (kbCount * 32 * 8) / 1000.00); 122 | kbCount = 0; 123 | } 124 | 125 | // Ping each connected node, one per second 126 | if (millis() - pingTimer > 1003 && mesh.addrListTop > 0) { 127 | pingTimer = millis(); 128 | if (nodeCounter == mesh.addrListTop) { 129 | nodeCounter = 0; 130 | } 131 | pingNode(nodeCounter); 132 | nodeCounter++; 133 | drawTopology(); 134 | } 135 | 136 | /* 137 | uint32_t nOK, nFails; 138 | network.failures(&nFails, &nOK); 139 | attron(A_BOLD | COLOR_PAIR(1)); 140 | mvprintw(2, 24, "[Transmit Results] "); 141 | attroff(A_BOLD | COLOR_PAIR(1)); 142 | mvprintw(3, 25, " #OK: %u ", nOK); 143 | mvprintw(4, 25, " #Fail: %u ", nFails); 144 | */ 145 | 146 | prefresh(topoPad, 0, 0, 18, 1, maxX - 1, maxY - 2); 147 | refresh(); 148 | 149 | delay(2); 150 | } //while 1 151 | 152 | endwin(); /* End curses mode */ 153 | return 0; 154 | } 155 | 156 | void printNodes(uint8_t boldID) 157 | { 158 | 159 | uint8_t xCoord = 2; 160 | attron(A_BOLD | COLOR_PAIR(1)); 161 | mvprintw(xCoord++, 27, "[Address Assignments]\n"); 162 | attroff(A_BOLD | COLOR_PAIR(1)); 163 | for (uint8_t i = 0; i < mesh.addrListTop; i++) { 164 | if (failID == mesh.addrList[i].nodeID) { 165 | attron(COLOR_PAIR(2)); 166 | } 167 | else if (boldID == mesh.addrList[i].nodeID) { 168 | attron(A_BOLD | COLOR_PAIR(1)); 169 | } 170 | mvprintw(xCoord++, 28, "ID: %d Network: 0%o ", mesh.addrList[i].nodeID, mesh.addrList[i].address); 171 | attroff(A_BOLD | COLOR_PAIR(1)); 172 | attroff(COLOR_PAIR(2)); 173 | } 174 | //mvprintw(xCoord++, 28, " "); 175 | //mvprintw(xCoord++, 28, " "); 176 | //mvprintw(xCoord++, 28, " "); 177 | getyx(win, nodeY, nodeX); 178 | } 179 | 180 | void pingNode(uint8_t listNo) 181 | { 182 | 183 | attron(A_BOLD | COLOR_PAIR(1)); 184 | mvprintw(11, 0, "[Ping Test]\n"); 185 | attroff(A_BOLD | COLOR_PAIR(1)); 186 | 187 | RF24NetworkHeader headers(mesh.addrList[listNo].address, NETWORK_PING); 188 | uint32_t pingtime = millis(); 189 | bool ok = false; 190 | if (headers.to_node) { 191 | ok = network.write(headers, 0, 0); 192 | if (ok && failID == mesh.addrList[listNo].nodeID) { 193 | failID = 0; 194 | } 195 | if (!ok) { 196 | failID = mesh.addrList[listNo].nodeID; 197 | } 198 | } 199 | pingtime = millis() - pingtime; 200 | mvprintw(12, 0, " ID:%d ", mesh.addrList[listNo].nodeID); 201 | mvprintw(13, 0, " Net:0%o ", mesh.addrList[listNo].address); 202 | mvprintw(14, 0, " Time:%ums ", pingtime); 203 | 204 | if (ok || !headers.to_node) { 205 | mvprintw(15, 0, " OK "); 206 | } 207 | else { 208 | attron(A_BOLD); 209 | mvprintw(15, 0, " FAIL"); 210 | attroff(A_BOLD); 211 | } 212 | } 213 | 214 | /****************************************************************************************/ 215 | 216 | void drawTopology() 217 | { 218 | wclear(topoPad); 219 | wattroff(topoPad, COLOR_PAIR(1)); 220 | mvprintw(17, 10, "Mesh Topology"); 221 | mvwaddch(topoPad, nodeY > 15 ? nodeY - 16 : 0, 0, 0); 222 | wattron(topoPad, COLOR_PAIR(1)); 223 | int topoPadmaxX; 224 | topoPadmaxX = getmaxx(topoPad); 225 | 226 | for (int i = 01; i < 06; i++) { 227 | for (int j = 0; j < mesh.addrListTop; j++) { 228 | 229 | if (mesh.addrList[j].address == i) { 230 | wprintw(topoPad, "0%o[%d] | ", mesh.addrList[j].address, mesh.addrList[j].nodeID); 231 | } 232 | } 233 | } 234 | wprintw(topoPad, "\n"); 235 | wattron(topoPad, COLOR_PAIR(4)); 236 | uint16_t g = 051; 237 | for (int h = 011; h <= 015; h++) { 238 | 239 | for (int i = h; i <= g; i += 010) { 240 | 241 | for (int j = 0; j < mesh.addrListTop; j++) { 242 | if (mesh.addrList[j].address == i) { 243 | int x = getcurx(topoPad); 244 | if (x >= topoPadmaxX) wprintw(topoPad, "\n"); 245 | wprintw(topoPad, "0%o[%d] ", mesh.addrList[j].address, mesh.addrList[j].nodeID); 246 | } 247 | } 248 | } 249 | g++; 250 | wprintw(topoPad, "| "); 251 | } 252 | wprintw(topoPad, "\n"); 253 | wattron(topoPad, COLOR_PAIR(5)); 254 | g = 0411; 255 | for (int h = 0111; h <= 0145; h++) { 256 | 257 | for (int i = h; i <= g; i += 0100) { 258 | 259 | for (int j = 0; j < mesh.addrListTop; j++) { 260 | if (mesh.addrList[j].address == i) { 261 | int x = getcurx(topoPad); 262 | if (x >= topoPadmaxX) wprintw(topoPad, "\n"); 263 | wprintw(topoPad, "0%o[%d] ", mesh.addrList[j].address, mesh.addrList[j].nodeID); 264 | } 265 | } 266 | } 267 | g++; 268 | } 269 | wprintw(topoPad, "\n"); 270 | wattron(topoPad, COLOR_PAIR(3)); 271 | g = 04111; 272 | 273 | for (int h = 01111; h <= 01445; h++) { 274 | 275 | for (int i = h; i <= g; i += 01000) { 276 | 277 | for (int j = 0; j < mesh.addrListTop; j++) { 278 | if (mesh.addrList[j].address == i) { 279 | int x = getcurx(topoPad); 280 | if (x >= topoPadmaxX) wprintw(topoPad, "\n"); 281 | wprintw(topoPad, "0%o[%d] ", mesh.addrList[j].address, mesh.addrList[j].nodeID); 282 | } 283 | } 284 | } 285 | g++; 286 | } 287 | wattroff(topoPad, COLOR_PAIR(2)); 288 | } -------------------------------------------------------------------------------- /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 | RF24Mesh/ 9 | examples_pico/ <-- you are here 10 | pico-sdk/ 11 | 12 | Be sure to set the PICO_SDK_PATH environment variable 13 | `export PICO_SDK_PATH=/path/to/github/repos/pico-sdk/` 14 | ]] 15 | 16 | # Pull in SDK (must be before project) 17 | include(../../RF24/cmake/pico_sdk_import.cmake) 18 | 19 | project(pico_examples C CXX ASM) 20 | 21 | # Initialize the Pico SDK 22 | pico_sdk_init() 23 | 24 | # In YOUR project, include RF24's CMakeLists.txt 25 | # giving the path depending on where the library 26 | # is cloned to in your project 27 | include(../../RF24/CMakeLists.txt) # for RF24 lib 28 | include(../../RF24Network/CMakeLists.txt) # for RF24Network lib 29 | include(../CMakeLists.txt) # for RF24Mesh lib 30 | 31 | # iterate over a list of examples by filename 32 | set(EXAMPLES_LIST 33 | RF24Mesh_Example 34 | RF24Mesh_Example_Master 35 | ) 36 | 37 | foreach(example ${EXAMPLES_LIST}) 38 | # make a target 39 | add_executable(${example} ${example}.cpp defaultPins.h) 40 | 41 | # link the necessary libs to the target 42 | target_link_libraries(${example} PUBLIC 43 | RF24 44 | RF24Network 45 | RF24Mesh 46 | pico_stdlib 47 | hardware_spi 48 | hardware_gpio 49 | ) 50 | 51 | # specify USB port as default serial communication's interface (not UART RX/TX pins) 52 | pico_enable_stdio_usb(${example} 1) 53 | pico_enable_stdio_uart(${example} 0) 54 | 55 | # create map/bin/hex file etc. 56 | pico_add_extra_outputs(${example}) 57 | endforeach() 58 | -------------------------------------------------------------------------------- /examples_pico/RF24Mesh_Example.cpp: -------------------------------------------------------------------------------- 1 | /** RF24Mesh_Example.cpp by TMRh20 2 | * 3 | * Note: This sketch only functions on RP2040 boards 4 | * 5 | * This example sketch shows how to manually configure a node via RF24Mesh, and send data to the 6 | * master node. 7 | * In this sketch, the nodes will refresh their network address as soon as a single write fails. This allows the 8 | * nodes to change position in relation to each other and the master node. 9 | * 10 | */ 11 | #include "pico/stdlib.h" // printf(), sleep_ms(), to_ms_since_boot(), get_absolute_time() 12 | #include // tud_cdc_connected() 13 | #include // RF24 radio object 14 | #include // RF24Network network object 15 | #include // RF24Mesh mesh object 16 | #include "defaultPins.h" // board presumptive default pin numbers for CE_PIN and CSN_PIN 17 | 18 | // instantiate an object for the nRF24L01 transceiver 19 | RF24 radio(CE_PIN, CSN_PIN); 20 | 21 | RF24Network network(radio); 22 | 23 | RF24Mesh mesh(radio, network); 24 | 25 | uint32_t displayTimer = 0; 26 | 27 | bool setup() 28 | { 29 | // wait here until the CDC ACM (serial port emulation) is connected 30 | while (!tud_cdc_connected()) { 31 | sleep_ms(10); 32 | } 33 | 34 | // Set the nodeID to 0 for the master node 35 | mesh.setNodeID(4); 36 | 37 | // Set the PA Level to MIN and disable LNA for testing & power supply related issues 38 | radio.begin(); 39 | radio.setPALevel(RF24_PA_MIN, 0); 40 | 41 | // Connect to the mesh 42 | printf("start nodeID %d\n", mesh.getNodeID()); 43 | if (!mesh.begin()) { 44 | if (radio.isChipConnected()) { 45 | do { 46 | // mesh.renewAddress() will return MESH_DEFAULT_ADDRESS on failure to connect 47 | printf("Could not connect to network.\nConnecting to the mesh...\n"); 48 | } while (mesh.renewAddress() == MESH_DEFAULT_ADDRESS); 49 | } 50 | else { 51 | printf("Radio hardware not responding.\n"); 52 | return 0; 53 | } 54 | } 55 | return true; 56 | } 57 | 58 | void loop() 59 | { 60 | // Call mesh.update to keep the network updated 61 | mesh.update(); 62 | 63 | // Send the current millis() to the master node every second 64 | if (to_ms_since_boot(get_absolute_time()) - displayTimer >= 1000) { 65 | displayTimer = to_ms_since_boot(get_absolute_time()); 66 | 67 | if (!mesh.write(&displayTimer, 'M', sizeof(displayTimer))) { 68 | // If a write fails, check connectivity to the mesh network 69 | if (!mesh.checkConnection()) { 70 | // The address could be refreshed per a specified timeframe or only when sequential writes fail, etc. 71 | do { 72 | printf("Renewing Address...\n"); 73 | } while (mesh.renewAddress() == MESH_DEFAULT_ADDRESS); 74 | } 75 | else { 76 | printf("Send fail, Test OK\n"); 77 | } 78 | } 79 | else { 80 | printf("Send OK: %u\n", displayTimer); 81 | } 82 | } 83 | } 84 | 85 | int main() 86 | { 87 | stdio_init_all(); // init necessary IO for the RP2040 88 | 89 | while (!setup()) { // if radio.begin() failed 90 | // hold program in infinite attempts to initialize radio 91 | } 92 | while (true) { 93 | loop(); 94 | } 95 | return 0; // we will never reach this 96 | } 97 | -------------------------------------------------------------------------------- /examples_pico/RF24Mesh_Example_Master.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This example sketch shows how to manually configure a node via RF24Mesh as a master node, which 3 | * will receive all data from sensor nodes. 4 | * 5 | * The nodes can change physical or logical position in the network, and reconnect through different 6 | * routing nodes as required. The master node manages the address assignments for the individual nodes 7 | * in a manner similar to DHCP. 8 | */ 9 | #include "pico/stdlib.h" // printf(), sleep_ms(), to_ms_since_boot(), get_absolute_time() 10 | #include // tud_cdc_connected() 11 | #include // RF24 radio object 12 | #include // RF24Network network object 13 | #include // RF24Mesh mesh object 14 | #include "defaultPins.h" // board presumptive default pin numbers for CE_PIN and CSN_PIN 15 | 16 | // instantiate an object for the nRF24L01 transceiver 17 | RF24 radio(CE_PIN, CSN_PIN); 18 | 19 | RF24Network network(radio); 20 | 21 | RF24Mesh mesh(radio, network); 22 | 23 | bool setup() 24 | { 25 | // wait here until the CDC ACM (serial port emulation) is connected 26 | while (!tud_cdc_connected()) { 27 | sleep_ms(10); 28 | } 29 | 30 | // Set the nodeID to 0 for the master node 31 | mesh.setNodeID(0); 32 | 33 | // Set the PA Level to MIN and disable LNA for testing & power supply related issues 34 | radio.begin(); 35 | radio.setPALevel(RF24_PA_MIN, 0); 36 | 37 | // Connect to the mesh 38 | printf("start\n"); 39 | if (!mesh.begin()) { 40 | // if mesh.begin() returns false for a master node, then radio.begin() returned false. 41 | printf("Radio hardware not responding.\n"); 42 | return 0; 43 | } 44 | 45 | radio.printDetails(); 46 | return true; 47 | } 48 | 49 | void loop() 50 | { 51 | // Call network.update as usual to keep the network updated 52 | mesh.update(); 53 | 54 | // In addition, keep the 'DHCP service' running on the master node so addresses will 55 | // be assigned to the sensor nodes 56 | mesh.DHCP(); 57 | 58 | // Check for incoming data from the sensors 59 | while (network.available()) { 60 | // printf("rcv\n"); 61 | RF24NetworkHeader header; 62 | network.peek(header); 63 | 64 | uint32_t dat = 0; 65 | switch (header.type) 66 | { // Display the incoming millis() values from the sensor nodes 67 | case 'M': 68 | network.read(header, &dat, sizeof(dat)); 69 | printf("Rcv %u from 0%o\n", dat, header.from_node); 70 | break; 71 | default: 72 | network.read(header, 0, 0); 73 | printf("Rcv bad type %d from 0%o\n", header.type, header.from_node); 74 | break; 75 | } 76 | } 77 | } 78 | 79 | int main() 80 | { 81 | stdio_init_all(); // init necessary IO for the RP2040 82 | 83 | while (!setup()) { // if radio.begin() failed 84 | // hold program in infinite attempts to initialize radio 85 | } 86 | while (true) { 87 | loop(); 88 | } 89 | return 0; // we will never reach this 90 | } 91 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /images/RF24Mesh_Ncurses.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nRF24/RF24Mesh/525facce480eb44224e8b5d73ebde48bc146d668/images/RF24Mesh_Ncurses.JPG -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RF24Mesh", 3 | "keywords": "rf, radio, wireless, spi, mesh, network", 4 | "description": "A simple and seamless 'mesh' layer for sensor networks. Designed to interface directly with with the RF24Network library, an OSI Network Layer using nRF24L01(+) and nRF52x radios.", 5 | "license": "GPL-2.0-only", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/nRF24/RF24Mesh.git" 9 | }, 10 | "version": "2.0.3", 11 | "dependencies": [ 12 | { 13 | "name": "RF24", 14 | "authors": "nRF24", 15 | "frameworks": "arduino" 16 | }, 17 | { 18 | "name": "RF24Network", 19 | "authors": "nRF24", 20 | "frameworks": "arduino", 21 | "version": ">=2.0.0" 22 | } 23 | ], 24 | "export": { 25 | "exclude": [ 26 | ".github/*", 27 | "keywords.txt", 28 | "examples_RPi/*", 29 | "pyRF24Mesh/*", 30 | "cmake/*", 31 | "CMakeLists.txt", 32 | "Makefile" 33 | ] 34 | }, 35 | "frameworks": "arduino", 36 | "platforms": [ 37 | "atmelavr", 38 | "atmelsam", 39 | "teensy", 40 | "atmelmegaavr", 41 | "espressif32", 42 | "espressif8266", 43 | "ststm32", 44 | "nordicnrf52" 45 | ] 46 | } -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=RF24Mesh 2 | version=2.0.3 3 | author=TMRh20 4 | maintainer=TMRh20,Avamander 5 | sentence=OSI Layer 7, Automated 'mesh' style networking for nrf24L01(+) & nrf52x radios. 6 | paragraph=Attempting to provide fully automated, wireless, mesh networking for sensor networks/IoT devices. Automated addressing, discovery and operation built on the RF24 communication stack. 7 | category=Communication 8 | url=https://nRF24.github.io/RF24Mesh/ 9 | architectures=* 10 | depends=RF24,RF24Network 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 = "pyRF24Mesh" 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 | -------------------------------------------------------------------------------- /pyRF24Mesh/README.md: -------------------------------------------------------------------------------- 1 | # Individual python wrapper 2 | 3 | > [!warning] 4 | > This python wrapper for the RF24Mesh 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 | -------------------------------------------------------------------------------- /pyRF24Mesh/pyRF24Mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "boost/python.hpp" 2 | #include "RF24/RF24.h" 3 | #include "RF24Network/RF24Network.h" 4 | #include "RF24Mesh/RF24Mesh.h" 5 | 6 | namespace bp = boost::python; 7 | 8 | // ******************** explicit wrappers ************************** 9 | // where needed, especially where buffer is involved 10 | 11 | void throw_ba_exception(void) 12 | { 13 | PyErr_SetString(PyExc_TypeError, "buf parameter must be bytes or bytearray"); 14 | bp::throw_error_already_set(); 15 | } 16 | 17 | char* get_bytes_or_bytearray_str(bp::object buf) 18 | { 19 | PyObject* py_ba; 20 | py_ba = buf.ptr(); 21 | if (PyByteArray_Check(py_ba)) 22 | return PyByteArray_AsString(py_ba); 23 | else if (PyBytes_Check(py_ba)) 24 | return PyBytes_AsString(py_ba); 25 | else 26 | throw_ba_exception(); 27 | 28 | return NULL; 29 | } 30 | 31 | int get_bytes_or_bytearray_ln(bp::object buf) 32 | { 33 | PyObject* py_ba; 34 | py_ba = buf.ptr(); 35 | if (PyByteArray_Check(py_ba)) 36 | return PyByteArray_Size(py_ba); 37 | else if (PyBytes_Check(py_ba)) 38 | return PyBytes_Size(py_ba); 39 | else 40 | throw_ba_exception(); 41 | 42 | return 0; 43 | } 44 | 45 | bool write_wrap1(RF24Mesh& ref, bp::object buf, uint8_t msg_type) 46 | { 47 | return ref.write(get_bytes_or_bytearray_str(buf), msg_type, get_bytes_or_bytearray_ln(buf)); 48 | } 49 | 50 | bool write_wrap2(RF24Mesh& ref, bp::object buf, uint8_t msg_type, uint8_t nodeID) 51 | { 52 | return ref.write(get_bytes_or_bytearray_str(buf), msg_type, get_bytes_or_bytearray_ln(buf), nodeID); 53 | } 54 | 55 | bool write_to_node_wrap(RF24Mesh& ref, uint16_t to_node, bp::object buf, uint8_t msg_type) 56 | { 57 | return ref.write(to_node, get_bytes_or_bytearray_str(buf), msg_type, get_bytes_or_bytearray_ln(buf)); 58 | } 59 | 60 | // ******************** overload wrappers ************************** 61 | BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(begin_overload, RF24Mesh::begin, 0, 3) 62 | BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(getNodeID_overload, RF24Mesh::getNodeID, 0, 1) 63 | BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(renewAddress_overload, RF24Mesh::renewAddress, 0, 1) 64 | 65 | // ******************** RF24Mesh exposed ************************** 66 | BOOST_PYTHON_MODULE(RF24Mesh) 67 | { 68 | { 69 | /* Binding this class is useless unless we can properly expose RF24Mesh::addrList. 70 | A converter from addrListStruct[] to bp::list needs to be implemented. 71 | // ::RF24Mesh::addrListStruct 72 | bp::class_("addrListStruct", bp::init<>()) 73 | .def_readonly("nodeID", &RF24Mesh::addrListStruct::nodeID) 74 | .def_readwrite("address", &RF24Mesh::addrListStruct::address); 75 | */ 76 | 77 | //::RF24Mesh 78 | bp::class_("RF24Mesh", bp::init((bp::arg("_radio"), bp::arg("_network")))) 79 | //bool begin(uint8_t channel = MESH_DEFAULT_CHANNEL, rf24_datarate_e data_rate = RF24_1MBPS, uint32_t timeout=MESH_RENEWAL_TIMEOUT ); 80 | .def("begin", &RF24Mesh::begin, begin_overload(bp::args("channel", "data_rate", "timeout"))) 81 | //uint8_t update(); 82 | .def("update", &RF24Mesh::update) 83 | //bool write(const void* data, uint8_t msg_type, size_t size, uint8_t nodeID=0); 84 | .def("write", &write_wrap1, (bp::arg("data"), bp::arg("msg_type"))) 85 | .def("write", &write_wrap2, (bp::arg("data"), bp::arg("msg_type"), bp::arg("nodeID"))) 86 | //bool write(uint16_t to_node, const void* data, uint8_t msg_type, size_t size ); 87 | .def("write", &write_to_node_wrap, (bp::arg("to_node"), bp::arg("data"), bp::arg("msg_type"))) 88 | //void setNodeID(uint8_t nodeID); 89 | .def("setNodeID", &RF24Mesh::setNodeID, (bp::arg("nodeID"))) 90 | //void DHCP(); 91 | .def("DHCP", &RF24Mesh::DHCP) 92 | //int16_t getNodeID(uint16_t address); 93 | .def("getNodeID", &RF24Mesh::getNodeID, getNodeID_overload(bp::args("address"))) 94 | //int16_t getNodeID(); where address arg defaults to MESH_BLANK_ID 95 | .def("getNodeID", &RF24Mesh::getNodeID, getNodeID_overload()) 96 | //bool checkConnection(); 97 | .def("checkConnection", &RF24Mesh::checkConnection) 98 | //uint16_t renewAddress(uint32_t timeout); 99 | .def("renewAddress", &RF24Mesh::renewAddress, renewAddress_overload(bp::args("timeout"))) 100 | //uint16_t renewAddress(); where timeout arg defaults to MESH_RENEWAL_TIMEOUT 101 | .def("renewAddress", &RF24Mesh::renewAddress, renewAddress_overload()) 102 | //bool releaseAddress(); 103 | .def("releaseAddress", (bool(RF24Mesh::*)()) & RF24Mesh::releaseAddress) 104 | #ifndef MESH_NOMASTER 105 | //bool releaseAddress(uint16_t address); 106 | .def("releaseAddress", (bool(RF24Mesh::*)(uint16_t)) & RF24Mesh::releaseAddress, (bp::args("address"))) 107 | #endif 108 | //int16_t getAddress(uint8_t nodeID); 109 | .def("getAddress", &RF24Mesh::getAddress, (bp::arg("nodeID"))) 110 | //void setChannel(uint8_t _channel); 111 | .def("setChannel", &RF24Mesh::setChannel, (bp::arg("_channel"))) 112 | //void setChild(bool allow); 113 | .def("setChild", &RF24Mesh::setChild, (bp::arg("allow"))) 114 | //void setAddress(uint8_t nodeID, uint16_t address); 115 | .def("setAddress", &RF24Mesh::setAddress, (bp::arg("nodeID"), bp::arg("address"))) 116 | //void saveDHCP(); 117 | .def("saveDHCP", &RF24Mesh::saveDHCP) 118 | //void loadDHCP(); 119 | .def("loadDHCP", &RF24Mesh::loadDHCP) 120 | // mesh_address 121 | .def_readwrite("mesh_address", &RF24Mesh::mesh_address) 122 | 123 | // Returning an array of wrapped addrListStruct objects in boost.python is non-trivial. 124 | // I'm commenting out the members related to the RF24Mesh::addrList until a solution can be found. 125 | // .def_readonly("addrListTop", &RF24Mesh::addrListTop) 126 | // .def_readonly("addrList", &RF24Mesh::addrList) 127 | 128 | //void setStaticAddress(uint8_t nodeID, uint16_t address); 129 | .def("setStaticAddress", &RF24Mesh::setStaticAddress, (bp::arg("nodeID"), bp::arg("address"))); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /pyRF24Mesh/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "RF24Mesh" 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 | -------------------------------------------------------------------------------- /pyRF24Mesh/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 | 14 | # get LIB_VERSION from library.properties file for Arduino IDE 15 | version = "1.0" 16 | with open(os.path.join(git_dir, "library.properties"), "r") as f: 17 | for line in f.read().splitlines(): 18 | if line.startswith("version"): 19 | version = line.split("=")[1] 20 | 21 | setup( 22 | version=version, 23 | ext_modules=[ 24 | Extension( 25 | "RF24Mesh", 26 | sources=["pyRF24Mesh.cpp"], 27 | libraries=["rf24mesh", "rf24network", "rf24", BOOST_LIB], 28 | ) 29 | ], 30 | ) 31 | --------------------------------------------------------------------------------