├── .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 | [](https://github.com/nRF24/RF24Mesh/actions/workflows/build_linux.yml)
3 | [](https://github.com/nRF24/RF24Mesh/actions/workflows/build_arduino.yml)
4 | [](https://github.com/nRF24/RF24Mesh/actions/workflows/build_platformIO.yml)
5 | [](https://github.com/nRF24/RF24Mesh/actions/workflows/build_rp2xxx.yml)
6 | [](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 |
--------------------------------------------------------------------------------