diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index eb9d15e96..a8998e3ef 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -15,7 +15,7 @@ A clear and concise description of what the bug is. Please include: 1. Code to reproduce 2. Expected behaviour -3. What device(es) are you using? Please specify make and model. +3. What device(s) are you using? Please specify make, model, and Operating System if applicable. **Additional context** Add any other context about the problem here. diff --git a/.github/workflows/build_arduino.yml b/.github/workflows/build_arduino.yml index c4ab06cdc..7cc24808b 100644 --- a/.github/workflows/build_arduino.yml +++ b/.github/workflows/build_arduino.yml @@ -2,16 +2,16 @@ name: Arduino CLI build on: pull_request: + types: [opened, reopened] paths: - ".github/workflows/build_arduino.yml" - "examples/**" - - "!examples/old_backups/recipes/pingpair_maple/**" - + - "!examples/old_backups/**" push: paths: - ".github/workflows/build_arduino.yml" - "examples/**" - - "!examples/old_backups/recipes/pingpair_maple/**" + - "!examples/old_backups/**" jobs: check_formatting: @@ -66,16 +66,16 @@ jobs: - "arduino:avr:one" - "arduino:avr:unowifi" - "arduino:mbed:nano33ble" - # - "arduino:samd:mkr1000" # InterruptConfigure.ino uses pin 2 - # - "arduino:samd:mkrzero" # InterruptConfigure.ino uses pin 2 - # - "arduino:samd:mkrwifi1010" # InterruptConfigure.ino uses pin 2 + - "arduino:samd:mkr1000" # InterruptConfigure.ino uses pin 2 + - "arduino:samd:mkrzero" # InterruptConfigure.ino uses pin 2 + - "arduino:samd:mkrwifi1010" # InterruptConfigure.ino uses pin 2 - "arduino:samd:nano_33_iot" - # - "arduino:samd:mkrfox1200" # InterruptConfigure.ino uses pin 2 - # - "arduino:samd:mkrwan1300" # InterruptConfigure.ino uses pin 2 - # - "arduino:samd:mkrwan1310" # InterruptConfigure.ino uses pin 2 - # - "arduino:samd:mkrgsm1400" # InterruptConfigure.ino uses pin 2 - # - "arduino:samd:mkrnb1500" # InterruptConfigure.ino uses pin 2 - # - "arduino:samd:mkrvidor4000" # InterruptConfigure.ino uses pin 2 + - "arduino:samd:mkrfox1200" # InterruptConfigure.ino uses pin 2 + - "arduino:samd:mkrwan1300" # InterruptConfigure.ino uses pin 2 + - "arduino:samd:mkrwan1310" # InterruptConfigure.ino uses pin 2 + - "arduino:samd:mkrgsm1400" # InterruptConfigure.ino uses pin 2 + - "arduino:samd:mkrnb1500" # InterruptConfigure.ino uses pin 2 + - "arduino:samd:mkrvidor4000" # InterruptConfigure.ino uses pin 2 - "arduino:samd:adafruit_circuitplayground_m0" - "arduino:samd:mzero_pro_bl" - "arduino:samd:mzero_bl" @@ -84,6 +84,7 @@ jobs: # - "arduino:megaavr:nano4809" # board not found - "arduino:sam:arduino_due_x_dbg" + steps: - name: Checkout uses: actions/checkout@v2 @@ -98,13 +99,13 @@ jobs: - examples/StreamingData - examples/MulticeiverDemo - examples/InterruptConfigure - # The following examples still exist for posterity + - examples/scanner + # The following examples still exist for posterity. They don't trigger this workflow # - examples/old_backups/GettingStarted_HandlingFailures # - examples/old_backups/pingpair_dyn # - examples/old_backups/pingpair_irq # - examples/old_backups/pingpair_multi_dyn # - examples/old_backups/pingpair_sleepy - # - examples/old_backups/scanner # - examples/old_backups/TransferTimeouts # - examples/old_backups/recipes/led_remote # - examples/old_backups/recipes/nordic_fob @@ -156,4 +157,4 @@ jobs: sketch-paths: | - examples/rf24_ATTiny/rf24ping85 - examples/rf24_ATTiny/timingSearch3pin - fqbn: ${{ matrix.fqbn }} \ No newline at end of file + fqbn: ${{ matrix.fqbn }} diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index e2799eb6d..670d59f98 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -1,8 +1,54 @@ name: Linux build -on: [push] +on: + pull_request: + types: [opened, reopened] + paths: + - "*.h" + - "*.cpp" + - "CMakeLists.txt" + - "cmake/**" + - "library.properties" # CMake & 'configure' gets lib info from here + - "configure" + - "Makefile" + - "utility/CMakeLists.txt" + # - "utility/LittleWire/*"" # this is not tested (anymore) + - "utility/wiringPi/*" + - "utility/MRAAA/*" + - "utility/SPIDEV/*" + - "examples_linux/*" + - "!examples_linux/*.py" + - "!examples_linux/*.md" + - "pyRF24/setup.py" + - ".github/workflows/build_linux.yml" + push: + paths: + - "*.h" + - "*.cpp" + - "CMakeLists.txt" + - "cmake/**" + - "library.properties" # CMake & 'configure' gets lib info from here + - "configure" + - "Makefile" + - "utility/CMakeLists.txt" + # - "utility/LittleWire/*"" # this is not tested (anymore) + - "utility/wiringPi/*" + - "utility/MRAAA/*" + - "utility/SPIDEV/*" + - "examples_linux/*" + - "!examples_linux/*.py" + - "!examples_linux/*.md" + - "pyRF24/setup.py" + - ".github/workflows/build_linux.yml" + release: + types: [published, edited] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release jobs: + ####################### using Makefile ############################# build: runs-on: ubuntu-latest @@ -13,46 +59,243 @@ jobs: config-options: - "--soc=BCM2835 --driver=RPi" - "--soc=BCM2836 --driver=RPi" - # - "--soc=BCM2835 --driver=wiringPi --extra-cflags=-I/usr/local/include" - "--driver=SPIDEV" - # - "--driver=MRAA" + - "--driver=MRAA" + # - "--soc=BCM2835 --driver=wiringPi" + + env: + CFLAGS: "-I /usr/local/include" steps: - uses: actions/checkout@v1 + - name: provide toolchain run: | sudo apt-get update sudo apt-get install binutils-arm-linux-gnueabi gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf arm-linux-gnueabihf-gcc -v arm-linux-gnueabihf-g++ -v + - name: provide WiringPi - if: ${{ matrix.config-options == '--soc=BCM2835 --driver=wiringPi --extra-cflags=-I/usr/local/include' }} + if: ${{ matrix.config-options == '--soc=BCM2835 --driver=wiringPi' }} + env: + CC: /usr/bin/arm-linux-gnueabihf-gcc + CFLAGS: "-I /usr/local/include -L /usr/local/lib -marm -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -lcrypt -lrt" run: | git clone https://github.com/WiringPi/WiringPi - cd WiringPi/wiringPi - CC="arm-linux-gnueabihf-gcc -marm -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard" V=1 make -j5 - sudo make install + cd WiringPi + ./build + - name: provide MRAA if: ${{ matrix.config-options == '--driver=MRAA' }} + env: + CC: /usr/bin/arm-linux-gnueabihf-gcc + CXX: /usr/bin/arm-linux-gnueabihf-g++ run: | git clone https://github.com/intel-iot-devkit/mraa.git cd mraa mkdir build cd build - cmake .. -DBUILDSWIGNODE=OFF + cmake .. -D BUILDSWIGNODE=OFF -D BUILDARCH=arm sudo make install sudo bash -c 'echo "/usr/local/lib/arm-linux-gnueabihf" >> /etc/ld.so.conf' sudo ldconfig + - name: library configure run: ./configure ${{ matrix.config-options }} + - name: library make run: make + - name: library make install run: sudo make install + - name: make linux examples - # compiling examples for wiringPi is broken see nRF24#669 issue - # if: ${{ matrix.config-options != '--soc=BCM2835 --driver=wiringPi --extra-cflags=-I/usr/local/include' }} + # compiling examples for wiringPi is broken see issue #669 + # executables linked to wiringPi additionally need to be linked to crypt and shm_open + # interruptConfigure.cpp example is incompatible with MRAA & wiringPi drivers + if: ${{ matrix.config-options != '--soc=BCM2835 --driver=wiringPi' && matrix.config-options != '--driver=MRAA' }} run: | cd examples_linux make file ./gettingstarted + + + ####################### using CMake ################################ + using_cmake: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + matrix: + toolchain: + - compiler: "armhf" + usr_dir: "arm-linux-gnueabihf" + - compiler: "arm64" + usr_dir: "aarch64-linux-gnu" + # - compiler: "x86_64" + # usr_dir: "x86_64-linux-gnux32" + # - compiler: "i686" + # usr_dir: "i686-linux-gnu" + - compiler: "default" # github runner is hosted on a "amd64" + usr_dir: "local" # using this toolchain to test python wrapper + driver: + - "RPi" + - "SPIDEV" + - "MRAA" + exclude: + # MRAA is not compatible with i686 arch + - driver: "MRAA" + toolchain: + compiler: "i686" + usr_dir: "i686-linux-gnu" + include: + # need to cross-compile wiringPi dependencies (libcrypt) + # only test default compiler with wiringPi + - driver: "wiringPi" + toolchain: + compiler: "default" # github runner is hosted on a "amd64" + usr_dir: "local" + + steps: + - name: Checkout RF24 repo + uses: actions/checkout@v1 + + # - name: provide toolchain (for x86_64) + # if: ${{ matrix.toolchain.compiler == 'x86_64' }} + # run: | + # sudo apt-get update + # sudo apt-get install gcc-x86-64-linux-gnux32 g++-x86-64-linux-gnux32 + + # - name: provide toolchain (for i686) + # if: ${{ matrix.toolchain.compiler == 'i686' }} + # run: | + # sudo apt-get update + # sudo apt-get install gcc-i686-linux-gnu g++-i686-linux-gnu + + - name: provide toolchain (for arm64) + if: ${{ matrix.toolchain.compiler == 'arm64' }} + run: | + sudo apt-get update + sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + + - name: provide toolchain (for armhf) + if: ${{ matrix.toolchain.compiler == 'armhf' }} + run: | + sudo apt-get update + sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf + + - name: provide MRAA + if: ${{ matrix.driver == 'MRAA' }} + run: | + git clone https://github.com/intel-iot-devkit/mraa.git + cd mraa + mkdir build + cd build + cmake .. -D BUILDSWIGNODE=OFF \ + -D CMAKE_INSTALL_PREFIX=/usr/${{ matrix.toolchain.usr_dir }} \ + -D CMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/cmake/toolchains/${{ matrix.toolchain.compiler }}.cmake + sudo make install + + - name: provide WiringPi + if: ${{ matrix.driver == 'wiringPi' && matrix.toolchain.compiler == 'default' }} + run: | + git clone https://github.com/WiringPi/WiringPi + cd WiringPi + ./build + + # - name: provide WiringPi (with toolchain compilers) + # if: ${{ matrix.driver == 'wiringPi' && matrix.toolchain.compiler != 'default' }} + # env: + # CC: /usr/bin/${{ matrix.toolchain.usr_dir }}-gcc + # CFLAGS: "-I/usr/${{ matrix.toolchain.usr_dir }}" + # run: | + # git clone https://github.com/WiringPi/WiringPi + # cd WiringPi + # ./build + + - name: create CMake build environment + run: cmake -E make_directory ${{ github.workspace }}/build + + - name: configure lib + working-directory: ${{ github.workspace }}/build + run: | + cmake .. -D CMAKE_BUILD_TYPE=$BUILD_TYPE \ + -D RF24_DRIVER=${{ matrix.driver }} \ + -D CMAKE_INSTALL_PREFIX=/usr/${{ matrix.toolchain.usr_dir }} \ + -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/${{ matrix.toolchain.compiler }}.cmake + + - name: build lib + working-directory: ${{ github.workspace }}/build + run: cmake --build . + + - name: install lib + working-directory: ${{ github.workspace }}/build + run: sudo cmake --install . + + - name: package lib + working-directory: ${{ github.workspace }}/build + run: sudo cpack + + - name: Save artifact + uses: actions/upload-artifact@v2 + with: + name: "pkg_RF24" + path: | + ${{ github.workspace }}/build/pkgs/*.deb + ${{ github.workspace }}/build/pkgs/*.rpm + + - name: Upload Release assets + if: github.event_name == 'release' && (matrix.toolchain.compiler == 'armhf' || matrix.toolchain.compiler == 'arm64') && (matrix.driver =='RPi' || matrix.driver =='SPIDEV') + uses: csexton/release-asset-action@master + with: + pattern: "${{ github.workspace }}/build/pkgs/librf24*" + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: clean build environment + working-directory: ${{ github.workspace }}/build + run: sudo rm -r ./* + + - name: configure examples + working-directory: ${{ github.workspace }}/build + # interruptConfigure isn't compatible with RF24 lib's support of MRAA as a driver + # interruptConfigure uses `attachInterrupt()` instead of wiringPi's `waitFor/interrupt()` + # executables linked to wiringPi additionally need to be linked to crypt and shm_open + run: | + cmake ../examples_linux -D RF24_DRIVER=${{ matrix.driver }} \ + -D CMAKE_TOOLCHAIN_FILE=../cmake/toolchains/${{ matrix.toolchain.compiler }}.cmake + + - name: build examples + working-directory: ${{ github.workspace }}/build + run: | + cmake --build . + file ./gettingstarted + + # cross-compiling a python C extension is better done with pypa/cibuildwheel action + - name: Set up Python 3.7 + if: ${{ matrix.toolchain.compiler == 'default' }} + uses: actions/setup-python@v1 + with: + python-version: 3.7 + + - name: provide python wrapper prerequisites + if: ${{ matrix.toolchain.compiler == 'default' }} + # python3-rpi.gpio is only required for physical hardware (namely the IRQ example) + run: | + sudo apt-get install python3-dev libboost-python-dev python3-pip + python3 -m pip install --upgrade pip setuptools + + - name: create alias symlink to libboost_python3*.so + if: ${{ matrix.toolchain.compiler == 'default' }} + run: sudo ln -s $(ls /usr/lib/$(ls /usr/lib/gcc | tail -1)/libboost_python3*.so | tail -1) /usr/lib/$(ls /usr/lib/gcc | tail -1)/libboost_python3.so + + - name: build python wrapper + if: ${{ matrix.toolchain.compiler == 'default' }} + working-directory: ${{ github.workspace }}/pyRF24 + run: python3 setup.py build + + - name: install python wrapper + if: ${{ matrix.toolchain.compiler == 'default' }} + working-directory: ${{ github.workspace }}/pyRF24 + run: sudo python3 setup.py install diff --git a/.github/workflows/build_platformIO.yml b/.github/workflows/build_platformIO.yml index ad6a24c92..b4fba7477 100644 --- a/.github/workflows/build_platformIO.yml +++ b/.github/workflows/build_platformIO.yml @@ -2,18 +2,66 @@ name: PlatformIO build on: pull_request: + types: [opened, reopened] paths: - ".github/workflows/build_platformIO.yml" + - "library.json" - "examples/**" - - "!examples/old_backups/recipes/pingpair_maple/**" - + - "!examples/old_backups/**" + - "!examples/rf24_ATTiny/**" push: paths: - ".github/workflows/build_platformIO.yml" + - "library.json" - "examples/**" - - "!examples/old_backups/recipes/pingpair_maple/**" + - "!examples/old_backups/**" + - "!examples/rf24_ATTiny/**" + release: + types: [created] jobs: + validate_lib_json: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: get latest release version number + id: latest_ver + run: echo "::set-output name=release::$(awk -F "=" '/version/ {print $2}' library.properties)" + + - name: Set up Python + uses: actions/setup-python@v2 + + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + + - name: package lib + run: pio package pack -o PlatformIO-RF24-${{ steps.latest_ver.outputs.release }}.tar.gz + + - name: Save artifact + uses: actions/upload-artifact@v2 + with: + name: "PIO_pkg_RF24" + path: PlatformIO*.tar.gz + + - name: Upload Release assets + if: github.event_name == 'release' + uses: csexton/release-asset-action@master + with: + pattern: "PlatformIO*.tar.gz" + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: upload package to PlatformIO Registry + if: github.event_name == 'release' && github.event_type != 'created' + # PIO lib packages cannot be re-published under the same tag + env: + PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }} + run: pio package publish --owner nrf24 --non-interactive + + check_formatting: runs-on: ubuntu-latest @@ -33,7 +81,7 @@ jobs: - examples build: - needs: check_formatting + needs: [check_formatting, validate_lib_json] runs-on: ubuntu-latest strategy: diff --git a/.github/workflows/build_rp2xxx.yml b/.github/workflows/build_rp2xxx.yml new file mode 100644 index 000000000..6172d3df0 --- /dev/null +++ b/.github/workflows/build_rp2xxx.yml @@ -0,0 +1,99 @@ +name: Pico SDK build + +on: + push: + paths: + - ".github/workflows/build_rp2xxx.yml" + - "*.h" + - "!printf.h" # Pico SDK has its own printf solution + - "*.cpp" + - "CMakeLists.txt" + - "cmake/" + - "utility/rp2/*" + - "examples_pico/*" + pull_request: + types: [opened, reopened] + paths: + - ".github/workflows/build_rp2xxx.yml" + - "*.h" + - "!printf.h" # Pico SDK has its own printf solution + - "*.cpp" + - "CMakeLists.txt" + - "cmake/**" + - "utility/rp2/*" + - "examples_pico/*" + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + matrix: + board: + - "pico" + - "adafruit_feather_rp2040" + - "adafruit_itsybitsy_rp2040" + - "adafruit_qtpy_rp2040" + - "pimoroni_tiny2040" # examples require PicoSDK v1.2.0 + - "sparkfun_micromod" # examples require PicoSDK v1.2.0 + - "sparkfun_promicro" # examples require PicoSDK v1.2.0 + - "sparkfun_thingplus" # examples require PicoSDK v1.2.0 + # - "vgaboard" # examples require PicoSDK v1.2.0 (this can be enabled on request) + - "arduino_nano_rp2040_connect" # requires PicoSDK v1.2.0 + - "pimoroni_picolipo_4mb" # requires PicoSDK v1.2.0 + - "pimoroni_picolipo_16mb" # requires PicoSDK v1.2.0 + - "pimoroni_pga2040" # requires PicoSDK v1.2.0 + # - "pimoroni_keybow2040" # no SPI bus exposed + # - "pimoroni_picosystem" # SPI is reserved for LCD + + steps: + - name: checkout RF24 lib + uses: actions/checkout@v2 + + - name: Install toolchain + run: sudo apt update && sudo apt install gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential + + - name: Clone pico-sdk + uses: actions/checkout@v2 + with: + repository: raspberrypi/pico-sdk + # master branch is latest stable release + path: pico-sdk + clean: false + submodules: true + + - name: Checkout pico-sdk submodules + working-directory: ${{ github.workspace }}/pico-sdk + run: git submodule update --init + + - name: Create Build Environment + env: + PICO_SDK_PATH: ${{ github.workspace }}/pico-sdk + run: cmake -E make_directory ${{ github.workspace }}/build + + - name: Configure CMake + working-directory: ${{ github.workspace }}/build + env: + PICO_SDK_PATH: ${{ github.workspace }}/pico-sdk + run: cmake ../examples_pico -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DPICO_BOARD=${{ matrix.board }} + + - name: Build + working-directory: ${{ github.workspace }}/build + # Execute the build. You can specify a specific target with "--target " + run: cmake --build . --config $BUILD_TYPE + + - name: Save artifact + uses: actions/upload-artifact@v2 + with: + name: examples_pico_${{ matrix.board }} + path: | + ${{ github.workspace }}/build/*.uf2 + ${{ github.workspace }}/build/*.elf + # ${{ github.workspace }}/build/*.hex + # ${{ github.workspace }}/build/*.bin diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 8f0bead73..2f6c74c3a 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -1,44 +1,79 @@ -name: DoxyGen build +name: build Docs on: pull_request: - branches: - - master + types: [opened, reopened] + paths: + - "*.h" + - "docs/**" + - "!docs/README.md" + - "*.md" + - "utility/template/*.h" + - "examples**.cpp" + - "examples**.ino" + - "images/**" + - "datasheets/**" + - ".github/workflows/doxygen.yml" + - "Doxyfile" + - "library.properties" # get lib version from here push: - branches: - - master + paths: + - "*.h" + - "docs/**" + - "!docs/README.md" + - "*.md" + - "utility/template/*.h" + - "examples**.cpp" + - "examples**.ino" + - "images/**" + - "datasheets/**" + - ".github/workflows/doxygen.yml" + - "Doxyfile" + - "library.properties" # get lib version from here release: - branches: - - master - types: - - published - - edited + types: [published, edited] + branches: [master] jobs: build-doxygen: runs-on: ubuntu-latest steps: - - name: get latest release version number - id: latest_ver - uses: pozetroninc/github-action-get-latest-release@master - with: - repository: nRF24/RF24 - - name: checkout - uses: actions/checkout@v2 - - name: overwrite doxygen tags - run: | - touch doxygenAction - echo "PROJECT_NUMBER = ${{ steps.latest_ver.outputs.release }}" >> doxygenAction - echo "@INCLUDE = doxygenAction" >> Doxyfile - - name: build doxygen - uses: mattnotmitt/doxygen-action@v1 - with: - working-directory: '.' - doxyfile-path: './Doxyfile' - - name: upload to github pages - if: ${{ github.event_name == 'release'}} - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./docs/html \ No newline at end of file + - uses: actions/checkout@v2 + - name: get latest release version number + id: latest_ver + run: echo "::set-output name=release::$(awk -F "=" '/version/ {print $2}' library.properties)" + - name: overwrite doxygen tags + run: | + touch doxygenAction + echo "PROJECT_NUMBER = ${{ steps.latest_ver.outputs.release }}" >> doxygenAction + echo "@INCLUDE = doxygenAction" >> Doxyfile + - name: build doxygen + uses: mattnotmitt/doxygen-action@v1 + with: + working-directory: '.' + doxyfile-path: './Doxyfile' + - name: Save doxygen docs as artifact + uses: actions/upload-artifact@v2 + with: + name: "RF24_doxygen_docs" + path: ${{ github.workspace }}/docs/html + - name: upload to github pages + if: ${{ github.event_name == 'release'}} + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs/html + + # build pretty docs using doxygen XML output with Sphinx + - uses: actions/setup-python@v2 + - name: Install sphinx deps + run: python -m pip install -r docs/sphinx/requirements.txt + - name: build docs with Sphinx + working-directory: docs + run: sphinx-build sphinx _build + - name: Save sphinx docs as artifact + uses: actions/upload-artifact@v2 + with: + name: "RF24_sphinx_docs" + path: ${{ github.workspace }}/docs/_build diff --git a/.gitignore b/.gitignore index 374ed8e61..783d309a4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,6 @@ .*.swp *.orig .swp -docs/html/ -docs/xml/ output/ ojam/ out/ @@ -27,11 +25,31 @@ examples_linux/**/* !examples_linux/**/*.cpp !examples_linux/Makefile !examples_linux/**/Makefile -*__pycache__/ +!examples_linux/CMakeLists.txt .directory .idea +docs/html/ +docs/latex/ +docs/*/xml/ +docs/_build/ doxygenAction .vscode/ -*venv +__pycache__/ *env -*.pyc \ No newline at end of file +*.pyc +*.egg* +build/ +*CMakeUserPresets*.json +*.tar.gz + +# Cmake build-in-source generated stuff +CMakeCache.txt +CPackConfig.cmake +CPackSourceConfig.cmake +CMakeFiles +DEBIAN +cmake_install.cmake +compile_commands.json +utility/Makefile +# Makefile is modified when `cmake .` is run +# Makefile # preserve old/traditional build system diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 000000000..c8437755e --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,24 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +build: + os: "ubuntu-20.04" + tools: + python: "3" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/sphinx/conf.py + +# Optionally build your docs in additional formats such as PDF +formats: + - pdf + +# install Python requirements required to build docs +python: + install: + - requirements: docs/sphinx/requirements.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..e3414b267 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,167 @@ +# Check if we are building a pico-sdk based project +# (or more exactly: if we just got included in a pico-sdk based project) +if (PICO_SDK_PATH) + # If so, load the relevant CMakeLists-file but don't do anything else + include(${CMAKE_CURRENT_LIST_DIR}/utility/rp2/CMakeLists.txt) + return() +endif() + +cmake_minimum_required(VERSION 3.15) + +# Set the project name to your project name +project(RF24 C CXX) +include(${CMAKE_CURRENT_LIST_DIR}/cmake/StandardProjectSettings.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/cmake/PreventInSourceBuilds.cmake) + +# get library info from Arduino IDE's required library.properties file +include(${CMAKE_CURRENT_LIST_DIR}/cmake/GetLibInfo.cmake) + +# allow CMake CLI options to configure RF24_config.h macros +option(SERIAL_DEBUG "enable/disable debugging output" OFF) +option(MINIMAL "exclude optional source code to keep compile size compact" OFF) + +# Link this 'library' to set the c++ standard / compile-time options requested +add_library(${LibTargetName}_project_options INTERFACE) +target_compile_features(${LibTargetName}_project_options INTERFACE cxx_std_17) +add_compile_options(-Ofast -Wall -pthread) + +if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + option(ENABLE_BUILD_WITH_TIME_TRACE "Enable -ftime-trace to generate time tracing .json files on clang" OFF) + if(ENABLE_BUILD_WITH_TIME_TRACE) + add_compile_definitions(${LibTargetName}_project_options INTERFACE -ftime-trace) + endif() +endif() + +# Link this 'library' to use the warnings specified in CompilerWarnings.cmake +add_library(${LibTargetName}_project_warnings INTERFACE) + +# enable cache system +include(${CMAKE_CURRENT_LIST_DIR}/cmake/Cache.cmake) + +# standard compiler warnings +include(${CMAKE_CURRENT_LIST_DIR}/cmake/CompilerWarnings.cmake) +set_project_warnings(${LibTargetName}_project_warnings) + +# sanitizer options if supported by compiler +include(${CMAKE_CURRENT_LIST_DIR}/cmake/Sanitizers.cmake) +enable_sanitizers(${LibTargetName}_project_options) + +# allow for static analysis options +include(${CMAKE_CURRENT_LIST_DIR}/cmake/StaticAnalyzers.cmake) + +option(BUILD_SHARED_LIBS "Enable compilation of shared libraries" OFF) +option(ENABLE_TESTING "Enable Test Builds" OFF) # for end-user projects +option(ENABLE_FUZZING "Enable Fuzzing Builds" OFF) # for end-user projects + +if(ENABLE_TESTING) + enable_testing() + message("Building Tests.") + add_subdirectory(test) # directory doesn't exist, so this does nothing. +endif() + +if(ENABLE_FUZZING) + message("Building Fuzz Tests, using fuzzing sanitizer https://www.llvm.org/docs/LibFuzzer.html") + add_subdirectory(fuzz_test) # directory doesn't exist, so this does nothing. +endif() + +##################################### +### Now we actually build the library +##################################### + +# detect the CPU make and type +include(${CMAKE_CURRENT_LIST_DIR}/cmake/detectCPU.cmake) # sets the variable SOC accordingly + +# auto-detect what driver to use +# auto-detect can be overriden using `cmake .. -D RF24_DRIVER=` +include(${CMAKE_CURRENT_LIST_DIR}/cmake/AutoConfig_RF24_DRIVER.cmake) + +#[[ adding the utility sub-directory will + 1. set variables RF24_DRIVER, RF24_LINKED_DRIVER, and RF24_DRIVER_SOURCES + 2. copy the approriate /utility/*/includes.h file to the /utility folder + 3. set additional install rules according to the RF24_DRIVER specified +]] +add_subdirectory(utility) + +# setup CPack options +# package dependencies are resolved correctly only after utility subdirectory is added +include(${CMAKE_CURRENT_LIST_DIR}/cmake/CPackInfo.cmake) + +add_library(${LibTargetName} SHARED + RF24.cpp + ${RF24_DRIVER_SOURCES} +) + +target_include_directories(${LibTargetName} PUBLIC utility) + +set_target_properties( + ${LibTargetName} + PROPERTIES + SOVERSION ${${LibName}_VERSION_MAJOR} + VERSION ${${LibName}_VERSION_STRING} +) + +if(NOT "${RF24_LINKED_DRIVER}" STREQUAL "") # linking to a pre-compiled utility driver + message(STATUS "Using utility library: ${RF24_LINKED_DRIVER}") + target_link_libraries(${LibTargetName} INTERFACE + ${LibTargetName}_project_options + ${LibTargetName}_project_warnings + STATIC RF24_LINKED_DRIVER + ) +else() # utility driver is compiled with the library - not linking to a pre-compiled utility driver + target_link_libraries(${LibTargetName} INTERFACE + ${LibTargetName}_project_options + ${LibTargetName}_project_warnings + ) +endif() + +# assert the appropriate preprocessor macros for RF24_config.h +if(SERIAL_DEBUG) + message(STATUS "SERIAL_DEBUG asserted") + target_compile_definitions(${LibTargetName} PUBLIC SERIAL_DEBUG) +endif() +if(MINIMAL) + message(STATUS "MINIMAL asserted") + target_compile_definitions(${LibTargetName} PUBLIC MINIMAL) +endif() +# for RF24_POWERUP_DELAY & RF24_SPI_SPEED, let the default be configured in source code +if(DEFINED RF24_POWERUP_DELAY) + message(STATUS "RF24_POWERUP_DELAY set to ${RF24_POWERUP_DELAY}") + target_compile_definitions(${LibTargetName} PUBLIC + RF24_POWERUP_DELAY=${RF24_POWERUP_DELAY} + ) +endif() +if(DEFINED RF24_SPI_SPEED) + message(STATUS "RF24_SPI_SPEED set to ${RF24_SPI_SPEED}") + target_compile_definitions(${LibTargetName} PUBLIC + RF24_SPI_SPEED=${RF24_SPI_SPEED} + ) +endif() + + +##################################### +### Install rules for root source dir +### There are separate install rules defined for each utility driver +### Installing the library requires sudo privileges +##################################### +install(TARGETS ${LibTargetName} + DESTINATION lib +) + +install(FILES + RF24.h + nRF24L01.h + printf.h + RF24_config.h + DESTINATION include/RF24 +) + +install(FILES + utility/includes.h + DESTINATION include/RF24/utility +) + +# CMAKE_CROSSCOMPILING is only TRUE when CMAKE_TOOLCHAIN_FILE is specified via CLI +if("${CMAKE_CROSSCOMPILING}" STREQUAL "FALSE") + install(CODE "message(STATUS \"Updating ldconfig\")") + install(CODE "execute_process(COMMAND ldconfig)") +endif() diff --git a/COMMON_ISSUES.md b/COMMON_ISSUES.md index 7c5b2ce20..79000fcf5 100644 --- a/COMMON_ISSUES.md +++ b/COMMON_ISSUES.md @@ -1,9 +1,13 @@ # Common Issues + + ## Settings that must match + Before you report undesirable behavior, please make sure that the following RF24 configurations match on both receiving and transmitting nRF24L01 transceivers: + 1. `RF24::setAddressWidth()` 2. `RF24::setChannel()` 3. `RF24::setDataRate()` @@ -24,15 +28,34 @@ all packets' payloads live in a TX or RX FIFO buffer. Remember that the TX FIFO buffers and the RX FIFO buffers both have a maximum occupancy of 3 payloads (regardless of the maximum 32-byte payload size). -## Here are the most common issues and their solutions. +## Prohibited usage of write*() in Interrupt Service Routine callbacks + +Because the RF24 library uses `millis()` to implement a timeout and `delay()` for mandatory wait times, the following functions cannot be used within an ISR callback method: + +- `RF24::write()` +- `RF24::writeBlocking()` +- `RF24::writeFast()` +- `RF24::startWrite()` +- `RF24::txStandBy()` & `RF24::txStandBy(uint32_t, bool)` +- `RF24::powerUp()` +- `RF24::startListening()` +- `RF24::stopListening()` + +@see The note in the documentation for `RF24::available()`. + +More info about why you can't call `millis()` (or `delay()`) from an ISR callback function is available at [the Arduino docs](https://www.google.com/url?sa=t&source=web&rct=j&url=https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/&ved=2ahUKEwjMhtSRl5jzAhVUsp4KHWIPCrIQFnoECAoQAQ&usg=AOvVaw1X9H0058Nz7Hck91VIC3bD). + +## Here are the most common issues and their solutions ### write() always returns true after setAutoAck(false) + Don't disabled the auto-ack feature. RF24::write() has no reason to doubt that the payload was delivered if the auto-ack feature is disabled. We recommend you read the docs about RF24::setAutoAck() before disabling the auto-ack feature. ### write() returns false when the payload was received + If the settings match on both endpoint transceivers, then this can only mean that the receiving nRF24L01 failed to send an acknowledgement (ACK) packet back to the transmitting nRF24L01. Usually this is due to @@ -47,7 +70,20 @@ Example issues: [#264](https://github.com/nRF24/RF24/issues/264) For reliability, please use Electrolytic or Tantalum capacitors. Ceramic capacitors may not be good enough (depending on the manufacturing source). +### Payloads received/sent are inaccurate or printDetails() outputs the unexpected value(s) + +This is likely due to the SPI speed being amped up to 10MHz by default. We recommend: + +1. Make sure the wires are not loose, and try to avoid using long wires. +2. If the previous point does not help, then try lowering the SPI speed like so + ```cpp + RF24 radio(7, 8, 4000000); // set SPI speed to 4MHz instead of default 10MHz + ``` + +In the RF24 library's beginnings, the default value was (prior to 2014) set to 4MHz. + ### my PA/LNA module fails to transmit + You may find variants of the nRF24L01 transceiver that are marketed as “nRF24L01+PA+LNA”. These modules are distinct in the fact that they come with a detachable (SMA-type) antenna. They employ seperate RFX24C01 IC with the antenna for enhanced Power Amplification (PA) and Low Noise Amplification (LNA) features. While they boast greater range with the same functionality, they are subject to a couple lesser known (and lesser advertised) drawbacks: 1. Stronger power source. Below is a chart of advertised current requirements that many MCU boards’ 3V regulators may not be able to provide (after supplying power to internal components). @@ -59,6 +95,6 @@ You may find variants of the nRF24L01 transceiver that are marketed as “nRF24L 2. Needs shielding from electromagnetic interference. Shielding usually works best when it has a path to ground (GND pin), but this connection to the GND pin is not required. It is important that the sheilding does not touch any current carrying parts. - Professionals tend to use a faraday cage/mesh to implement electromagnetic shielding, but it can be pricey for this scenario. - - A quick do-it-yourself solution (as proof-of-concept) would be to wrap the PA/LNA module with electrical tape and then wrap foil around the electrical tape (for shielding) while being very careful to not let the foil touch any current carrying parts (like the GPIO pins, the antenna mount, and the soldier joints for the antenna mount).
- See [![ghetto_shielding_1.png](https://github.com/nRF24/RF24/blob/master/images/ghetto_sheilding_1.png)](https://github.com/nRF24/RF24/blob/master/images/ghetto_sheilding_1.png) - and [![ghetto_shielding_2.png](https://github.com/nRF24/RF24/blob/master/images/ghetto_sheilding_2.png)](https://github.com/nRF24/RF24/blob/master/images/ghetto_sheilding_2.png) + - A quick do-it-yourself solution (as proof-of-concept) would be to wrap the PA/LNA module with electrical tape and then wrap foil around the electrical tape (for shielding) while being very careful to not let the foil touch any current carrying parts (like the GPIO pins, the antenna mount, and the soldier joints for the antenna mount). Observe + [![ghetto_shielding_1.png](https://github.com/nRF24/RF24/blob/master/images/ghetto_sheilding_1.png)](https://github.com/nRF24/RF24/blob/master/images/ghetto_sheilding_1.png) + [![ghetto_shielding_2.png](https://github.com/nRF24/RF24/blob/master/images/ghetto_sheilding_2.png)](https://github.com/nRF24/RF24/blob/master/images/ghetto_sheilding_2.png) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3a08ebab7..0218e2b4c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,16 @@ +# Contributing guidelines + These are the current requirements for getting your code included in RF24: -* 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 +- Try your best to follow the rest of the code, if you're unsure then [the NASA C style guide](https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19950022400.pdf) can help as it's closest to the current style. + +- Definetly follow [PEP-8](https://www.python.org/dev/peps/pep-0008/) if it's Python code. -* Definetly follow [PEP-8](https://www.python.org/dev/peps/pep-0008/) if it's Python code. +- Follow the [Arduino IDE formatting style](https://www.arduino.cc/en/Reference/StyleGuide) for Arduino examples -* Follow the [Arduino IDE formatting style](https://www.arduino.cc/en/Reference/StyleGuide) for Arduino examples +- 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 -* 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 +- CMake modules and CMakeLists.txt files should also have a uniform syntax. + - Indentation is a mandatory 4 spaces (not a `\t` character). + - Closing parenthesis for multi-line commands should have the same indentation as the line that opened the parenthesis. + - 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. diff --git a/Doxyfile b/Doxyfile index 6de46e16a..3a9a29f53 100644 --- a/Doxyfile +++ b/Doxyfile @@ -796,7 +796,7 @@ WARN_NO_PARAMDOC = NO # a warning is encountered. # The default value is: NO. -WARN_AS_ERROR = NO +WARN_AS_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which @@ -894,8 +894,8 @@ FILE_PATTERNS = *.c \ *.ucf \ *.qsf \ *.as \ - *.js \ - Makefile + *.js + # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -910,7 +910,8 @@ RECURSIVE = NO # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = Makefile \ + configure # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -2041,7 +2042,7 @@ MAN_LINKS = NO # captures the structure of the code including all documentation. # The default value is: NO. -GENERATE_XML = NO +GENERATE_XML = YES # The XML_OUTPUT tag is used to specify where the XML pages will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -2049,7 +2050,7 @@ GENERATE_XML = NO # The default directory is: xml. # This tag requires that the tag GENERATE_XML is set to YES. -XML_OUTPUT = xml +XML_OUTPUT = sphinx/xml # If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to diff --git a/Makefile b/Makefile index 758c042f8..fb1779fcc 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,12 @@ # Makefile for librf24 # # License: GPL (General Public License) -# Author: Charles-Henri Hallard -# Date: 2013/03/13 +# Author: Charles-Henri Hallard +# Date: 2013/03/13 # # Description: # ------------ -# use make all and make install to install the library +# use make all and make install to install the library # CONFIG_FILE=Makefile.inc @@ -38,7 +38,7 @@ $(LIBNAME): $(OBJECTS) $(CC) $(SHARED_LINKER_FLAGS) $(CFLAGS) -o $(LIBNAME) $^ $(SHARED_LINKER_LIBS) # Library parts -RF24.o: RF24.cpp +RF24.o: RF24.cpp $(CXX) -fPIC $(CFLAGS) -c $^ bcm2835.o: $(DRIVER_DIR)/bcm2835.c @@ -53,9 +53,9 @@ compatibility.o: $(DRIVER_DIR)/compatibility.cpp gpio.o: $(DRIVER_DIR)/gpio.cpp $(CXX) -fPIC $(CFLAGS) -c $(DRIVER_DIR)/gpio.cpp -interrupt.o: $(DRIVER_DIR)/interrupt.c - $(CXX) -fPIC $(CFLAGS) -c $(DRIVER_DIR)/interrupt.c - +interrupt.o: $(DRIVER_DIR)/interrupt.cpp + $(CXX) -fPIC $(CFLAGS) -c $(DRIVER_DIR)/interrupt.cpp + # clear configuration files cleanconfig: @echo "[Cleaning configuration]" diff --git a/README.md b/README.md index e1717487f..4dead6225 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ + [![Arduino CLI build](https://github.com/nRF24/RF24/workflows/Arduino%20CLI%20build/badge.svg)](https://github.com/nRF24/RF24/actions?query=workflow%3A%22Arduino+CLI+build%22) [![Linux build](https://github.com/nRF24/RF24/workflows/Linux%20build/badge.svg)](https://github.com/nRF24/RF24/actions?query=workflow%3A%22Linux+build%22) [![PlatformIO build](https://github.com/nRF24/RF24/actions/workflows/build_platformIO.yml/badge.svg)](https://github.com/nRF24/RF24/actions/workflows/build_platformIO.yml) +[![RP2xxx build](https://github.com/nRF24/RF24/actions/workflows/build_rp2xxx.yml/badge.svg)](https://github.com/nRF24/RF24/actions/workflows/build_rp2xxx.yml) # See http://nRF24.github.io/RF24 for all documentation ## Having problems? + Please read our **[solutions to common problems](COMMON_ISSUES.md)**. If that doesn't help, then open an issue describing your problem with as much detail as possible. ### Want to contribute? + Awesome! However, please check our [contributing guidelines](CONTRIBUTING.md) before opening a pull request. diff --git a/RF24.cpp b/RF24.cpp index 1cefa162f..454574b66 100644 --- a/RF24.cpp +++ b/RF24.cpp @@ -32,7 +32,7 @@ void RF24::csn(bool mode) // Return, CSN toggle complete return; - #elif defined(ARDUINO) && !defined(RF24_SPI_TRANSACTIONS) + #elif defined (ARDUINO) && !defined(RF24_SPI_TRANSACTIONS) // Minimum ideal SPI bus speed is 2x data rate // If we assume 2Mbs data rate and 16Mhz clock, a // divider of 4 is the minimum we want. @@ -94,6 +94,8 @@ void RF24::csn(bool mode) #if !defined(RF24_LINUX) digitalWrite(csn_pin, mode); delayMicroseconds(csDelay); + #else + static_cast(mode); // ignore -Wunused-parameter #endif // !defined(RF24_LINUX) } @@ -113,7 +115,11 @@ inline void RF24::beginTransaction() { #if defined (RF24_SPI_TRANSACTIONS) #if defined (RF24_SPI_PTR) + #if defined (RF24_RP2) + _spi->beginTransaction(spi_speed); + #else // ! defined (RF24_RP2) _spi->beginTransaction(SPISettings(spi_speed, MSBFIRST, SPI_MODE0)); + #endif // ! defined (RF24_RP2) #else // !defined(RF24_SPI_PTR) _SPI.beginTransaction(SPISettings(spi_speed, MSBFIRST, SPI_MODE0)); #endif // !defined(RF24_SPI_PTR) @@ -139,24 +145,30 @@ inline void RF24::endTransaction() void RF24::read_register(uint8_t reg, uint8_t* buf, uint8_t len) { - #if defined(RF24_LINUX) + #if defined (RF24_LINUX) || defined (RF24_RP2) beginTransaction(); //configures the spi settings for RPi, locks mutex and setting csn low uint8_t * prx = spi_rxbuff; uint8_t * ptx = spi_txbuff; - uint8_t size = len + 1; // Add register value to transmit buffer + uint8_t size = static_cast(len + 1); // Add register value to transmit buffer *ptx++ = (R_REGISTER | reg); while (len--){ *ptx++ = RF24_NOP; } // Dummy operation, just for reading - _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, size); + #if defined (RF24_RP2) + _spi->transfernb((const uint8_t*)spi_txbuff, spi_rxbuff, size); + #else // !defined (RF24_RP2) + _SPI.transfernb(reinterpret_cast(spi_txbuff), reinterpret_cast(spi_rxbuff), size); + #endif // !defined (RF24_RP2) status = *prx++; // status is 1st byte of receive buffer // decrement before to skip status byte while (--size) { *buf++ = *prx++; } + endTransaction(); // unlocks mutex and setting csn high - #else // !defined(RF24_LINUX) + + #else // !defined(RF24_LINUX) && !defined(RF24_RP2) beginTransaction(); #if defined (RF24_SPI_PTR) @@ -169,7 +181,7 @@ void RF24::read_register(uint8_t reg, uint8_t* buf, uint8_t len) #endif // !defined(RF24_SPI_PTR) endTransaction(); - #endif // !defined(RF24_LINUX) + #endif // !defined(RF24_LINUX) && !defined(RF24_RP2) } /****************************************************************************/ @@ -178,7 +190,7 @@ uint8_t RF24::read_register(uint8_t reg) { uint8_t result; - #if defined(RF24_LINUX) + #if defined (RF24_LINUX) || defined (RF24_RP2) beginTransaction(); uint8_t * prx = spi_rxbuff; @@ -186,12 +198,17 @@ uint8_t RF24::read_register(uint8_t reg) *ptx++ = (R_REGISTER | reg); *ptx++ = RF24_NOP ; // Dummy operation, just for reading - _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, 2); + #if defined (RF24_RP2) + _spi->transfernb((const uint8_t*)spi_txbuff, spi_rxbuff, 2); + #else // !defined(RF24_RP2) + _SPI.transfernb(reinterpret_cast(spi_txbuff), reinterpret_cast(spi_rxbuff), 2); + #endif // !defined(RF24_RP2) + status = *prx; // status is 1st byte of receive buffer result = *++prx; // result is 2nd byte of receive buffer endTransaction(); - #else // !defined(RF24_LINUX) + #else // !defined(RF24_LINUX) && !defined(RF24_RP2) beginTransaction(); #if defined (RF24_SPI_PTR) @@ -204,7 +221,7 @@ uint8_t RF24::read_register(uint8_t reg) #endif // !defined(RF24_SPI_PTR) endTransaction(); - #endif // !defined(RF24_LINUX) + #endif // !defined(RF24_LINUX) && !defined(RF24_RP2) return result; } @@ -213,20 +230,24 @@ uint8_t RF24::read_register(uint8_t reg) void RF24::write_register(uint8_t reg, const uint8_t* buf, uint8_t len) { - #if defined(RF24_LINUX) + #if defined (RF24_LINUX) || defined (RF24_RP2) beginTransaction(); uint8_t * prx = spi_rxbuff; uint8_t * ptx = spi_txbuff; - uint8_t size = len + 1; // Add register value to transmit buffer + uint8_t size = static_cast(len + 1); // Add register value to transmit buffer *ptx++ = (W_REGISTER | (REGISTER_MASK & reg)); - while (len--) - *ptx++ = *buf++; + while (len--) { *ptx++ = *buf++; } + + #if defined (RF24_RP2) + _spi->transfernb((const uint8_t*)spi_txbuff, spi_rxbuff, size); + #else // !defined(RF24_RP2) + _SPI.transfernb(reinterpret_cast(spi_txbuff), reinterpret_cast(spi_rxbuff), size); + #endif // !defined(RF24_RP2) - _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, size); status = *prx; // status is 1st byte of receive buffer endTransaction(); - #else // !defined(RF24_LINUX) + #else // !defined(RF24_LINUX) && !defined(RF24_RP2) beginTransaction(); #if defined (RF24_SPI_PTR) @@ -239,7 +260,7 @@ void RF24::write_register(uint8_t reg, const uint8_t* buf, uint8_t len) #endif // !defined(RF24_SPI_PTR) endTransaction(); - #endif // !defined(RF24_LINUX) + #endif // !defined(RF24_LINUX) && !defined(RF24_RP2) } /****************************************************************************/ @@ -253,28 +274,33 @@ void RF24::write_register(uint8_t reg, uint8_t value, bool is_cmd_only) beginTransaction(); #if defined (RF24_LINUX) status = _SPI.transfer(W_REGISTER | reg); - #else + #else // !defined(RF24_LINUX) || defined (RF24_RP2) #if defined (RF24_SPI_PTR) status = _spi->transfer(W_REGISTER | reg); #else // !defined (RF24_SPI_PTR) status = _SPI.transfer(W_REGISTER | reg); #endif // !defined (RF24_SPI_PTR) - #endif // !defined(RF24_LINUX) + #endif // !defined(RF24_LINUX) || defined(RF24_RP2) endTransaction(); } else { IF_SERIAL_DEBUG(printf_P(PSTR("write_register(%02x,%02x)\r\n"), reg, value)); - #if defined(RF24_LINUX) + #if defined (RF24_LINUX) || defined (RF24_RP2) beginTransaction(); uint8_t * prx = spi_rxbuff; uint8_t * ptx = spi_txbuff; *ptx++ = (W_REGISTER | reg); *ptx = value; - _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, 2); + #if defined (RF24_RP2) + _spi->transfernb((const uint8_t*)spi_txbuff, spi_rxbuff, 2); + #else // !defined(RF24_RP2) + _SPI.transfernb(reinterpret_cast(spi_txbuff), reinterpret_cast(spi_rxbuff), 2); + #endif // !defined(RF24_RP2) + status = *prx++; // status is 1st byte of receive buffer endTransaction(); - #else // !defined(RF24_LINUX) + #else // !defined(RF24_LINUX) && !defined(RF24_RP2) beginTransaction(); #if defined (RF24_SPI_PTR) @@ -285,7 +311,7 @@ void RF24::write_register(uint8_t reg, uint8_t value, bool is_cmd_only) _SPI.transfer(value); #endif // !defined(RF24_SPI_PTR) endTransaction(); - #endif // !defined(RF24_LINUX) + #endif // !defined(RF24_LINUX) && !defined(RF24_RP2) } } @@ -298,31 +324,36 @@ void RF24::write_payload(const void* buf, uint8_t data_len, const uint8_t writeT uint8_t blank_len = !data_len ? 1 : 0; if (!dynamic_payloads_enabled) { data_len = rf24_min(data_len, payload_size); - blank_len = payload_size - data_len; + blank_len = static_cast(payload_size - data_len); } else { - data_len = rf24_min(data_len, 32); + data_len = rf24_min(data_len, static_cast(32)); } //printf("[Writing %u bytes %u blanks]",data_len,blank_len); IF_SERIAL_DEBUG(printf("[Writing %u bytes %u blanks]\n", data_len, blank_len); ); - #if defined(RF24_LINUX) + #if defined (RF24_LINUX) || defined (RF24_RP2) beginTransaction(); uint8_t * prx = spi_rxbuff; uint8_t * ptx = spi_txbuff; uint8_t size; - size = data_len + blank_len + 1 ; // Add register value to transmit buffer + size = static_cast(data_len + blank_len + 1); // Add register value to transmit buffer *ptx++ = writeType; while (data_len--) { *ptx++ = *current++; } while (blank_len--) { *ptx++ = 0; } - _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, size); + #if defined (RF24_RP2) + _spi->transfernb((const uint8_t*)spi_txbuff, spi_rxbuff, size); + #else // !defined(RF24_RP2) + _SPI.transfernb(reinterpret_cast(spi_txbuff), reinterpret_cast(spi_rxbuff), size); + #endif // !defined(RF24_RP2) + status = *prx; // status is 1st byte of receive buffer endTransaction(); - #else // !defined(RF24_LINUX) + #else // !defined(RF24_LINUX) && !defined(RF24_RP2) beginTransaction(); #if defined (RF24_SPI_PTR) @@ -333,11 +364,12 @@ void RF24::write_payload(const void* buf, uint8_t data_len, const uint8_t writeT #else // !defined(RF24_SPI_PTR) status = _SPI.transfer(writeType); while (data_len--) { _SPI.transfer(*current++); } + while (blank_len--) { _SPI.transfer(0); } #endif // !defined(RF24_SPI_PTR) endTransaction(); - #endif // !defined(RF24_LINUX) + #endif // !defined(RF24_LINUX) && !defined(RF24_RP2) } /****************************************************************************/ @@ -349,46 +381,51 @@ void RF24::read_payload(void* buf, uint8_t data_len) uint8_t blank_len = 0; if (!dynamic_payloads_enabled) { data_len = rf24_min(data_len, payload_size); - blank_len = payload_size - data_len; + blank_len = static_cast(payload_size - data_len); } else { - data_len = rf24_min(data_len, 32); + data_len = rf24_min(data_len, static_cast(32)); } //printf("[Reading %u bytes %u blanks]",data_len,blank_len); IF_SERIAL_DEBUG(printf("[Reading %u bytes %u blanks]\n", data_len, blank_len); ); - #if defined(RF24_LINUX) + #if defined (RF24_LINUX) || defined (RF24_RP2) beginTransaction(); uint8_t * prx = spi_rxbuff; uint8_t * ptx = spi_txbuff; uint8_t size; - size = data_len + blank_len + 1; // Add register value to transmit buffer + size = static_cast(data_len + blank_len + 1); // Add register value to transmit buffer *ptx++ = R_RX_PAYLOAD; while(--size) { *ptx++ = RF24_NOP; } - size = data_len + blank_len + 1; // Size has been lost during while, re affect + size = static_cast(data_len + blank_len + 1); // Size has been lost during while, re affect - _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, size); + #if defined (RF24_RP2) + _spi->transfernb((const uint8_t*)spi_txbuff, spi_rxbuff, size); + #else // !defined(RF24_RP2) + _SPI.transfernb(reinterpret_cast(spi_txbuff), reinterpret_cast(spi_rxbuff), size); + #endif // !defined(RF24_RP2) status = *prx++; // 1st byte is status if (data_len > 0) { - while (--data_len) // Decrement before to skip 1st status byte - *current++ = *prx++; + // Decrement before to skip 1st status byte + while (--data_len) { *current++ = *prx++; } - *current = *prx; + *current = *prx; } endTransaction(); - #else // !defined(RF24_LINUX) + #else // !defined(RF24_LINUX) && !defined(RF24_RP2) beginTransaction(); #if defined (RF24_SPI_PTR) status = _spi->transfer(R_RX_PAYLOAD); while (data_len--) { *current++ = _spi->transfer(0xFF); } - while (blank_len--) { _spi->transfer(0xff); } + + while (blank_len--) { _spi->transfer(0xFF); } #else // !defined(RF24_SPI_PTR) status = _SPI.transfer(R_RX_PAYLOAD); @@ -398,7 +435,7 @@ void RF24::read_payload(void* buf, uint8_t data_len) #endif // !defined(RF24_SPI_PTR) endTransaction(); - #endif // !defined(RF24_LINUX) + #endif // !defined(RF24_LINUX) && !defined(RF24_RP2) } /****************************************************************************/ @@ -469,17 +506,17 @@ void RF24::print_address_register(const char* name, uint8_t reg, uint8_t qty) #else // !defined(RF24_LINUX) printf_P(PSTR(PRIPSTR"\t="), name); #endif // !defined(RF24_LINUX) + uint8_t *buffer = new uint8_t[addr_width]; while (qty--) { - uint8_t buffer[addr_width]; - read_register(reg++ & REGISTER_MASK, buffer, sizeof(buffer)); + read_register(reg++ & REGISTER_MASK, buffer, addr_width); printf_P(PSTR(" 0x")); - uint8_t* bufptr = buffer + sizeof(buffer); + uint8_t* bufptr = buffer + addr_width; while (--bufptr >= buffer) { printf_P(PSTR("%02x"), *bufptr); } } - + delete[] buffer; printf_P(PSTR("\r\n")); } @@ -488,7 +525,7 @@ void RF24::print_address_register(const char* name, uint8_t reg, uint8_t qty) /****************************************************************************/ RF24::RF24(uint16_t _cepin, uint16_t _cspin, uint32_t _spi_speed) - :ce_pin(_cepin), csn_pin(_cspin), spi_speed(_spi_speed), payload_size(32), dynamic_payloads_enabled(true), addr_width(5), _is_p_variant(false), + :ce_pin(_cepin), csn_pin(_cspin), spi_speed(_spi_speed), payload_size(32), _is_p_variant(false), _is_p0_rx(false), addr_width(5), dynamic_payloads_enabled(true), csDelay(5) { _init_obj(); @@ -497,7 +534,7 @@ RF24::RF24(uint16_t _cepin, uint16_t _cspin, uint32_t _spi_speed) /****************************************************************************/ RF24::RF24(uint32_t _spi_speed) - :ce_pin(0xFFFF), csn_pin(0xFFFF), spi_speed(_spi_speed), payload_size(32), dynamic_payloads_enabled(true), addr_width(5), _is_p_variant(false), + :ce_pin(0xFFFF), csn_pin(0xFFFF), spi_speed(_spi_speed), payload_size(32), _is_p_variant(false), _is_p0_rx(false), addr_width(5), dynamic_payloads_enabled(true), csDelay(5) { _init_obj(); @@ -508,7 +545,8 @@ RF24::RF24(uint32_t _spi_speed) void RF24::_init_obj() { // Use a pointer on the Arduino platform - #if defined (RF24_SPI_PTR) + + #if defined (RF24_SPI_PTR) && !defined (RF24_RP2) _spi = &SPI; #endif // defined (RF24_SPI_PTR) @@ -528,7 +566,6 @@ void RF24::setChannel(uint8_t channel) uint8_t RF24::getChannel() { - return read_register(RF_CH); } @@ -537,11 +574,11 @@ uint8_t RF24::getChannel() void RF24::setPayloadSize(uint8_t size) { // payload size must be in range [1, 32] - payload_size = rf24_max(1, rf24_min(32, size)); + payload_size = static_cast(rf24_max(1, rf24_min(32, size))); // write static payload size setting for all pipes for (uint8_t i = 0; i < 6; ++i) - write_register(RX_PW_P0 + i, payload_size); + write_register(static_cast(RX_PW_P0 + i), payload_size); } /****************************************************************************/ @@ -618,12 +655,12 @@ void RF24::printDetails(void) #if defined(RF24_LINUX) printf("================ SPI Configuration ================\n" ); - uint8_t bus_ce = csn_pin % 10; - uint8_t bus_numb = (csn_pin - bus_ce) / 10; + uint8_t bus_ce = static_cast(csn_pin % 10); + uint8_t bus_numb = static_cast((csn_pin - bus_ce) / 10); printf("CSN Pin\t\t= /dev/spidev%d.%d\n", bus_numb, bus_ce); printf("CE Pin\t\t= Custom GPIO%d\n", ce_pin); #endif - printf_P(PSTR("SPI Speedz\t= %d Mhz\n"),(uint8_t)(spi_speed/1000000)); //Print the SPI speed on non-Linux devices + printf_P(PSTR("SPI Speedz\t= %d Mhz\n"), static_cast(spi_speed / 1000000)); //Print the SPI speed on non-Linux devices #if defined(RF24_LINUX) printf("================ NRF Configuration ================\n"); #endif // defined(RF24_LINUX) @@ -644,16 +681,16 @@ void RF24::printDetails(void) printf_P(PSTR("Data Rate\t" PRIPSTR - "\r\n"),(char*)pgm_read_ptr(&rf24_datarate_e_str_P[getDataRate()])); + "\r\n"), (char *)(pgm_read_ptr(&rf24_datarate_e_str_P[getDataRate()]))); printf_P(PSTR("Model\t\t= " PRIPSTR - "\r\n"),(char*)pgm_read_ptr(&rf24_model_e_str_P[isPVariant()])); + "\r\n"), (char *)(pgm_read_ptr(&rf24_model_e_str_P[isPVariant()]))); printf_P(PSTR("CRC Length\t" PRIPSTR - "\r\n"),(char*)pgm_read_ptr(&rf24_crclength_e_str_P[getCRCLength()])); + "\r\n"), (char *)(pgm_read_ptr(&rf24_crclength_e_str_P[getCRCLength()]))); printf_P(PSTR("PA Power\t" PRIPSTR - "\r\n"),(char*)pgm_read_ptr(&rf24_pa_dbm_e_str_P[getPALevel()])); + "\r\n"), (char *)(pgm_read_ptr(&rf24_pa_dbm_e_str_P[getPALevel()]))); printf_P(PSTR("ARC\t\t= %d\r\n"), getARC()); } @@ -661,37 +698,37 @@ void RF24::printPrettyDetails(void) { #if defined(RF24_LINUX) printf("================ SPI Configuration ================\n"); - uint8_t bus_ce = csn_pin % 10; - uint8_t bus_numb = (csn_pin - bus_ce) / 10; + uint8_t bus_ce = static_cast(csn_pin % 10); + uint8_t bus_numb = static_cast((csn_pin - bus_ce) / 10); printf("CSN Pin\t\t\t= /dev/spidev%d.%d\n", bus_numb, bus_ce); printf("CE Pin\t\t\t= Custom GPIO%d\n", ce_pin); #endif - printf_P(PSTR("SPI Frequency\t\t= %d Mhz\n"), (uint8_t)(spi_speed / 1000000)); //Print the SPI speed on non-Linux devices + printf_P(PSTR("SPI Frequency\t\t= %d Mhz\n"), static_cast(spi_speed / 1000000)); //Print the SPI speed on non-Linux devices #if defined(RF24_LINUX) printf("================ NRF Configuration ================\n"); #endif // defined(RF24_LINUX) uint8_t channel = getChannel(); - uint16_t frequency = (uint16_t)channel + 2400; + uint16_t frequency = static_cast(channel + 2400); printf_P(PSTR("Channel\t\t\t= %u (~ %u MHz)\r\n"), channel, frequency); printf_P(PSTR("RF Data Rate\t\t" PRIPSTR - "\r\n"), (char*)pgm_read_ptr(&rf24_datarate_e_str_P[getDataRate()])); + "\r\n"), (char *)(pgm_read_ptr(&rf24_datarate_e_str_P[getDataRate()]))); printf_P(PSTR("RF Power Amplifier\t" PRIPSTR - "\r\n"), (char*)pgm_read_ptr(&rf24_pa_dbm_e_str_P[getPALevel()])); + "\r\n"), (char *)(pgm_read_ptr(&rf24_pa_dbm_e_str_P[getPALevel()]))); printf_P(PSTR("RF Low Noise Amplifier\t" PRIPSTR - "\r\n"), (char*)pgm_read_ptr(&rf24_feature_e_str_P[(bool)(read_register(RF_SETUP) & 1) * 1])); + "\r\n"), (char *)(pgm_read_ptr(&rf24_feature_e_str_P[(read_register(RF_SETUP) & 1) * 1]))); printf_P(PSTR("CRC Length\t\t" PRIPSTR - "\r\n"), (char*)pgm_read_ptr(&rf24_crclength_e_str_P[getCRCLength()])); + "\r\n"), (char *)(pgm_read_ptr(&rf24_crclength_e_str_P[getCRCLength()]))); printf_P(PSTR("Address Length\t\t= %d bytes\r\n"), (read_register(SETUP_AW) & 3) + 2); printf_P(PSTR("Static Payload Length\t= %d bytes\r\n"), getPayloadSize()); uint8_t setupRetry = read_register(SETUP_RETR); - printf_P(PSTR("Auto Retry Delay\t= %d microseconds\r\n"), (uint16_t)(setupRetry >> ARD) * 250 + 250); + printf_P(PSTR("Auto Retry Delay\t= %d microseconds\r\n"), (setupRetry >> ARD) * 250 + 250); printf_P(PSTR("Auto Retry Attempts\t= %d maximum\r\n"), setupRetry & 0x0F); uint8_t observeTx = read_register(OBSERVE_TX); @@ -701,31 +738,31 @@ void RF24::printPrettyDetails(void) { uint8_t features = read_register(FEATURE); printf_P(PSTR("Multicast\t\t" PRIPSTR - "\r\n"), (char*)pgm_read_ptr(&rf24_feature_e_str_P[(bool)(features & _BV(EN_DYN_ACK)) * 2])); + "\r\n"), (char *)(pgm_read_ptr(&rf24_feature_e_str_P[static_cast(features & _BV(EN_DYN_ACK)) * 2]))); printf_P(PSTR("Custom ACK Payload\t" PRIPSTR - "\r\n"), (char*)pgm_read_ptr(&rf24_feature_e_str_P[(bool)(features & _BV(EN_ACK_PAY)) * 1])); + "\r\n"), (char *)(pgm_read_ptr(&rf24_feature_e_str_P[static_cast(features & _BV(EN_ACK_PAY)) * 1]))); uint8_t dynPl = read_register(DYNPD); printf_P(PSTR("Dynamic Payloads\t" PRIPSTR - "\r\n"), (char*)pgm_read_ptr(&rf24_feature_e_str_P[(dynPl && (features &_BV(EN_DPL))) * 1])); + "\r\n"), (char *)(pgm_read_ptr(&rf24_feature_e_str_P[(dynPl && (features &_BV(EN_DPL))) * 1]))); uint8_t autoAck = read_register(EN_AA); if (autoAck == 0x3F || autoAck == 0) { // all pipes have the same configuration about auto-ack feature printf_P(PSTR("Auto Acknowledgment\t" PRIPSTR - "\r\n"), (char*)pgm_read_ptr(&rf24_feature_e_str_P[(bool)(autoAck) * 1])); + "\r\n"), (char *)(pgm_read_ptr(&rf24_feature_e_str_P[static_cast(autoAck) * 1]))); } else { // representation per pipe printf_P(PSTR("Auto Acknowledgment\t= 0b%c%c%c%c%c%c\r\n"), - (char)((bool)(autoAck & _BV(ENAA_P5)) + 48), - (char)((bool)(autoAck & _BV(ENAA_P4)) + 48), - (char)((bool)(autoAck & _BV(ENAA_P3)) + 48), - (char)((bool)(autoAck & _BV(ENAA_P2)) + 48), - (char)((bool)(autoAck & _BV(ENAA_P1)) + 48), - (char)((bool)(autoAck & _BV(ENAA_P0)) + 48)); + static_cast(static_cast(autoAck & _BV(ENAA_P5)) + 48), + static_cast(static_cast(autoAck & _BV(ENAA_P4)) + 48), + static_cast(static_cast(autoAck & _BV(ENAA_P3)) + 48), + static_cast(static_cast(autoAck & _BV(ENAA_P2)) + 48), + static_cast(static_cast(autoAck & _BV(ENAA_P1)) + 48), + static_cast(static_cast(autoAck & _BV(ENAA_P0)) + 48)); } config_reg = read_register(NRF_CONFIG); @@ -737,12 +774,12 @@ void RF24::printPrettyDetails(void) { bool isOpen = openPipes & _BV(i); printf_P(PSTR("pipe %u (" PRIPSTR - ") bound"), i, (char*)pgm_read_ptr(&rf24_feature_e_str_P[isOpen + 3])); + ") bound"), i, (char *)(pgm_read_ptr(&rf24_feature_e_str_P[isOpen + 3]))); if (i < 2) { - print_address_register(PSTR(""), RX_ADDR_P0 + i); + print_address_register(PSTR(""), static_cast(RX_ADDR_P0 + i)); } else { - print_byte_register(PSTR(""), RX_ADDR_P0 + i); + print_byte_register(PSTR(""), static_cast(RX_ADDR_P0 + i)); } } } @@ -755,9 +792,7 @@ void RF24::printPrettyDetails(void) { bool RF24::begin(_SPI* spiBus) { _spi = spiBus; - if (_init_pins()) - return _init_radio(); - return false; + return _init_pins() && _init_radio(); } /****************************************************************************/ @@ -784,7 +819,6 @@ bool RF24::begin(uint16_t _cepin, uint16_t _cspin) bool RF24::begin(void) { - #if defined (RF24_LINUX) #if defined (RF24_RPi) switch(csn_pin) { // Ensure valid hardware CS pin @@ -805,6 +839,9 @@ bool RF24::begin(void) #elif defined (XMEGA_D3) _spi->begin(csn_pin); + #elif defined (RF24_RP2) + _spi->begin(PICO_DEFAULT_SPI ? spi1 : spi0); + #else // using an Arduino platform || defined (LITTLEWIRE) #if defined (RF24_SPI_PTR) @@ -945,12 +982,7 @@ bool RF24::_init_radio() bool RF24::isChipConnected() { - uint8_t setup = read_register(SETUP_AW); - if (setup >= 1 && setup <= 3) { - return true; - } - - return false; + return read_register(SETUP_AW) == (addr_width - static_cast(2)); } /****************************************************************************/ @@ -973,7 +1005,7 @@ void RF24::startListening(void) ce(HIGH); // Restore the pipe0 address, if exists - if (pipe0_reading_address[0] > 0) { + if (_is_p0_rx) { write_register(RX_ADDR_P0, pipe0_reading_address, addr_width); } else { closeReadingPipe(0); @@ -989,12 +1021,12 @@ void RF24::stopListening(void) ce(LOW); //delayMicroseconds(100); - delayMicroseconds(txDelay); + delayMicroseconds(static_cast(txDelay)); if (ack_payloads_enabled){ flush_tx(); } - config_reg &= ~_BV(PRIM_RX); + config_reg = static_cast(config_reg & ~_BV(PRIM_RX)); write_register(NRF_CONFIG, config_reg); #if defined(RF24_TINY) || defined(LITTLEWIRE) @@ -1004,7 +1036,7 @@ void RF24::stopListening(void) powerUp(); } #endif - write_register(EN_RXADDR, read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[0]))); // Enable RX on pipe0 + write_register(EN_RXADDR, static_cast(read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[0])))); // Enable RX on pipe0 } /****************************************************************************/ @@ -1012,8 +1044,8 @@ void RF24::stopListening(void) void RF24::powerDown(void) { ce(LOW); // Guarantee CE is low on powerDown - config_reg &= ~_BV(PWR_UP); - write_register(NRF_CONFIG,config_reg); + config_reg = static_cast(config_reg & ~_BV(PWR_UP)); + write_register(NRF_CONFIG, config_reg); } /****************************************************************************/ @@ -1034,14 +1066,14 @@ void RF24::powerUp(void) } /******************************************************************/ -#if defined(FAILURE_HANDLING) || defined(RF24_LINUX) +#if defined (FAILURE_HANDLING) || defined (RF24_LINUX) void RF24::errNotify() { - #if defined(SERIAL_DEBUG) || defined(RF24_LINUX) + #if defined (SERIAL_DEBUG) || defined (RF24_LINUX) printf_P(PSTR("RF24 HARDWARE FAIL: Radio not responding, verify pin connections, wiring, etc.\r\n")); #endif - #if defined(FAILURE_HANDLING) + #if defined (FAILURE_HANDLING) failureDetected = 1; #else delay(5000); @@ -1288,9 +1320,9 @@ bool RF24::txStandBy(uint32_t timeout, bool startTx) void RF24::maskIRQ(bool tx, bool fail, bool rx) { /* clear the interrupt flags */ - config_reg &= ~(1 << MASK_MAX_RT | 1 << MASK_TX_DS | 1 << MASK_RX_DR); + config_reg = static_cast(config_reg & ~(1 << MASK_MAX_RT | 1 << MASK_TX_DS | 1 << MASK_RX_DR)); /* set the specified interrupt flags */ - config_reg |= fail << MASK_MAX_RT | tx << MASK_TX_DS | rx << MASK_RX_DR; + config_reg = static_cast(config_reg | fail << MASK_MAX_RT | tx << MASK_TX_DS | rx << MASK_RX_DR); write_register(NRF_CONFIG, config_reg); } @@ -1389,6 +1421,7 @@ void RF24::openReadingPipe(uint8_t child, uint64_t address) // startListening() will have to restore it. if (child == 0) { memcpy(pipe0_reading_address, &address, addr_width); + _is_p0_rx = true; } if (child <= 5) { @@ -1402,20 +1435,21 @@ void RF24::openReadingPipe(uint8_t child, uint64_t address) // Note it would be more efficient to set all of the bits for all open // pipes at once. However, I thought it would make the calling code // more simple to do it this way. - write_register(EN_RXADDR, read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[child]))); + write_register(EN_RXADDR, static_cast(read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[child])))); } } /****************************************************************************/ + void RF24::setAddressWidth(uint8_t a_width) { - - if (a_width -= 2) { - write_register(SETUP_AW, a_width % 4); - addr_width = (a_width % 4) + 2; + a_width = static_cast(a_width - 2); + if (a_width) { + write_register(SETUP_AW, static_cast(a_width % 4)); + addr_width = static_cast((a_width % 4) + 2); } else { - write_register(SETUP_AW, 0); - addr_width = 2; + write_register(SETUP_AW, static_cast(0)); + addr_width = static_cast(2); } } @@ -1429,6 +1463,7 @@ void RF24::openReadingPipe(uint8_t child, const uint8_t* address) // startListening() will have to restore it. if (child == 0) { memcpy(pipe0_reading_address, address, addr_width); + _is_p0_rx = true; } if (child <= 5) { // For pipes 2-5, only write the LSB @@ -1441,7 +1476,7 @@ void RF24::openReadingPipe(uint8_t child, const uint8_t* address) // Note it would be more efficient to set all of the bits for all open // pipes at once. However, I thought it would make the calling code // more simple to do it this way. - write_register(EN_RXADDR, read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[child]))); + write_register(EN_RXADDR, static_cast(read_register(EN_RXADDR) | _BV(pgm_read_byte(&child_pipe_enable[child])))); } } @@ -1450,7 +1485,11 @@ void RF24::openReadingPipe(uint8_t child, const uint8_t* address) void RF24::closeReadingPipe(uint8_t pipe) { - write_register(EN_RXADDR, read_register(EN_RXADDR) & ~_BV(pgm_read_byte(&child_pipe_enable[pipe]))); + write_register(EN_RXADDR, static_cast(read_register(EN_RXADDR) & ~_BV(pgm_read_byte(&child_pipe_enable[pipe])))); + if (!pipe) { + // keep track of pipe 0's RX state to avoid null vs 0 in addr cache + _is_p0_rx = false; + } } /****************************************************************************/ @@ -1532,7 +1571,7 @@ void RF24::disableAckPayload(void) { // disable ack payloads (leave dynamic payload features as is) if (ack_payloads_enabled){ - write_register(FEATURE, read_register(FEATURE) | ~_BV(EN_ACK_PAY)); + write_register(FEATURE, static_cast(read_register(FEATURE) | ~_BV(EN_ACK_PAY))); IF_SERIAL_DEBUG(printf("FEATURE=%i\r\n", read_register(FEATURE))); @@ -1602,9 +1641,9 @@ void RF24::setAutoAck(uint8_t pipe, bool enable) if (pipe < 6) { uint8_t en_aa = read_register(EN_AA); if (enable) { - en_aa |= _BV(pipe); + en_aa |= static_cast(_BV(pipe)); }else{ - en_aa &= ~_BV(pipe); + en_aa = static_cast(en_aa & ~_BV(pipe)); if (ack_payloads_enabled && !pipe){ disableAckPayload(); } @@ -1634,10 +1673,10 @@ void RF24::setPALevel(uint8_t level, bool lnaEnable) uint8_t setup = read_register(RF_SETUP) & 0xF8; - if (level > 3) { // If invalid level, go to max PA - level = (RF24_PA_MAX << 1) + lnaEnable; // +1 to support the SI24R1 chip extra bit + if (level > 3) { // If invalid level, go to max PA + level = static_cast((RF24_PA_MAX << 1) + lnaEnable); // +1 to support the SI24R1 chip extra bit } else { - level = (level << 1) + lnaEnable; // Else set level as requested + level = static_cast((level << 1) + lnaEnable); // Else set level as requested } write_register(RF_SETUP, setup |= level); // Write it to the chip @@ -1667,7 +1706,7 @@ bool RF24::setDataRate(rf24_datarate_e speed) uint8_t setup = read_register(RF_SETUP); // HIGH and LOW '00' is 1Mbs - our default - setup &= ~(_BV(RF_DR_LOW) | _BV(RF_DR_HIGH)); + setup = static_cast(setup & ~(_BV(RF_DR_LOW) | _BV(RF_DR_HIGH))); #if !defined(F_CPU) || F_CPU > 20000000 txDelay = 280; @@ -1730,7 +1769,7 @@ rf24_datarate_e RF24::getDataRate(void) void RF24::setCRCLength(rf24_crclength_e length) { - config_reg &= ~(_BV(CRCO) | _BV(EN_CRC)); + config_reg = static_cast(config_reg & ~(_BV(CRCO) | _BV(EN_CRC))); // switch uses RAM (evil!) if (length == RF24_CRC_DISABLED) { @@ -1767,14 +1806,14 @@ rf24_crclength_e RF24::getCRCLength(void) void RF24::disableCRC(void) { - config_reg &= ~_BV(EN_CRC); + config_reg = static_cast(config_reg & ~_BV(EN_CRC)); write_register(NRF_CONFIG, config_reg); } /****************************************************************************/ void RF24::setRetries(uint8_t delay, uint8_t count) { - write_register(SETUP_RETR, rf24_min(15, delay) << ARD | rf24_min(15, count)); + write_register(SETUP_RETR, static_cast(rf24_min(15, delay) << ARD | rf24_min(15, count))); } /****************************************************************************/ @@ -1821,6 +1860,6 @@ void RF24::stopConstCarrier() * however, both registers are set PWR_UP = 0 will turn TX mode off. */ powerDown(); // per datasheet recommendation (just to be safe) - write_register(RF_SETUP, read_register(RF_SETUP) & ~_BV(CONT_WAVE) & ~_BV(PLL_LOCK)); + write_register(RF_SETUP, static_cast(read_register(RF_SETUP) & ~_BV(CONT_WAVE) & ~_BV(PLL_LOCK))); ce(LOW); } diff --git a/RF24.h b/RF24.h index 55b2bbb60..ee7698041 100644 --- a/RF24.h +++ b/RF24.h @@ -28,8 +28,9 @@ * @defgroup PALevel Power Amplifier level * Power Amplifier level. The units dBm (decibel-milliwatts or dBmW) * represents a logarithmic signal loss. - * @see RF24::setPALevel() - * @see RF24::getPALevel() + * @see + * - RF24::setPALevel() + * - RF24::getPALevel() * @{ */ typedef enum { @@ -71,8 +72,9 @@ typedef enum { * @} * @defgroup Datarate datarate * How fast data moves through the air. Units are in bits per second (bps). - * @see RF24::setDataRate() - * @see RF24::getDataRate() + * @see + * - RF24::setDataRate() + * - RF24::getDataRate() * @{ */ typedef enum { @@ -89,9 +91,10 @@ typedef enum { * @defgroup CRCLength CRC length * The length of a CRC checksum that is used (if any).
Cyclical Redundancy * Checking (CRC) is commonly used to ensure data integrity. - * @see RF24::setCRCLength() - * @see RF24::getCRCLength() - * @see RF24::disableCRC() + * @see + * - RF24::setCRCLength() + * - RF24::getCRCLength() + * - RF24::disableCRC() * @{ */ typedef enum { @@ -116,7 +119,7 @@ class RF24 { SPIUARTClass uspi; #endif - #if defined (RF24_LINUX) || defined (XMEGA_D3) /* XMEGA can use SPI class */ + #if defined (RF24_LINUX) || defined (XMEGA_D3) || defined (RF24_RP2) /* XMEGA can use SPI class */ SPI spi; #endif // defined (RF24_LINUX) || defined (XMEGA_D3) #if defined (RF24_SPI_PTR) @@ -126,22 +129,19 @@ class RF24 { GPIO gpio; #endif - uint16_t ce_pin; /**< "Chip Enable" pin, activates the RX or TX role */ - uint16_t csn_pin; /**< SPI Chip select */ - uint32_t spi_speed; /**< SPI Bus Speed */ - #if defined (RF24_LINUX) || defined (XMEGA_D3) + uint16_t ce_pin; /** "Chip Enable" pin, activates the RX or TX role */ + uint16_t csn_pin; /** SPI Chip select */ + uint32_t spi_speed; /** SPI Bus Speed */ + #if defined (RF24_LINUX) || defined (XMEGA_D3) || defined (RF24_RP2) uint8_t spi_rxbuff[32+1] ; //SPI receive buffer (payload max 32 bytes) uint8_t spi_txbuff[32+1] ; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command) #endif uint8_t status; /** The status byte returned from every SPI transaction */ - uint8_t payload_size; /**< Fixed size of payloads */ - bool dynamic_payloads_enabled; /**< Whether dynamic payloads are enabled. */ - bool ack_payloads_enabled; /**< Whether ack payloads are enabled. */ - uint8_t pipe0_reading_address[5]; /**< Last address set on pipe 0 for reading. */ - uint8_t addr_width; /**< The address width to use - 3,4 or 5 bytes. */ - uint8_t config_reg; /**< For storing the value of the NRF_CONFIG register */ + uint8_t payload_size; /** Fixed size of payloads */ + uint8_t pipe0_reading_address[5]; /** Last address set on pipe 0 for reading. */ + uint8_t config_reg; /** For storing the value of the NRF_CONFIG register */ bool _is_p_variant; /** For storing the result of testing the toggleFeatures() affect */ - + bool _is_p0_rx; /** For keeping track of pipe 0's usage in user-triggered RX mode. */ protected: /** @@ -154,6 +154,29 @@ class RF24 { inline void endTransaction(); + bool ack_payloads_enabled; /** Whether ack payloads are enabled. */ + uint8_t addr_width; /** The address width to use (3, 4 or 5 bytes). */ + bool dynamic_payloads_enabled; /** Whether dynamic payloads are enabled. */ + + /** + * Read a chunk of data in from a register + * + * @param reg Which register. Use constants from nRF24L01.h + * @param buf Where to put the data + * @param len How many bytes of data to transfer + * @return Nothing. Older versions of this function returned the status + * byte, but that it now saved to a private member on all SPI transactions. + */ + void read_register(uint8_t reg, uint8_t* buf, uint8_t len); + + /** + * Read single byte from a register + * + * @param reg Which register. Use constants from nRF24L01.h + * @return Current value of register @p reg + */ + uint8_t read_register(uint8_t reg); + public: /** @@ -226,7 +249,7 @@ class RF24 { * @param spiBus A pointer or reference to an instantiated SPI bus object. * * @note The _SPI datatype is a "wrapped" definition that will represent - * various SPI implementations based on the specified platform (or SoftSPI). + * various SPI implementations based on the specified platform. * @see Review the [Arduino support page](md_docs_arduino.html). * * @return same result as begin() @@ -248,7 +271,7 @@ class RF24 { * is not supported. This means that the Due's pins 4, 10, or 52 are not mandated options (can use any digital output pin) for the radio's CSN pin. * * @note The _SPI datatype is a "wrapped" definition that will represent - * various SPI implementations based on the specified platform (or SoftSPI). + * various SPI implementations based on the specified platform. * @see Review the [Arduino support page](md_docs_arduino.html). * * @return same result as begin() @@ -346,8 +369,9 @@ class RF24 { * Read payload data from the RX FIFO buffer(s). * * The length of data read is usually the next available payload's length - * @see getPayloadSize() - * @see getDynamicPayloadSize() + * @see + * - getPayloadSize() + * - getDynamicPayloadSize() * * @note I specifically chose `void*` as a data type to make it easier * for beginners to use. No casting needed. @@ -363,20 +387,20 @@ class RF24 { * payload. A payload is not removed from the RX FIFO until it's * entire length (or more) is fetched using read(). * @remarks - * - If @a len parameter's value is less than the available payload's + * - If `len` parameter's value is less than the available payload's * length, then the payload remains in the RX FIFO. - * - If @a len parameter's value is greater than the first of multiple - * available payloads, then the data saved to the @a buf + * - If `len` parameter's value is greater than the first of multiple + * available payloads, then the data saved to the `buf` * parameter's object will be supplemented with data from the next * available payload. - * - If @a len parameter's value is greater than the last available + * - If `len` parameter's value is greater than the last available * payload's length, then the last byte in the payload is used as - * padding for the data saved to the @a buf parameter's object. + * padding for the data saved to the `buf` parameter's object. * The nRF24L01 will repeatedly use the last byte from the last * payload even when read() is called with an empty RX FIFO. * * @note To use this function in the python wrapper, remember that - * only the @a len parameter is required because this function (in the + * only the `len` parameter is required because this function (in the * python wrapper) returns the payload data as a buffer protocol object * (bytearray object). * @code{.py} @@ -420,7 +444,7 @@ class RF24 { * radio.write(&data,sizeof(data)); * @endcode * - * @note The @a len parameter must be omitted when using the python + * @note The `len` parameter must be omitted when using the python * wrapper because the length of the payload is determined automatically. *
To use this function in the python wrapper: * @code{.py} @@ -469,8 +493,9 @@ class RF24 { * disabled, then this function will still overwrite the address for * reading pipe 0 regardless. * - * @see setAddressWidth() - * @see startListening() + * @see + * - setAddressWidth() + * - startListening() * * @param address The address to be used for outgoing transmissions (uses * pipe 0). Coordinate this address amongst other receiving nodes (the @@ -489,8 +514,9 @@ class RF24 { * Up to 6 pipes can be open for reading at once. Open all the required * reading pipes, and then call startListening(). * - * @see openWritingPipe() - * @see setAddressWidth() + * @see + * - openWritingPipe() + * - setAddressWidth() * * @note Pipes 0 and 1 will store a full 5-byte address. Pipes 2-5 will technically * only store a single byte, borrowing up to 4 additional bytes from pipe 1 per the @@ -507,8 +533,7 @@ class RF24 { * * @warning If the reading pipe 0 is opened by this function, the address * passed to this function (for pipe 0) will be restored at every call to - * startListening(), but the address for pipe 0 is ONLY restored if the LSB is a - * non-zero value.
Read + * startListening().
Read * http://maniacalbits.blogspot.com/2013/04/rf24-addressing-nrf24l01-radios-require.html * to understand how to avoid using malformed addresses. This address * restoration is implemented because of the underlying neccessary @@ -605,7 +630,7 @@ class RF24 { * } * @endcode * - * @warning According to the datasheet, the data saved to @a pipe_num is + * @warning According to the datasheet, the data saved to `pipe_num` is * "unreliable" during a FALLING transition on the IRQ pin. This means you * should call whatHappened() before calling this function during * an ISR (Interrupt Service Routine).
For example: @@ -679,8 +704,9 @@ class RF24 { * multicast parameter set to true. * * Can be used with enableAckPayload() to request a response - * @see setAutoAck() - * @see write() + * @see + * - setAutoAck() + * - write() * * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent @@ -696,7 +722,7 @@ class RF24 { * packet. This condition can only be reported if the auto-ack feature * is on. * - * @note The @a len parameter must be omitted when using the python + * @note The `len` parameter must be omitted when using the python * wrapper because the length of the payload is determined automatically. *
To use this function in the python wrapper: * @code{.py} @@ -717,19 +743,19 @@ class RF24 { * retransmit is enabled, the nRF24L01 is never in TX mode long enough to disobey this rule. Allow the FIFO * to clear by issuing txStandBy() or ensure appropriate time between transmissions. * - * @code * Example (Partial blocking): + * @code + * radio.writeFast(&buf,32); // Writes 1 payload to the buffers + * txStandBy(); // Returns 0 if failed. 1 if success. Blocks only until MAX_RT timeout or success. Data flushed on fail. * - * radio.writeFast(&buf,32); // Writes 1 payload to the buffers - * txStandBy(); // Returns 0 if failed. 1 if success. Blocks only until MAX_RT timeout or success. Data flushed on fail. - * - * radio.writeFast(&buf,32); // Writes 1 payload to the buffers - * txStandBy(1000); // Using extended timeouts, returns 1 if success. Retries failed payloads for 1 seconds before returning 0. + * radio.writeFast(&buf,32); // Writes 1 payload to the buffers + * txStandBy(1000); // Using extended timeouts, returns 1 if success. Retries failed payloads for 1 seconds before returning 0. * @endcode * - * @see txStandBy() - * @see write() - * @see writeBlocking() + * @see + * - txStandBy() + * - write() + * - writeBlocking() * * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent @@ -742,7 +768,7 @@ class RF24 { * packet. This condition can only be reported if the auto-ack feature * is on. * - * @note The @a len parameter must be omitted when using the python + * @note The `len` parameter must be omitted when using the python * wrapper because the length of the payload is determined automatically. *
To use this function in the python wrapper: * @code{.py} @@ -766,13 +792,13 @@ class RF24 { * (true). Be sure to have called enableDynamicAck() at least once before * setting this parameter. * @return - * - `true` if the payload passed to @a buf was loaded in the TX FIFO. - * - `false` if the payload passed to @a buf was not loaded in the TX FIFO + * - `true` if the payload passed to `buf` was loaded in the TX FIFO. + * - `false` if the payload passed to `buf` was not loaded in the TX FIFO * because a previous payload already in the TX FIFO failed to * transmit. This condition can only be reported if the auto-ack feature * is on. * - * @note The @a len parameter must be omitted when using the python + * @note The `len` parameter must be omitted when using the python * wrapper because the length of the payload is determined automatically. *
To use this function in the python wrapper: * @code{.py} @@ -799,15 +825,16 @@ class RF24 { * // Blocks only until user timeout or success. Data flushed on fail. * @endcode * @note If used from within an interrupt, the interrupt should be disabled until completion, and sei(); called to enable millis(). - * @see txStandBy() - * @see write() - * @see writeFast() + * @see + * - txStandBy() + * - write() + * - writeFast() * * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent * @param timeout User defined timeout in milliseconds. * - * @note The @a len parameter must be omitted when using the python + * @note The `len` parameter must be omitted when using the python * wrapper because the length of the payload is determined automatically. *
To use this function in the python wrapper: * @code{.py} @@ -817,8 +844,8 @@ class RF24 { * @endcode * * @return - * - `true` if the payload passed to @a buf was loaded in the TX FIFO. - * - `false` if the payload passed to @a buf was not loaded in the TX FIFO + * - `true` if the payload passed to `buf` was loaded in the TX FIFO. + * - `false` if the payload passed to `buf` was not loaded in the TX FIFO * because a previous payload already in the TX FIFO failed to * transmit. This condition can only be reported if the auto-ack feature * is on. @@ -840,13 +867,13 @@ class RF24 { * * Example (Partial blocking): * @code - * radio.writeFast(&buf,32); - * radio.writeFast(&buf,32); - * radio.writeFast(&buf,32); //Fills the FIFO buffers up - * bool ok = txStandBy(); //Returns 0 if failed. 1 if success. - * //Blocks only until MAX_RT timeout or success. Data flushed on fail. + * radio.writeFast(&buf, 32); + * radio.writeFast(&buf, 32); + * radio.writeFast(&buf, 32); //Fills the FIFO buffers up + * bool ok = radio.txStandBy(); //Returns 0 if failed. 1 if success. + * //Blocks only until MAX_RT timeout or success. Data flushed on fail. * @endcode - * @see txStandBy(unsigned long timeout) + * @see txStandBy(uint32_t timeout, bool startTx) * @return * - `true` if all payloads in the TX FIFO were delivered successfully and * an acknowledgement (ACK packet) was received for each. If auto-ack is @@ -863,11 +890,11 @@ class RF24 { * * Fully Blocking Example: * @code - * radio.writeFast(&buf,32); - * radio.writeFast(&buf,32); - * radio.writeFast(&buf,32); //Fills the FIFO buffers up - * bool ok = txStandBy(1000); //Returns 0 if failed after 1 second of retries. 1 if success. - * //Blocks only until user defined timeout or success. Data flushed on fail. + * radio.writeFast(&buf, 32); + * radio.writeFast(&buf, 32); + * radio.writeFast(&buf, 32); //Fills the FIFO buffers up + * bool ok = radio.txStandBy(1000); //Returns 0 if failed after 1 second of retries. 1 if success. + * //Blocks only until user defined timeout or success. Data flushed on fail. * @endcode * @note If used from within an interrupt, the interrupt should be disabled until completion, and sei(); called to enable millis(). * @param timeout Number of milliseconds to retry failed payloads @@ -888,11 +915,12 @@ class RF24 { /** * Write an acknowledgement (ACK) payload for the specified pipe * - * The next time a message is received on a specified @a pipe, the data in - * @a buf will be sent back in the ACK payload. + * The next time a message is received on a specified `pipe`, the data in + * `buf` will be sent back in the ACK payload. * - * @see enableAckPayload() - * @see enableDynamicPayloads() + * @see + * - enableAckPayload() + * - enableDynamicPayloads() * * @note ACK payloads are handled automatically by the radio chip when a * regular payload is received. It is important to discard regular payloads @@ -913,7 +941,7 @@ class RF24 { * @param len Length of the data to send, up to 32 bytes max. Not affected * by the static payload set by setPayloadSize(). * - * @note The @a len parameter must be omitted when using the python + * @note The `len` parameter must be omitted when using the python * wrapper because the length of the payload is determined automatically. *
To use this function in the python wrapper: * @code{.py} @@ -972,13 +1000,12 @@ class RF24 { * retransmit/autoAck is enabled, the nRF24L01 is never in TX mode long enough to disobey this rule. Allow the FIFO * to clear by issuing txStandBy() or ensure appropriate time between transmissions. * - * @see write() - * @see writeFast() - * @see startWrite() - * @see writeBlocking() - * - * For single noAck writes: - * @see setAutoAck() + * @see + * - write() + * - writeFast() + * - startWrite() + * - writeBlocking() + * - setAutoAck() (for single noAck writes) * * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent @@ -990,7 +1017,7 @@ class RF24 { * effect on the nRF24L01's CE pin and simply loads the payload into the * TX FIFO. * - * @note The @a len parameter must be omitted when using the python + * @note The `len` parameter must be omitted when using the python * wrapper because the length of the payload is determined automatically. *
To use this function in the python wrapper: * @code{.py} @@ -1009,13 +1036,12 @@ class RF24 { * Just like write(), but it returns immediately. To find out what happened * to the send, catch the IRQ and then call whatHappened(). * - * @see write() - * @see writeFast() - * @see startFastWrite() - * @see whatHappened() - * - * For single noAck writes see: - * @see setAutoAck() + * @see + * - write() + * - writeFast() + * - startFastWrite() + * - whatHappened() + * - setAutoAck() (for single noAck writes) * * @param buf Pointer to the data to be sent * @param len Number of bytes to be sent @@ -1028,7 +1054,7 @@ class RF24 { * transmission was started. * - `false` if the TX FIFO is full and the payload could not be written. In * this condition, the transmission process is restarted. - * @note The @a len parameter must be omitted when using the python + * @note The `len` parameter must be omitted when using the python * wrapper because the length of the payload is determined automatically. *
To use this function in the python wrapper: * @code{.py} @@ -1134,6 +1160,7 @@ class RF24 { */ void closeReadingPipe(uint8_t pipe); + #if defined (FAILURE_HANDLING) /** * * If a failure has been detected, it usually indicates a hardware issue. By default the library @@ -1155,17 +1182,16 @@ class RF24 { * * @code * if(radio.failureDetected){ - * radio.begin(); // Attempt to re-configure the radio with defaults - * radio.failureDetected = 0; // Reset the detection value - * radio.openWritingPipe(addresses[1]); // Re-configure pipe addresses - * radio.openReadingPipe(1,addresses[0]); - * report_failure(); // Blink leds, send a message, etc. to indicate failure + * radio.begin(); // Attempt to re-configure the radio with defaults + * radio.failureDetected = 0; // Reset the detection value + * radio.openWritingPipe(addresses[1]); // Re-configure pipe addresses + * radio.openReadingPipe(1, addresses[0]); + * report_failure(); // Blink leds, send a message, etc. to indicate failure * } * @endcode */ - //#if defined (FAILURE_HANDLING) bool failureDetected; - //#endif + #endif // defined (FAILURE_HANDLING) /**@}*/ /** @@ -1348,8 +1374,9 @@ class RF24 { * about all outgoing payloads (using pipe 0) or incoming payloads * (concerning all RX pipes), use setAutoAck() * - * @see setAutoAck() for all pipes - * @see setAutoAck(uint8_t, bool) for individual pipes + * @see + * - setAutoAck() for all pipes + * - setAutoAck(uint8_t, bool) for individual pipes * * @code * radio.write(&data, 32, 1); // Sends a payload with no acknowledgement requested @@ -1386,11 +1413,12 @@ class RF24 { * feature is also disabled as this feature is required to send ACK * payloads. * - * @see write() - * @see writeFast() - * @see startFastWrite() - * @see startWrite() - * @see writeAckPayload() + * @see + * - write() + * - writeFast() + * - startFastWrite() + * - startWrite() + * - writeAckPayload() * * @param enable Whether to enable (true) or disable (false) the * auto-acknowledgment feature for all pipes @@ -1421,13 +1449,14 @@ class RF24 { * payloads feature is also disabled as this feature is required on pipe 0 * to send ACK payloads. * - * @see write() - * @see writeFast() - * @see startFastWrite() - * @see startWrite() - * @see writeAckPayload() - * @see enableAckPayloads() - * @see disableAckPayloads() + * @see + * - write() + * - writeFast() + * - startFastWrite() + * - startWrite() + * - writeAckPayload() + * - enableAckPayload() + * - disableAckPayload() * * @param pipe Which pipe to configure. This number should be in range * [0, 5]. @@ -1480,11 +1509,11 @@ class RF24 { * * @param speed Specify one of the following values (as defined by * @ref rf24_datarate_e): - * | @p speed (enum value) | description | - * |:---------------------:|:-----------:| - * | @ref RF24_1MBPS (0) | for 1 Mbps | - * | @ref RF24_2MBPS (1) | for 2 Mbps | - * | @ref RF24_250KBPS (2) | for 250 kbs | + * | @p speed (enum value) | description | + * |:---------------------:|:------------:| + * | @ref RF24_1MBPS (0) | for 1 Mbps | + * | @ref RF24_2MBPS (1) | for 2 Mbps | + * | @ref RF24_250KBPS (2) | for 250 kbps | * * @return true if the change was successful */ @@ -1629,13 +1658,13 @@ class RF24 { * @warning Pipes 1-5 should share the first 32 bits. * Only the least significant byte should be unique, e.g. * @code - * openReadingPipe(1, 0xF0F0F0F0AA); - * openReadingPipe(2, 0xF0F0F0F066); + * openReadingPipe(1, 0xF0F0F0F0AA); + * openReadingPipe(2, 0xF0F0F0F066); * @endcode * * @warning Pipe 0 is also used by the writing pipe so should typically be avoided as a reading pipe.
- * If used, the reading pipe 0 address needs to be restored at avery call to startListening(), and the address
- * is ONLY restored if the LSB is a non-zero value.
See http://maniacalbits.blogspot.com/2013/04/rf24-addressing-nrf24l01-radios-require.html + * If used, the reading pipe 0 address needs to be restored at every call to startListening(). + *
See http://maniacalbits.blogspot.com/2013/04/rf24-addressing-nrf24l01-radios-require.html * * @param number Which pipe# to open, 0-5. * @param address The 40-bit address of the pipe to open. @@ -1650,7 +1679,7 @@ class RF24 { * Addresses are 40-bit hex values, e.g.: * * @code - * openWritingPipe(0xF0F0F0F0F0); + * openWritingPipe(0xF0F0F0F0F0); * @endcode * * @param address The 40-bit address of the pipe to open. @@ -1661,7 +1690,8 @@ class RF24 { * Determine if an ack payload was received in the most recent call to * write(). The regular available() can also be used. * - * @deprecated Call read() to retrieve the ack payload. + * @deprecated For compatibility with old code only, see synonomous function available(). + * Use read() to retrieve the ack payload and getDynamicPayloadSize() to get the ACK payload size. * * @return True if an ack payload is available. */ @@ -1717,25 +1747,6 @@ class RF24 { */ void ce(bool level); - /** - * Read a chunk of data in from a register - * - * @param reg Which register. Use constants from nRF24L01.h - * @param buf Where to put the data - * @param len How many bytes of data to transfer - * @return Nothing. Older versions of this function returned the status - * byte, but that it now saved to a private member on all SPI transactions. - */ - void read_register(uint8_t reg, uint8_t* buf, uint8_t len); - - /** - * Read single byte from a register - * - * @param reg Which register. Use constants from nRF24L01.h - * @return Current value of register @p reg - */ - uint8_t read_register(uint8_t reg); - /** * Write a chunk of data to a register * @@ -1752,6 +1763,8 @@ class RF24 { * * @param reg Which register. Use constants from nRF24L01.h * @param value The new value to write + * @param is_cmd_only if this parameter is true, then the `reg` parameter + * is written, and the `value` param is ignored. * @return Nothing. Older versions of this function returned the status * byte, but that it now saved to a private member on all SPI transactions. */ @@ -1764,6 +1777,7 @@ class RF24 { * * @param buf Where to get the data * @param len Number of bytes to be sent + * @param writeType Specify if individual payload should be acknowledged * @return Nothing. Older versions of this function returned the status * byte, but that it now saved to a private member on all SPI transactions. */ @@ -2119,7 +2133,20 @@ class RF24 { */ /** - * @example{lineno} examples/old_backups/scanner/scanner.ino + * @example{lineno} examples_linux/scanner.cpp + * + * Example to detect interference on the various channels available. + * This is a good diagnostic tool to check whether you're picking a + * good channel for your application. + * + * Inspired by cpixip. + * See http://arduino.cc/forum/index.php/topic,54795.0.html + * + * Use ctrl+C to exit + */ + +/** + * @example{lineno} examples/scanner/scanner.ino * * Example to detect interference on the various channels available. * This is a good diagnostic tool to check whether you're picking a diff --git a/RF24_config.h b/RF24_config.h index 60d03d1f0..cb7d638e0 100644 --- a/RF24_config.h +++ b/RF24_config.h @@ -39,7 +39,10 @@ #define rf24_max(a, b) (a>b?a:b) #define rf24_min(a, b) (a #define _SPI SPI @@ -153,7 +159,7 @@ #include #define PRIPSTR "%s" #ifndef pgm_read_ptr - #define pgm_read_ptr(p) (*(p)) + #define pgm_read_ptr(p) (*(p)) #endif #elif defined (ARDUINO) && !defined (ESP_PLATFORM) && !defined (__arm__) && !defined (__ARDUINO_X86__) || defined (XMEGA) #include @@ -169,8 +175,8 @@ // Since the official arduino/ArduinoCore-samd repo switched to a unified API in 2016, // Serial.printf() is no longer defined in the unifying Arduino/ArduinoCore-API repo - #if defined (ARDUINO_ARCH_SAMD) && !defined (ARDUINO_API_VERSION) - // likely using the adafruit/ArduinoCore-samd repo + #if defined (ARDUINO_ARCH_SAMD) && defined (ARDUINO_SAMD_ADAFRUIT) + // it is defined if using the adafruit/ArduinoCore-samd repo #define printf_P Serial.printf #endif // defined (ARDUINO_ARCH_SAMD) diff --git a/cmake/AutoConfig_RF24_DRIVER.cmake b/cmake/AutoConfig_RF24_DRIVER.cmake new file mode 100644 index 000000000..34f1a043e --- /dev/null +++ b/cmake/AutoConfig_RF24_DRIVER.cmake @@ -0,0 +1,45 @@ +set(RF24_LINKED_DRIVER "") +set(RF24_DRIVER "UNKNOWN" CACHE STRING "override automatic configuration of RF24's utility driver. + Specify 1 of the following supported drivers (ie -DRF24_DRIVER=SPIDEV): + wiringPi + RPi + SPIDEV + MRAA + LittleWire" +) + +########################### +# detect pre-existing (locally installed) 3rd party libraries +########################### + +# detect installed libraries despite what RF24_DRIVER is set to +# this is always done for cross-compiling purposes +find_library(LibMRAA mraa) +find_library(LibWiringPi wiringPi) +find_library(LibLittleWire littlewire-spi) +if(EXISTS /dev/spidev0.0) + set(SPIDEV_EXISTS TRUE) +else() + set(SPIDEV_EXISTS FALSE) +endif() + + +if(${RF24_DRIVER} STREQUAL "UNKNOWN") # invokes automatic configuration + if("${SOC}" STREQUAL "BCM2708" OR "${SOC}" STREQUAL "BCM2709" OR "${SOC}" STREQUAL "BCM2835") + set(RF24_DRIVER RPi CACHE STRING "using folder /utility/RPi" FORCE) + elseif(NOT "${LibMRAA}" STREQUAL "LibMRAA-NOTFOUND") + message(STATUS "Found MRAA library: ${LibMRAA}") + set(RF24_DRIVER MRAA CACHE STRING "using folder /utility/MRAA" FORCE) + elseif(NOT "${LibWiringPi}" STREQUAL "LibWiringPi-NOTFOUND") + message(STATUS "Found wiringPi library: ${LibWiringPi}") + set(RF24_DRIVER wiringPi CACHE STRING "using folder /utility/wiringPi" FORCE) + elseif(NOT "${LibLittleWire}" STREQUAL "LibLittleWire-NOTFOUND") + message(STATUS "Found LittleWire library: ${LibLittleWire}") + set(RF24_DRIVER LittleWire CACHE STRING "using folder /utility/LittleWire" FORCE) + elseif(SPIDEV_EXISTS) # should be a non-empty string if SPI is enabled + message(STAUS "detected that SPIDEV is enabled: ${SPIDEV_EXISTS}") + set(RF24_DRIVER SPIDEV CACHE STRING "using folder /utility/SPIDEV" FORCE) + endif() +endif() + +message(STATUS "Using driver: ${RF24_DRIVER}") diff --git a/cmake/CPackInfo.cmake b/cmake/CPackInfo.cmake new file mode 100644 index 000000000..808cdff2e --- /dev/null +++ b/cmake/CPackInfo.cmake @@ -0,0 +1,75 @@ +# This module will build a debian compatible package to install - handy for cross-compiling + +if(NOT PKG_REV) + set(PKG_REV "1") +endif() + +# get target arch if not cross-compiling +if(NOT TARGET_ARCH) # TARGET_ARCH is defined only in the toolchain_.cmake files + execute_process(COMMAND dpkg --print-architecture + OUTPUT_VARIABLE TARGET_ARCH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endif() + +# set the Cpack generators (specific to types of packages to create) +set(CPACK_GENERATOR DEB RPM) # RPM requires rpmbuild executable + +# assemble a debian package filename from known info +include(InstallRequiredSystemLibraries) +set(CPACK_PACKAGE_FILE_NAME "lib${LibTargetName}-${RF24_DRIVER}_${${LibName}_VERSION_STRING}-${PKG_REV}_${TARGET_ARCH}") +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") +set(CPACK_PACKAGE_VERSION_MAJOR "${${LibName}_VERSION_MAJOR}") +set(CPACK_PACKAGE_VERSION_MINOR "${${LibName}_VERSION_MINOR}") +set(CPACK_PACKAGE_VERSION_PATCH "${${LibName}_VERSION_PATCH}") +set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/pkgs") # for easy uploading to github releases + +############################### +# info specific debian packages +############################### +set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${TARGET_ARCH}) +set(CPACK_DEBIAN_PACKAGE_SECTION libs) +set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE) + + +############################### +# info specific rpm (fedora) packages +############################### +set(CPACK_RPM_FILE_NAME "lib${LibTargetName}-${RF24_DRIVER}-${${LibName}_VERSION_STRING}-${PKG_REV}.${TARGET_ARCH}.rpm") +set(CPACK_RPM_PACKAGE_ARCHITECTURE ${TARGET_ARCH}) +set(CPACK_RPM_PACKAGE_LICENSE "GPLv2.0") +set(CPACK_RPM_PACKAGE_VENDOR "Humanity") + +# set dependencies based on utility drivers +if("${RF24_DRIVER}" STREQUAL "MRAA") + set(CPACK_DEBIAN_PACKAGE_DEPENDS mraa) + set(CPACK_RPM_PACKAGE_REQUIRES "mraa") +elseif("${RF24_DRIVER}" STREQUAL "wiringPi") + set(CPACK_DEBIAN_PACKAGE_DEPENDS wiringPi) + set(CPACK_RPM_PACKAGE_REQUIRES "wiringPi") +elseif("${RF24_DRIVER}" STREQUAL "littlewire-spi") + set(CPACK_DEBIAN_PACKAGE_DEPENDS littlewire-spi) + set(CPACK_RPM_PACKAGE_REQUIRES "littlewire-spi") +endif() + +# create a post-install & post-removal scripts to update linker +set(POST_SCRIPTS + ${CMAKE_BINARY_DIR}/DEBIAN/postrm + ${CMAKE_BINARY_DIR}/DEBIAN/postinst +) +foreach(script ${POST_SCRIPTS}) + file(WRITE ${script} ldconfig) + execute_process(COMMAND chmod +x ${script}) + execute_process(COMMAND chmod 775 ${script}) +endforeach() +# declare scripts for deb pkgs +list(JOIN POST_SCRIPTS ";" EXTRA_CTRL_FILES) +set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA ${EXTRA_CTRL_FILES}) +# declare scripts for rpm pkgs +list(POP_FRONT POST_SCRIPTS CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE) +list(POP_FRONT POST_SCRIPTS CPACK_RPM_POST_INSTALL_SCRIPT_FILE) + +message(STATUS "ready to package: ${CPACK_PACKAGE_FILE_NAME}.deb") +message(STATUS "ready to package: ${CPACK_RPM_FILE_NAME}") + +include(CPack) diff --git a/cmake/Cache.cmake b/cmake/Cache.cmake new file mode 100644 index 000000000..e27a501f1 --- /dev/null +++ b/cmake/Cache.cmake @@ -0,0 +1,28 @@ +option(ENABLE_CACHE "Enable cache if available" ON) +if(NOT ENABLE_CACHE) + return() +endif() + +set(CACHE_OPTION "ccache" CACHE STRING "Compiler cache to be used") +set(CACHE_OPTION_VALUES "ccache" "sccache") +set_property(CACHE CACHE_OPTION PROPERTY STRINGS ${CACHE_OPTION_VALUES}) +list( + FIND + CACHE_OPTION_VALUES + ${CACHE_OPTION} + CACHE_OPTION_INDEX +) + +if(${CACHE_OPTION_INDEX} EQUAL -1) + message(STATUS + "Using custom compiler cache system: '${CACHE_OPTION}', explicitly supported entries are ${CACHE_OPTION_VALUES}" + ) +endif() + +find_program(CACHE_BINARY ${CACHE_OPTION}) +if(CACHE_BINARY) + message(STATUS "${CACHE_OPTION} found and enabled") + set(CMAKE_CXX_COMPILER_LAUNCHER ${CACHE_BINARY}) +else() + message(WARNING "${CACHE_OPTION} is enabled but was not found. Not using it") +endif() diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake new file mode 100644 index 000000000..e40f0ab79 --- /dev/null +++ b/cmake/CompilerWarnings.cmake @@ -0,0 +1,78 @@ +# from here: +# +# https://github.com/lefticus/cppbestpractices/blob/master/02-Use_the_Tools_Available.md + +function(set_project_warnings project_name) + option(WARNINGS_AS_ERRORS "Treat compiler warnings as errors" TRUE) + + set(MSVC_WARNINGS + /W4 # Baseline reasonable warnings + /w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss of data + /w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data + /w14263 # 'function': member function does not override any base class virtual member function + /w14265 # 'classname': class has virtual functions, but destructor is not virtual instances of this class may not + # be destructed correctly + /w14287 # 'operator': unsigned/negative constant mismatch + /we4289 # nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside + # the for-loop scope + /w14296 # 'operator': expression is always 'boolean_value' + /w14311 # 'variable': pointer truncation from 'type1' to 'type2' + /w14545 # expression before comma evaluates to a function which is missing an argument list + /w14546 # function call before comma missing argument list + /w14547 # 'operator': operator before comma has no effect; expected operator with side-effect + /w14549 # 'operator': operator before comma has no effect; did you intend 'operator'? + /w14555 # expression has no effect; expected expression with side- effect + /w14619 # pragma warning: there is no warning number 'number' + /w14640 # Enable warning on thread un-safe static member initialization + /w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior. + /w14905 # wide string literal cast to 'LPSTR' + /w14906 # string literal cast to 'LPWSTR' + /w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied + /permissive- # standards conformance mode for MSVC compiler. + ) + + set(CLANG_WARNINGS + -Wall + -Wextra # reasonable and standard + -Wshadow # warn the user if a variable declaration shadows one from a parent context + -Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor. This helps + # catch hard to track down memory errors + # -Wold-style-cast # warn for c-style casts + -Wcast-align # warn for potential performance problem casts + -Wunused # warn on anything being unused + -Woverloaded-virtual # warn if you overload (not override) a virtual function + -Wpedantic # warn if non-standard C++ is used + -Wconversion # warn on type conversions that may lose data + -Wsign-conversion # warn on sign conversions + -Wnull-dereference # warn if a null dereference is detected + -Wdouble-promotion # warn if float is implicit promoted to double + -Wformat=2 # warn on security issues around functions that format output (ie printf) + ) + + if(WARNINGS_AS_ERRORS) + set(CLANG_WARNINGS ${CLANG_WARNINGS} -Werror) + set(MSVC_WARNINGS ${MSVC_WARNINGS} /WX) + endif() + + set(GCC_WARNINGS + ${CLANG_WARNINGS} + -Wmisleading-indentation # warn if indentation implies blocks where blocks do not exist + -Wduplicated-cond # warn if if / else chain has duplicated conditions + -Wduplicated-branches # warn if if / else branches have duplicated code + -Wlogical-op # warn about logical operations being used where bitwise were probably wanted + -Wuseless-cast # warn if you perform a cast to the same type + ) + + if(MSVC) + set(PROJECT_WARNINGS ${MSVC_WARNINGS}) + elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + set(PROJECT_WARNINGS ${CLANG_WARNINGS}) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(PROJECT_WARNINGS ${GCC_WARNINGS}) + else() + message(AUTHOR_WARNING "No compiler warnings set for '${CMAKE_CXX_COMPILER_ID}' compiler.") + endif() + + target_compile_options(${project_name} INTERFACE ${PROJECT_WARNINGS}) + +endfunction() diff --git a/cmake/GetLibInfo.cmake b/cmake/GetLibInfo.cmake new file mode 100644 index 000000000..3871395ed --- /dev/null +++ b/cmake/GetLibInfo.cmake @@ -0,0 +1,43 @@ +# get lib info from the maintained library.properties required by the Arduino IDE +file(STRINGS ${CMAKE_CURRENT_LIST_DIR}/../library.properties LibInfo) +foreach(line ${LibInfo}) + string(FIND ${line} "=" label_delimiter) + if(${label_delimiter} GREATER 0) + math(EXPR label_delimiter "${label_delimiter} + 1") + string(FIND ${line} "version" has_version) + string(FIND ${line} "name" has_name) + string(FIND ${line} "maintainer" has_maintainer) + string(FIND ${line} "sentence" has_sentence) + string(FIND ${line} "url" has_url) + string(FIND ${line} "paragraph" has_paragraph) + if(${has_version} EQUAL 0) + string(SUBSTRING ${line} ${label_delimiter} "-1" VERSION) + elseif(${has_name} EQUAL 0) + string(SUBSTRING ${line} ${label_delimiter} "-1" LibName) + elseif(${has_maintainer} EQUAL 0) + string(SUBSTRING ${line} ${label_delimiter} "-1" CPACK_PACKAGE_CONTACT) + elseif(${has_sentence} EQUAL 0) + string(SUBSTRING ${line} ${label_delimiter} "-1" CPACK_PACKAGE_DESCRIPTION_SUMMARY) + elseif(${has_url} EQUAL 0) + string(SUBSTRING ${line} ${label_delimiter} "-1" CMAKE_PROJECT_HOMEPAGE_URL) + elseif(${has_paragraph} EQUAL 0) + string(SUBSTRING ${line} ${label_delimiter} "-1" CPACK_PACKAGE_DESCRIPTION) + endif() + endif() +endforeach() + +# convert the LibName to lower case +string(TOLOWER ${LibName} LibTargetName) + +#parse the version information into pieces. +string(REGEX REPLACE "^([0-9]+)\\..*" "\\1" VERSION_MAJOR "${VERSION}") +string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${VERSION}") +string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_PATCH "${VERSION}") + +# this is the library version +set(${LibName}_VERSION_MAJOR ${VERSION_MAJOR}) +set(${LibName}_VERSION_MINOR ${VERSION_MINOR}) +set(${LibName}_VERSION_PATCH ${VERSION_PATCH}) +set(${LibName}_VERSION_STRING ${${LibName}_VERSION_MAJOR}.${${LibName}_VERSION_MINOR}.${${LibName}_VERSION_PATCH}) + +message(STATUS "${LibName} library version: ${${LibName}_VERSION_STRING}") diff --git a/cmake/PreventInSourceBuilds.cmake b/cmake/PreventInSourceBuilds.cmake new file mode 100644 index 000000000..dc4fd811b --- /dev/null +++ b/cmake/PreventInSourceBuilds.cmake @@ -0,0 +1,18 @@ +# +# This function will prevent in-source builds +function(AssureOutOfSourceBuilds) + # make sure the user doesn't play dirty with symlinks + get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) + get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) + + # disallow in-source builds + if("${srcdir}" STREQUAL "${bindir}") + message("######################################################") + message("Warning: in-source builds are disabled") + message("Please create a separate build directory and run cmake from there") + message("######################################################") + message(FATAL_ERROR "Quitting configuration") + endif() +endfunction() + +assureoutofsourcebuilds() diff --git a/cmake/Sanitizers.cmake b/cmake/Sanitizers.cmake new file mode 100644 index 000000000..c9d3ac821 --- /dev/null +++ b/cmake/Sanitizers.cmake @@ -0,0 +1,55 @@ +function(enable_sanitizers project_name) + + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + option(ENABLE_COVERAGE "Enable coverage reporting for gcc/clang" FALSE) + + if(ENABLE_COVERAGE) + target_compile_options(${project_name} INTERFACE --coverage -O0 -g) + target_link_libraries(${project_name} INTERFACE --coverage) + endif() + + set(SANITIZERS "") + + option(ENABLE_SANITIZER_ADDRESS "Enable address sanitizer" FALSE) + if(ENABLE_SANITIZER_ADDRESS) + list(APPEND SANITIZERS "address") + endif() + + option(ENABLE_SANITIZER_LEAK "Enable leak sanitizer" FALSE) + if(ENABLE_SANITIZER_LEAK) + list(APPEND SANITIZERS "leak") + endif() + + option(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR "Enable undefined behavior sanitizer" FALSE) + if(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR) + list(APPEND SANITIZERS "undefined") + endif() + + option(ENABLE_SANITIZER_THREAD "Enable thread sanitizer" FALSE) + if(ENABLE_SANITIZER_THREAD) + if("address" IN_LIST SANITIZERS OR "leak" IN_LIST SANITIZERS) + message(WARNING "Thread sanitizer does not work with Address and Leak sanitizer enabled") + else() + list(APPEND SANITIZERS "thread") + endif() + endif() + + option(ENABLE_SANITIZER_MEMORY "Enable memory sanitizer" FALSE) + if(ENABLE_SANITIZER_MEMORY AND CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + if("address" IN_LIST SANITIZERS OR "thread" IN_LIST SANITIZERS OR "leak" IN_LIST SANITIZERS) + message(WARNING "Memory sanitizer does not work with Address, Thread and Leak sanitizer enabled") + else() + list(APPEND SANITIZERS "memory") + endif() + endif() + + list(JOIN SANITIZERS "," LIST_OF_SANITIZERS) + + endif() + + if(LIST_OF_SANITIZERS AND NOT "${LIST_OF_SANITIZERS}" STREQUAL "") + target_compile_options(${project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS}) + target_link_libraries(${project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS}) + endif() + +endfunction() diff --git a/cmake/StandardProjectSettings.cmake b/cmake/StandardProjectSettings.cmake new file mode 100644 index 000000000..35fdec0fd --- /dev/null +++ b/cmake/StandardProjectSettings.cmake @@ -0,0 +1,33 @@ +# Set a default build type if none was specified +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) + message(STATUS "Setting build type to '${CMAKE_BUILD_TYPE}' as none was specified.") + + # Set the possible values of build type for cmake-gui, ccmake + set_property( + CACHE CMAKE_BUILD_TYPE + PROPERTY STRINGS + "Debug" + "Release" + "MinSizeRel" + "RelWithDebInfo" + ) +endif() + +# Generate compile_commands.json to make it easier to work with clang based tools +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +option(ENABLE_IPO "Enable Interprocedural Optimization, aka Link Time Optimization (LTO)" OFF) + +if(ENABLE_IPO) + include(CheckIPOSupported) + check_ipo_supported( + RESULT result + OUTPUT output + ) + if(result) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + else() + message(SEND_ERROR "IPO is not supported: ${output}") + endif() +endif() diff --git a/cmake/StaticAnalyzers.cmake b/cmake/StaticAnalyzers.cmake new file mode 100644 index 000000000..5f8e56aa1 --- /dev/null +++ b/cmake/StaticAnalyzers.cmake @@ -0,0 +1,38 @@ +option(ENABLE_CPPCHECK "Enable static analysis with cppcheck" OFF) +option(ENABLE_CLANG_TIDY "Enable static analysis with clang-tidy" OFF) +option(ENABLE_INCLUDE_WHAT_YOU_USE "Enable static analysis with include-what-you-use" OFF) + +if(ENABLE_CPPCHECK) + find_program(CPPCHECK cppcheck) + if(CPPCHECK) + set(CMAKE_CXX_CPPCHECK + ${CPPCHECK} + --suppress=missingInclude + --enable=all + --inline-suppr + --inconclusive + -i + ${CMAKE_SOURCE_DIR}/imgui/lib + ) + else() + message(SEND_ERROR "cppcheck requested but executable not found") + endif() +endif() + +if(ENABLE_CLANG_TIDY) + find_program(CLANGTIDY clang-tidy) + if(CLANGTIDY) + set(CMAKE_CXX_CLANG_TIDY ${CLANGTIDY} -extra-arg=-Wno-unknown-warning-option) + else() + message(SEND_ERROR "clang-tidy requested but executable not found") + endif() +endif() + +if(ENABLE_INCLUDE_WHAT_YOU_USE) + find_program(INCLUDE_WHAT_YOU_USE include-what-you-use) + if(INCLUDE_WHAT_YOU_USE) + set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${INCLUDE_WHAT_YOU_USE}) + else() + message(SEND_ERROR "include-what-you-use requested but executable not found") + endif() +endif() diff --git a/cmake/detectCPU.cmake b/cmake/detectCPU.cmake new file mode 100644 index 000000000..cc3236282 --- /dev/null +++ b/cmake/detectCPU.cmake @@ -0,0 +1,78 @@ +# try to get the CPU model using a Linux bash command +if(NOT SOC) # if SOC variable not defined by user at CLI + if(EXISTS "/sys/class/sunxi_info/sys_info") + execute_process(COMMAND grep sunxi_platform /sys/class/sunxi_info/sys_info + OUTPUT_VARIABLE CPU_MODEL + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + else() + execute_process(COMMAND grep Hardware /proc/cpuinfo + OUTPUT_VARIABLE CPU_MODEL + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endif() + + string(FIND "${CPU_MODEL}" ":" cpu_is_described) + if(${cpu_is_described} GREATER 0) # Hardware field does exist + math(EXPR cpu_is_described "${cpu_is_described} + 1") + string(SUBSTRING "${CPU_MODEL}" ${cpu_is_described} -1 SOC) + string(STRIP "${SOC}" SOC) + else() # Hardware field does not exist + set(SOC "UNKNOWN") # use this string as a sentinel + endif() + message(STATUS "detected SoC: ${SOC}") +else() + message(STATUS "SOC set to ${SOC}") +endif() + +string(FIND "${SOC}" "Generic AM33XX" is_AM33XX) + +#[[ detect machine hardware name +This CPU_TYPE variable is not used anywhere. +It remains as useful prompt info & to be consistent with old build system ]] +execute_process(COMMAND uname -m + OUTPUT_VARIABLE CPU_TYPE + OUTPUT_STRIP_TRAILING_WHITESPACE +) +message(STATUS "detected CPU type: ${CPU_TYPE}") + +# identify the compiler base name for customizing flags +# THIS ONLY WORKS/TESTED FOR GNU COMPILERS +if(NOT CMAKE_CROSSCOMPILING) # need to use /usr/lib/gcc soft symlink + # NOTE the following command doesn't work with " | tail -1" appended + execute_process(COMMAND ls /usr/lib/gcc + OUTPUT_VARIABLE tool_name + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # use only last entry if multiple entries are returned; this tactic is a possible point of error + string(FIND "${tool_name}" "\n" last_list_delimiter REVERSE) + if(last_list_delimiter GREATER -1) + math(EXPR last_list_delimiter "${last_list_delimiter} + 1") + string(SUBSTRING "${tool_name}" ${last_list_delimiter} -1 tool_name) + endif() + +else() # we can use the compiler's name of the path set in the toolchain file + string(REGEX REPLACE "^\/usr\/bin\/(.*)-gcc.*" "\\1" tool_name "${CMAKE_C_COMPILER}") +endif() + +message(STATUS "tool name being used: ${tool_name}") + +# add compiler flags to optomize builds with arm-linux-gnueabihf-g* compilers +if("${tool_name}" STREQUAL "arm-linux-gnueabihf") + if("${SOC}" STREQUAL "BCM2835" OR "${SOC}" STREQUAL "BCM2708") + add_compile_options(-marm -march=armv6zk -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard) + elseif("$SOC" STREQUAL "BCM2836" OR "${SOC}" STREQUAL "BCM2709") + add_compile_options(-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard) + elseif(${is_AM33XX} GREATER -1) + add_compile_options(-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard) + elseif("$SOC" STREQUAL "sun4i" OR "${SOC}" STREQUAL "Sun4iw1p1") # A10 + add_compile_options(-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard) + elseif("$SOC" STREQUAL "sun5i" OR "${SOC}" STREQUAL "Sun4iw2p1") # A13 + add_compile_options(-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard) + elseif("$SOC" STREQUAL "sun7i" OR "${SOC}" STREQUAL "Sun8iw2p1") # A20 + add_compile_options(-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard) + elseif("$SOC" STREQUAL "sun8i" OR "${SOC}" STREQUAL "Sun8iw7p1") # H3 + add_compile_options(-march=armv8-a -mtune=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard) + endif() +endif() diff --git a/cmake/pico_sdk_import.cmake b/cmake/pico_sdk_import.cmake new file mode 100644 index 000000000..0a1da564f --- /dev/null +++ b/cmake/pico_sdk_import.cmake @@ -0,0 +1,62 @@ +# This is a copy of /external/pico_sdk_import.cmake +# +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if(DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif() + +if(DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif() + +if(DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") + +if(NOT PICO_SDK_PATH) + if(PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if(PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif() + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + ) + if(NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif() + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif() +endif() + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if(NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif() + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if(NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif() + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/cmake/toolchains/arm64.cmake b/cmake/toolchains/arm64.cmake new file mode 100644 index 000000000..23e41ca7f --- /dev/null +++ b/cmake/toolchains/arm64.cmake @@ -0,0 +1,33 @@ +###################### FOR CROSS-COMPILING using the aarch64-linux-gnu-g** compiler +# invoke this toolchain file using `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/.cmake` +# this file is meant to be used generically, but will not work for all CMake projects +# this toolchain file's cmds was copied from the CMake docs then modified for better explanation and re-use + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR arm64) +set(TARGET_ARCH arm64) # only used in cmake/createDebianPkg.cmake +set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++) + +# CMAKE_SYSROOT can only be set in a toolchain file +# set(CMAKE_SYSROOT /usr/aarch64-linux-gnu) # useful when a target machine's files are available + +# set the directory for searching installed headers +# add_compile_options(-I /usr/aarch64-linux-gnu/include) # this may not be best practice + +#[[ +# CMAKE_STAGING_PREFIX is only useful for transfering a built CMake project to a target machine +set(CMAKE_STAGING_PREFIX /home/devel/stage) # use CMAKE_INSTALL_PREFIX instead (see below comments) + +CMAKE_FIND_ROOT_PATH is an empty list by default (this list can be modified where applicable) +if cross-compiling a dependent lib (like MRAA - which is optional), then +set the lib's CMAKE_INSTALL_PREFIX to a value that is appended to RF24 lib's CMAKE_FIND_ROOT_PATH +example using MRAA: +(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 +(for RF24/build dir) `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/arm64.cmake +]] +list(APPEND CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # search CMAKE_SYSROOT when find_program() is called +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_library() is called +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_file() is called +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_package() is called diff --git a/cmake/toolchains/armhf.cmake b/cmake/toolchains/armhf.cmake new file mode 100644 index 000000000..488b81a89 --- /dev/null +++ b/cmake/toolchains/armhf.cmake @@ -0,0 +1,33 @@ +###################### FOR CROSS-COMPILING using the arm-linux-gnueabihf-g** compiler +# invoke this toolchain file using `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/.cmake` +# this file is meant to be used generically, but will not work for all CMake projects +# this toolchain file's cmds was copied from the CMake docs then modified for better explanation and re-use + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR armhf) +set(TARGET_ARCH armhf) # only used in cmake/CPackInfo.cmake +set(CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabihf-gcc) +set(CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabihf-g++) + +# CMAKE_SYSROOT can only be set in a toolchain file +# set(CMAKE_SYSROOT /usr/arm-linux-gnueabihf) # useful when a target machine's files are available + +# set the directory for searching installed headers +# add_compile_options(-I /usr/arm-linux-gnueabihf/include) # this may not be best practice + +#[[ +# CMAKE_STAGING_PREFIX is only useful for transfering a built CMake project to a target machine +set(CMAKE_STAGING_PREFIX /home/devel/stage) # use CMAKE_INSTALL_PREFIX instead (see below comments) + +CMAKE_FIND_ROOT_PATH is an empty list by default (this list can be modified where applicable) +if cross-compiling a dependent lib (like MRAA - which is optional), then +set the lib's CMAKE_INSTALL_PREFIX to a value that is appended to RF24 lib's CMAKE_FIND_ROOT_PATH +example using MRAA: +(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 +(for RF24/build dir) `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/arm.cmake +]] +list(APPEND CMAKE_FIND_ROOT_PATH /usr/arm-linux-gnueabihf) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # search CMAKE_SYSROOT when find_program() is called +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_library() is called +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_file() is called +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_package() is called diff --git a/cmake/toolchains/default.cmake b/cmake/toolchains/default.cmake new file mode 100644 index 000000000..e67d723f8 --- /dev/null +++ b/cmake/toolchains/default.cmake @@ -0,0 +1 @@ +# empty toolchain file to allow CI scripts to still use system default toolchains \ No newline at end of file diff --git a/cmake/toolchains/i686.cmake b/cmake/toolchains/i686.cmake new file mode 100644 index 000000000..f3c42be06 --- /dev/null +++ b/cmake/toolchains/i686.cmake @@ -0,0 +1,33 @@ +###################### FOR CROSS-COMPILING using the i686-linux-gnu-g** compiler +# invoke this toolchain file using `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/.cmake` +# this file is meant to be used generically, but will not work for all CMake projects +# this toolchain file's cmds was copied from the CMake docs then modified for better explanation and re-use + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR i686) +set(TARGET_ARCH i686) # only used in cmake/createDebianPkg.cmake +set(CMAKE_C_COMPILER /usr/bin/i686-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER /usr/bin/i686-linux-gnu-g++) + +# CMAKE_SYSROOT can only be set in a toolchain file +# set(CMAKE_SYSROOT /usr/i686-linux-gnu) # useful when a target machine's files are available + +# set the directory for searching installed headers +# add_compile_options(-I /usr/i686-linux-gnu/include) # this may not be best practice + +#[[ +# CMAKE_STAGING_PREFIX is only useful for transfering a built CMake project to a target machine +set(CMAKE_STAGING_PREFIX /home/devel/stage) # use CMAKE_INSTALL_PREFIX instead (see below comments) + +CMAKE_FIND_ROOT_PATH is an empty list by default (this list can be modified where applicable) +if cross-compiling a dependent lib (like MRAA - which is optional), then +set the lib's CMAKE_INSTALL_PREFIX to a value that is appended to RF24 lib's CMAKE_FIND_ROOT_PATH +example using MRAA: +(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 +(for RF24/build dir) `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/i686.cmake +]] +list(APPEND CMAKE_FIND_ROOT_PATH /usr/i686-linux-gnu) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # search CMAKE_SYSROOT when find_program() is called +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_library() is called +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_file() is called +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_package() is called diff --git a/cmake/toolchains/x86_64.cmake b/cmake/toolchains/x86_64.cmake new file mode 100644 index 000000000..e4ff737a8 --- /dev/null +++ b/cmake/toolchains/x86_64.cmake @@ -0,0 +1,33 @@ +###################### FOR CROSS-COMPILING using the x86_64-linux-gnux32-g** compiler +# invoke this toolchain file using `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/.cmake` +# this file is meant to be used generically, but will not work for all CMake projects +# this toolchain file's cmds was copied from the CMake docs then modified for better explanation and re-use + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR x86_64) +set(TARGET_ARCH x86_64) # only used in cmake/createDebianPkg.cmake +set(CMAKE_C_COMPILER /usr/bin/x86_64-linux-gnux32-gcc) +set(CMAKE_CXX_COMPILER /usr/bin/x86_64-linux-gnux32-g++) + +# CMAKE_SYSROOT can only be set in a toolchain file +# set(CMAKE_SYSROOT /usr/x86_64-linux-gnux32) # useful when a target machine's files are available + +# set the directory for searching installed headers +# add_compile_options(-I /usr/x86_64-linux-gnux32/include) # this may not be best practice + +#[[ +# CMAKE_STAGING_PREFIX is only useful for transfering a built CMake project to a target machine +set(CMAKE_STAGING_PREFIX /home/devel/stage) # use CMAKE_INSTALL_PREFIX instead (see below comments) + +CMAKE_FIND_ROOT_PATH is an empty list by default (this list can be modified where applicable) +if cross-compiling a dependent lib (like MRAA - which is optional), then +set the lib's CMAKE_INSTALL_PREFIX to a value that is appended to RF24 lib's CMAKE_FIND_ROOT_PATH +example using MRAA: +(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 +(for RF24/build dir) `cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/x86_64.cmake +]] +list(APPEND CMAKE_FIND_ROOT_PATH /usr/x86_64-linux-gnux32) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # search CMAKE_SYSROOT when find_program() is called +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_library() is called +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_file() is called +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) # search CMAKE_FIND_ROOT_PATH entries when find_package() is called diff --git a/docs/README.md b/docs/README.md index 1fa6589c3..51aa389e8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1 +1,3 @@ -These markdown files (*.md) contain relative hyperlinks. Any relative hyperlinks will not work when viewing these markdown files in github. \ No newline at end of file +# Intended for use in Doxygen + +These markdown files (*.md) contain relative hyperlinks. Any relative hyperlinks will not work when viewing these markdown files in github. diff --git a/docs/arduino.md b/docs/arduino.md index 1866662f8..c0e106eee 100644 --- a/docs/arduino.md +++ b/docs/arduino.md @@ -1,7 +1,9 @@ # Arduino + + RF24 is fully compatible with Arduino boards. -See http://www.arduino.cc/en/Reference/Board and http://arduino.cc/en/Reference/SPI for more information +See [Arduino Board reference](http://www.arduino.cc/en/Reference/Board) and [Arduino SPI reference](http://arduino.cc/en/Reference/SPI) for more information RF24 makes use of the standard hardware SPI pins (MISO, MOSI, SCK) and requires two additional pins, to control the chip-select and chip-enable functions. @@ -9,6 +11,7 @@ the chip-select and chip-enable functions. ```cpp RF24 radio(ce_pin, cs_pin); ``` + These pins must be chosen and designated by the user and can use any available pins. @@ -17,9 +20,11 @@ available pins. RF24 supports alternate SPI methods, in case the standard hardware SPI pins are otherwise unavailable. ### Software Driven SPI + Software driven SPI is provided by the [DigitalIO library](https://github.com/greiman/DigitalIO). Setup: + 1. Install the digitalIO library 2. Open RF24_config.h in a text editor. Uncomment the line @@ -36,23 +41,28 @@ Setup: ``` @note Note: Pins are listed as follows and can be modified by editing the RF24_config.h file. + ```cpp #define SOFT_SPI_MISO_PIN 16 #define SOFT_SPI_MOSI_PIN 15 #define SOFT_SPI_SCK_PIN 14 ``` + Or add the build flag/option + ```shell -DSOFT_SPI_MISO_PIN=16 -DSOFT_SPI_MOSI_PIN=15 -DSOFT_SPI_SCK_PIN=14 ``` -### Alternate Hardware (UART) Driven SPI +### Alternate Hardware (UART) Driven SPI + The Serial Port (UART) on Arduino can also function in SPI mode, and can double-buffer data, while the default SPI hardware cannot. -The SPI_UART library is available at https://github.com/TMRh20/Sketches/tree/master/SPI_UART +The SPI_UART library is available at [TMRh20/Sketches](https://github.com/TMRh20/Sketches/tree/master/SPI_UART) Enabling: + 1. Install the SPI_UART library 2. Edit RF24_config.h and uncomment ```cpp @@ -66,28 +76,28 @@ Enabling: SPI_UART SPI Pin Connections: | NRF |Arduino Uno Pin| |----:|:--------------| -| MOSI| TX(0) | -| MISO| RX(1) | -| SCK | XCK(4) | -| CE | User Specified| +| MOSI| TX(0) | +| MISO| RX(1) | +| SCK | XCK(4) | +| CE | User Specified| | CSN | User Specified| - -@note SPI_UART on Mega boards requires soldering to an unused pin on the chip.
See -https://github.com/TMRh20/RF24/issues/24 for more information on SPI_UART. +@note SPI_UART on Mega boards requires soldering to an unused pin on the chip. See [#24](https://github.com/TMRh20/RF24/issues/24) for more information on SPI_UART. ### Using a specific SPI Bus + An alternate SPI bus can be specified using the overloaded `RF24::begin(_SPI*)` method. This is useful for some boards that offer more than 1 hardware-driven SPI bus or cetain Arduino cores that implement a software-driven (AKA bit-banged) SPI bus that does not use the DigitalIO library. -@warning The SPI bus object's `SPIClass::begin()` method must be called before +@warning The SPI bus object's `SPIClass::begin()` method **must** be called before calling the overloaded `RF24::begin(_SPI*)` method. Below are some example snippets that demonstrate how this can be done. #### ESP8266 example + @see The following example code is meant for the popular NodeMCU board. Please refer to the [ESP8266 ArduinoCore's SPI documentation](https://arduino-esp8266.readthedocs.io/en/latest/libraries.html#spi) for [other ESP8266-based boards](https://arduino-esp8266.readthedocs.io/en/latest/boards.html#). @@ -124,6 +134,7 @@ void setup() { ``` #### ESP32 example + @see Please review the Espressif's [SPI_Multiple_Buses.ino example for the ESP32](https://github.com/espressif/arduino-esp32/blob/master/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino) located in their ArduinoCore repository (along with the SPI library for the ESP32). @@ -167,7 +178,8 @@ void setup() { ``` #### Teensy example -@see The overloaded RF24::begin(_SPI*) is not needed according to the + +@see The overloaded RF24::begin(\_SPI\*) is not needed according to the [Teensyduino SPI documentation](https://www.pjrc.com/teensy/td_libs_SPI.html). Please review the table provided in the [Teensyduino documentation](https://www.pjrc.com/teensy/td_libs_SPI.html) for what pins are used by diff --git a/docs/attiny.md b/docs/attiny.md index bdcd449d5..379d81b1f 100644 --- a/docs/attiny.md +++ b/docs/attiny.md @@ -1,19 +1,21 @@ # ATTiny -ATTiny support for this library relys on the SpenceKonde ATTinyCore. Be sure to have added this core to the Arduino Boards Manager with the following guide:
-http://highlowtech.org/?p=1695
+ +ATTiny support for this library relys on the SpenceKonde ATTinyCore. Be sure to have added this core to the Arduino Boards Manager with [this install guide](http://highlowtech.org/?p=1695) + See the included rf24ping85 example for pin info and usage @warning The ATTiny2313 is unsupported due to lack of sufficient memory resources -Some versions of Arduino IDE may require a patch to allow use of the full program space on ATTiny
-See https://github.com/TCWORLD/ATTinyCore/tree/master/PCREL%20Patch%20for%20GCC for ATTiny patch +Some versions of Arduino IDE may require a patch to allow use of the full program space on ATTiny. See [this resource](https://github.com/TCWORLD/ATTinyCore/tree/master/PCREL%20Patch%20for%20GCC) for the ATTiny patch. -ATTiny board support initially added from https://github.com/jscrane/RF24 +ATTiny board support initially added from [jscrane/RF24](https://github.com/jscrane/RF24) ## Hardware Configuration + By [tong67](https://github.com/tong67) ### ATtiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 4 + ```text +-\/-+ NC PB5 1|o |8 Vcc --- nRF24L01 VCC, pin2 --- LED --- 5V @@ -24,7 +26,8 @@ nRF24L01 GND, pin1 --- GND 4| |5 PB0 --- nRF24L01 MISO, pin7 ``` ### ATtiny25/45/85 Pin map with CE_PIN 3 and CSN_PIN 3 - PB3 and PB4 are free to use for application -- Circuit idea from http://nerdralph.blogspot.ca/2014/01/nrf24l01-control-with-3-attiny85-pins.html + +- Circuit idea from [NerdRalph's 3 pin solution](http://nerdralph.blogspot.ca/2014/01/nrf24l01-control-with-3-attiny85-pins.html) - Original RC combination was 1K/100nF. 22K/10nF combination worked better. - For best settletime delay value in RF24::csn() the timingSearch3pin.ino sketch can be used. - This configuration is enabled when CE_PIN and CSN_PIN are equal, e.g. both 3 @@ -43,6 +46,7 @@ nRF24L01 GND, pin1 -x- GND 4| |5 PB0 --- nRF24L01 MISO, pin7 | ``` ### ATtiny24/44/84 Pin map with CE_PIN 8 and CSN_PIN 7 + - Schematic provided and successfully tested by [Carmine Pastore](https://github.com/Carminepz) ```text @@ -58,6 +62,7 @@ nRF24L01 MISO, pin7 --- PA6 7| |8 PA5 --- nRF24L01 MOSI, pin6 ``` ### ATtiny2313/4313 Pin map with CE_PIN 12 and CSN_PIN 13 + ```text +-\/-+ PA2 1|o |20 VCC --- nRF24L01 VCC, pin2 diff --git a/docs/atxmega.md b/docs/atxmega.md index d1ebf61e6..b79659072 100644 --- a/docs/atxmega.md +++ b/docs/atxmega.md @@ -1,9 +1,11 @@ # ATXMEGA + The RF24 driver can be build as a static library with Atmel Studio 7 in order to be included as any other library in another program for the XMEGA family. -Currently only the [ATXMEGA D3](https://www.microchip.com/wwwproducts/en/ATxmega64d3) family is implemented. +Currently only the [ATXMEGA D3](https://www.microchip.com/wwwproducts/en/ATxmega64d3) family is implemented. ## Preparation + Create an empty GCC Static Library project in Atmel Studio 7. As not all files are required, copy the following directory structure in the project: @@ -30,14 +32,17 @@ RF24_config.h ## Usage -Add the library to your project!
+Add the library to your project! + In the file where the `main()` is put the following in order to update the millisecond functionality: + ```cpp ISR(TCE0_OVF_vect) { - update_milisec(); + update_milisec(); } ``` + Declare the rf24 radio with `RF24 radio(XMEGA_PORTC_PIN3, XMEGA_SPI_PORT_C);` 1. First parameter is the CE pin which can be any available pin on the microcontroller. @@ -45,6 +50,6 @@ Declare the rf24 radio with `RF24 radio(XMEGA_PORTC_PIN3, XMEGA_SPI_PORT_C);` Call the `__start_timer()` to start the millisecond timer. -@note -The millisecond functionality is based on the TCE0 so don't use these pins as IO.
-The operating frequency of the uC is 32MHz. If you have a different frequency, change the TCE0 registers appropriatly in function `__start_timer()` in **compatibility.c** file for your frequency. +@note The millisecond functionality is based on the TCE0 so don't use these pins as IO. + +@note The operating frequency of the uC is 32MHz. If you have a different frequency, change the TCE0 registers appropriatly in function `__start_timer()` in **compatibility.c** file for your frequency. diff --git a/docs/cross_compile.md b/docs/cross_compile.md index 16c94b04f..bcff6c5fc 100644 --- a/docs/cross_compile.md +++ b/docs/cross_compile.md @@ -1,12 +1,19 @@ # Linux cross-compilation + + +@warning These instructions are no longer recommended because they involve disabling security measures +for the target system. Please try the [instructions using CMake](md_docs_using_cmake.html). + RF24 library supports cross-compilation. Advantages of cross-compilation: + - development tools don't have to be installed on target machine - resources of target machine don't have to be sufficient for compilation - compilation time can be reduced for large projects Following prerequisites need to be assured: -- ssh passwordless access to target machine (https://linuxconfig.org/passwordless-ssh) -- sudo of a remote user without password (http://askubuntu.com/questions/334318/sudoers-file-enable-nopasswd-for-user-all-commands) + +- ssh passwordless access to target machine [Here is a hint](https://linuxconfig.org/passwordless-ssh) +- sudo of a remote user without password [Here is a hint](http://askubuntu.com/questions/334318/sudoers-file-enable-nopasswd-for-user-all-commands) - cross-compilation toolchain for your target machine; for RPi ```shell git clone https://github.com/raspberrypi/tools rpi_tools @@ -16,7 +23,8 @@ Following prerequisites need to be assured: export PATH=$PATH:/your/dir/rpi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin ``` -## Cross compilation steps: +## Cross compilation steps + 1. clone RF24 to a machine for cross-compilation ```shell git clone https://github.com/nRF24/RF24 @@ -55,6 +63,7 @@ Following prerequisites need to be assured: ## Cross comilation steps for python wrapper ### Prerequisites + - Python setuptools must be installed on both target and cross-compilation machines ```shell sudo pip install setuptools @@ -65,27 +74,25 @@ Following prerequisites need to be assured: ``` ### Installation steps + 1. Assure having libboost-python-dev library in your cross-compilation environment. Alternatively, you can install it into your target machine and copy /usr and /lib directories to the cross-compilation machine. For example ```shell mkdir -p rpi_root && rsync -a pi@target_linux_host:/usr :/lib rpi_root export CFLAGS="--sysroot=/your/dir/rpi_root -I/your/dir/rpi_root/usr/include/python2.7/" ``` - 2. Build the python wrapper ```shell cd pyRF24 ./setup.py build --compiler=crossunix ``` - 3. Make the egg package ```shell ./setup.py bdist_egg --plat-name=cross ``` `dist/RF24--cross.egg` should be created. - 4. Upload it to the target machine and install there: ```shell scp dist/RF24-*-cross.egg pi@target_linux_host: ssh pi@target_linux_host 'sudo easy_install RF24-*-cross.egg' - ``` + ``` diff --git a/docs/linux_install.md b/docs/linux_install.md index caaf0f8ea..e1b23c866 100644 --- a/docs/linux_install.md +++ b/docs/linux_install.md @@ -1,13 +1,20 @@ # Linux Installation + + Generic Linux devices are supported via SPIDEV, MRAA, RPi native via BCM2835, or using LittleWire. -@note The SPIDEV option should work with most Linux systems supporting spi userspace device.
+@note The SPIDEV option should work with most Linux systems supporting spi userspace device. + +@warning These instructions are beginning to age because they were designed with the assumption that +the arm-linux-gnueabihf-g\*\* compilers were available and default for the system. If you have problems +using these instructions, please try the [instructions using CMake](md_docs_using_cmake.html). ## Automated Install + **Designed & Tested on RPi** - Defaults to SPIDEV on devices supporting it 1. Install prerequisites if there are any (MRAA, LittleWire libraries, setup SPI device etc) -2. Download the install.sh file from http://tmrh20.github.io/RF24Installer/RPi/install.sh +2. Download the install.sh file from [tmrh20.github.io/RF24Installer/RPi](http://tmrh20.github.io/RF24Installer/RPi/install.sh) ```shell wget http://tmrh20.github.io/RF24Installer/RPi/install.sh ``` @@ -29,10 +36,11 @@ Generic Linux devices are supported via SPIDEV, MRAA, RPi native via BCM2835, or make sudo ./gettingstarted ``` + ## Manual Install 1. Install prerequisites if there are any (MRAA, LittleWire libraries, setup SPI device etc) -@note See the [MRAA](http://iotdk.intel.com/docs/master/mraa/index.html) documentation for more info on installing MRAA
+ @note See the [MRAA](http://iotdk.intel.com/docs/master/mraa/index.html) documentation for more info on installing MRAA 2. Make a directory to contain the RF24 and possibly RF24Network lib and enter it ```shell mkdir ~/rf24libs @@ -50,7 +58,8 @@ Generic Linux devices are supported via SPIDEV, MRAA, RPi native via BCM2835, or ```shell ./configure ``` - script. It auto detectes device and build environment.
+ script. It auto detectes device and build environment. + For overriding autodetections, use command-line switches, see ```shell ./configure --help diff --git a/docs/main_page.md b/docs/main_page.md index c89dccebc..2c814d185 100644 --- a/docs/main_page.md +++ b/docs/main_page.md @@ -1,20 +1,24 @@ # Optimized High Speed Driver for nRF24L01(+) 2.4GHz Wireless Transceiver ## Design Goals + This library fork is designed to be... + - More compliant with the manufacturer specified operation of the chip, while allowing advanced users -to work outside the recommended operation. + to work outside the recommended operation. - Utilize the capabilities of the radio to their full potential via Arduino - More reliable, responsive, bug-free and feature rich - Easy for beginners to use, with well documented examples and features - Consumed with a public interface that's similar to other Arduino standard libraries ## News + See the releases' descriptions on [the library's release page](http://github.com/nRF24/RF24/releases) for a list of changes. ## Useful References + - [RF24 Class Documentation](classRF24.html) - [Support & Configuration](pages.html) - [Source Code](https://github.com/nRF24/RF24/) @@ -22,6 +26,7 @@ changes. - [nRF24L01+ v1.0 Datasheet](http://github.com/nRF24/RF24/raw/master/datasheets/nRF24L01P_datasheet_v1.pdf) ### Additional Information and Add-ons + - [RF24Network](http://nRF24.github.io/RF24Network): OSI Network Layer for multi-device communication. Create a home sensor network. - [RF24Mesh](http://nRF24.github.io/RF24Mesh): Dynamic Mesh Layer for RF24Network - [RF24Ethernet](http://nRF24.github.io/RF24Ethernet): TCP/IP Radio Mesh Networking (shares Arduino Ethernet API) @@ -31,6 +36,7 @@ changes. - [All TMRh20 Documentation Main Page](http://tmrh20.github.io/) ### More Information + - [Project Blog: TMRh20.blogspot.com](http://TMRh20.blogspot.com) - [Maniacal Bits Blog](http://maniacalbits.blogspot.ca/) - [Original Maniacbug RF24Network Blog Post](https://maniacbug.wordpress.com/2012/03/30/rf24network/) @@ -38,33 +44,38 @@ changes. - [MySensors.org](http://www.mysensors.org/) (User friendly sensor networks/IoT) ## Platform Support Pages + - [Arduino](md_docs_arduino.html) (Uno, Nano, Mega, Due, Galileo, etc) - [ATTiny](md_docs_attiny.html) -- [Linux Installation](md_docs_linux_install.html) ([Linux/RPi General](md_docs_rpi_general.html), [MRAA](md_docs_mraa.html) supported boards (Galileo, Edison, etc), LittleWire) +- [Pico SDK support](md_docs_pico_sdk.html) +- [Linux Installation](md_docs_linux_install.html) (or the alternative [instructions using CMake](md_docs_using_cmake.html)), + ([Linux/RPi General](md_docs_rpi_general.html), [MRAA](md_docs_mraa.html) supported boards (Galileo, Edison, etc), LittleWire) - [Cross-compilation](md_docs_cross_compile.html) for linux devices - [Python wrapper](md_docs_python_wrapper.html) available for Linux devices ### General µC Pin layout + @see also the individual board [support pages](pages.html) for more info -Observe
+Observe + ![ @image html pinout.jpg - ](https://github.com/nRF24/RF24/blob/master/images/pinout.png) + ](https://github.com/nRF24/RF24/blob/master/images/pinout.jpg) The table below shows how to connect the the pins of the NRF24L01(+) to different boards. CE and CSN are configurable. -| PIN | NRF24L01 | Arduino UNO | ATtiny25/45/85 [0] | ATtiny44/84 [1] | LittleWire [2] | RPI | RPi -P1 Connector | -|-----|----------|-------------|--------------------|-----------------|-------------------------|------------|-------------------| -| 1 | GND | GND | pin 4 | pin 14 | GND | rpi-gnd | (25) | -| 2 | VCC | 3.3V | pin 8 | pin 1 | regulator 3.3V required | rpi-3v3 | (17) | -| 3 | CE | digIO 7 | pin 2 | pin 12 | pin to 3.3V | rpi-gpio22 | (15) | -| 4 | CSN | digIO 8 | pin 3 | pin 11 | RESET | rpi-gpio8 | (24) | -| 5 | SCK | digIO 13 | pin 7 | pin 9 | SCK | rpi-sckl | (23) | -| 6 | MOSI | digIO 11 | pin 6 | pin 7 | MOSI | rpi-mosi | (19) | -| 7 | MISO | digIO 12 | pin 5 | pin 8 | MISO | rpi-miso | (21) | -| 8 | IRQ | - | - | - | - | - | - | +| PIN | NRF24L01 | Arduino UNO | ATtiny25/45/85 [0] | ATtiny44/84 [1] | LittleWire [2] | RPI | RPi -P1 Connector | +| --- | -------- | ----------- | ------------------ | --------------- | ----------------------- | ---------- | ----------------- | +| 1 | GND | GND | pin 4 | pin 14 | GND | rpi-gnd | (25) | +| 2 | VCC | 3.3V | pin 8 | pin 1 | regulator 3.3V required | rpi-3v3 | (17) | +| 3 | CE | digIO 7 | pin 2 | pin 12 | pin to 3.3V | rpi-gpio22 | (15) | +| 4 | CSN | digIO 8 | pin 3 | pin 11 | RESET | rpi-gpio8 | (24) | +| 5 | SCK | digIO 13 | pin 7 | pin 9 | SCK | rpi-sckl | (23) | +| 6 | MOSI | digIO 11 | pin 6 | pin 7 | MOSI | rpi-mosi | (19) | +| 7 | MISO | digIO 12 | pin 5 | pin 8 | MISO | rpi-miso | (21) | +| 8 | IRQ | - | - | - | - | - | - | - [0] https://learn.sparkfun.com/tutorials/tiny-avr-programmer-hookup-guide/attiny85-use-hints - [1] http://highlowtech.org/?p=1695 The ATTiny2313 is unsupported due to lack of sufficient memory resources. diff --git a/docs/mraa.md b/docs/mraa.md index 26fa7eb1f..7d8f5d936 100644 --- a/docs/mraa.md +++ b/docs/mraa.md @@ -1,13 +1,16 @@ # MRAA -MRAA is a Low Level Skeleton Library for Communication on GNU/Linux platforms
-See http://iotdk.intel.com/docs/master/mraa/index.html for more information + + +MRAA is a Low Level Skeleton Library for Communication on GNU/Linux platforms. +Review the [MRAA documentation](http://iotdk.intel.com/docs/master/mraa/index.html) for more information RF24 supports all MRAA supported platforms, but it might not have been tested on each individual platform due to the wide range of hardware support: + - [Report an RF24 bug or issue](https://github.com/TMRh20/RF24/issues) ## Setup and installation -Build using the **MRAA** library from http://iotdk.intel.com/docs/master/mraa/index.html +Build using the **MRAA** library from [MRAA documentation](http://iotdk.intel.com/docs/master/mraa/index.html) MRAA is not included. @@ -20,7 +23,6 @@ MRAA is not included. cmake .. -DBUILDSWIGNODE=OFF sudo make install ``` - 2. Complete the install ```shell nano /etc/ld.so.conf @@ -33,6 +35,6 @@ MRAA is not included. ```shell sudo ldconfig ``` +3. Install RF24, using MRAA -3. Install RF24, using MRAA
See [Linux Install instructions](md_docs_linux_install.html) diff --git a/docs/pico_sdk.md b/docs/pico_sdk.md new file mode 100644 index 000000000..cfdddee05 --- /dev/null +++ b/docs/pico_sdk.md @@ -0,0 +1,175 @@ +# RaspberryPi Pico SDK (for the RP2040) + + +Just to be very clear and concise: The following instructions are +**not required to use the Arduino IDE** with any RP2040-based boards. +These instructions pertain to using only the +[Raspberry Pi foundation's Pico SDK](https://github.com/raspberrypi/pico-sdk) +for RP2040 based boards. + +## Prerequisite + +Follow the Raspberry Pi Foundation's +["Getting Started with Pico" document](https://rptl.io/pico-get-started) to +setup a proper development environment on your host PC (the machine that +will build your project). Notice that the setup instructions are a little +different for building on a Windows PC. + +Either set an environment variable named `PICO_SDK_PATH` that points to your +local clone of the pico-sdk or put the pico-sdk next to the RF24 folder or +next to the folder containing your project using the RF24 library: + + path/to/github/repos/ + pico-sdk/ + RF24/ + my_rf24_project/ + +Alternatively, the RF24 repository (and optionally the RF24Network and RF24Mesh +repositories) can be included into your project's "lib" folder as copies or +git submodules. For more detail, see the below instructions to incorporate +RF24 libs into your project. + +## Building the RF24 examples for the Pico SDK + +Each example imports a set of constants (`CE_PIN`, `CSN_PIN`, `IRQ_PIN`) from the +examples_pico/defaultPins.h file. Default values for SPI pins (SCK, MOSI, MISO) +come from the Pico SDK repository's +[pico-sdk/src/boards/include/boards/\.h files](https://github.com/raspberrypi/pico-sdk/tree/master/src/boards/include/boards) + +1. Create a "build" directory in the RF24 repository's root directory and + navigate to it: + ```shell + cd RF24 + mkdir build + cd build + ``` +2. Configure CMake for your desired build type and specific RP2040-based board + ```shell + cmake ../examples_pico -DCMAKE_BUILD_TYPE=Release -DPICO_BOARD=pico + ``` + Or if building on a Windows PC: + ```shell + cmake -G "NMake Makefiles" ../examples_pico -DCMAKE_BUILD_TYPE=Release -DPICO_BOARD=pico + ``` + The supported RP2040-based boards are listed in header files in the Pico SDK + repository's [pico-sdk/src/boards/include/boards/\.h files](https://github.com/raspberrypi/pico-sdk/tree/master/src/boards/include/boards). + If the `-DPICO_BOARD` option is not specified, then the Pico SDK will default to building for the Raspberry Pi Pico board. +3. Build the examples using the CMakeLists.txt file located in the + RF24/examples_pico directory. + ```shell + cmake --build . --config Release + ``` + Notice we specified the build type again using the `--config` option. + + @note If you see an error stating "'PICO_DEFAULT_SPI_SCK_PIN' was not declared in this scope", + then it means the board you selected with the `-DPICO_BOARD` option (in step 2) does not have a + default set of SPI pins defined for it. To workaround this error, see the below instructions to + use different pins for the SPI bus. + + @warning If doing consecutive build attempts, it is strongly encouraged to delete all files in the build + directory before re-attempting to build the project. + +## Incorporating RF24 libs into your project + +In order to use the RF24 libraries in your RP2040 based project: + +1. Make a copy of the RF24 library (and optionally RF24Network and RF24Mesh + libraries) in a "lib" directory located in your project's root directory. + + path/to/my/project/ + lib/ + RF24/ + RF24Network/ + RF24Mesh/ + src/ + CMakeLists.txt + ... + + Alternatively you can add the RF24\* repositories as [git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules). +2. Include their CMakeLists.txt files from the RF24 libraries in your project's top-level + CMakeLists.txt file (usually located in the "src" directory). The following snippet + assumes that your project's "src" directory is on the same level as the previously + mentioned "lib" directory. + ```cmake + include(../lib/RF24/CMakeLists.txt) + include(../lib/RF24Network/CMakeLists.txt) + include(../lib/RF24Mesh/CMakeLists.txt) + ``` +3. In the same CMakeLists.txt file from step 2, add the RF24 libraries into the + `target_link_libraries` configuration: + ```cmake + target_link_libraries(${CMAKE_PROJECT_NAME} + # ... Your project's other libraries ... + RF24 + RF24Network + RF24Mesh + ) + ``` + If you are using tinyUSB, this line (or similar) should already exist: + ```cmake + target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}) + ``` +4. Finally, remember to include the necessary RF24\* libraries' header files in your + project's source code where applicable. + ```cpp + #include + #include + #include + ``` + @note Any of the project's source file(s) that includes any of RF24\* libraries must be a C++ file. + It is highly recommended to use the `.cpp` file extension for such project source files. + +## Using different pins for the SPI bus + +Initially (without modification), the SPI bus uses the default pins defined in the +Pico SDK repository's [pico-sdk/src/boards/include/boards/\.h files](https://github.com/raspberrypi/pico-sdk/tree/master/src/boards/include/boards). +However, there may be some boards that do not define the necessary pins to use as defaults. This can +be rememdied using either project source code or build-time configuration. + +@warning There is no support for software driven SPI on RP2040 based boards at this time. +If someone is so inclined to implement this using the Pico SDK's PIO (Programable Input +Output) feature, please submit an issue or pull request to the +[RF24 repository](http://github.com/nRF24/RF24). + +@note Before deciding what pins to use for the SPI bus, review the +[GPIO pins' "Function Select Table" in the Pico SDK documentation](https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__gpio.html#details). +There are essentially 2 SPI buses with multiple pin options for each. + +### Project Source code option + +This option is the most reliable and flexible. It involves calling `SPI.begin()` and then passing the `SPI` object to `RF24::begin(_SPI*)`. + +```cpp +#include + +RF24 radio(7, 8); // pin numbers connected to the radio's CE and CSN pins (respectively) + +int main() +{ + // again please review the GPIO pins' "Function Select Table" in the Pico SDK docs + spi.begin(spi0, 2, 3, 4); // spi0 or spi1 bus, SCK, TX, RX + + if (!radio.begin(&spi)) { + printf("Radio hardware is not responding!\n"); + } + // continue with program as normal ... +} +``` + +### Build-time configuration option + +To specify the default SPI pins used at build time, you can use either: + +1. declare these pins in the CMakeLists.txt file + ```cmake + target_compile_definitions(${CMAKE_PROJECT_NAME} + PUBLIC PICO_DEFAULT_SPI=0 # can only be 0 or 1 (as in `spi0` or `spi1`) + PUBLIC PICO_DEFAULT_SPI_SCK_PIN=2 # depends on which SPI bus (0 or 1) is being used + PUBLIC PICO_DEFAULT_SPI_TX_PIN=3 # depends on which SPI bus (0 or 1) is being used + PUBLIC PICO_DEFAULT_SPI_RX_PIN=4 # depends on which SPI bus (0 or 1) is being used + ) + ``` +2. additional command line arguments + ```shell + cmake --build . --config Release -DPICO_DEFAULT_SPI=0 -DPICO_DEFAULT_SPI_SCK_PIN=2 -DPICO_DEFAULT_SPI_TX_PIN=3 -DPICO_DEFAULT_SPI_RX_PIN=4 + ``` diff --git a/docs/portabillity.md b/docs/portability.md similarity index 76% rename from docs/portabillity.md rename to docs/portability.md index 6ac047d18..3d92ebbaa 100644 --- a/docs/portabillity.md +++ b/docs/portability.md @@ -1,6 +1,8 @@ # RF24 Portability + The RF24 radio driver mainly utilizes the [Arduino API](http://arduino.cc/en/reference/homePage) -for GPIO, SPI, and timing functions, which are easily replicated on various platforms.
+for GPIO, SPI, and timing functions, which are easily replicated on various platforms. + Support files for these platforms are stored under RF24/utility, and can be modified to provide the required functionality. @@ -8,11 +10,12 @@ required functionality. ### RF24/utility -The RF24 library now includes a basic hardware template to assist in porting to various platforms.
The following files can be included -to replicate standard Arduino functions as needed, allowing devices from ATTiny to Raspberry Pi to utilize the same core RF24 driver. +The RF24 library now includes a basic hardware template to assist in porting to various platforms. + +The following files can be included to replicate standard Arduino functions as needed, allowing devices from ATTiny to Raspberry Pi to utilize the same core RF24 driver. -| File | Purpose | -|--------------------|------------------------------------------------------------------------------| +| File | Purpose | +| ------------------ | ---------------------------------------------------------------------------- | | RF24_arch_config.h | Basic Arduino/AVR compatibility, includes for remaining support files, etc | | includes.h | Linux only. Defines specific platform, include correct RF24_arch_config file | | spi.h | Provides standardized SPI (`transfer()`) methods | @@ -20,13 +23,16 @@ to replicate standard Arduino functions as needed, allowing devices from ATTiny | compatibility.h | Provides standardized timing (`millis()`, `delay()`) methods | | your_custom_file.h | Provides access to custom drivers for spi, gpio, etc | -Examples are provided via the included hardware support templates in **RF24/utility**
+Examples are provided via the included hardware support templates in **RF24/utility** + See the [modules](modules.html) page for examples of class declarations. ## Device Detection + 1. The main detection for Linux devices is done in the configure script, with the includes.h from the proper hardware directory copied to RF24/utility/includes.h 2. Secondary detection is completed in RF24_config.h, causing the include.h file to be included for all supported Linux devices 3. RF24.h contains the declaration for SPI and GPIO objects 'spi' and 'gpio' to be used for porting-in related functions. ## Code -To have your ported code included in this library, or for assistance in porting, create a pull request or open an issue at https://github.com/nRF24/RF24 + +To have your ported code included in this library, or for assistance in porting, create a pull request or open an issue at [RF24 Library issues](https://github.com/nRF24/RF24) diff --git a/docs/python_wrapper.md b/docs/python_wrapper.md index 171042e35..eba446b10 100644 --- a/docs/python_wrapper.md +++ b/docs/python_wrapper.md @@ -1,28 +1,48 @@ # Python Wrapper + + By [mz-fuzzy](https://github.com/mz-fuzzy) -# Prerequisites +## Prerequisites + +### RF24 + +The RF24 lib needs to be built in C++ & installed for the python wrapper to wrap it. + +See [Linux Installation](md_docs_linux_install.html) (or [installing with CMake](md_docs_using_cmake.html) +alternatively) and [Linux/RPi General](md_docs_rpi_general.html) + +### Python2 + +```shell +sudo apt-get install python-dev libboost-python-dev python-pip python-rpi.gpio +``` + +Next, install some up-to-date python packages. + +```shell +python -m pip install --upgrade pip setuptools +``` -## RF24 -The RF24 lib needs to be built in C++ & installed for the python wrapper to wrap it
-See [Linux Installation](md_docs_linux_install.html) and [Linux/RPi General](md_docs_rpi_general.html) +### Python3 -## Python2 ```shell -sudo apt-get install python-dev libboost-python-dev python-setuptools python-rpi.gpio +sudo apt-get install python3-dev libboost-python-dev python3-pip python3-rpi.gpio ``` -## Python3 +Next, install some up-to-date python3 packages. + ```shell -sudo apt-get install python3-dev libboost-python-dev python3-setuptools python3-rpi.gpio +python3 -m pip install --upgrade pip setuptools ``` -# Installation: -1. For python3 in Raspbian, it's needed to manually link python boost library, like this: +## Installation + +1. For python3, setup.py needs a manually created symlink for the boost.python library: ```shell - sudo ln -s $(ls /usr/lib/arm-linux-gnueabihf/libboost_python3-py3*.so | tail -1) /usr/lib/arm-linux-gnueabihf/libboost_python3.so + sudo ln -s $(ls /usr/lib/$(ls /usr/lib/gcc | tail -1)/libboost_python3*.so | tail -1) /usr/lib/$(ls /usr/lib/gcc | tail -1)/libboost_python3.so ``` -2. Build the library. From the rf24libs/RF24/pyRF24 directory: +2. Build the library from the rf24libs/RF24/pyRF24 directory: ```shell ./setup.py build ``` @@ -30,8 +50,7 @@ sudo apt-get install python3-dev libboost-python-dev python3-setuptools python3- ```shell python3 setup.py build ``` -@note Build takes several minutes on arm-based machines. Machines with RAM less than 1GB may need to increase amount of swap for build. - + @note Build takes several minutes on arm-based machines. Machines with RAM less than 1GB may need to increase amount of swap for build. 3. Install the library ```shell sudo ./setup.py install @@ -42,14 +61,19 @@ sudo apt-get install python3-dev libboost-python-dev python3-setuptools python3- ``` See the additional [Platform Support pages](pages.html) for information on connecting your hardware. - See the included [*.py files in the "examples_linux" folder](examples.html) for usage information. - + See the included [\*.py files in the "examples_linux" folder](examples.html) for usage information. 4. Running the Example: + + Navigate to the examples_linux directory + ```shell + cd ../examples_linux + ``` Edit the getting_started.py example to configure the appropriate pins per the [Linux/RPi General](md_docs_rpi_general.html) documentation. ```shell nano getting_started.py ``` - Configure another device, Arduino or RPi with the [getting_started.py example](examples_linux_2getting_started_8py-example.html)
+ Configure another device, Arduino or RPi with the same example code. It could be C++ or python (see the [list of available examples](examples.html)), but we'll use the same example file on a different device in this tutorial. + Run the example ```shell sudo python getting_started.py diff --git a/docs/rpi_general.md b/docs/rpi_general.md index 8c08cb64f..1081b2c08 100644 --- a/docs/rpi_general.md +++ b/docs/rpi_general.md @@ -1,13 +1,17 @@ # Linux General/Raspberry Pi + + RF24 supports a variety of Linux based devices via various drivers. Some boards like RPi can utilize multiple methods to drive the GPIO and SPI functionality. ## Potential PreConfiguration If SPI is not already enabled, load it on boot: + ```shell sudo raspi-config ``` + 1. Update the tool via the menu as required 2. Select **Advanced** and **enable the SPI kernel module** 3. Update other software and libraries @@ -17,7 +21,8 @@ sudo raspi-config ``` ## Build Options -The default build on Raspberry Pi utilizes the included **BCM2835** driver from http://www.airspayce.com/mikem/bcm2835 + +The default build on Raspberry Pi utilizes the included **BCM2835** driver from [the BCM2835 Library](http://www.airspayce.com/mikem/bcm2835) 1. See [the Linux section for automated installation](md_docs_linux_install.html). 2. Manual install: @@ -27,49 +32,60 @@ The default build on Raspberry Pi utilizes the included **BCM2835** driver from ``` ## Connections and Pin Configuration + Using pin 15(GPIO22) for CE, pin 24(GPIO8 commonly labeled as CE0) for CSN -Can use any available SPI BUS for CSN.
+Can use any available SPI BUS for CSN. + In general, use + ```cpp RF24 radio(, *10+); ``` + for proper constructor to address the correct spi device at /dev/spidev\.\ Choose any GPIO output pin for radio CE pin. ### General + ```cpp RF24 radio(22,0); ``` ### MRAA Constructor + ```cpp RF24 radio(15,0); ``` -See http://iotdk.intel.com/docs/master/mraa/rasppi.html + +See [the MRAA documentation for Raspberry Pi support](http://iotdk.intel.com/docs/master/mraa/rasppi.html) ### SPI_DEV Constructor + ```cpp -RF24 radio(22,0); +RF24 radio(22, 0); ``` -See https://www.raspberrypi.org/documentation/usage/gpio/ + +See [the Raspberry Pi documentation about the GPIO pins](https://www.raspberrypi.com/documentation/computers/os.html#gpio-and-the-40-pin-header) ### Pins -| PIN | NRF24L01 | RPI | RPi -P1 Connector | -|-----|----------|------------|-------------------| -| 1 | GND | rpi-gnd | (25) | -| 2 | VCC | rpi-3v3 | (17) | -| 3 | CE | rpi-gpio22 | (15) | -| 4 | CSN | rpi-gpio8 | (24) | -| 5 | SCK | rpi-sckl | (23) | -| 6 | MOSI | rpi-mosi | (19) | -| 7 | MISO | rpi-miso | (21) | -| 8 | IRQ | - | - | +| PIN | NRF24L01 | RPI | RPi -P1 Connector | +| --- | -------- | ---------- | ----------------- | +| 1 | GND | rpi-gnd | (25) | +| 2 | VCC | rpi-3v3 | (17) | +| 3 | CE | rpi-gpio22 | (15) | +| 4 | CSN | rpi-gpio8 | (24) | +| 5 | SCK | rpi-sckl | (23) | +| 6 | MOSI | rpi-mosi | (19) | +| 7 | MISO | rpi-miso | (21) | +| 8 | IRQ | - | - | ## breif history of RF24 library lineage -Based on the arduino lib from [J. Coliz](maniacbug@ymail.com)
-the library was berryfied by [Purinda Gunasekara](purinda@gmail.com)
-then forked from github stanleyseow/RF24 to https://github.com/jscrane/RF24-rpi
-Network lib also based on https://github.com/farconada/RF24Network + +Based on the arduino lib from [J. Coliz](maniacbug@ymail.com), +the library was berryfied by [Purinda Gunasekara](purinda@gmail.com) +then forked from github [stanleyseow/RF24](https://github.com/stanleyseow/RF24) to [jscrane/RF24-rpi](https://github.com/jscrane/RF24-rpi) + +Network lib also based on [farconada/RF24Network](https://github.com/farconada/RF24Network) diff --git a/docs/sphinx/Makefile b/docs/sphinx/Makefile new file mode 100644 index 000000000..bbe765a0f --- /dev/null +++ b/docs/sphinx/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = ../sphinx +BUILDDIR = ../_build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/sphinx/README.md b/docs/sphinx/README.md new file mode 100644 index 000000000..5ca5047f1 --- /dev/null +++ b/docs/sphinx/README.md @@ -0,0 +1,3 @@ +# Intended for Sphinx only + +The files in this folder are only used to generate documentation using Sphinx (from Doxygen's XML output). diff --git a/docs/sphinx/RF24_config_8h.rst b/docs/sphinx/RF24_config_8h.rst new file mode 100644 index 000000000..8bfe17def --- /dev/null +++ b/docs/sphinx/RF24_config_8h.rst @@ -0,0 +1,7 @@ +RF24_config.h +============= + +.. literalinclude:: ../../RF24_config.h + :linenos: + :lineno-match: + :start-at: /*** USER DEFINES: ***/ diff --git a/docs/sphinx/_static/Logo large.png b/docs/sphinx/_static/Logo large.png new file mode 100644 index 000000000..25e42159f Binary files /dev/null and b/docs/sphinx/_static/Logo large.png differ diff --git a/docs/sphinx/_static/custom_material.css b/docs/sphinx/_static/custom_material.css new file mode 100644 index 000000000..5c6c888fd --- /dev/null +++ b/docs/sphinx/_static/custom_material.css @@ -0,0 +1,71 @@ +.md-typeset .admonition.tip>.admonition-title::before, +.md-typeset .admonition.hint>.admonition-title::before { + mask-image: url('data:image/svg+xml;charset=utf-8,'); +} + +.md-typeset .admonition.seealso>.admonition-title::before { + mask-image: url('data:image/svg+xml;charset=utf-8,'); + background-color: hsl(301, 100%, 63%); +} + +.md-typeset .admonition.seealso { + border-left: .2rem solid hsl(301, 100%, 63%); +} + +.md-typeset .admonition.seealso>.admonition-title { + background-color: hsla(287, 100%, 63%, 0.25); +} + +.md-typeset .admonition.important>.admonition-title::before { + mask-image: url('data:image/svg+xml;charset=utf-8,'); + background-color: hsl(123, 100%, 63%); +} + +.md-typeset .admonition.important { + border-left: .2rem solid hsl(123, 100%, 63%); +} + +.md-typeset .admonition.important>.admonition-title { + background-color: hsla(123, 100%, 63%, 0.25); +} + +.md-typeset .admonition.warning>.admonition-title::before { + background-color: hsl(0, 100%, 63%); +} + +.md-typeset .admonition.warning { + border-left: .2rem solid hsl(0, 100%, 63%); +} + +.md-typeset .admonition.warning>.admonition-title { + background-color: hsla(0, 100%, 63%, 0.25); +} + +html .md-nav--primary .md-nav__title--site .md-nav__button { + top: 0; + left: 0; + width: inherit; + height: auto; +} + +.md-typeset table:not([class]) th { + background-color: rgba(23, 35, 83, 0.8); +} + +.md-typeset table:not([class]) tr:hover { + background-color: rgba(56, 2, 81, 0.8); + box-shadow: inset 0 .05rem 0 #9515ff; +} + +[data-md-color-scheme="default"] { + --md-code-bg-color: #e8e7e7; +} + +.md-nav__title .md-nav__button.md-logo img, .md-nav__title .md-nav__button.md-logo svg { + height: 3rem; + width: auto; +} + +.md-header__button.md-logo img, .md-header__button.md-logo svg { + width: auto; +} diff --git a/docs/sphinx/_static/new_favicon.ico b/docs/sphinx/_static/new_favicon.ico new file mode 100644 index 000000000..c15a1650a Binary files /dev/null and b/docs/sphinx/_static/new_favicon.ico differ diff --git a/docs/sphinx/classRF24.rst b/docs/sphinx/classRF24.rst new file mode 100644 index 000000000..69a0e6318 --- /dev/null +++ b/docs/sphinx/classRF24.rst @@ -0,0 +1,95 @@ +RF24 class +~~~~~~~~~~ + +.. cpp:class:: RF24 + +Basic API +============ + +.. doxygenfunction:: RF24::RF24 (uint16_t,uint16_t,uint32_t) +.. doxygenfunction:: RF24::RF24 (uint32_t _spi_speed=RF24_SPI_SPEED) +.. doxygenfunction:: RF24::begin (void) +.. doxygenfunction:: RF24::begin (_SPI *spiBus) +.. doxygenfunction:: RF24::begin (_SPI *spiBus, uint16_t _cepin, uint16_t _cspin) +.. doxygenfunction:: RF24::begin (uint16_t _cepin, uint16_t _cspin) +.. doxygenfunction:: RF24::isChipConnected +.. doxygenfunction:: RF24::startListening +.. doxygenfunction:: RF24::stopListening +.. doxygenfunction:: RF24::available (void) +.. doxygenfunction:: RF24::read +.. doxygenfunction:: RF24::write (const void *buf, uint8_t len) +.. doxygenfunction:: RF24::openWritingPipe (const uint8_t *address) +.. doxygenfunction:: RF24::openReadingPipe (uint8_t number, const uint8_t *address) + +Advanced API +============ + +.. doxygenvariable:: RF24::failureDetected +.. doxygenfunction:: RF24::printDetails +.. doxygenfunction:: RF24::printPrettyDetails +.. doxygenfunction:: RF24::available (uint8_t *pipe_num) +.. doxygenfunction:: RF24::rxFifoFull +.. doxygenfunction:: RF24::powerDown +.. doxygenfunction:: RF24::powerUp +.. doxygenfunction:: RF24::write (const void *buf, uint8_t len, const bool multicast) +.. doxygenfunction:: RF24::writeFast (const void *buf, uint8_t len) +.. doxygenfunction:: RF24::writeFast (const void *buf, uint8_t len, const bool multicast) +.. doxygenfunction:: RF24::writeBlocking +.. doxygenfunction:: RF24::txStandBy() +.. doxygenfunction:: RF24::txStandBy (uint32_t timeout, bool startTx=0) +.. doxygenfunction:: RF24::writeAckPayload +.. doxygenfunction:: RF24::whatHappened +.. doxygenfunction:: RF24::startFastWrite +.. doxygenfunction:: RF24::startWrite +.. doxygenfunction:: RF24::reUseTX +.. doxygenfunction:: RF24::flush_tx +.. doxygenfunction:: RF24::flush_rx +.. doxygenfunction:: RF24::testCarrier +.. doxygenfunction:: RF24::testRPD +.. doxygenfunction:: RF24::isValid +.. doxygenfunction:: RF24::closeReadingPipe + +Configuration API +================== + +.. doxygenvariable:: RF24::txDelay +.. doxygenvariable:: RF24::csDelay +.. doxygenfunction:: RF24::setAddressWidth +.. doxygenfunction:: RF24::setRetries +.. doxygenfunction:: RF24::setChannel +.. doxygenfunction:: RF24::getChannel +.. doxygenfunction:: RF24::setPayloadSize +.. doxygenfunction:: RF24::getPayloadSize +.. doxygenfunction:: RF24::getDynamicPayloadSize +.. doxygenfunction:: RF24::enableAckPayload +.. doxygenfunction:: RF24::disableAckPayload +.. doxygenfunction:: RF24::enableDynamicPayloads +.. doxygenfunction:: RF24::disableDynamicPayloads +.. doxygenfunction:: RF24::enableDynamicAck +.. doxygenfunction:: RF24::isPVariant +.. doxygenfunction:: RF24::setAutoAck (bool enable) +.. doxygenfunction:: RF24::setAutoAck (uint8_t pipe, bool enable) +.. doxygenfunction:: RF24::setPALevel +.. doxygenfunction:: RF24::getPALevel +.. doxygenfunction:: RF24::getARC +.. doxygenfunction:: RF24::setDataRate +.. doxygenfunction:: RF24::getDataRate +.. doxygenfunction:: RF24::setCRCLength +.. doxygenfunction:: RF24::getCRCLength +.. doxygenfunction:: RF24::disableCRC +.. doxygenfunction:: RF24::maskIRQ +.. doxygenfunction:: RF24::startConstCarrier +.. doxygenfunction:: RF24::stopConstCarrier + +Protected API +============== + +These are the members and functions made available to derivatives that inherit from the RF24 class. + +.. doxygenfunction:: RF24::beginTransaction +.. doxygenfunction:: RF24::endTransaction +.. doxygenfunction:: RF24::read_register (uint8_t reg, uint8_t *buf, uint8_t len) +.. doxygenfunction:: RF24::read_register (uint8_t reg) +.. doxygenvariable:: RF24::ack_payloads_enabled +.. doxygenvariable:: RF24::addr_width +.. doxygenvariable:: RF24::dynamic_payloads_enabled diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py new file mode 100644 index 000000000..d529c6ff0 --- /dev/null +++ b/docs/sphinx/conf.py @@ -0,0 +1,141 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) +import subprocess +import os + +# -- Project information ----------------------------------------------------- + +project = "RF24 library" +copyright = "2021, `nRF24 org `_" +author = "nRF24" + +# The full version, including alpha/beta/rc tags +release = "1.4.2" + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = "en" + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "breathe", + "sphinx_immaterial", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + +# code-blocks will use this as their default syntax highlighting +highlight_language="c++" + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = True + +# -- Options for breathe (XML output from doxygen) --------------------------- + +breathe_projects = {"RF24": "xml"} +breathe_default_project = "RF24" + +READTHEDOCS = os.environ.get('READTHEDOCS', None) == 'True' + +if READTHEDOCS: + subprocess.call("cd ../..; doxygen", shell=True) + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "sphinx_immaterial" +html_theme_options = { + "features": [ + # "navigation.expand", + "navigation.tabs", + # "toc.integrate", + # "navigation.sections", + "navigation.instant", + # "header.autohide", + "navigation.top", + # "search.highlight", + "search.share", + ], + "palette": [ + { + "media": "(prefers-color-scheme: dark)", + "scheme": "slate", + "primary": "lime", + "accent": "light-blue", + "toggle": { + "icon": "material/lightbulb", + "name": "Switch to light mode", + }, + }, + { + "media": "(prefers-color-scheme: light)", + "scheme": "default", + "primary": "light-blue", + "accent": "green", + "toggle": { + "icon": "material/lightbulb-outline", + "name": "Switch to dark mode", + }, + }, + ], + # Set the repo location to get a badge with stats + "repo_url": "https://github.com/nRF24/RF24/", + "repo_name": "RF24", + "repo_type": "github", + # Visible levels of the global TOC; -1 means unlimited + "globaltoc_depth": 3, + # If False, expand all TOC entries + "globaltoc_collapse": False, + # If True, show hidden TOC entries + "globaltoc_includehidden": True, +} +# Set link name generated in the top bar. +html_title = "RF24 C++ library" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +html_favicon = "_static/new_favicon.ico" + +# project logo +html_logo = "_static/Logo large.png" + +# These paths are either relative to html_static_path +# or fully qualified paths (eg. https://...) +html_css_files = [ + "custom_material.css", +] diff --git a/docs/sphinx/deprecated.rst b/docs/sphinx/deprecated.rst new file mode 100644 index 000000000..3e1b5a0a5 --- /dev/null +++ b/docs/sphinx/deprecated.rst @@ -0,0 +1,5 @@ +Deprecated API +============== + +.. doxygenpage:: deprecated + :content-only: diff --git a/docs/sphinx/enums.rst b/docs/sphinx/enums.rst new file mode 100644 index 000000000..4c6090539 --- /dev/null +++ b/docs/sphinx/enums.rst @@ -0,0 +1,12 @@ +Enumerations +============ + + +.. doxygengroup:: PALevel + :members: + +.. doxygengroup:: Datarate + :members: + +.. doxygengroup:: CRCLength + :members: diff --git a/docs/sphinx/examples.rst b/docs/sphinx/examples.rst new file mode 100644 index 000000000..e5513ea7a --- /dev/null +++ b/docs/sphinx/examples.rst @@ -0,0 +1,43 @@ +Examples +========== + +Arduino Examples +---------------- + +.. toctree:: + :maxdepth: 1 + + examples/Arduino/GettingStarted + examples/Arduino/AcknowledgementPayloads + examples/Arduino/ManualAcknowledgements + examples/Arduino/StreamingData + examples/Arduino/MulticeiverDemo + examples/Arduino/Scanner + examples/Arduino/InterruptConfigure + +Linux Examples +---------------- + +.. toctree:: + :maxdepth: 1 + + examples/Linux/GettingStarted + examples/Linux/AcknowledgementPayloads + examples/Linux/ManualAcknowledgements + examples/Linux/StreamingData + examples/Linux/MulticeiverDemo + examples/Linux/Scanner + examples/Linux/InterruptConfigure + +Python Examples +---------------- + +.. toctree:: + :maxdepth: 1 + + examples/Python/GettingStarted + examples/Python/AcknowledgementPayloads + examples/Python/ManualAcknowledgements + examples/Python/StreamingData + examples/Python/MulticeiverDemo + examples/Python/InterruptConfigure diff --git a/docs/sphinx/examples/Arduino/AcknowledgementPayloads.rst b/docs/sphinx/examples/Arduino/AcknowledgementPayloads.rst new file mode 100644 index 000000000..70deeb2fe --- /dev/null +++ b/docs/sphinx/examples/Arduino/AcknowledgementPayloads.rst @@ -0,0 +1,7 @@ +AcknowledgementPayloads.ino +=========================== + +.. literalinclude:: ../../../../examples/AcknowledgementPayloads/AcknowledgementPayloads.ino + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Arduino/GettingStarted.rst b/docs/sphinx/examples/Arduino/GettingStarted.rst new file mode 100644 index 000000000..f873a6750 --- /dev/null +++ b/docs/sphinx/examples/Arduino/GettingStarted.rst @@ -0,0 +1,7 @@ +GettingStarted.ino +================== + +.. literalinclude:: ../../../../examples/GettingStarted/GettingStarted.ino + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Arduino/InterruptConfigure.rst b/docs/sphinx/examples/Arduino/InterruptConfigure.rst new file mode 100644 index 000000000..fe59f38d6 --- /dev/null +++ b/docs/sphinx/examples/Arduino/InterruptConfigure.rst @@ -0,0 +1,7 @@ +InterruptConfigure.ino +====================== + +.. literalinclude:: ../../../../examples/InterruptConfigure/InterruptConfigure.ino + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Arduino/ManualAcknowledgements.rst b/docs/sphinx/examples/Arduino/ManualAcknowledgements.rst new file mode 100644 index 000000000..ad6b904c2 --- /dev/null +++ b/docs/sphinx/examples/Arduino/ManualAcknowledgements.rst @@ -0,0 +1,7 @@ +ManualAcknowledgements.ino +========================== + +.. literalinclude:: ../../../../examples/ManualAcknowledgements/ManualAcknowledgements.ino + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Arduino/MulticeiverDemo.rst b/docs/sphinx/examples/Arduino/MulticeiverDemo.rst new file mode 100644 index 000000000..1e30f7b00 --- /dev/null +++ b/docs/sphinx/examples/Arduino/MulticeiverDemo.rst @@ -0,0 +1,7 @@ +MulticeiverDemo.ino +==================== + +.. literalinclude:: ../../../../examples/MulticeiverDemo/MulticeiverDemo.ino + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Arduino/Scanner.rst b/docs/sphinx/examples/Arduino/Scanner.rst new file mode 100644 index 000000000..c91103996 --- /dev/null +++ b/docs/sphinx/examples/Arduino/Scanner.rst @@ -0,0 +1,7 @@ +Scanner.ino +================== + +.. literalinclude:: ../../../../examples/Scanner/Scanner.ino + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Arduino/StreamingData.rst b/docs/sphinx/examples/Arduino/StreamingData.rst new file mode 100644 index 000000000..b13add5da --- /dev/null +++ b/docs/sphinx/examples/Arduino/StreamingData.rst @@ -0,0 +1,7 @@ +StreamingData.ino +================== + +.. literalinclude:: ../../../../examples/StreamingData/StreamingData.ino + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Linux/AcknowledgementPayloads.rst b/docs/sphinx/examples/Linux/AcknowledgementPayloads.rst new file mode 100644 index 000000000..00473fb66 --- /dev/null +++ b/docs/sphinx/examples/Linux/AcknowledgementPayloads.rst @@ -0,0 +1,7 @@ +AcknowledgementPayloads.cpp +=========================== + +.. literalinclude:: ../../../../examples_linux/acknowledgementPayloads.cpp + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Linux/GettingStarted.rst b/docs/sphinx/examples/Linux/GettingStarted.rst new file mode 100644 index 000000000..d4d5c24db --- /dev/null +++ b/docs/sphinx/examples/Linux/GettingStarted.rst @@ -0,0 +1,7 @@ +GettingStarted.cpp +================== + +.. literalinclude:: ../../../../examples_linux/gettingstarted.cpp + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Linux/InterruptConfigure.rst b/docs/sphinx/examples/Linux/InterruptConfigure.rst new file mode 100644 index 000000000..7591bb0f9 --- /dev/null +++ b/docs/sphinx/examples/Linux/InterruptConfigure.rst @@ -0,0 +1,7 @@ +InterruptConfigure.cpp +====================== + +.. literalinclude:: ../../../../examples_linux/interruptConfigure.cpp + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Linux/ManualAcknowledgements.rst b/docs/sphinx/examples/Linux/ManualAcknowledgements.rst new file mode 100644 index 000000000..a2a8b9a04 --- /dev/null +++ b/docs/sphinx/examples/Linux/ManualAcknowledgements.rst @@ -0,0 +1,7 @@ +ManualAcknowledgements.cpp +========================== + +.. literalinclude:: ../../../../examples_linux/manualAcknowledgements.cpp + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Linux/MulticeiverDemo.rst b/docs/sphinx/examples/Linux/MulticeiverDemo.rst new file mode 100644 index 000000000..bb4e9e816 --- /dev/null +++ b/docs/sphinx/examples/Linux/MulticeiverDemo.rst @@ -0,0 +1,7 @@ +MulticeiverDemo.cpp +==================== + +.. literalinclude:: ../../../../examples_linux/multiceiverDemo.cpp + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Linux/Scanner.rst b/docs/sphinx/examples/Linux/Scanner.rst new file mode 100644 index 000000000..7e82d4ab4 --- /dev/null +++ b/docs/sphinx/examples/Linux/Scanner.rst @@ -0,0 +1,7 @@ +Scanner.cpp +================== + +.. literalinclude:: ../../../../examples_linux/scanner.cpp + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Linux/StreamingData.rst b/docs/sphinx/examples/Linux/StreamingData.rst new file mode 100644 index 000000000..53121fae5 --- /dev/null +++ b/docs/sphinx/examples/Linux/StreamingData.rst @@ -0,0 +1,7 @@ +StreamingData.cpp +================== + +.. literalinclude:: ../../../../examples_linux/streamingData.cpp + :lines: 7- + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Python/AcknowledgementPayloads.rst b/docs/sphinx/examples/Python/AcknowledgementPayloads.rst new file mode 100644 index 000000000..43b04c841 --- /dev/null +++ b/docs/sphinx/examples/Python/AcknowledgementPayloads.rst @@ -0,0 +1,7 @@ +acknowledgement_payloads.py +=========================== + +.. literalinclude:: ../../../../examples_linux/acknowledgement_payloads.py + :language: python + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Python/GettingStarted.rst b/docs/sphinx/examples/Python/GettingStarted.rst new file mode 100644 index 000000000..ac5cea505 --- /dev/null +++ b/docs/sphinx/examples/Python/GettingStarted.rst @@ -0,0 +1,7 @@ +getting_started.py +================== + +.. literalinclude:: ../../../../examples_linux/getting_started.py + :language: python + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Python/InterruptConfigure.rst b/docs/sphinx/examples/Python/InterruptConfigure.rst new file mode 100644 index 000000000..f9706caf0 --- /dev/null +++ b/docs/sphinx/examples/Python/InterruptConfigure.rst @@ -0,0 +1,7 @@ +interrupt_configure.py +====================== + +.. literalinclude:: ../../../../examples_linux/interrupt_configure.py + :language: python + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Python/ManualAcknowledgements.rst b/docs/sphinx/examples/Python/ManualAcknowledgements.rst new file mode 100644 index 000000000..d12a8429c --- /dev/null +++ b/docs/sphinx/examples/Python/ManualAcknowledgements.rst @@ -0,0 +1,7 @@ +manual_acknowledgements.py +========================== + +.. literalinclude:: ../../../../examples_linux/manual_acknowledgements.py + :language: python + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Python/MulticeiverDemo.rst b/docs/sphinx/examples/Python/MulticeiverDemo.rst new file mode 100644 index 000000000..84b7305d4 --- /dev/null +++ b/docs/sphinx/examples/Python/MulticeiverDemo.rst @@ -0,0 +1,7 @@ +multiceiver_demo.py +==================== + +.. literalinclude:: ../../../../examples_linux/multiceiver_demo.py + :language: python + :linenos: + :lineno-match: diff --git a/docs/sphinx/examples/Python/StreamingData.rst b/docs/sphinx/examples/Python/StreamingData.rst new file mode 100644 index 000000000..d7e4903ad --- /dev/null +++ b/docs/sphinx/examples/Python/StreamingData.rst @@ -0,0 +1,7 @@ +streaming_data.py +================== + +.. literalinclude:: ../../../../examples_linux/streaming_data.py + :language: python + :linenos: + :lineno-match: diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst new file mode 100644 index 000000000..0fd1be2fa --- /dev/null +++ b/docs/sphinx/index.rst @@ -0,0 +1,44 @@ + +:hero: Optimized high speed nRF24L01+ driver class documentation + +Introduction +============= + +.. doxygenpage:: index + :content-only: + +Site Index +----------- + +:ref:`Site index` + +.. toctree:: + :maxdepth: 2 + :caption: API Reference + :hidden: + + classRF24 + enums + deprecated + nRF24L01_8h + RF24_config_8h + + +.. toctree:: + :maxdepth: 1 + :hidden: + + pages + + +.. toctree:: + :maxdepth: 1 + :hidden: + + modules + +.. toctree:: + :maxdepth: 2 + :hidden: + + examples diff --git a/docs/sphinx/make.bat b/docs/sphinx/make.bat new file mode 100644 index 000000000..bba10073f --- /dev/null +++ b/docs/sphinx/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=../sphinx +set BUILDDIR=../_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/sphinx/md_common_issues.rst b/docs/sphinx/md_common_issues.rst new file mode 100644 index 000000000..26fecd73b --- /dev/null +++ b/docs/sphinx/md_common_issues.rst @@ -0,0 +1,14 @@ +Common Issues +============= + +.. doxygenpage:: md_COMMON_ISSUES + :content-only: + + +.. image:: ../../images/ghetto_sheilding_1.png + :target: https://github.com/nRF24/RF24/blob/master/images/ghetto_sheilding_1.png + :height: 750 + +.. image:: ../../images/ghetto_sheilding_2.png + :target: https://github.com/nRF24/RF24/blob/master/images/ghetto_sheilding_2.png + :height: 750 diff --git a/docs/sphinx/md_contributing.rst b/docs/sphinx/md_contributing.rst new file mode 100644 index 000000000..8a9b00db5 --- /dev/null +++ b/docs/sphinx/md_contributing.rst @@ -0,0 +1,5 @@ +Contributing +============= + +.. doxygenpage:: md_CONTRIBUTING + :content-only: diff --git a/docs/sphinx/md_docs_arduino.rst b/docs/sphinx/md_docs_arduino.rst new file mode 100644 index 000000000..48f9376f8 --- /dev/null +++ b/docs/sphinx/md_docs_arduino.rst @@ -0,0 +1,5 @@ +Arduino +============= + +.. doxygenpage:: md_docs_arduino + :content-only: diff --git a/docs/sphinx/md_docs_attiny.rst b/docs/sphinx/md_docs_attiny.rst new file mode 100644 index 000000000..1c07080f1 --- /dev/null +++ b/docs/sphinx/md_docs_attiny.rst @@ -0,0 +1,6 @@ +ATTiny +============= +.. highlight:: none + +.. doxygenpage:: md_docs_attiny + :content-only: diff --git a/docs/sphinx/md_docs_atxmega.rst b/docs/sphinx/md_docs_atxmega.rst new file mode 100644 index 000000000..5a9ff21d9 --- /dev/null +++ b/docs/sphinx/md_docs_atxmega.rst @@ -0,0 +1,5 @@ +ATXMEGA +============= + +.. doxygenpage:: md_docs_atxmega + :content-only: diff --git a/docs/sphinx/md_docs_cross_compile.rst b/docs/sphinx/md_docs_cross_compile.rst new file mode 100644 index 000000000..8ffccf90a --- /dev/null +++ b/docs/sphinx/md_docs_cross_compile.rst @@ -0,0 +1,7 @@ +Linux cross-compilation +======================= + +.. highlight:: none + +.. doxygenpage:: md_docs_cross_compile + :content-only: diff --git a/docs/sphinx/md_docs_linux_install.rst b/docs/sphinx/md_docs_linux_install.rst new file mode 100644 index 000000000..2f3d04aa5 --- /dev/null +++ b/docs/sphinx/md_docs_linux_install.rst @@ -0,0 +1,5 @@ +Linux Installation +================== + +.. doxygenpage:: md_docs_linux_install + :content-only: diff --git a/docs/sphinx/md_docs_mraa.rst b/docs/sphinx/md_docs_mraa.rst new file mode 100644 index 000000000..361d98c3e --- /dev/null +++ b/docs/sphinx/md_docs_mraa.rst @@ -0,0 +1,5 @@ +MRAA +============= + +.. doxygenpage:: md_docs_mraa + :content-only: diff --git a/docs/sphinx/md_docs_pico_sdk.rst b/docs/sphinx/md_docs_pico_sdk.rst new file mode 100644 index 000000000..983a95367 --- /dev/null +++ b/docs/sphinx/md_docs_pico_sdk.rst @@ -0,0 +1,7 @@ +Raspberry Pi Pico SDK +===================== + +.. highlight:: cmake + +.. doxygenpage:: md_docs_pico_sdk + :content-only: diff --git a/docs/sphinx/md_docs_portability.rst b/docs/sphinx/md_docs_portability.rst new file mode 100644 index 000000000..7801a9cc2 --- /dev/null +++ b/docs/sphinx/md_docs_portability.rst @@ -0,0 +1,5 @@ +RF24 portability +================ + +.. doxygenpage:: md_docs_portability + :content-only: diff --git a/docs/sphinx/md_docs_python_wrapper.rst b/docs/sphinx/md_docs_python_wrapper.rst new file mode 100644 index 000000000..d0120e4bc --- /dev/null +++ b/docs/sphinx/md_docs_python_wrapper.rst @@ -0,0 +1,5 @@ +Python wrapper +============== + +.. doxygenpage:: md_docs_python_wrapper + :content-only: diff --git a/docs/sphinx/md_docs_rpi_general.rst b/docs/sphinx/md_docs_rpi_general.rst new file mode 100644 index 000000000..a69ff21e6 --- /dev/null +++ b/docs/sphinx/md_docs_rpi_general.rst @@ -0,0 +1,5 @@ +Linux General/Raspberry Pi +========================== + +.. doxygenpage:: md_docs_rpi_general + :content-only: diff --git a/docs/sphinx/md_docs_using_cmake.rst b/docs/sphinx/md_docs_using_cmake.rst new file mode 100644 index 000000000..8ef13be89 --- /dev/null +++ b/docs/sphinx/md_docs_using_cmake.rst @@ -0,0 +1,7 @@ +Using CMake +============= + +.. highlight:: none + +.. doxygenpage:: md_docs_using_cmake + :content-only: diff --git a/docs/sphinx/modules.rst b/docs/sphinx/modules.rst new file mode 100644 index 000000000..3fd4cccc0 --- /dev/null +++ b/docs/sphinx/modules.rst @@ -0,0 +1,11 @@ +Modules +========= + +.. toctree:: + :maxdepth: 2 + + modules/Porting_Timing + modules/Porting_GPIO + modules/Porting_Includes + modules/Porting_General + modules/Porting_SPI diff --git a/docs/sphinx/modules/Porting_GPIO.rst b/docs/sphinx/modules/Porting_GPIO.rst new file mode 100644 index 000000000..78d0c3f5a --- /dev/null +++ b/docs/sphinx/modules/Porting_GPIO.rst @@ -0,0 +1,18 @@ +Porting: GPIO +============= + +Sample docs +----------- + +.. doxygengroup:: Porting_GPIO + :members: + :undoc-members: + :protected-members: + :private-members: + :content-only: + +Source code +----------- + +.. literalinclude:: ../../../utility/Template/gpio.h + :caption: utility/Template/gpio.h diff --git a/docs/sphinx/modules/Porting_General.rst b/docs/sphinx/modules/Porting_General.rst new file mode 100644 index 000000000..e856bd1cc --- /dev/null +++ b/docs/sphinx/modules/Porting_General.rst @@ -0,0 +1,18 @@ +Porting: General +================ + +Sample docs +----------- + +.. doxygengroup:: Porting_General + :members: + :undoc-members: + :protected-members: + :private-members: + :content-only: + +Source code +----------- + +.. literalinclude:: ../../../utility/Template/RF24_arch_config.h + :caption: utility/Template/RF24_arch_config.h diff --git a/docs/sphinx/modules/Porting_Includes.rst b/docs/sphinx/modules/Porting_Includes.rst new file mode 100644 index 000000000..9ae078631 --- /dev/null +++ b/docs/sphinx/modules/Porting_Includes.rst @@ -0,0 +1,18 @@ +Porting: Includes +================== + +Sample docs +----------- + +.. doxygengroup:: Porting_Includes + :members: + :undoc-members: + :protected-members: + :private-members: + :content-only: + +Source code +----------- + +.. literalinclude:: ../../../utility/Template/includes.h + :caption: utility/Template/includes.h diff --git a/docs/sphinx/modules/Porting_SPI.rst b/docs/sphinx/modules/Porting_SPI.rst new file mode 100644 index 000000000..43629d86e --- /dev/null +++ b/docs/sphinx/modules/Porting_SPI.rst @@ -0,0 +1,18 @@ +Porting: SPI +============ + +Sample docs +----------- + +.. doxygengroup:: Porting_SPI + :members: + :undoc-members: + :protected-members: + :private-members: + :content-only: + +Source code +----------- + +.. literalinclude:: ../../../utility/Template/spi.h + :caption: utility/Template/spi.h diff --git a/docs/sphinx/modules/Porting_Timing.rst b/docs/sphinx/modules/Porting_Timing.rst new file mode 100644 index 000000000..6c32a84f9 --- /dev/null +++ b/docs/sphinx/modules/Porting_Timing.rst @@ -0,0 +1,18 @@ +Porting: Timing +=============== + +Sample docs +----------- + +.. doxygengroup:: Porting_Timing + :members: + :undoc-members: + :protected-members: + :private-members: + :content-only: + +Source code +----------- + +.. literalinclude:: ../../../utility/Template/compatibility.h + :caption: utility/Template/compatibility.h diff --git a/docs/sphinx/nRF24L01_8h.rst b/docs/sphinx/nRF24L01_8h.rst new file mode 100644 index 000000000..3ea691364 --- /dev/null +++ b/docs/sphinx/nRF24L01_8h.rst @@ -0,0 +1,7 @@ +nRF24L01.h +========== + +.. literalinclude:: ../../nRF24L01.h + :linenos: + :lineno-match: + :start-at: /* Memory Map */ diff --git a/docs/sphinx/pages.rst b/docs/sphinx/pages.rst new file mode 100644 index 000000000..a14c72a35 --- /dev/null +++ b/docs/sphinx/pages.rst @@ -0,0 +1,19 @@ +Related Pages +============= + +.. toctree:: + :maxdepth: 1 + + md_common_issues + md_contributing + md_docs_arduino + md_docs_attiny + md_docs_atxmega + md_docs_cross_compile + md_docs_linux_install + md_docs_mraa + md_docs_pico_sdk + md_docs_portability + md_docs_python_wrapper + md_docs_rpi_general + md_docs_using_cmake diff --git a/docs/sphinx/requirements.txt b/docs/sphinx/requirements.txt new file mode 100644 index 000000000..1707fa2f1 --- /dev/null +++ b/docs/sphinx/requirements.txt @@ -0,0 +1,2 @@ +breathe +sphinx-immaterial diff --git a/docs/using_cmake.md b/docs/using_cmake.md new file mode 100644 index 000000000..4e7cf4360 --- /dev/null +++ b/docs/using_cmake.md @@ -0,0 +1,170 @@ +# Using CMake + + +A more modern approach instead of using hand-crafted _Makefiles_ & _configure_ scripts +to build & install software. Please note that these instructions are not needed if you +have already installed the library using [these older instructions](md_docs_linux_install.html) + +## Installing the library + +### Using a package manager + +The RF24 library now (as of v1.4.1) has pre-built packages (_.deb_ or _.rpm_ files) that can be installed on a +Raspberry Pi. These packages can be found on the library's +[GitHub release page](https://GitHub.com/nRF24/RF24/releases) + +@warning If you have previously installed the library from source code, then you will need to uninstall it manually to avoid runtime conflicts. +```shell +sudo rm /usr/local/lib/librf24.* +sudo rm /usr/local/lib/librf24-bcm.so +sudo rm -r /usr/local/include/RF24 +``` + +The _librf24-bcm.so_ file may not exist if you used CMake to install the library. + +1. Download the appropriate package for your machine + + Go to the library's [GitHub release page](https://GitHub.com/nRF24/RF24/releases), and look for + the latest release's assets. + + For all Raspberry Pi variants using the Raspberry Pi OS (aka Raspbian), you need the file marked + for _armhf_ architecture. + + For Raspberry Pi variants using a 64-bit OS (like Ubuntu), you need the file marked for + _arm64_ architecture. + + Notice that the filenames will include the name of the utility driver that the package was built with. + This does not mean that the LittleWire, MRAA, or wiringPi libraries are included in the package (you will still + need to install those yourself beforehand). +2. Install the downloaded pkg + + If you downloaded the file directly from your target machine using the desktop environment, then + you only need to double-click the package (deb or rpm) file, and the OS should do the rest. + + If you downloaded the file remotely and want to copy it over ssh, then use the `scp` command in a terminal. + ```shell + scp pkg_filename.deb pi@host_name:~/Downloads + ``` + @note You do not need to do this from within an ssh session. Also, you can use the target machine's IP + address instead of its host name. + + The `scp` command will ask you for a password belonging to the user's name on the remote machine (we used + `pi` in the above example). + + Now you can open up a ssh session and install the copied package from the terminal. + ```shell + ssh pi@host_name + cd Downloads + dpkg -i pkg_filename.deb + ``` + +### Building from source code + +1. Install prerequisites if there are any (wiringPi, MRAA, LittleWire libraries, setup SPI device etc) + + CMake may need to be installed + ```shell + sudo apt-get install cmake + ``` + @note See the [MRAA documentation](http://iotdk.intel.com/docs/master/mraa/index.html) for more information on installing MRAA +2. Make a directory to contain the RF24 library and possibly other RF24\* libraries and enter it + ```shell + mkdir ~/rf24libs + cd ~/rf24libs + ``` +3. Clone the [RF24 repo](https://github.com/nRF24/RF24) and navigate to it + ```shell + git clone https://github.com/nRF24/RF24.git RF24 + cd RF24 + ``` +4. Create a build directory inside the RF24 directory and navigate to it. + ```shell + mkdir build + cd build + ``` +5. Configure build environment + + @note When using these instructions to install RF24Mesh, RF24Network, or RF24Gateway, + the following `RF24_DRIVER` option is not needed (it is only for the RF24 library). + + ```shell + cmake .. -D RF24_DRIVER=SPIDEV + ``` + Instead of using `SPIDEV` driver (recommended), you can also specify the `RPi`, `wiringPi`, + `MRAA`, or `LittleWire` as alternative drivers. + + If the `RF24_DRIVER` option is not specified, then it will be automatically configured based + on the detected CPU or installed libraries (defaults to `SPIDEV` when auto-detection fails). +6. Build and install the library + ```shell + make + sudo make install + ``` +7. Build the examples + + Navigate to the _examples_linux_ directory + ```shell + cd ../examples_linux + ``` + Make sure the pins used in the examples match the pins you used to connect the radio module + ```shell + nano gettingstarted.cpp + ``` + and edit the pin numbers as directed in the [linux/RPi general documation](md_docs_rpi_general.html). + Create a build directory in the examples_linux directory and navigate to it. + ```shell + mkdir build + cd build + ``` + Now you are ready to build the examples. + ```shell + cmake .. + make + ``` + If using the `MRAA` or `wiringPi` drivers, then you may need to specify the `RF24_DRIVER` + option again. + ```shell + cmake .. -D RF24_DRIVER=wiringPi + make + ``` +8. Run an example file + ```shell + sudo ./gettingstarted + ``` + +## Cross-compiling the library + +The RF24 library comes with some pre-made toolchain files (located in the _RF24/cmake/toolchains_ +directory) to use in CMake. To use these toolchain files, additional command line options are needed +when configuring CMake to build the library (step 5 in the above instructions to build from source). + +```shell +cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/armhf.cmake +make +``` + +If you plan on using the cross-compiled library with your personal cross-compiled project, then +it is advised to specify the path that your project will look in when linking to the RF24 library: + +```shell +cmake .. -D CMAKE_INSTALL_PREFIX=/usr/arm-linux-gnueabihf -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/armhf.cmake +make +sudo make install +``` + +Remember to also specify the `RF24_DRIVER` option if not using the auto-configuration feature (see step 5 +in the above instructions to build from source). + +### Installing the library remotely + +To install remotely, you can create an installable package file using CMake's built-in program called CPack. + +```shell +cmake .. -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/armhf.cmake +make +cpack +``` + +This will create a deb file and a rpm file in a new sub-directory called "pkgs" within the build directory. +You can use either of these packages to install the library to your target machine (see the above +instructions about using a package manager). diff --git a/examples/old_backups/scanner/scanner.ino b/examples/scanner/scanner.ino similarity index 96% rename from examples/old_backups/scanner/scanner.ino rename to examples/scanner/scanner.ino index c5b425a9f..0473193d0 100644 --- a/examples/old_backups/scanner/scanner.ino +++ b/examples/scanner/scanner.ino @@ -144,7 +144,11 @@ void loop(void) int i = 0; while ( i < num_channels ) { - Serial.print(min(0xf, values[i]), HEX); + if (values[i]) + Serial.print(min(0xf, values[i]), HEX); + else + Serial.print(F("-")); + ++i; } Serial.println(); diff --git a/examples_linux/CMakeLists.txt b/examples_linux/CMakeLists.txt new file mode 100644 index 000000000..c27646a7a --- /dev/null +++ b/examples_linux/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.12) + +# iterate over a list of examples by filename +set(EXAMPLES_LIST + gettingstarted + acknowledgementPayloads + manualAcknowledgements + streamingData + multiceiverDemo + scanner +) + +project(RF24LogExamples) +add_compile_options(-Ofast -Wall) # passing the compiler a `-pthread` flag doesn't work here + +# detect the CPU make and type +include(../cmake/detectCPU.cmake) # sets the variable SOC accordingly + +# auto-detect what driver to use +# auto-detect can be overriden using `cmake .. -D RF24_DRIVER=` +include(../cmake/AutoConfig_RF24_DRIVER.cmake) + +find_library(RF24 rf24 REQUIRED) +message(STATUS "using RF24 library: ${RF24}") + +# conditionally append "interruptConfigure" to the EXAMPLES_LIST +if("${RF24_DRIVER}" STREQUAL "MRAA" OR "${RF24_DRIVER}" STREQUAL "wiringPi") + message(STATUS "Skipping interruptConfigure.cpp example as it is incompatible with selected driver library") +else() # not using MRAA or wiringPi drivers + list(APPEND EXAMPLES_LIST interruptConfigure) +endif() + +foreach(example ${EXAMPLES_LIST}) + #make a target + add_executable(${example} ${example}.cpp) + + # link the RF24 lib to the target. Notice we specify pthread as a linked lib here + if("${RF24_DRIVER}" STREQUAL "MRAA") + target_link_libraries(${example} PUBLIC ${RF24} pthread ${LibMRAA}) + elseif("${RF24_DRIVER}" STREQUAL "wiringPi") + # wiringPi additionally needs to link to crypt and shm_open libraries + target_link_libraries(${example} PUBLIC ${RF24} pthread ${LibWiringPi} crypt rt) + else() # not using MRAA or wiringPi drivers + target_link_libraries(${example} PUBLIC ${RF24} pthread) + endif() +endforeach() diff --git a/examples_linux/Makefile b/examples_linux/Makefile index f035127f1..e3a3c4998 100644 --- a/examples_linux/Makefile +++ b/examples_linux/Makefile @@ -18,6 +18,6 @@ endif include ../Makefile.inc # define all programs -PROGRAMS = gettingstarted acknowledgementPayloads manualAcknowledgements streamingData multiceiverDemo interruptConfigure +PROGRAMS = gettingstarted acknowledgementPayloads manualAcknowledgements streamingData multiceiverDemo scanner interruptConfigure include Makefile.examples diff --git a/examples_linux/acknowledgement_payloads.py b/examples_linux/acknowledgement_payloads.py index 91811fa87..c326a6580 100644 --- a/examples_linux/acknowledgement_payloads.py +++ b/examples_linux/acknowledgement_payloads.py @@ -199,10 +199,6 @@ def set_role(): ) ) - # set the Power Amplifier level to -12 dBm since this test example is - # usually run with nRF24L01 transceivers in close proximity of each other - radio.setPALevel(RF24_PA_LOW) # RF24_PA_MAX is default - # ACK payloads are dynamically sized. radio.enableDynamicPayloads() # to use ACK payloads diff --git a/examples_linux/extra/Makefile b/examples_linux/extra/Makefile index 6a5dbff4a..de7ba5b65 100644 --- a/examples_linux/extra/Makefile +++ b/examples_linux/extra/Makefile @@ -19,6 +19,6 @@ endif include ../../Makefile.inc # define all programs -PROGRAMS = rpi-hub scanner +PROGRAMS = rpi-hub include ../Makefile.examples diff --git a/examples_linux/multiceiver_demo.py b/examples_linux/multiceiver_demo.py index f653b1654..1209dc81d 100644 --- a/examples_linux/multiceiver_demo.py +++ b/examples_linux/multiceiver_demo.py @@ -63,7 +63,7 @@ def master(node_number): # According to the datasheet, the auto-retry features's delay value should # be "skewed" to allow the RX node to receive 1 transmission at a time. # So, use varying delay between retry attempts and 15 (at most) retry attempts - radio.setRetries(((node_number * 3) % 12) + 3, 15); # maximum value is 15 for both args + radio.setRetries(((node_number * 3) % 12) + 3, 15) # maximum value is 15 for both args radio.stopListening() # put radio in TX mode # set the TX address to the address of the base station. diff --git a/examples_linux/extra/scanner.cpp b/examples_linux/scanner.cpp similarity index 72% rename from examples_linux/extra/scanner.cpp rename to examples_linux/scanner.cpp index ee8ef1e11..7a3be9744 100644 --- a/examples_linux/extra/scanner.cpp +++ b/examples_linux/scanner.cpp @@ -4,11 +4,11 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. - - + + 03/17/2013 : Charles-Henri Hallard (http://hallard.me) Modified to use with Arduipi board http://hallard.me/arduipi - Changed to use modified bcm2835 and RF24 library + Changed to use modified bcm2835 and RF24 library */ @@ -29,27 +29,20 @@ using namespace std; -// -// Hardware configuration -// - -// CE Pin, CSN Pin, SPI Speed - -// Setup for GPIO 22 CE and GPIO 25 CSN with SPI Speed @ 1Mhz -//RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_18, BCM2835_SPI_SPEED_1MHZ); - -// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz -//RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ); +/****************** Linux ***********************/ +// Radio CE Pin, CSN Pin, SPI Speed +// CE Pin uses GPIO number with BCM and SPIDEV drivers, other platforms use their own pin numbering +// CS Pin addresses the SPI bus number at /dev/spidev
. +// ie: RF24 radio(, *10+); spidev1.0 is 10, spidev1.1 is 11 etc.. -// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 8Mhz -//RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ); - -// Generic setup +// Generic: RF24 radio(22, 0); +/****************** Linux (BBB,x86,etc) ***********************/ +// See http://nRF24.github.io/RF24/pages.html for more information on usage +// See http://iotdk.intel.com/docs/master/mraa/ for more information on MRAA +// See https://www.kernel.org/doc/Documentation/spi/spidev for more information on SPIDEV -// // Channel info -// const uint8_t num_channels = 126; uint8_t values[num_channels]; @@ -58,13 +51,10 @@ int reset_array = 0; int main(int argc, char** argv) { - // // Print preamble - // - //Serial.begin(115200); - //printf_begin(); - printf("RF24/examples/scanner/\n"); + // print example's name + printf("%s", argv[0]); // // Setup and configure rf radio @@ -125,7 +115,11 @@ int main(int argc, char** argv) // Print out channel measurements, clamped to a single hex digit i = 0; while (i < num_channels) { - printf("%x", min(0xf, (values[i] & 0xf))); + if (values[i]) + printf("%x", min(0xf, (values[i] & 0xf))); + else + printf("-"); + ++i; } printf("\n"); diff --git a/examples_linux/streaming_data.py b/examples_linux/streaming_data.py index fecd275ac..02efedf0a 100644 --- a/examples_linux/streaming_data.py +++ b/examples_linux/streaming_data.py @@ -124,6 +124,7 @@ def slave(timeout=6): # recommended behavior is to keep in TX mode while idle radio.stopListening() # put the radio in TX mode + print("Nothing received in ", timeout, " seconds. Leaving RX role") def set_role(): """Set the role using stdin stream. Role args can be specified using space diff --git a/examples_pico/CMakeLists.txt b/examples_pico/CMakeLists.txt new file mode 100644 index 000000000..fe1968489 --- /dev/null +++ b/examples_pico/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.12) + +# Pull in SDK (must be before project) +include(../cmake/pico_sdk_import.cmake) + +project(pico_examples C CXX ASM) + +# Initialize the Pico SDK +pico_sdk_init() + +# In YOUR project, include RF24's CMakeLists.txt +# giving the path depending on where the library +# is cloned to in your project +include(../CMakeLists.txt) + +# iterate over a list of examples by name +set(EXAMPLES_LIST + gettingStarted + acknowledgementPayloads + streamingData + manualAcknowledgements + multiceiverDemo + interruptConfigure + scanner +) + +foreach(example ${EXAMPLES_LIST}) + # make a target + add_executable(${example} ${example}.cpp defaultPins.h) + + # link the necessary libs to the target + target_link_libraries(${example} PUBLIC + RF24 + pico_stdlib + hardware_spi + hardware_gpio + ) + + # specify USB port as default serial communication's interface (not UART RX/TX pins) + pico_enable_stdio_usb(${example} 1) + pico_enable_stdio_uart(${example} 0) + + # create map/bin/hex file etc. + pico_add_extra_outputs(${example}) +endforeach() diff --git a/examples_pico/acknowledgementPayloads.cpp b/examples_pico/acknowledgementPayloads.cpp new file mode 100644 index 000000000..318540a7a --- /dev/null +++ b/examples_pico/acknowledgementPayloads.cpp @@ -0,0 +1,229 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with Acknowledgement (ACK) payloads attached to ACK packets. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Terminal to change each node's behavior. + */ +#include "pico/stdlib.h" // printf(), sleep_ms(), getchar_timeout_us(), to_us_since_boot(), get_absolute_time() +#include "pico/bootrom.h" // reset_usb_boot() +#include // tud_cdc_connected() +#include // RF24 radio object +#include "defaultPins.h" // board presumptive default pin numbers for CE_PIN and CSN_PIN + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// Used to control whether this node is sending or receiving +bool role = false; // true = TX role, false = RX role + +// For this example, we'll be using a payload containing +// a string & an integer number that will be incremented +// on every successful transmission. +// Make a data structure to store the entire payload of different datatypes +struct PayloadStruct { + char message[7]; // only using 6 characters for TX & ACK payloads + uint8_t counter; +}; +PayloadStruct payload; + + +bool setup() { + + // an identifying device destination + // Let these addresses be used for the pair + uint8_t address[][6] = {"1Node", "2Node"}; + // It is very helpful to think of an address as a path instead of as + // an identifying device destination + // to use different addresses on a pair of radios, we need a variable to + + // uniquely identify which address this radio will use to transmit + bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + + // wait here until the CDC ACM (serial port emulation) is connected + while (!tud_cdc_connected()) { + sleep_ms(10); + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + printf("radio hardware is not responding!!\n"); + return false; + } + + // print example's introductory prompt + printf("RF24/examples_pico/acknowledgementPayloads\n"); + + // To set the radioNumber via the Serial monitor on startup + printf("Which radio is this? Enter '0' or '1'. Defaults to '0'\n"); + char input = getchar(); + radioNumber = input == 49; + printf("radioNumber = %d\n", (int)radioNumber); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // to use ACK payloads, we need to enable dynamic payload lengths (for all nodes) + radio.enableDynamicPayloads(); // ACK payloads are dynamically sized + + // Acknowledgement packets have no payloads by default. We need to enable + // this feature for all nodes (TX & RX) to use ACK payloads. + radio.enableAckPayload(); + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // additional setup specific to the node's role + if (role) { + // setup the TX payload + + memcpy(payload.message, "Hello ", 6); // set the payload message + radio.stopListening(); // put radio in TX mode + } + else { + // setup the ACK payload & load the first response into the FIFO + + memcpy(payload.message, "World ", 6); // set the payload message + // load the payload for the first received transmission on pipe 0 + radio.writeAckPayload(1, &payload, sizeof(payload)); + + radio.startListening(); // put radio in RX mode + } + + // For debugging info + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + + // role variable is hardcoded to RX behavior, inform the user of this + printf("*** PRESS 'T' to begin transmitting to the other node\n"); + + return true; +} + +void loop() { + + if (role) { + // This device is a TX node + + uint64_t start_timer = to_us_since_boot(get_absolute_time()); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + uint64_t end_timer = to_us_since_boot(get_absolute_time()); // end the timer + + if (report) { + + // print details about outgoing payload + printf("Transmission successful! Time to transmit = %llu us. Sent: %s%d", + end_timer - start_timer, + payload.message, + payload.counter); + + uint8_t pipe; + if (radio.available(&pipe)) { // is there an ACK payload? grab the pipe number that received it + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming ACK payload + + // print details about incoming payload + printf(" Recieved %d bytes on pipe %d: %s%d\n", + radio.getDynamicPayloadSize(), + pipe, + received.message, + received.counter); + + // save incoming counter & increment for next outgoing + payload.counter = received.counter + 1; + + } + else { + printf(" Recieved: an empty ACK packet\n"); // empty ACK packet received + } + + + } + else { + printf("Transmission failed or timed out\n"); // payload was not delivered + } + + // to make this example readable in the serial terminal + sleep_ms(1000); // slow transmissions down by 1 second + } + else { + // This device is a RX node + + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it + uint8_t bytes = radio.getDynamicPayloadSize(); // get the size of the payload + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming payload + + // print the details of transaction + printf("Received %d bytes on pipe %d: %s%d Sent: %s%d\n", + bytes, + pipe, + received.message, + received.counter, + payload.message, + payload.counter); + + // save incoming counter & increment for next outgoing + payload.counter = received.counter + 1; + // load the payload for the first received transmission on pipe 0 + radio.writeAckPayload(1, &payload, sizeof(payload)); + } + } // role + + char input = getchar_timeout_us(0); // get char from buffer for user input + if (input != PICO_ERROR_TIMEOUT) { + // change the role via the serial terminal + + if ((input == 'T' || input == 't') && !role) { + // Become the TX node + + role = true; + printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n"); + + memcpy(payload.message, "Hello ", 6); // change payload message + radio.stopListening(); // this also discards any unused ACK payloads + + } + else if ((input == 'R' || input == 'r') && role) { + // Become the RX node + + role = false; + printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n"); + memcpy(payload.message, "World ", 6); // change payload message + + // load the payload for the first received transmission on pipe 0 + radio.writeAckPayload(1, &payload, sizeof(payload)); + radio.startListening(); + } + else if (input == 'b' || input == 'B') { + // reset to bootloader + radio.powerDown(); + reset_usb_boot(0, 0); + } + } +} // loop + +int main() +{ + stdio_init_all(); // init necessary IO for the RP2040 + + while (!setup()) { // if radio.begin() failed + // hold program in infinite attempts to initialize radio + } + while (true) { + loop(); + } + return 0; // we will never reach this +} diff --git a/examples_pico/defaultPins.h b/examples_pico/defaultPins.h new file mode 100644 index 000000000..1178e2601 --- /dev/null +++ b/examples_pico/defaultPins.h @@ -0,0 +1,33 @@ +// pre-chossen pins for different boards +#ifndef DEFAULTPINS_H +#define DEFAULTPINS_H + +#if defined (ADAFRUIT_QTPY_RP2040) +// for this board, you can still use the Stemma QT connector as a separate I2C bus (`i2c1`) +#define CE_PIN PICO_DEFAULT_I2C_SDA_PIN // the pin labeled SDA +#define CSN_PIN PICO_DEFAULT_I2C_SCL_PIN // the pin labeled SCL +#define IRQ_PIN PICO_DEFAULT_UART_RX_PIN // the pin labeled RX + +#elif defined (PIMORONI_TINY2040) +// default SPI_SCK_PIN = 6 +// default SPI_TX_PIN = 7 +// default SPI_RX_PIN = 4 +#define CE_PIN PICO_DEFAULT_I2C_SCL_PIN // pin 3 +#define CSN_PIN PICO_DEFAULT_SPI_CSN_PIN // pin 5 +#define IRQ_PIN PICO_DEFAULT_I2C_SDA_PIN // pin 2 + + +#elif defined(SPARFUN_THINGPLUS) +#define CSN_PIN 16 // the pin labeled 16 +#define CE_PIN 7 // the pin labeled SCL +#define IRQ_PIN 6 // the pin labeled SDA + +#else +// pins available on (ADAFRUIT_ITSYBITSY_RP2040 || ADAFRUIT_FEATHER_RP2040 || Pico_board || Sparkfun_ProMicro || SparkFun MicroMod) + +#define CE_PIN 7 +#define CSN_PIN 8 +#define IRQ_PIN 6 +#endif // board detection macro defs + +#endif // DEFAULTPINS_H diff --git a/examples_pico/gettingStarted.cpp b/examples_pico/gettingStarted.cpp new file mode 100644 index 000000000..cf2637221 --- /dev/null +++ b/examples_pico/gettingStarted.cpp @@ -0,0 +1,169 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from 1 nRF24L01 transceiver to another. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Terminal to change each node's behavior. + */ +#include "pico/stdlib.h" // printf(), sleep_ms(), getchar_timeout_us(), to_us_since_boot(), get_absolute_time() +#include "pico/bootrom.h" // reset_usb_boot() +#include // tud_cdc_connected() +#include // RF24 radio object +#include "defaultPins.h" // board presumptive default pin numbers for CE_PIN and CSN_PIN + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// Used to control whether this node is sending or receiving +bool role = false; // true = TX role, false = RX role + +// For this example, we'll be using a payload containing +// a single float number that will be incremented +// on every successful transmission +float payload = 0.0; + + +bool setup() +{ + // Let these addresses be used for the pair + uint8_t address[][6] = {"1Node", "2Node"}; + // It is very helpful to think of an address as a path instead of as + // an identifying device destination + + // to use different addresses on a pair of radios, we need a variable to + // uniquely identify which address this radio will use to transmit + bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + + // wait here until the CDC ACM (serial port emulation) is connected + while (!tud_cdc_connected()) { + sleep_ms(10); + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + printf("radio hardware is not responding!!\n"); + return false; + } + + // print example's introductory prompt + printf("RF24/examples_pico/gettingStarted\n"); + + // To set the radioNumber via the Serial terminal on startup + printf("Which radio is this? Enter '0' or '1'. Defaults to '0'\n"); + char input = getchar(); + radioNumber = input == 49; + printf("radioNumber = %d\n", (int)radioNumber); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // float datatype occupies 4 bytes + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // additional setup specific to the node's role + if (role) { + radio.stopListening(); // put radio in TX mode + } + else { + radio.startListening(); // put radio in RX mode + } + + // For debugging info + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + + // role variable is hardcoded to RX behavior, inform the user of this + printf("*** PRESS 'T' to begin transmitting to the other node\n"); + + return true; +} // setup + +void loop() +{ + if (role) { + // This device is a TX node + + uint64_t start_timer = to_us_since_boot(get_absolute_time()); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + uint64_t end_timer = to_us_since_boot(get_absolute_time()); // end the timer + + if (report) { + // payload was delivered; print the payload sent & the timer result + printf("Transmission successful! Time to transmit = %llu us. Sent: %f\n", end_timer - start_timer, payload); + + // increment float payload + payload += 0.01; + } + else { + // payload was not delivered + printf("Transmission failed or timed out\n"); + } + + // to make this example readable in the serial terminal + sleep_ms(1000); // slow transmissions down by 1 second + } + else { + // This device is a RX node + + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it + uint8_t bytes = radio.getPayloadSize(); // get the size of the payload + radio.read(&payload, bytes); // fetch payload from FIFO + + // print the size of the payload, the pipe number, payload's value + printf("Received %d bytes on pipe %d: %f\n", bytes, pipe, payload); + } + } // role + + char input = getchar_timeout_us(0); // get char from buffer for user input + if (input != PICO_ERROR_TIMEOUT) { + // change the role via the serial terminal + + if ((input == 'T' || input == 't') && !role) { + // Become the TX node + + role = true; + printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n"); + radio.stopListening(); + } + else if ((input == 'R' || input == 'r') && role) { + // Become the RX node + + role = false; + printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n"); + radio.startListening(); + } + else if (input == 'b' || input == 'B') { + // reset to bootloader + radio.powerDown(); + reset_usb_boot(0, 0); + } + } +} // loop + +int main() +{ + stdio_init_all(); // init necessary IO for the RP2040 + + while (!setup()) { // if radio.begin() failed + // hold program in infinite attempts to initialize radio + } + while (true) { + loop(); + } + return 0; // we will never reach this +} diff --git a/examples_pico/interruptConfigure.cpp b/examples_pico/interruptConfigure.cpp new file mode 100644 index 000000000..134a90c97 --- /dev/null +++ b/examples_pico/interruptConfigure.cpp @@ -0,0 +1,367 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * This example uses Acknowledgement (ACK) payloads attached to ACK packets to + * demonstrate how the nRF24L01's IRQ (Interrupt Request) pin can be + * configured to detect when data is received, or when data has transmitted + * successfully, or when data has failed to transmit. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Terminal to change each node's behavior. + */ +#include "pico/stdlib.h" // printf(), sleep_ms(), getchar_timeout_us(), to_us_since_boot(), get_absolute_time() +#include "pico/bootrom.h" // reset_usb_boot() +#include // tud_cdc_connected() +#include // RF24 radio object +#include "defaultPins.h" // board presumptive default pin numbers for IRQ_PIN, CE_PIN, and CSN_PIN + +// We will be using the nRF24L01's IRQ pin for this example +volatile bool wait_for_event = false; // used to wait for an IRQ event to trigger + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// Used to control whether this node is sending or receiving +bool role = false; // true = TX node, false = RX node + +// For this example, we'll be using a payload containing +// a string that changes on every transmission. (successful or not) +// Make a couple arrays of payloads & an iterator to traverse them +const uint8_t tx_pl_size = 5; +const uint8_t ack_pl_size = 4; +uint8_t pl_iterator = 0; +// The " + 1" compensates for the c-string's NULL terminating 0 +char tx_payloads[][tx_pl_size + 1] = {"Ping ", "Pong ", "Radio", "1FAIL"}; +char ack_payloads[][ack_pl_size + 1] = {"Yak ", "Back", " ACK"}; + +void interruptHandler(uint gpio, uint32_t events); // prototype to handle IRQ events +void printRxFifo(); // prototype to print RX FIFO with 1 buffer + + +bool setup() +{ + // Let these addresses be used for the pair + uint8_t address[][6] = {"1Node", "2Node"}; + // It is very helpful to think of an address as a path instead of as + // an identifying device destination + + // to use different addresses on a pair of radios, we need a variable to + // uniquely identify which address this radio will use to transmit + bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + + // wait here until the CDC ACM (serial port emulation) is connected + while (!tud_cdc_connected()) { + sleep_ms(10); + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + printf("radio hardware is not responding!!\n"); + return false; + } + + // print example's introductory prompt + printf("RF24/examples_pico/interruptConfigure\n"); + + // To set the radioNumber via the Serial terminal on startup + printf("Which radio is this? Enter '0' or '1'. Defaults to '0'\n"); + char input = getchar(); + radioNumber = input == 49; + printf("radioNumber = %d\n", (int)radioNumber); + + // setup the IRQ_PIN + gpio_set_irq_enabled_with_callback(IRQ_PIN, GPIO_IRQ_EDGE_FALL, true, &interruptHandler); + // IMPORTANT: do not call radio.available() before calling + // radio.whatHappened() when the interruptHandler() is triggered by the + // IRQ pin FALLING event. According to the datasheet, the pipe information + // is unreliable during the IRQ pin FALLING transition. + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // For this example we use acknowledgment (ACK) payloads to trigger the + // IRQ pin when data is received on the TX node. + // to use ACK payloads, we need to enable dynamic payload lengths + radio.enableDynamicPayloads(); // ACK payloads are dynamically sized + + // Acknowledgement packets have no payloads by default. We need to enable + // this feature for all nodes (TX & RX) to use ACK payloads. + radio.enableAckPayload(); + // Fot this example, we use the same address to send data back and forth + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // additional setup specific to the node's role + if (role) { + // setup for TX mode + radio.stopListening(); // put radio in TX mode + + } + else { + // setup for RX mode + + // let IRQ pin not trigger in RX mode + radio.maskIRQ(1, 1, 1); // args = "data_sent", "data_fail", "data_ready" + + // Fill the TX FIFO with 3 ACK payloads for the first 3 received + // transmissions on pipe 1 + radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); + + radio.startListening(); // put radio in RX mode + } + + // For debugging info + // printf_begin(); // needed only once for printing details + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + + // role variable is hardcoded to RX behavior, inform the user of this + printf("*** PRESS 'T' to begin transmitting to the other node\n"); + + return true; +} + +void loop() +{ + if (role && !wait_for_event) { + // This device is a TX node. This if block is only triggered when + // NOT waiting for an IRQ event to happen + + if (pl_iterator == 0) { + // Test the "data ready" event with the IRQ pin + + printf("\nConfiguring IRQ pin to ignore the 'data sent' event\n"); + radio.maskIRQ(true, false, false); // args = "data_sent", "data_fail", "data_ready" + printf(" Pinging RX node for 'data ready' event...\n"); + + } + else if (pl_iterator == 1) { + // Test the "data sent" event with the IRQ pin + + printf("\nConfiguring IRQ pin to ignore the 'data ready' event\n"); + radio.maskIRQ(false, false, true); // args = "data_sent", "data_fail", "data_ready" + printf(" Pinging RX node for 'data sent' event...\n"); + + } + else if (pl_iterator == 2) { + // Use this iteration to fill the RX node's FIFO which sets us up for the next test. + + // write() uses virtual interrupt flags that work despite the masking of the IRQ pin + radio.maskIRQ(1, 1, 1); // disable IRQ masking for this step + + printf("\nSending 1 payload to fill RX node's FIFO. IRQ pin is neglected.\n"); + // write() will call flush_tx() on 'data fail' events + if (radio.write(&tx_payloads[pl_iterator], tx_pl_size)) { + if (radio.rxFifoFull()) { + printf("RX node's FIFO is full; it is not listening any more\n"); + } + else { + printf("Transmission successful, but the RX node might still be listening.\n"); + } + } + else { + printf("Transmission failed or timed out. Continuing anyway.\n"); + radio.flush_tx(); // discard payload(s) that failed to transmit + } + + } + else if (pl_iterator == 3) { + // test the "data fail" event with the IRQ pin + + printf("\nConfiguring IRQ pin to reflect all events\n"); + radio.maskIRQ(0, 0, 0); // args = "data_sent", "data_fail", "data_ready" + printf(" Pinging inactive RX node for 'data fail' event...\n"); + } + + if (pl_iterator < 4 && pl_iterator != 2) { + + // IRQ pin is LOW when activated. Otherwise it is always HIGH + // Wait until IRQ pin is activated. + wait_for_event = true; + + // use the non-blocking call to write a payload and begin transmission + // the "false" argument means we are expecting an ACK packet response + radio.startFastWrite(tx_payloads[pl_iterator++], tx_pl_size, false); + + // In this example, the "data fail" event is always configured to + // trigger the IRQ pin active. Because the auto-ACK feature is on by + // default, we don't need a timeout check to prevent an infinite loop. + } + else if (pl_iterator == 4) { + // all IRQ tests are done; flush_tx() and print the ACK payloads for fun + + // CE pin is still HIGH which consumes more power. Example is now idling so... + radio.stopListening(); // ensure CE pin is LOW + // stopListening() also calls flush_tx() when ACK payloads are enabled + + printRxFifo(); + pl_iterator++; + + // inform user what to do next + printf("\n*** PRESS 'T' to restart the transmissions"); + printf("\n*** PRESS 'R' to change to Receive role\n"); + + } + else if (pl_iterator == 2) { + pl_iterator++; // proceed from step 3 to last step (stop at step 4 for readability) + } + + } + else if (!role && radio.rxFifoFull()) { + // This device is a RX node + // + // The RX role waits until RX FIFO is full then stops listening while + // the FIFOs get reset and starts listening again. + radio.stopListening(); // also calls flush_tx() when ACKs are enabled + printRxFifo(); // also clears RX FIFO + + // Fill the TX FIFO with 3 ACK payloads for the first 3 received + // transmissions on pipe 1. + radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); + + sleep_ms(200); // let radio TX role complete + radio.startListening(); // We're ready to start over. Begin listening. + + } // role + + char input = getchar_timeout_us(0); // get char from buffer for user input + if (input != PICO_ERROR_TIMEOUT) { + // change the role via the serial terminal + + if (input == 'T' || input == 't') { + // Become the TX node + if (!role) + printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n"); + else if (role && wait_for_event) // don't interrupt on ongoing test + return; // exit now; start next loop() + else + printf("*** RESTARTING IRQ PIN TEST ***\n"); + + role = true; + wait_for_event = false; + pl_iterator = 0; // reset the iterator + radio.flush_tx(); // discard any payloads in the TX FIFO + + // startListening() clears the IRQ masks also. This is required for + // continued TX operations when a transmission fails. + radio.stopListening(); // this also discards any unused ACK payloads + } + else if ((input == 'R' || input == 'r')/* && role */) { + // Become the RX node + printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n"); + + role = false; + radio.maskIRQ(1, 1, 1); // the IRQ pin should not trigger in this example's RX rode + + // Fill the TX FIFO with 3 ACK payloads for the first 3 received + // transmissions on pipe 1 + radio.flush_tx(); // make sure there is room for 3 new ACK payloads + radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); + radio.startListening(); + } + else if (input == 'b' || input == 'B') { + // reset to bootloader + radio.powerDown(); + reset_usb_boot(0, 0); + } + } // user input +} // loop + +/** + * when the IRQ pin goes active LOW, call this fuction print out why + */ +void interruptHandler(uint gpio, uint32_t events) +{ + + if (gpio != IRQ_PIN && !(events | GPIO_IRQ_EDGE_FALL)) { + // the gpio pin and event does not match the configuration we specified + return; + } + + // print IRQ status and all masking flags' states + printf("\tIRQ pin is actively LOW\n"); // show that this function was called + bool tx_ds, tx_df, rx_dr; // declare variables for IRQ masks + radio.whatHappened(tx_ds, tx_df, rx_dr); // get values for IRQ masks + // whatHappened() clears the IRQ masks also. This is required for + // continued TX operations when a transmission fails. + // clearing the IRQ masks resets the IRQ pin to its inactive state (HIGH) + + // print "data sent", "data fail", "data ready" mask states + printf("\tdata_sent: %s, data_fail: %s, data_ready: %s\n", + tx_ds ? "true" : "false", + tx_df ? "true" : "false", + rx_dr ? "true" : "false"); + + if (tx_df) // if TX payload failed + radio.flush_tx(); // clear all payloads from the TX FIFO + + // print if test passed or failed. Unintentional fails mean the RX node was not listening. + // pl_iterator has already been incremented by now + if (pl_iterator <= 1) { + printf(" 'Data Ready' event test %s\n", rx_dr ? "passed" : "failed"); + } + else if (pl_iterator == 2) { + printf(" 'Data Sent' event test %s\n", tx_ds ? "passed" : "failed"); + } + else if (pl_iterator == 4) { + printf(" 'Data Fail' event test %s\n", tx_df ? "passed" : "failed"); + } + wait_for_event = false; // ready to continue with loop() operations +} // interruptHandler + + +/** + * Print the entire RX FIFO with one buffer. This will also flush the RX FIFO. + * Remember that the payload sizes are declared as tx_pl_size and ack_pl_size. + */ +void printRxFifo() +{ + if (radio.available()) { // if there is data in the RX FIFO + // to flush the data from the RX FIFO, we'll fetch it all using 1 buffer + + uint8_t pl_size = !role ? tx_pl_size : ack_pl_size; + char rx_fifo[pl_size * 3 + 1]; // RX FIFO is full & we know ACK payloads' size + if (radio.rxFifoFull()) { + rx_fifo[pl_size * 3] = 0; // add a NULL terminating char to use as a c-string + radio.read(&rx_fifo, pl_size * 3); // this clears the RX FIFO (for this example) + } + else { + uint8_t i = 0; + while (radio.available()) { + radio.read(&rx_fifo + (i * pl_size), pl_size); + i++; + } + rx_fifo[i * pl_size] = 0; // add a NULL terminating char to use as a c-string + } + printf("Complete RX FIFO: %s\n", rx_fifo); // print the entire RX FIFO with 1 buffer + } +} + +int main() +{ + stdio_init_all(); // init necessary IO for the RP2040 + + while (!setup()) { // if radio.begin() failed + // hold program in infinite attempts to initialize radio + } + while (true) { + loop(); + } + return 0; // we will never reach this +} diff --git a/examples_pico/manualAcknowledgements.cpp b/examples_pico/manualAcknowledgements.cpp new file mode 100644 index 000000000..9f40ecaf1 --- /dev/null +++ b/examples_pico/manualAcknowledgements.cpp @@ -0,0 +1,239 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty (2bndy5) + */ + +/** + * A simple example of sending data from 1 nRF24L01 transceiver to another + * with manually transmitted (non-automatic) Acknowledgement (ACK) payloads. + * This example still uses ACK packets, but they have no payloads. Instead the + * acknowledging response is sent with `write()`. This tactic allows for more + * updated acknowledgement payload data, where actual ACK payloads' data are + * outdated by 1 transmission because they have to loaded before receiving a + * transmission. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Terminal to change each node's behavior. + */ +#include "pico/stdlib.h" // printf(), sleep_ms(), getchar_timeout_us(), to_us_since_boot(), get_absolute_time() +#include "pico/bootrom.h" // reset_usb_boot() +#include // tud_cdc_connected() +#include // RF24 radio object +#include "defaultPins.h" // board presumptive default pin numbers for CE_PIN and CSN_PIN + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// Used to control whether this node is sending or receiving +bool role = false; // true = TX node, false = RX node + +// For this example, we'll be using a payload containing +// a string & an integer number that will be incremented +// on every successful transmission. +// Make a data structure to store the entire payload of different datatypes +struct PayloadStruct { + char message[7]; // only using 6 characters for TX & RX payloads + uint8_t counter; +}; +PayloadStruct payload; + +bool setup() +{ + // append a NULL terminating character for printing as a c-string + payload.message[6] = 0; + + // Let these addresses be used for the pair + uint8_t address[][6] = {"1Node", "2Node"}; + // It is very helpful to think of an address as a path instead of as + // an identifying device destination + + // to use different addresses on a pair of radios, we need a variable to + // uniquely identify which address this radio will use to transmit + bool radioNumber = 1; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + + // wait here until the CDC ACM (serial port emulation) is connected + while (!tud_cdc_connected()) { + sleep_ms(10); + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + printf("radio hardware is not responding!!\n"); + return false; + } + + // print example's introductory prompt + printf("RF24/examples_pico/manualAcknowledgements\n"); + + // To set the radioNumber via the Serial monitor on startup + printf("Which radio is this? Enter '0' or '1'. Defaults to '0'\n"); + char input = getchar(); + radioNumber = input == 49; + printf("radioNumber = %d\n", (int)radioNumber); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // char[7] & uint8_t datatypes occupy 8 bytes + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + if (role) { + // setup the TX node + + memcpy(payload.message, "Hello ", 6); // set the outgoing message + radio.stopListening(); // put radio in TX mode + } + else { + // setup the RX node + + memcpy(payload.message, "World ", 6); // set the outgoing message + radio.startListening(); // put radio in RX mode + } + + // For debugging info + // printf_begin(); // needed only once for printing details + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + + // role variable is hardcoded to RX behavior, inform the user of this + printf("*** PRESS 'T' to begin transmitting to the other node\n"); + + return true; +} // setup() + +void loop() +{ + if (role) { + // This device is a TX node + + uint64_t start_timer = to_us_since_boot(get_absolute_time()); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + + if (report) { + // transmission successful; wait for response and print results + + radio.startListening(); // put in RX mode + uint64_t start_timeout = to_ms_since_boot(get_absolute_time()); // timer to detect timeout + while (!radio.available()) { // wait for response + if (to_ms_since_boot(get_absolute_time()) - start_timeout > 200) // only wait 200 ms + break; + } + uint64_t end_timer = to_us_since_boot(get_absolute_time()); // end the timer + radio.stopListening(); // put back in TX mode + + // print summary of transactions + printf("Transmission successful!"); // payload was delivered + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload received + // print details about outgoing payload + printf(" Round-trip delay: %llu us. Sent: %s%d", + end_timer - start_timer, + payload.message, + payload.counter); + + PayloadStruct received; + radio.read(&received, sizeof(received)); // get payload from RX FIFO + + // print details about incoming payload + printf(" Received %d bytes on pipe %d: %s%d\n", + radio.getPayloadSize(), + pipe, + received.message, + received.counter); + + payload.counter = received.counter; // save incoming counter for next outgoing counter + } + else { + printf(" Recieved no response.\n"); // no response received + } + } + else { + printf("Transmission failed or timed out\n"); // payload was not delivered + } // report + + // to make this example readable in the serial terminal + sleep_ms(1000); // slow transmissions down by 1 second + } + else { + // This device is a RX node + + uint8_t pipe; + if (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it + PayloadStruct received; + radio.read(&received, sizeof(received)); // get incoming payload + payload.counter = received.counter + 1; // increment incoming counter for next outgoing response + + // transmit response & save result to `report` + radio.stopListening(); // put in TX mode + radio.writeFast(&payload, sizeof(payload)); // load response to TX FIFO + bool report = radio.txStandBy(150); // keep retrying for 150 ms + radio.startListening(); // put back in RX mode + + // print summary of transactions, starting with details about incoming payload + printf("Received %d bytes on pipe %d: %s%d", + radio.getPayloadSize(), + pipe, + received.message, + received.counter); + + if (report) { + // print outgoing payload and its counter + printf(" Sent: %s%d", payload.message, payload.counter); + } + else { + printf(" Response failed.\n"); // failed to send response + } + } + } // role + + char input = getchar_timeout_us(0); // get char from buffer for user input + if (input != PICO_ERROR_TIMEOUT) { + // change the role via the serial terminal + + if ((input == 'T' || input == 't') && !role) { + // Become the TX node + + role = true; + memcpy(payload.message, "Hello ", 6); // set the outgoing message + printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n"); + radio.stopListening(); // put in TX mode + + } + else if ((input == 'R' || input == 'r') && role) { + // Become the RX node + + role = false; + memcpy(payload.message, "World ", 6); // set the response message + printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n"); + radio.startListening(); // put in RX mode + } + else if (input == 'b' || input == 'B') { + // reset to bootloader + radio.powerDown(); + reset_usb_boot(0, 0); + } + } +} // loop + +int main() +{ + stdio_init_all(); // init necessary IO for the RP2040 + + while (!setup()) { // if radio.begin() failed + // hold program in infinite attempts to initialize radio + } + while (true) { + loop(); + } + return 0; // we will never reach this +} diff --git a/examples_pico/multiceiverDemo.cpp b/examples_pico/multiceiverDemo.cpp new file mode 100644 index 000000000..d970ece84 --- /dev/null +++ b/examples_pico/multiceiverDemo.cpp @@ -0,0 +1,220 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty 2bndy5 + */ + +/** + * A simple example of sending data from as many as 6 nRF24L01 transceivers to + * 1 receiving transceiver. This technique is trademarked by + * Nordic Semiconductors as "MultiCeiver". + * + * This example was written to be used on up to 6 devices acting as TX nodes & + * only 1 device acting as the RX node (that's a maximum of 7 devices). + * Use the Serial Terminal to change each node's behavior. + */ +#include "pico/stdlib.h" // printf(), sleep_ms(), getchar_timeout_us(), to_us_since_boot(), get_absolute_time() +#include "pico/bootrom.h" // reset_usb_boot() +#include // tud_cdc_connected() +#include // RF24 radio object +#include "defaultPins.h" // board presumptive default pin numbers for CE_PIN and CSN_PIN + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// For this example, we'll be using 6 addresses; 1 for each TX node +// It is very helpful to think of an address as a path instead of as +// an identifying device destination +// Notice that the last byte is the only byte that changes in the last 5 +// addresses. This is a limitation of the nRF24L01 transceiver for pipes 2-5 +// because they use the same first 4 bytes from pipe 1. +uint64_t address[6] = {0x7878787878LL, + 0xB3B4B5B6F1LL, + 0xB3B4B5B6CDLL, + 0xB3B4B5B6A3LL, + 0xB3B4B5B60FLL, + 0xB3B4B5B605LL + }; + +// Because this example allow up to 6 nodes (specified by numbers 0-5) to +// transmit and only 1 node to receive, we will use a negative value in our +// role variable to signify this node is a receiver. +// role variable is used to control whether this node is sending or receiving +char role = 'R'; // integers 0-5 = TX node; character 'R' or integer 82 = RX node + +// For this example, we'll be using a payload containing +// a node ID number and a single integer number that will be incremented +// on every successful transmission. +// Make a data structure to use as a payload. +struct PayloadStruct +{ + unsigned long nodeID; + unsigned long payloadID; +}; +PayloadStruct payload; + +// This example uses all 6 pipes to receive while TX nodes only use 2 pipes +// To make this easier we'll use a function to manage the addresses, and the +// payload's nodeID +void setRole(); // declare a prototype; definition is found after the loop() + + +bool setup() +{ + // wait here until the CDC ACM (serial port emulation) is connected + while (!tud_cdc_connected()) { + sleep_ms(10); + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + printf("radio hardware is not responding!!\n"); + return false; + } + + // print example's introductory prompt + printf("RF24/examples_pico/multiceiverDemo\n"); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity of + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit a float + radio.setPayloadSize(sizeof(payload)); // 2x int datatype occupy 8 bytes + + // Set the pipe addresses accordingly. This function additionally also + // calls startListening() or stopListening() and sets the payload's nodeID + setRole(); + + // For debugging info + // printf_begin(); // needed only once for printing details + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + + // role variable is hardcoded to RX behavior, inform the user of this + printf("*** Enter a number between 0 and 5 (inclusive) to change\n"); + printf(" the identifying node number that transmits.\n"); + + return true; +} // setup() + + +void loop() +{ + if (role <= 53) { + // This device is a TX node + + uint64_t start_timer = to_us_since_boot(get_absolute_time()); // start the timer + bool report = radio.write(&payload, sizeof(payload)); // transmit & save the report + uint64_t end_timer = to_us_since_boot(get_absolute_time()); // end the timer + + if (report) { + // payload was delivered + printf("Transmission of payloadID %ld as node %ld successful! Time to transmit: %llu us\n", + payload.payloadID, + payload.nodeID, + end_timer - start_timer); + } + else { + printf("Transmission failed or timed out\n"); // payload was not delivered + } + + payload.payloadID++; // increment payload number + + // to make this example readable in the serial terminal + sleep_ms(1000); // slow transmissions down by 1 second + } + else if (role == 'R') { + // This device is the RX node + + uint8_t pipe; + while (radio.available(&pipe)) { // is there a payload? get the pipe number that recieved it + uint8_t bytes = radio.getPayloadSize(); // get the size of the payload + radio.read(&payload, bytes); // fetch payload from FIFO + + // print details about incoming payload + printf("Received %d bytes on pipe %d from node %ld. PayloadID: %ld\n", + bytes, + pipe, + payload.nodeID, + payload.payloadID); + } + } // role + + char input = getchar_timeout_us(0); // get char from buffer for user input + if (input != PICO_ERROR_TIMEOUT) { + // change the role via the serial terminal + + if ((input == 'R' || input == 'r') && role <= 53) { + // Become the RX node + + role = 'R'; + printf("*** CHANGING ROLE TO RECEIVER ***\n"); + printf("--- Enter a number between 0 and 5 (inclusive) to act as\n"); + printf(" a unique node number that transmits to the RX node.\n"); + setRole(); // change address on all pipes to TX nodes + + } + else if (input >= 48 && input <= 53 && input != role) { + // Become a TX node with identifier 'input' + + role = input - 48; + printf("*** CHANGING ROLE TO NODE %c ***\n", input); + printf("--- Enter a number between 0 and 5 (inclusive) to change\n"); + printf(" the identifying node number that transmits.\n"); + printf("--- PRESS 'R' to act as the RX node.\n"); + setRole(); // change address on pipe 0 to the RX node + } + else if (input == 'b' || input == 'B') { + // reset to bootloader + radio.powerDown(); + reset_usb_boot(0, 0); + } + } + +} // loop + +void setRole() +{ + if (role == 'R') { + // For the RX node + + // Set the addresses for all pipes to TX nodes + for (uint8_t i = 0; i < 6; ++i) + radio.openReadingPipe(i, address[i]); + + radio.startListening(); // put radio in RX mode + + } + else { + // For the TX node + + // set the payload's nodeID & reset the payload's identifying number + payload.nodeID = role; + payload.payloadID = 0; + + // Set the address on pipe 0 to the RX node. + radio.stopListening(); // put radio in TX mode + radio.openWritingPipe(address[role]); + + // According to the datasheet, the auto-retry features's delay value should + // be "skewed" to allow the RX node to receive 1 transmission at a time. + // So, use varying delay between retry attempts and 15 (at most) retry attempts + radio.setRetries(((role * 3) % 12) + 3, 15); // maximum value is 15 for both args + } +} // setRole + +int main() +{ + stdio_init_all(); // init necessary IO for the RP2040 + + while (!setup()) { // if radio.begin() failed + // hold program in infinite attempts to initialize radio + } + while (true) { + loop(); + } + return 0; // we will never reach this +} diff --git a/examples_pico/scanner.cpp b/examples_pico/scanner.cpp new file mode 100644 index 000000000..d67bd8b43 --- /dev/null +++ b/examples_pico/scanner.cpp @@ -0,0 +1,123 @@ +/* + Copyright (C) 2011 J. Coliz + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + + + 06/04/2021 : Brendan Doherty (https://github.com/2bndy5) + Modified to use with PicoSDK + + */ + +/** + * Channel scanner + * + * Example to detect interference on the various channels available. + * This is a good diagnostic tool to check whether you're picking a + * good channel for your application. + * + * Inspired by cpixip. + * See http://arduino.cc/forum/index.php/topic,54795.0.html + */ + +#include "pico/stdlib.h" // printf(), sleep_ms(), getchar_timeout_us(), to_us_since_boot(), get_absolute_time() +#include "pico/bootrom.h" // reset_usb_boot() +#include // tud_cdc_connected() +#include // RF24 radio object, rf24_min() +#include "defaultPins.h" // board presumptive default pin numbers for CE_PIN and CSN_PIN + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// Channel info +const uint8_t num_channels = 126; +uint8_t values[num_channels]; + +const int num_reps = 100; +int reset_array = 0; + +int main() +{ + stdio_init_all(); // init necessary IO for the RP2040 + + // wait here until the CDC ACM (serial port emulation) is connected + while (!tud_cdc_connected()) { + sleep_ms(10); + } + + // initialize the transceiver on the SPI bus + while (!radio.begin()) { + printf("radio hardware is not responding!!\n"); + } + + // print example's name + printf("RF24/examples_pico/scanner\n"); + + radio.setAutoAck(false); + + // Get into standby mode + radio.startListening(); + radio.stopListening(); + + // radio.printDetails(); + + // Print out header, high then low digit + int i = 0; + + while (i < num_channels) { + printf("%x", i >> 4); + ++i; + } + printf("\n"); + + i = 0; + while (i < num_channels) { + printf("%x", i & 0xf); + ++i; + } + printf("\n"); + + // forever loop + while (1) { + // Clear measurement values + memset(values, 0, sizeof(values)); + + // Scan all channels num_reps times + int rep_counter = num_reps; + while (rep_counter--) { + + int i = num_channels; + while (i--) { + + // Select this channel + radio.setChannel(i); + + // Listen for a little + radio.startListening(); + sleep_us(128); + radio.stopListening(); + + // Did we get a carrier? + if (radio.testCarrier()) { + ++values[i]; + } + } + } + + // Print out channel measurements, clamped to a single hex digit + i = 0; + while (i < num_channels) { + if (values[i]) + printf("%x", rf24_min(0xf, (values[i] & 0xf))); + else + printf("-"); + + ++i; + } + printf("\n"); + } + + return 0; +} diff --git a/examples_pico/streamingData.cpp b/examples_pico/streamingData.cpp new file mode 100644 index 000000000..be7f4d484 --- /dev/null +++ b/examples_pico/streamingData.cpp @@ -0,0 +1,199 @@ +/* + * See documentation at https://nRF24.github.io/RF24 + * See License information at root directory of this library + * Author: Brendan Doherty 2bndy5 + */ + +/** + * A simple example of streaming data from 1 nRF24L01 transceiver to another. + * + * This example was written to be used on 2 devices acting as "nodes". + * Use the Serial Terminal to change each node's behavior. + */ +#include "pico/stdlib.h" // printf(), sleep_ms(), getchar_timeout_us(), to_us_since_boot(), get_absolute_time() +#include "pico/bootrom.h" // reset_usb_boot() +#include // tud_cdc_connected() +#include // abs() +#include // RF24 radio object +#include "defaultPins.h" // board presumptive default pin numbers for CE_PIN and CSN_PIN + +// instantiate an object for the nRF24L01 transceiver +RF24 radio(CE_PIN, CSN_PIN); + +// Used to control whether this node is sending or receiving +bool role = false; // true = TX node, false = RX node + +// For this example, we'll be sending 32 payloads each containing +// 32 bytes of data that looks like ASCII art when printed to the serial +// monitor. The TX node and RX node needs only a single 32 byte buffer. +#define SIZE 32 // this is the maximum for this example. (minimum is 1) +char buffer[SIZE + 1]; // for the RX node +uint8_t counter = 0; // for counting the number of received payloads +void makePayload(uint8_t); // prototype to construct a payload dynamically + + +bool setup() +{ + buffer[SIZE] = 0; // add a NULL terminating character (for easy printing) + + // Let these addresses be used for the pair + uint8_t address[][6] = {"1Node", "2Node"}; + // It is very helpful to think of an address as a path instead of as + // an identifying device destination + + // to use different addresses on a pair of radios, we need a variable to + // uniquely identify which address this radio will use to transmit + bool radioNumber; // 0 uses address[0] to transmit, 1 uses address[1] to transmit + + // wait here until the CDC ACM (serial port emulation) is connected + while (!tud_cdc_connected()) { + sleep_ms(10); + } + + // initialize the transceiver on the SPI bus + if (!radio.begin()) { + printf("radio hardware is not responding!!\n"); + return false; + } + + // print example's introductory prompt + printf("RF24/examples_pico/streamingData\n"); + + // To set the radioNumber via the Serial monitor on startup + printf("Which radio is this? Enter '0' or '1'. Defaults to '0'\n"); + char input = getchar(); + radioNumber = input == 49; + printf("radioNumber = %d\n", (int)radioNumber); + + // Set the PA Level low to try preventing power supply related problems + // because these examples are likely run with nodes in close proximity to + // each other. + radio.setPALevel(RF24_PA_LOW); // RF24_PA_MAX is default. + + // save on transmission time by setting the radio to only transmit the + // number of bytes we need to transmit + radio.setPayloadSize(SIZE); // default value is the maximum 32 bytes + + // set the TX address of the RX node into the TX pipe + radio.openWritingPipe(address[radioNumber]); // always uses pipe 0 + + // set the RX address of the TX node into a RX pipe + radio.openReadingPipe(1, address[!radioNumber]); // using pipe 1 + + // additional setup specific to the node's role + if (role) { + radio.stopListening(); // put radio in TX mode + } + else { + radio.startListening(); // put radio in RX mode + } + + // For debugging info + // radio.printDetails(); // (smaller) function that prints raw register values + // radio.printPrettyDetails(); // (larger) function that prints human readable data + + // role variable is hardcoded to RX behavior, inform the user of this + printf("*** PRESS 'T' to begin transmitting to the other node\n"); + + return true; +} // setup() + + +void loop() { + + if (role) { + // This device is a TX node + + radio.flush_tx(); + uint8_t i = 0; + uint8_t failures = 0; + uint64_t start_timer = to_us_since_boot(get_absolute_time()); // start the timer + while (i < SIZE) { + makePayload(i); // make the payload + if (!radio.writeFast(&buffer, SIZE)) { + failures++; + radio.reUseTX(); + } + else { + i++; + } + + if (failures >= 100) { + printf("Too many failures detected. Aborting at payload %c\n", buffer[0]); + break; + } + } + uint64_t end_timer = to_us_since_boot(get_absolute_time()); // end the timer + + // print results from transmitting stream + printf("Time to transmit = %llu us with %d failures detected\n", end_timer - start_timer, failures); + + // to make this example readable in the serial terminal + sleep_ms(1000); // slow transmissions down by 1 second + } + else { + // This device is a RX node + + if (radio.available()) { // is there a payload? + radio.read(&buffer, SIZE); // fetch payload from FIFO + + // print the received payload and its counter + printf("Received: %s - %d\n", buffer, counter++); + } + } // role + + char input = getchar_timeout_us(0); // get char from buffer for user input + if (input != PICO_ERROR_TIMEOUT) { + // change the role via the serial terminal + + if ((input == 'T' || input == 't') && !role) { + // Become the TX node + + role = true; + counter = 0; //reset the RX node's counter + printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n"); + radio.stopListening(); + + } + else if ((input == 'R' || input == 'r') && role) { + // Become the RX node + + role = false; + printf("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK\n"); + radio.startListening(); + } + else if (input == 'b' || input == 'B') { + // reset to bootloader + radio.powerDown(); + reset_usb_boot(0, 0); + } + } +} // loop + + +void makePayload(uint8_t i) { + // Make a single payload based on position in stream. + // This example employs function to save memory on certain boards. + + // let the first character be an identifying alphanumeric prefix + // this lets us see which payload didn't get received + buffer[0] = i + (i < 26 ? 65 : 71); + for (uint8_t j = 0; j < SIZE - 1; ++j) { + char chr = j >= (SIZE - 1) / 2 + abs((SIZE - 1) / 2 - i); + chr |= j < (SIZE - 1) / 2 - abs((SIZE - 1) / 2 - i); + buffer[j + 1] = chr + 48; + } +} + +int main() +{ + stdio_init_all(); // init necessary IO for the RP2040 + + while (!setup()) { // if radio.begin() failed + // hold program in infinite attempts to initialize radio + } + while (true) { + loop(); + } + return 0; // we will never reach this +} diff --git a/library.json b/library.json index 838412a4f..79208dbd0 100644 --- a/library.json +++ b/library.json @@ -1,21 +1,43 @@ { - "name": "RF24", - "keywords": "rf, radio, wireless, spi", - "description": "Radio driver, OSI layer 2 library for nrf24L01(+) modules.", - "repository": { - "type": "git", - "url": "https://github.com/nRF24/RF24.git" - }, - "version": "1.4.1", - "frameworks": "arduino", - "platforms": [ - "atmelavr", - "atmelsam", - "teensy", - "atmelmegaavr", - "espressif32", - "espressif8266", - "linux_arm", - "ststm32" - ] + "name": "RF24", + "keywords": "rf, radio, wireless, spi", + "description": "Radio driver, OSI layer 2 library for nRF24L01(+) transceiver modules.", + "license": "GPL-2.0-only", + "repository": { + "type": "git", + "url": "https://github.com/nRF24/RF24.git" + }, + "version": "1.4.2", + "export": { + "exclude": [ + "datasheets", + ".github/*", + "keywords.txt", + "configure", + "examples_pico/*", + "examples_linux/*", + "pyRF24/*", + "cmake/*", + "CMakeLists.txt", + "Makefile", + "utility/CMakeLists.txt", + "utility/wiringPi/*", + "utility/MRAA/*", + "utility/LittleWire/*", + "utility/RPi/*", + "utility/SPIDEV/*", + "utility/rp2/*", + "utility/ATXMegaD3/*" + ] + }, + "frameworks": "arduino", + "platforms": [ + "atmelavr", + "atmelsam", + "teensy", + "atmelmegaavr", + "espressif32", + "espressif8266", + "ststm32" + ] } diff --git a/library.properties b/library.properties index 2df0b3475..2fa682c5b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RF24 -version=1.4.1 +version=1.4.2 author=TMRh20 maintainer=TMRh20,Avamander sentence=Radio driver, OSI layer 2 library for nrf24L01(+) modules. diff --git a/pyRF24/pyRF24.cpp b/pyRF24/pyRF24.cpp index efa4afed7..a21bb8b9d 100644 --- a/pyRF24/pyRF24.cpp +++ b/pyRF24/pyRF24.cpp @@ -17,13 +17,13 @@ char* get_bytes_or_bytearray_str(bp::object buf) { PyObject* py_ba; py_ba = buf.ptr(); - if (PyByteArray_Check(py_ba)) { + if (PyByteArray_Check(py_ba)) return PyByteArray_AsString(py_ba); - } else if (PyBytes_Check(py_ba)) { + else if (PyBytes_Check(py_ba)) return PyBytes_AsString(py_ba); - } else { + else throw_ba_exception(); - } + return NULL; } @@ -31,13 +31,13 @@ int get_bytes_or_bytearray_ln(bp::object buf) { PyObject* py_ba; py_ba = buf.ptr(); - if (PyByteArray_Check(py_ba)) { + if (PyByteArray_Check(py_ba)) return PyByteArray_Size(py_ba); - } else if (PyBytes_Check(py_ba)) { + else if (PyBytes_Check(py_ba)) return PyBytes_Size(py_ba); - } else { + else throw_ba_exception(); - } + return 0; } @@ -64,7 +64,6 @@ bool write_wrap2(RF24& ref, bp::object buf, const bool multicast) void writeAckPayload_wrap(RF24& ref, uint8_t pipe, bp::object buf) { ref.writeAckPayload(pipe, get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf)); - } bool writeFast_wrap1(RF24& ref, bp::object buf) @@ -141,106 +140,106 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(txStandBy_wrap1, RF24::txStandBy, 0, 2) // ******************** enums ************************** // from both RF24 and bcm2835 -// -BOOST_PYTHON_MODULE(RF24){ +BOOST_PYTHON_MODULE(RF24) +{ #ifdef BCM2835_H -bp::enum_< RPiGPIOPin>("RPiGPIOPin") - .value("RPI_GPIO_P1_03", RPI_GPIO_P1_03) - .value("RPI_GPIO_P1_05", RPI_GPIO_P1_05) - .value("RPI_GPIO_P1_07", RPI_GPIO_P1_07) - .value("RPI_GPIO_P1_08", RPI_GPIO_P1_08) - .value("RPI_GPIO_P1_10", RPI_GPIO_P1_10) - .value("RPI_GPIO_P1_11", RPI_GPIO_P1_11) - .value("RPI_GPIO_P1_12", RPI_GPIO_P1_12) - .value("RPI_GPIO_P1_13", RPI_GPIO_P1_13) - .value("RPI_GPIO_P1_15", RPI_GPIO_P1_15) - .value("RPI_GPIO_P1_16", RPI_GPIO_P1_16) - .value("RPI_GPIO_P1_18", RPI_GPIO_P1_18) - .value("RPI_GPIO_P1_19", RPI_GPIO_P1_19) - .value("RPI_GPIO_P1_21", RPI_GPIO_P1_21) - .value("RPI_GPIO_P1_22", RPI_GPIO_P1_22) - .value("RPI_GPIO_P1_23", RPI_GPIO_P1_23) - .value("RPI_GPIO_P1_24", RPI_GPIO_P1_24) - .value("RPI_GPIO_P1_26", RPI_GPIO_P1_26) - .value("RPI_V2_GPIO_P1_03", RPI_V2_GPIO_P1_03) - .value("RPI_V2_GPIO_P1_05", RPI_V2_GPIO_P1_05) - .value("RPI_V2_GPIO_P1_07", RPI_V2_GPIO_P1_07) - .value("RPI_V2_GPIO_P1_08", RPI_V2_GPIO_P1_08) - .value("RPI_V2_GPIO_P1_10", RPI_V2_GPIO_P1_10) - .value("RPI_V2_GPIO_P1_11", RPI_V2_GPIO_P1_11) - .value("RPI_V2_GPIO_P1_12", RPI_V2_GPIO_P1_12) - .value("RPI_V2_GPIO_P1_13", RPI_V2_GPIO_P1_13) - .value("RPI_V2_GPIO_P1_15", RPI_V2_GPIO_P1_15) - .value("RPI_V2_GPIO_P1_16", RPI_V2_GPIO_P1_16) - .value("RPI_V2_GPIO_P1_18", RPI_V2_GPIO_P1_18) - .value("RPI_V2_GPIO_P1_19", RPI_V2_GPIO_P1_19) - .value("RPI_V2_GPIO_P1_21", RPI_V2_GPIO_P1_21) - .value("RPI_V2_GPIO_P1_22", RPI_V2_GPIO_P1_22) - .value("RPI_V2_GPIO_P1_23", RPI_V2_GPIO_P1_23) - .value("RPI_V2_GPIO_P1_24", RPI_V2_GPIO_P1_24) - .value("RPI_V2_GPIO_P1_26", RPI_V2_GPIO_P1_26) - .value("RPI_V2_GPIO_P5_03", RPI_V2_GPIO_P5_03) - .value("RPI_V2_GPIO_P5_04", RPI_V2_GPIO_P5_04) - .value("RPI_V2_GPIO_P5_05", RPI_V2_GPIO_P5_05) - .value("RPI_V2_GPIO_P5_06", RPI_V2_GPIO_P5_06) - .value("RPI_BPLUS_GPIO_J8_03", RPI_BPLUS_GPIO_J8_03) - .value("RPI_BPLUS_GPIO_J8_05", RPI_BPLUS_GPIO_J8_05) - .value("RPI_BPLUS_GPIO_J8_07", RPI_BPLUS_GPIO_J8_07) - .value("RPI_BPLUS_GPIO_J8_08", RPI_BPLUS_GPIO_J8_08) - .value("RPI_BPLUS_GPIO_J8_10", RPI_BPLUS_GPIO_J8_10) - .value("RPI_BPLUS_GPIO_J8_11", RPI_BPLUS_GPIO_J8_11) - .value("RPI_BPLUS_GPIO_J8_12", RPI_BPLUS_GPIO_J8_12) - .value("RPI_BPLUS_GPIO_J8_13", RPI_BPLUS_GPIO_J8_13) - .value("RPI_BPLUS_GPIO_J8_15", RPI_BPLUS_GPIO_J8_15) - .value("RPI_BPLUS_GPIO_J8_16", RPI_BPLUS_GPIO_J8_16) - .value("RPI_BPLUS_GPIO_J8_18", RPI_BPLUS_GPIO_J8_18) - .value("RPI_BPLUS_GPIO_J8_19", RPI_BPLUS_GPIO_J8_19) - .value("RPI_BPLUS_GPIO_J8_21", RPI_BPLUS_GPIO_J8_21) - .value("RPI_BPLUS_GPIO_J8_22", RPI_BPLUS_GPIO_J8_22) - .value("RPI_BPLUS_GPIO_J8_23", RPI_BPLUS_GPIO_J8_23) - .value("RPI_BPLUS_GPIO_J8_24", RPI_BPLUS_GPIO_J8_24) - .value("RPI_BPLUS_GPIO_J8_26", RPI_BPLUS_GPIO_J8_26) - .value("RPI_BPLUS_GPIO_J8_29", RPI_BPLUS_GPIO_J8_29) - .value("RPI_BPLUS_GPIO_J8_31", RPI_BPLUS_GPIO_J8_31) - .value("RPI_BPLUS_GPIO_J8_32", RPI_BPLUS_GPIO_J8_32) - .value("RPI_BPLUS_GPIO_J8_33", RPI_BPLUS_GPIO_J8_33) - .value("RPI_BPLUS_GPIO_J8_35", RPI_BPLUS_GPIO_J8_35) - .value("RPI_BPLUS_GPIO_J8_36", RPI_BPLUS_GPIO_J8_36) - .value("RPI_BPLUS_GPIO_J8_37", RPI_BPLUS_GPIO_J8_37) - .value("RPI_BPLUS_GPIO_J8_38", RPI_BPLUS_GPIO_J8_38) - .value("RPI_BPLUS_GPIO_J8_40", RPI_BPLUS_GPIO_J8_40) - .export_values() - ; - -bp::enum_< bcm2835SPIClockDivider>("bcm2835SPIClockDivider") - .value("BCM2835_SPI_CLOCK_DIVIDER_65536", BCM2835_SPI_CLOCK_DIVIDER_65536) - .value("BCM2835_SPI_CLOCK_DIVIDER_32768", BCM2835_SPI_CLOCK_DIVIDER_32768) - .value("BCM2835_SPI_CLOCK_DIVIDER_16384", BCM2835_SPI_CLOCK_DIVIDER_16384) - .value("BCM2835_SPI_CLOCK_DIVIDER_8192", BCM2835_SPI_CLOCK_DIVIDER_8192) - .value("BCM2835_SPI_CLOCK_DIVIDER_4096", BCM2835_SPI_CLOCK_DIVIDER_4096) - .value("BCM2835_SPI_CLOCK_DIVIDER_2048", BCM2835_SPI_CLOCK_DIVIDER_2048) - .value("BCM2835_SPI_CLOCK_DIVIDER_1024", BCM2835_SPI_CLOCK_DIVIDER_1024) - .value("BCM2835_SPI_CLOCK_DIVIDER_512", BCM2835_SPI_CLOCK_DIVIDER_512) - .value("BCM2835_SPI_CLOCK_DIVIDER_256", BCM2835_SPI_CLOCK_DIVIDER_256) - .value("BCM2835_SPI_CLOCK_DIVIDER_128", BCM2835_SPI_CLOCK_DIVIDER_128) - .value("BCM2835_SPI_CLOCK_DIVIDER_64", BCM2835_SPI_CLOCK_DIVIDER_64) - .value("BCM2835_SPI_CLOCK_DIVIDER_32", BCM2835_SPI_CLOCK_DIVIDER_32) - .value("BCM2835_SPI_CLOCK_DIVIDER_16", BCM2835_SPI_CLOCK_DIVIDER_16) - .value("BCM2835_SPI_CLOCK_DIVIDER_8", BCM2835_SPI_CLOCK_DIVIDER_8) - .value("BCM2835_SPI_CLOCK_DIVIDER_4", BCM2835_SPI_CLOCK_DIVIDER_4) - .value("BCM2835_SPI_CLOCK_DIVIDER_2", BCM2835_SPI_CLOCK_DIVIDER_2) - .value("BCM2835_SPI_CLOCK_DIVIDER_1", BCM2835_SPI_CLOCK_DIVIDER_1) - .export_values(); - - -bp::enum_< bcm2835SPIChipSelect>("bcm2835SPIChipSelect") - .value("BCM2835_SPI_CS0", BCM2835_SPI_CS0) - .value("BCM2835_SPI_CS1", BCM2835_SPI_CS1) - .value("BCM2835_SPI_CS2", BCM2835_SPI_CS2) - .value("BCM2835_SPI_CS_NONE", BCM2835_SPI_CS_NONE) - .export_values(); + bp::enum_< RPiGPIOPin>("RPiGPIOPin") + .value("RPI_GPIO_P1_03", RPI_GPIO_P1_03) + .value("RPI_GPIO_P1_05", RPI_GPIO_P1_05) + .value("RPI_GPIO_P1_07", RPI_GPIO_P1_07) + .value("RPI_GPIO_P1_08", RPI_GPIO_P1_08) + .value("RPI_GPIO_P1_10", RPI_GPIO_P1_10) + .value("RPI_GPIO_P1_11", RPI_GPIO_P1_11) + .value("RPI_GPIO_P1_12", RPI_GPIO_P1_12) + .value("RPI_GPIO_P1_13", RPI_GPIO_P1_13) + .value("RPI_GPIO_P1_15", RPI_GPIO_P1_15) + .value("RPI_GPIO_P1_16", RPI_GPIO_P1_16) + .value("RPI_GPIO_P1_18", RPI_GPIO_P1_18) + .value("RPI_GPIO_P1_19", RPI_GPIO_P1_19) + .value("RPI_GPIO_P1_21", RPI_GPIO_P1_21) + .value("RPI_GPIO_P1_22", RPI_GPIO_P1_22) + .value("RPI_GPIO_P1_23", RPI_GPIO_P1_23) + .value("RPI_GPIO_P1_24", RPI_GPIO_P1_24) + .value("RPI_GPIO_P1_26", RPI_GPIO_P1_26) + .value("RPI_V2_GPIO_P1_03", RPI_V2_GPIO_P1_03) + .value("RPI_V2_GPIO_P1_05", RPI_V2_GPIO_P1_05) + .value("RPI_V2_GPIO_P1_07", RPI_V2_GPIO_P1_07) + .value("RPI_V2_GPIO_P1_08", RPI_V2_GPIO_P1_08) + .value("RPI_V2_GPIO_P1_10", RPI_V2_GPIO_P1_10) + .value("RPI_V2_GPIO_P1_11", RPI_V2_GPIO_P1_11) + .value("RPI_V2_GPIO_P1_12", RPI_V2_GPIO_P1_12) + .value("RPI_V2_GPIO_P1_13", RPI_V2_GPIO_P1_13) + .value("RPI_V2_GPIO_P1_15", RPI_V2_GPIO_P1_15) + .value("RPI_V2_GPIO_P1_16", RPI_V2_GPIO_P1_16) + .value("RPI_V2_GPIO_P1_18", RPI_V2_GPIO_P1_18) + .value("RPI_V2_GPIO_P1_19", RPI_V2_GPIO_P1_19) + .value("RPI_V2_GPIO_P1_21", RPI_V2_GPIO_P1_21) + .value("RPI_V2_GPIO_P1_22", RPI_V2_GPIO_P1_22) + .value("RPI_V2_GPIO_P1_23", RPI_V2_GPIO_P1_23) + .value("RPI_V2_GPIO_P1_24", RPI_V2_GPIO_P1_24) + .value("RPI_V2_GPIO_P1_26", RPI_V2_GPIO_P1_26) + .value("RPI_V2_GPIO_P5_03", RPI_V2_GPIO_P5_03) + .value("RPI_V2_GPIO_P5_04", RPI_V2_GPIO_P5_04) + .value("RPI_V2_GPIO_P5_05", RPI_V2_GPIO_P5_05) + .value("RPI_V2_GPIO_P5_06", RPI_V2_GPIO_P5_06) + .value("RPI_BPLUS_GPIO_J8_03", RPI_BPLUS_GPIO_J8_03) + .value("RPI_BPLUS_GPIO_J8_05", RPI_BPLUS_GPIO_J8_05) + .value("RPI_BPLUS_GPIO_J8_07", RPI_BPLUS_GPIO_J8_07) + .value("RPI_BPLUS_GPIO_J8_08", RPI_BPLUS_GPIO_J8_08) + .value("RPI_BPLUS_GPIO_J8_10", RPI_BPLUS_GPIO_J8_10) + .value("RPI_BPLUS_GPIO_J8_11", RPI_BPLUS_GPIO_J8_11) + .value("RPI_BPLUS_GPIO_J8_12", RPI_BPLUS_GPIO_J8_12) + .value("RPI_BPLUS_GPIO_J8_13", RPI_BPLUS_GPIO_J8_13) + .value("RPI_BPLUS_GPIO_J8_15", RPI_BPLUS_GPIO_J8_15) + .value("RPI_BPLUS_GPIO_J8_16", RPI_BPLUS_GPIO_J8_16) + .value("RPI_BPLUS_GPIO_J8_18", RPI_BPLUS_GPIO_J8_18) + .value("RPI_BPLUS_GPIO_J8_19", RPI_BPLUS_GPIO_J8_19) + .value("RPI_BPLUS_GPIO_J8_21", RPI_BPLUS_GPIO_J8_21) + .value("RPI_BPLUS_GPIO_J8_22", RPI_BPLUS_GPIO_J8_22) + .value("RPI_BPLUS_GPIO_J8_23", RPI_BPLUS_GPIO_J8_23) + .value("RPI_BPLUS_GPIO_J8_24", RPI_BPLUS_GPIO_J8_24) + .value("RPI_BPLUS_GPIO_J8_26", RPI_BPLUS_GPIO_J8_26) + .value("RPI_BPLUS_GPIO_J8_29", RPI_BPLUS_GPIO_J8_29) + .value("RPI_BPLUS_GPIO_J8_31", RPI_BPLUS_GPIO_J8_31) + .value("RPI_BPLUS_GPIO_J8_32", RPI_BPLUS_GPIO_J8_32) + .value("RPI_BPLUS_GPIO_J8_33", RPI_BPLUS_GPIO_J8_33) + .value("RPI_BPLUS_GPIO_J8_35", RPI_BPLUS_GPIO_J8_35) + .value("RPI_BPLUS_GPIO_J8_36", RPI_BPLUS_GPIO_J8_36) + .value("RPI_BPLUS_GPIO_J8_37", RPI_BPLUS_GPIO_J8_37) + .value("RPI_BPLUS_GPIO_J8_38", RPI_BPLUS_GPIO_J8_38) + .value("RPI_BPLUS_GPIO_J8_40", RPI_BPLUS_GPIO_J8_40) + .export_values() + ; + + bp::enum_< bcm2835SPIClockDivider>("bcm2835SPIClockDivider") + .value("BCM2835_SPI_CLOCK_DIVIDER_65536", BCM2835_SPI_CLOCK_DIVIDER_65536) + .value("BCM2835_SPI_CLOCK_DIVIDER_32768", BCM2835_SPI_CLOCK_DIVIDER_32768) + .value("BCM2835_SPI_CLOCK_DIVIDER_16384", BCM2835_SPI_CLOCK_DIVIDER_16384) + .value("BCM2835_SPI_CLOCK_DIVIDER_8192", BCM2835_SPI_CLOCK_DIVIDER_8192) + .value("BCM2835_SPI_CLOCK_DIVIDER_4096", BCM2835_SPI_CLOCK_DIVIDER_4096) + .value("BCM2835_SPI_CLOCK_DIVIDER_2048", BCM2835_SPI_CLOCK_DIVIDER_2048) + .value("BCM2835_SPI_CLOCK_DIVIDER_1024", BCM2835_SPI_CLOCK_DIVIDER_1024) + .value("BCM2835_SPI_CLOCK_DIVIDER_512", BCM2835_SPI_CLOCK_DIVIDER_512) + .value("BCM2835_SPI_CLOCK_DIVIDER_256", BCM2835_SPI_CLOCK_DIVIDER_256) + .value("BCM2835_SPI_CLOCK_DIVIDER_128", BCM2835_SPI_CLOCK_DIVIDER_128) + .value("BCM2835_SPI_CLOCK_DIVIDER_64", BCM2835_SPI_CLOCK_DIVIDER_64) + .value("BCM2835_SPI_CLOCK_DIVIDER_32", BCM2835_SPI_CLOCK_DIVIDER_32) + .value("BCM2835_SPI_CLOCK_DIVIDER_16", BCM2835_SPI_CLOCK_DIVIDER_16) + .value("BCM2835_SPI_CLOCK_DIVIDER_8", BCM2835_SPI_CLOCK_DIVIDER_8) + .value("BCM2835_SPI_CLOCK_DIVIDER_4", BCM2835_SPI_CLOCK_DIVIDER_4) + .value("BCM2835_SPI_CLOCK_DIVIDER_2", BCM2835_SPI_CLOCK_DIVIDER_2) + .value("BCM2835_SPI_CLOCK_DIVIDER_1", BCM2835_SPI_CLOCK_DIVIDER_1) + .export_values(); + + + bp::enum_< bcm2835SPIChipSelect>("bcm2835SPIChipSelect") + .value("BCM2835_SPI_CS0", BCM2835_SPI_CS0) + .value("BCM2835_SPI_CS1", BCM2835_SPI_CS1) + .value("BCM2835_SPI_CS2", BCM2835_SPI_CS2) + .value("BCM2835_SPI_CS_NONE", BCM2835_SPI_CS_NONE) + .export_values(); #endif // BCM2835_H @@ -265,7 +264,6 @@ bp::enum_< bcm2835SPIChipSelect>("bcm2835SPIChipSelect") .export_values(); // ******************** RF24 class ************************** - // bp::class_< RF24 >("RF24", bp::init< uint16_t, uint16_t >((bp::arg("_cepin"), bp::arg("_cspin")))) #if defined (RF24_LINUX) && !defined (MRAA) .def(bp::init< uint16_t, uint16_t, uint32_t >((bp::arg("_cepin"), bp::arg("_cspin"), bp::arg("spispeed")))) @@ -334,4 +332,5 @@ bp::enum_< bcm2835SPIChipSelect>("bcm2835SPIChipSelect") .add_property("payloadSize", &RF24::getPayloadSize, &RF24::setPayloadSize) .def("setPayloadSize", &RF24::setPayloadSize, (bp::arg("size"))) .def("getPayloadSize", &RF24::getPayloadSize) - .def_readwrite("failureDetected", &RF24::failureDetected);} + .def_readwrite("failureDetected", &RF24::failureDetected); +} diff --git a/pyRF24/pyRF24Mesh/pyRF24Mesh.cpp b/pyRF24/pyRF24Mesh/pyRF24Mesh.cpp index da83a865d..bccc268ba 100644 --- a/pyRF24/pyRF24Mesh/pyRF24Mesh.cpp +++ b/pyRF24/pyRF24Mesh/pyRF24Mesh.cpp @@ -5,7 +5,6 @@ namespace bp = boost::python; - // ******************** explicit wrappers ************************** // where needed, especially where buffer is involved @@ -15,93 +14,93 @@ void throw_ba_exception(void) bp::throw_error_already_set(); } -char* get_bytes_or_bytearray_str(bp::object buf) +char *get_bytes_or_bytearray_str(bp::object buf) { - PyObject* py_ba; + PyObject *py_ba; py_ba = buf.ptr(); - if (PyByteArray_Check(py_ba)) { + if (PyByteArray_Check(py_ba)) return PyByteArray_AsString(py_ba); - } else if (PyBytes_Check(py_ba)) { + else if (PyBytes_Check(py_ba)) return PyBytes_AsString(py_ba); - } else { + else throw_ba_exception(); - } + return NULL; } int get_bytes_or_bytearray_ln(bp::object buf) { - PyObject* py_ba; + PyObject *py_ba; py_ba = buf.ptr(); - if (PyByteArray_Check(py_ba)) { + if (PyByteArray_Check(py_ba)) return PyByteArray_Size(py_ba); - } else if (PyBytes_Check(py_ba)) { + else if (PyBytes_Check(py_ba)) return PyBytes_Size(py_ba); - } else { + else throw_ba_exception(); - } + return 0; } -bool write_wrap1(RF24Mesh& ref, bp::object buf, uint8_t msg_type) +bool write_wrap1(RF24Mesh &ref, bp::object buf, uint8_t msg_type) { return ref.write(get_bytes_or_bytearray_str(buf), msg_type, get_bytes_or_bytearray_ln(buf)); } -bool write_wrap2(RF24Mesh& ref, bp::object buf, uint8_t msg_type, uint8_t nodeID) +bool write_wrap2(RF24Mesh &ref, bp::object buf, uint8_t msg_type, uint8_t nodeID) { return ref.write(get_bytes_or_bytearray_str(buf), msg_type, get_bytes_or_bytearray_ln(buf), nodeID); } -bool write_to_node_wrap(RF24Mesh& ref, uint16_t to_node, bp::object buf, uint8_t msg_type) +bool write_to_node_wrap(RF24Mesh &ref, uint16_t to_node, bp::object buf, uint8_t msg_type) { return ref.write(to_node, get_bytes_or_bytearray_str(buf), msg_type, get_bytes_or_bytearray_ln(buf)); } // ******************** overload wrappers ************************** -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(begin_overload, RF24Mesh::begin, -0, 3) -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(getNodeID_overload, RF24Mesh::getNodeID, -0, 1) -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(renewAddress_overload, RF24Mesh::renewAddress, -0, 1) +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(begin_overload, RF24Mesh::begin, 0, 3) +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(getNodeID_overload, RF24Mesh::getNodeID, 0, 1) +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(renewAddress_overload, RF24Mesh::renewAddress, 0, 1) // ******************** RF24Mesh exposed ************************** BOOST_PYTHON_MODULE(RF24Mesh) - {{ //::RF24Mesh - bp::class_("RF24Mesh", bp::init((bp::arg("_radio"), bp::arg("_network")))) - //bool begin(uint8_t channel = MESH_DEFAULT_CHANNEL, rf24_datarate_e data_rate = RF24_1MBPS, uint32_t timeout=MESH_RENEWAL_TIMEOUT ); - .def("begin", &RF24Mesh::begin, begin_overload(bp::args("channel", "data_rate", "timeout"))) - //uint8_t update(); - .def("update", &RF24Mesh::update) - //bool write(const void* data, uint8_t msg_type, size_t size, uint8_t nodeID=0); - .def("write", &write_wrap1, (bp::arg("data"), bp::arg("msg_type"))).def("write", &write_wrap2, - (bp::arg("data"), bp::arg("msg_type"), bp::arg("nodeID"))) - //bool write(uint16_t to_node, const void* data, uint8_t msg_type, size_t size ); - .def("write", &write_to_node_wrap, (bp::arg("to_node"), bp::arg("data"), bp::arg("msg_type"), bp::arg("size"))) - //void setNodeID(uint8_t nodeID); - .def("setNodeID", &RF24Mesh::setNodeID, (bp::arg("nodeID"))) - //void DHCP(); - .def("DHCP", &RF24Mesh::DHCP) - //int16_t getNodeID(uint16_t address=MESH_BLANK_ID); - .def("getNodeID", &RF24Mesh::getNodeID, getNodeID_overload(bp::args("address"))) - //bool checkConnection(); - .def("checkConnection", &RF24Mesh::checkConnection) - //uint16_t renewAddress(uint32_t timeout=MESH_RENEWAL_TIMEOUT); - .def("renewAddress", &RF24Mesh::renewAddress, getNodeID_overload(bp::args("timeout"))) - //bool releaseAddress(); - .def("releaseAddress", &RF24Mesh::releaseAddress) - //int16_t getAddress(uint8_t nodeID); - .def("getAddress", &RF24Mesh::getAddress, (bp::arg("nodeID"))) - //void setChannel(uint8_t _channel); - .def("setChannel", &RF24Mesh::setChannel, (bp::arg("_channel"))) - //void setChild(bool allow); - .def("setChild", &RF24Mesh::setChild, (bp::arg("allow"))) - //void setAddress(uint8_t nodeID, uint16_t address); - .def("setAddress", &RF24Mesh::setAddress, (bp::arg("nodeID"), bp::arg("address"))) - //void saveDHCP(); - .def("saveDHCP", &RF24Mesh::saveDHCP) - //void loadDHCP(); - .def("loadDHCP", &RF24Mesh::loadDHCP) - //void setStaticAddress(uint8_t nodeID, uint16_t address); - .def("setStaticAddress", &RF24Mesh::setStaticAddress, (bp::arg("nodeID"), bp::arg("address")));}} \ No newline at end of file +{ + { //::RF24Mesh + bp::class_("RF24Mesh", bp::init((bp::arg("_radio"), bp::arg("_network")))) + //bool begin(uint8_t channel = MESH_DEFAULT_CHANNEL, rf24_datarate_e data_rate = RF24_1MBPS, uint32_t timeout=MESH_RENEWAL_TIMEOUT ); + .def("begin", &RF24Mesh::begin, begin_overload(bp::args("channel", "data_rate", "timeout"))) + //uint8_t update(); + .def("update", &RF24Mesh::update) + //bool write(const void* data, uint8_t msg_type, size_t size, uint8_t nodeID=0); + .def("write", &write_wrap1, (bp::arg("data"), bp::arg("msg_type"))) + .def("write", &write_wrap2, (bp::arg("data"), bp::arg("msg_type"), bp::arg("nodeID"))) + //bool write(uint16_t to_node, const void* data, uint8_t msg_type, size_t size ); + .def("write", &write_to_node_wrap, (bp::arg("to_node"), bp::arg("data"), bp::arg("msg_type"))) + //void setNodeID(uint8_t nodeID); + .def("setNodeID", &RF24Mesh::setNodeID, (bp::arg("nodeID"))) + //void DHCP(); + .def("DHCP", &RF24Mesh::DHCP) + //int16_t getNodeID(uint16_t address=MESH_BLANK_ID); + .def("getNodeID", &RF24Mesh::getNodeID, getNodeID_overload(bp::args("address"))) + //bool checkConnection(); + .def("checkConnection", &RF24Mesh::checkConnection) + //uint16_t renewAddress(uint32_t timeout=MESH_RENEWAL_TIMEOUT); + .def("renewAddress", &RF24Mesh::renewAddress, getNodeID_overload(bp::args("timeout"))) + //bool releaseAddress(); + .def("releaseAddress", &RF24Mesh::releaseAddress) + //int16_t getAddress(uint8_t nodeID); + .def("getAddress", &RF24Mesh::getAddress, (bp::arg("nodeID"))) + //void setChannel(uint8_t _channel); + .def("setChannel", &RF24Mesh::setChannel, (bp::arg("_channel"))) + //void setChild(bool allow); + .def("setChild", &RF24Mesh::setChild, (bp::arg("allow"))) + //void setAddress(uint8_t nodeID, uint16_t address); + .def("setAddress", &RF24Mesh::setAddress, (bp::arg("nodeID"), bp::arg("address"))) + //void saveDHCP(); + .def("saveDHCP", &RF24Mesh::saveDHCP) + //void loadDHCP(); + .def("loadDHCP", &RF24Mesh::loadDHCP) + //void setStaticAddress(uint8_t nodeID, uint16_t address); + .def("setStaticAddress", &RF24Mesh::setStaticAddress, (bp::arg("nodeID"), bp::arg("address"))); + } +} \ No newline at end of file diff --git a/pyRF24/pyRF24Mesh/setup.py b/pyRF24/pyRF24Mesh/setup.py index f7d5679b8..e24569276 100644 --- a/pyRF24/pyRF24Mesh/setup.py +++ b/pyRF24/pyRF24Mesh/setup.py @@ -1,17 +1,44 @@ #!/usr/bin/env python -from distutils.core import setup, Extension -import sys +import os +from setuptools import setup, Extension +from sys import version_info -if sys.version_info >= (3,): +if version_info >= (3,): BOOST_LIB = "boost_python3" else: BOOST_LIB = "boost_python" -module_RF24Mesh = Extension( - "RF24Mesh", - libraries=["rf24mesh", "rf24network", BOOST_LIB], - sources=["pyRF24Mesh.cpp"], -) +# NOTE can't access "../../LICENSE" from working dir because +# it's relative. Brute force absolute path dynamically. +git_dir = os.path.split(os.path.abspath(os.getcwd()))[0] +git_dir = os.path.split(git_dir)[0] # remove the "pyRF24" dir from working path + +long_description = """ +.. warning:: This python wrapper for the RF24Mesh C++ library was not intended + for distribution on pypi.org. If you're reading this, then this package + is likely unauthorized or unofficial. +""" -setup(name="RF24Mesh", version="1.0", ext_modules=[module_RF24Mesh]) + +setup( + name="RF24Mesh", + version="1.0", + license="GPLv2", + license_files=(os.path.join(git_dir, "LICENSE"),), + long_description=long_description, + long_description_content_type="text/x-rst", + classifiers=[ + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "Programming Language :: C++", + "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", + ], + ext_modules=[ + Extension( + "RF24Mesh", + libraries=["rf24", "rf24network", "rf24mesh", BOOST_LIB], + sources=["pyRF24Mesh.cpp"], + ) + ], +) diff --git a/pyRF24/pyRF24Network/pyRF24Network.cpp b/pyRF24/pyRF24Network/pyRF24Network.cpp index 50c019bde..2074a6eed 100644 --- a/pyRF24/pyRF24Network/pyRF24Network.cpp +++ b/pyRF24/pyRF24Network/pyRF24Network.cpp @@ -6,128 +6,136 @@ namespace bp = boost::python; // **************** expicit wrappers ***************** // where needed, especially where buffer is involved -// + void throw_ba_exception(void) { PyErr_SetString(PyExc_TypeError, "buf parameter must be bytes or bytearray"); bp::throw_error_already_set(); } -char* get_bytes_or_bytearray_str(bp::object buf) +char *get_bytes_or_bytearray_str(bp::object buf) { - PyObject* py_ba; + PyObject *py_ba; py_ba = buf.ptr(); - if (PyByteArray_Check(py_ba)) { + if (PyByteArray_Check(py_ba)) return PyByteArray_AsString(py_ba); - } else if (PyBytes_Check(py_ba)) { + else if (PyBytes_Check(py_ba)) return PyBytes_AsString(py_ba); - } else { + else throw_ba_exception(); - } + return NULL; } int get_bytes_or_bytearray_ln(bp::object buf) { - PyObject* py_ba; + PyObject *py_ba; py_ba = buf.ptr(); - if (PyByteArray_Check(py_ba)) { + if (PyByteArray_Check(py_ba)) return PyByteArray_Size(py_ba); - } else if (PyBytes_Check(py_ba)) { + else if (PyBytes_Check(py_ba)) return PyBytes_Size(py_ba); - } else { + else throw_ba_exception(); - } + return 0; } -bp::tuple read_wrap(RF24Network& ref, size_t maxlen) +bp::tuple read_wrap(RF24Network &ref, size_t maxlen) { - char* buf = new char[maxlen + 1]; RF24NetworkHeader header; + char *buf = new char[maxlen + 1]; uint16_t len = ref.read(header, buf, maxlen); - bp::object - py_ba(bp::handle<>(PyByteArray_FromStringAndSize(buf, len))); + bp::object py_ba(bp::handle<>(PyByteArray_FromStringAndSize(buf, len))); delete[] buf; return bp::make_tuple(header, py_ba); } -bool write_wrap(RF24Network& ref, RF24NetworkHeader& header, bp::object buf) +bp::tuple peek_read_wrap(RF24Network &ref, size_t maxlen) +{ + RF24NetworkHeader header; + char *buf = new char[maxlen + 1]; + + uint16_t len = rf24_min(maxlen, ref.peek(header)); + ref.peek(header, buf, len); + bp::object py_ba(bp::handle<>(PyByteArray_FromStringAndSize(buf, len))); + delete[] buf; + + return bp::make_tuple(header, py_ba); +} + +bool write_wrap(RF24Network &ref, RF24NetworkHeader &header, bp::object buf) { return ref.write(header, get_bytes_or_bytearray_str(buf), get_bytes_or_bytearray_ln(buf)); } -std::string toString_wrap(RF24NetworkHeader& ref) +std::string toString_wrap(RF24NetworkHeader &ref) { return std::string(ref.toString()); } // **************** RF24Network exposed ***************** -// -BOOST_PYTHON_MODULE(RF24Network){{ //::RF24Network - typedef bp::class_< RF24Network > RF24Network_exposer_t; - RF24Network_exposer_t RF24Network_exposer = RF24Network_exposer_t( "RF24Network", bp::init< RF24 & >(( bp::arg("_radio")))); - bp::scope RF24Network_scope( RF24Network_exposer ); - bp::implicitly_convertible< RF24 &, RF24Network >(); - { //::RF24Network::available - - typedef bool ( ::RF24Network::*available_function_type )(); - - RF24Network_exposer.def("available", available_function_type(&::RF24Network::available)); - - } - { //::RF24Network::begin - - typedef void ( ::RF24Network::*begin_function_type )(::uint8_t, ::uint16_t); - RF24Network_exposer.def("begin", begin_function_type(&::RF24Network::begin), - (bp::arg("_channel"), bp::arg("_node_address"))); - - } - { //::RF24Network::parent - - typedef ::uint16_t ( ::RF24Network::*parent_function_type )() const; - - RF24Network_exposer.def("parent", parent_function_type(&::RF24Network::parent)); - - } - { //::RF24Network::read - - typedef bp::tuple ( * read_function_type )(::RF24Network&, size_t); - - RF24Network_exposer.def("read" - //, read_function_type( &::RF24Network::read ) - , read_function_type(&read_wrap), (bp::arg("maxlen"))); - - } - { //::RF24Network::update - - typedef void ( ::RF24Network::*update_function_type )(); - - RF24Network_exposer.def("update", update_function_type(&::RF24Network::update)); - - } - { //::RF24Network::write - - typedef bool ( * write_function_type )(::RF24Network&, ::RF24NetworkHeader&, bp::object); - - RF24Network_exposer.def("write", write_function_type(&write_wrap), - (bp::arg("header"), bp::arg("buf"))); - - } - RF24Network_exposer.def_readwrite( "txTimeout", &RF24Network::txTimeout );} - - // **************** RF24NetworkHeader exposed ***************** - // - bp::class_< RF24NetworkHeader >( "RF24NetworkHeader", bp::init< >()) - .def( bp::init< uint16_t, bp::optional< unsigned char > >(( bp::arg("_to"), bp::arg("_type")=(unsigned char)(0)))) - .def("toString", &toString_wrap ) - .def_readwrite( "from_node", &RF24NetworkHeader::from_node ) - .def_readwrite( "id", &RF24NetworkHeader::id ) - .def_readwrite( "next_id", RF24NetworkHeader::next_id ) - .def_readwrite( "reserved", &RF24NetworkHeader::reserved ) - .def_readwrite( "to_node", &RF24NetworkHeader::to_node ) - .def_readwrite( "type", &RF24NetworkHeader::type );} +BOOST_PYTHON_MODULE(RF24Network) +{ + { //::RF24Network + typedef bp::class_ RF24Network_exposer_t; + RF24Network_exposer_t RF24Network_exposer = RF24Network_exposer_t("RF24Network", bp::init((bp::arg("_radio")))); + bp::scope RF24Network_scope(RF24Network_exposer); + bp::implicitly_convertible(); + { //::RF24Network::available + typedef bool (::RF24Network::*available_function_type)(); + RF24Network_exposer.def("available", available_function_type(&::RF24Network::available)); + } + { //::RF24Network::begin (marked as deprecated) + typedef void (::RF24Network::*begin_function_type)(::uint8_t, ::uint16_t); + RF24Network_exposer.def("begin", begin_function_type(&::RF24Network::begin), (bp::arg("_channel"), bp::arg("_node_address"))); + } + { //::RF24Network::begin + typedef void (::RF24Network::*begin_function_type)(::uint16_t); + RF24Network_exposer.def("begin", begin_function_type(&::RF24Network::begin), (bp::arg("_node_address"))); + } + { //::RF24Network::parent + typedef ::uint16_t (::RF24Network::*parent_function_type)() const; + RF24Network_exposer.def("parent", parent_function_type(&::RF24Network::parent)); + } + { //::RF24Network::peek + typedef uint16_t (::RF24Network::*peek_header)(::RF24NetworkHeader &); + RF24Network_exposer.def("peek", peek_header(&::RF24Network::peek), (bp::arg("header"))); + } + { //::RF24Network::peek + typedef bp::tuple (*peek_frame)(::RF24Network &, size_t); + RF24Network_exposer.def("peek", peek_frame(&peek_read_wrap), (bp::arg("maxlen")=MAX_PAYLOAD_SIZE)); + } + { //::RF24Network::read + typedef bp::tuple (*read_function_type)(::RF24Network &, size_t); + RF24Network_exposer.def( + "read", + // read_function_type( &::RF24Network::read ), + read_function_type(&read_wrap), (bp::arg("maxlen")=MAX_PAYLOAD_SIZE)); + } + { //::RF24Network::update + typedef void (::RF24Network::*update_function_type)(); + RF24Network_exposer.def("update", update_function_type(&::RF24Network::update)); + } + { //::RF24Network::write + typedef bool (*write_function_type)(::RF24Network &, ::RF24NetworkHeader &, bp::object); + RF24Network_exposer.def("write", write_function_type(&write_wrap), (bp::arg("header"), bp::arg("buf"))); + } + RF24Network_exposer.def_readwrite("txTimeout", &RF24Network::txTimeout); + } + // **************** RF24NetworkHeader exposed ***************** + + bp::class_("RF24NetworkHeader", bp::init<>()) + .def(bp::init>((bp::arg("_to"), bp::arg("_type") = (unsigned char)(0)))) + .def("toString", &toString_wrap) + .def_readwrite("from_node", &RF24NetworkHeader::from_node) + .def_readwrite("id", &RF24NetworkHeader::id) + .def_readwrite("next_id", RF24NetworkHeader::next_id) + .def_readwrite("reserved", &RF24NetworkHeader::reserved) + .def_readwrite("to_node", &RF24NetworkHeader::to_node) + .def_readwrite("type", &RF24NetworkHeader::type); +} diff --git a/pyRF24/pyRF24Network/setup.py b/pyRF24/pyRF24Network/setup.py index a215c2bab..e29d5ef7b 100644 --- a/pyRF24/pyRF24Network/setup.py +++ b/pyRF24/pyRF24Network/setup.py @@ -1,15 +1,44 @@ #!/usr/bin/env python -from distutils.core import setup, Extension -import sys +import os +from setuptools import setup, Extension +from sys import version_info -if sys.version_info >= (3,): +if version_info >= (3,): BOOST_LIB = "boost_python3" else: BOOST_LIB = "boost_python" -module_RF24Network = Extension( - "RF24Network", libraries=["rf24network", BOOST_LIB], sources=["pyRF24Network.cpp"] -) +# NOTE can't access "../../LICENSE" from working dir because +# it's relative. Brute force absolute path dynamically. +git_dir = os.path.split(os.path.abspath(os.getcwd()))[0] +git_dir = os.path.split(git_dir)[0] # remove the "pyRF24" dir from working path + -setup(name="RF24Network", version="1.0", ext_modules=[module_RF24Network]) +long_description = """ +.. warning:: This python wrapper for the RF24Network C++ library was not intended + for distribution on pypi.org. If you're reading this, then this package + is likely unauthorized or unofficial. +""" + +setup( + name="RF24Network", + version="1.0", + license="GPLv2", + license_files=(os.path.join(git_dir, "LICENSE"),), + long_description=long_description, + long_description_content_type="text/x-rst", + classifiers=[ + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "Programming Language :: C++", + "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", + ], + ext_modules=[ + Extension( + "RF24Network", + libraries=["rf24", "rf24network", BOOST_LIB], + sources=["pyRF24Network.cpp"], + ) + ], +) diff --git a/pyRF24/setup.py b/pyRF24/setup.py index e2acbee12..b0cbfda09 100644 --- a/pyRF24/setup.py +++ b/pyRF24/setup.py @@ -1,56 +1,108 @@ #!/usr/bin/env python import os -import sys -import setuptools +from sys import version_info +from setuptools import setup, Extension import crossunixccompiler version = "" +cflags = os.getenv("CFLAGS", "") +symlink_directory = [] +# NOTE current repo directory structure requires the use of +# `python3 setup.py build` and `python3 setup.py install` +# where `pip3 install ./pyRF24` copies pyRF24 directory to +# `tmp` folder that doesn't have the needed `../Makefile.inc` +# NOTE can't access "../Makefile.inc" from working dir because +# it's relative. Brute force absolute path dynamically. +git_dir = os.path.split(os.path.abspath(os.getcwd()))[0] -def process_configparams(): - version = "" # using python keyword `global` is bad practice - - # NOTE current repo directory structure requires the use of - # `python3 setup.py build` and `python3 setup.py install` - # where `pip3 install ./pyRF24` copies pyRF24 directory to - # `tmp` folder that doesn't have the needed `../Makefile.inc` - # NOTE can't access "../Makefile.inc" from working dir because - # it's relative. Brute force absolute path dynamically. - script_dir = os.path.split(os.path.abspath(os.getcwd()))[0] - abs_file_path = os.path.join(script_dir, "Makefile.inc") - with open(abs_file_path) as f: - config_lines = f.read().splitlines() - - cflags = os.getenv("CFLAGS", "") - for line in config_lines: - identifier, value = line.split('=', 1) - if identifier == "CPUFLAGS": - cflags += " " + value - elif identifier == "HEADER_DIR": - cflags += " -I" + os.path.dirname(value) - elif identifier == "LIB_DIR": - cflags += " -L" + value - elif identifier == "LIB_VERSION": - version = value - elif identifier in ("CC", "CXX"): - os.environ[identifier] = value - - os.environ["CFLAGS"] = cflags - return version - -if sys.version_info >= (3,): +try: # get compiler options from the generated Makefile.inc + with open(os.path.join(git_dir, "Makefile.inc"), "r") as f: + for line in f.read().splitlines(): + identifier, value = line.split("=", 1) + if identifier == "CPUFLAGS": + # this is never reached as CPUFLAGS var is concatenated into CFLAGS var. + # however the CFLAGS var may conditionally contain "-lwiringPi" + cflags += " " + value + elif identifier == "HEADER_DIR": + cflags += " -I" + os.path.dirname(value) + elif identifier == "LIB_DIR": + cflags += " -L" + value + elif identifier == "LIB_VERSION": + version = value + elif identifier in ("CC", "CXX"): + os.environ[identifier] = value + +except FileNotFoundError: # assuming lib was built & installed with CMake + + # get LIB_VERSION from library.properties file for Arduino IDE + with open(os.path.join(git_dir, "library.properties"), "r") as f: + for line in f.read().splitlines(): + if line.startswith("version"): + version = line.split("=")[1] + +# check C++ RF24 lib is installed +finally: + + # check for possible linker flags set via CFLAGS environment varible + for flag in cflags.split("-"): + if flag.startswith("L"): + symlink_directory.append( + flag[1:].strip() + (" " if len(symlink_directory) else "") + ) + + if not symlink_directory: + print( + "install location of librf24.so isn't explicit; trying default locations." + ) + symlink_directory = ["/usr/local/lib", "/usr/lib"] + + found_symlink = False + for symlink_loc in symlink_directory: + if os.path.isfile(symlink_loc + "/librf24.so"): + print("librf24.so found at", symlink_loc) + found_symlink = True + + if not found_symlink: + raise FileNotFoundError( + "RF24 library is not installed. librf24.so does not exist in {}.".format( + " or ".join(symlink_directory) + ) + ) + +# append any additionally found compiler flags +os.environ["CFLAGS"] = cflags + +# get the proper boost.python lib symlink name according to version of python +if version_info >= (3,): BOOST_LIB = "boost_python3" else: BOOST_LIB = "boost_python" -version = process_configparams() crossunixccompiler.register() -module_RF24 = setuptools.Extension("RF24", - libraries=["rf24", BOOST_LIB], - sources=["pyRF24.cpp"]) +long_description = """ +.. warning:: This python wrapper for the RF24 C++ library was not intended + for distribution on pypi.org. If you're reading this, then this package + is likely unauthorized or unofficial. +""" + -setuptools.setup(name="RF24", - version=version, - ext_modules=[module_RF24]) +setup( + name="RF24", + version=version, + license="GPLv2", + license_files=(os.path.join(git_dir, "LICENSE"),), + long_description=long_description, + long_description_content_type="text/x-rst", + classifiers=[ + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + "Programming Language :: C++", + "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", + ], + ext_modules=[ + Extension("RF24", sources=["pyRF24.cpp"], libraries=["rf24", BOOST_LIB]) + ], +) diff --git a/tests/README b/tests/README deleted file mode 100644 index 43ceaf540..000000000 --- a/tests/README +++ /dev/null @@ -1,7 +0,0 @@ -The sketches in this directory are intended to be checkin tests. -No code should be pushed to github without these tests passing. - -See "runtests.sh" script inside each sketch dir. This script is fully compatible with -git bisest. - -Note that this requires python and py-serial diff --git a/tests/native/Jamfile b/tests/native/Jamfile deleted file mode 100644 index 10d0336cc..000000000 --- a/tests/native/Jamfile +++ /dev/null @@ -1,300 +0,0 @@ -PROJECT_NAME = $(PWD:B) ; -PROJECT_DIR = . ; -PROJECT_LIBS = RF24 ; - -OUT_DIR = ojam ; -F_CPU = 16000000 ; -MCU = atmega328p ; -PORTS = /dev/tty.usbserial-A600eHIs /dev/tty.usbserial-A40081RP /dev/tty.usbserial-A9007LmI ; - -UPLOAD_RATE = 57600 ; -AVRDUDE_PROTOCOL = stk500v1 ; -COM = 33 ; - -# Host-specific overrides for locations -if $(OS) = MACOSX -{ -ARDUINO_VERSION = 22 ; -OLD_DIR = /opt/arduino-0021 ; -AVR_TOOLS_PATH = $(OLD_DIR)/hardware/tools/avr/bin ; -AVRDUDECONFIG_PATH = $(OLD_DIR)/hardware/tools/avr/etc ; -ARDUINO_DIR = /opt/Arduino ; -ARDUINO_AVR = /usr/lib/avr/include ; -} - -# Where is everything? -ARDUINO_VERSION ?= 22 ; -SKETCH_DIR = $(HOME)/Source/Arduino ; -AVR_TOOLS_PATH ?= /usr/bin ; -ARDUINO_DIR ?= /opt/arduino-00$(ARDUINO_VERSION) ; -ARDUINO_AVR ?= $(ARDUINO_DIR)/hardware/tools/avr/avr/include/avr ; -AVRDUDECONFIG_PATH ?= $(ARDUINO_DIR)/hardware/tools ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/arduino ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(SKETCH_DIR)/libraries ; -AVR_AS = $(AVR_TOOLS_PATH)/avr-as ; -AVR_CC = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_CXX = $(AVR_TOOLS_PATH)/avr-g++ ; -AVR_LD = $(AVR_TOOLS_PATH)/avr-gcc ; -AVR_OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy ; -AVRDUDE = $(AVR_TOOLS_PATH)/avrdude ; - -DEFINES = F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H HAL=1 ; -CTUNING = -ffunction-sections -fdata-sections ; -CXXTUNING = -fno-exceptions -fno-strict-aliasing ; -ASFLAGS = -mmcu=$(MCU) ; -CFLAGS = -Os -Wall -Wextra $(ASFLAGS) $(CTUNING) ; -CXXFLAGS = $(CFLAGS) $(CXXTUNING) ; -LDFLAGS = -Os -lm -Wl,--gc-sections -mmcu=atmega328p ; - -# Search everywhere for headers -HDRS = $(PROJECT_DIR) $(ARDUINO_AVR) $(ARDUINO_CORE) [ GLOB $(ARDUINO_LIB) $(SKETCH_LIB) : [^.]* ] ; -HDRS += [ GLOB $(HDRS) : utility ] ; - -# Grab everything from the core directory -CORE_MODULES = [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -LIB_MODULES = [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# In addition to explicitly-specified program modules, pick up anything from the current -# dir. -PROJECT_MODULES += [ GLOB $(PROJECT_DIR) : *.c *.cpp *.pde ] ; - -# Shortcut for the out files -OUT = $(OUT_DIR)/$(PROJECT_NAME) ; - -# AvrDude setup -AVRDUDE_FLAGS = -V -F -D -C $(AVRDUDECONFIG_PATH)/avrdude.conf -p $(MCU) -c $(AVRDUDE_PROTOCOL) -b $(UPLOAD_RATE) ; - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -# GitVersion version.h ; - -rule AvrAsm -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrAsm -{ - $(AVR_AS) $(ASFLAGS) -o $(<) $(>) -} - -rule AvrCc -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrCc -{ - $(AVR_CC) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CFLAGS) $(>) -} - -rule AvrC++ -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrC++ -{ - $(AVR_CXX) -c -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) -} - -rule AvrAsmFromC++ -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; - - CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ; - CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ; -} - -actions AvrAsmFromC++ -{ - $(AVR_CXX) -S -fverbose-asm -o $(<) $(CCHDRS) $(CCDEFS) $(CXXFLAGS) $(>) -} - -rule Pde -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Clean clean : $(<) ; -} - -actions Pde -{ - echo "#include " > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule AvrPde -{ - local _CPP = $(OUT_DIR)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - AvrC++ $(<) : $(_CPP) ; -} - -rule AvrObject -{ - switch $(>:S) - { - case .S : AvrAsm $(<) : $(>) ; - case .c : AvrCc $(<) : $(>) ; - case .cpp : AvrC++ $(<) : $(>) ; - case .pde : AvrPde $(<) : $(>) ; - } -} - -rule AvrObjects -{ - for _I in $(<) - { - AvrObject $(OUT_DIR)/$(_I:B).o : $(_I) ; - } -} - -rule AvrMainFromObjects -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - MkDir $(<:D) ; - Depends all : $(<) ; - Clean clean : $(<) ; -} - -actions AvrMainFromObjects -{ - $(AVR_LD) $(LDFLAGS) -o $(<) $(>) -} - -rule AvrMain -{ - AvrMainFromObjects $(<) : $(OUT_DIR)/$(>:B).o ; - AvrObjects $(>) ; -} - -rule AvrHex -{ - Depends $(<) : $(>) ; - Depends $(<) : $(<:D) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions AvrHex -{ - $(AVR_OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule AvrUpload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - AvrUploadAction $(2) : $(3) ; -} - -actions AvrUploadAction -{ - $(AVRDUDE) $(AVRDUDE_FLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -AvrMain $(OUT).elf : $(CORE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) -AvrHex $(OUT).hex : $(OUT).elf ; - -AvrUpload p6 : /dev/tty.usbserial-A600eHIs : $(OUT).hex ; -AvrUpload p4 : /dev/tty.usbserial-A40081RP : $(OUT).hex ; -AvrUpload p9 : /dev/tty.usbserial-A9007LmI : $(OUT).hex ; - -# -# Native -# - -OUT_DIR_NATIVE = out_native ; -OUT_NATIVE = $(OUT_DIR_NATIVE)/$(PROJECT_NAME) ; -NATIVE_CORE = $(SKETCH_DIR)/hardware/native ; -HDRS = $(NATIVE_CORE) $(HDRS) ; -NATIVE_CORE_MODULES = [ GLOB $(NATIVE_CORE) : *.c *.cpp ] ; -NATIVE_MODULES = ; -DEFINES += NATIVE ; - -rule NativePde -{ - local _CPP = $(OUT_DIR_NATIVE)/$(_I:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule UserObject -{ - switch $(>) - { - case *.pde : NativePde $(<) : $(>) ; - } -} - -rule Objects -{ - for _I in $(<) - { - local _O = $(OUT_DIR_NATIVE)/$(_I:B).o ; - Object $(_O) : $(_I) ; - } -} - -rule Main -{ - MainFromObjects $(<) : $(OUT_DIR_NATIVE)/$(>:B).o ; - Objects $(>) ; -} - -actions C++ -{ - c++ -c -o $(<) $(CCHDRS) $(CCDEFS) $(>) -} - -actions Link -{ - c++ -o $(<) $(>) -} - - - -MkDir $(OUT_DIR_NATIVE) ; -Depends $(OUT_NATIVE) : $(OUT_DIR_NATIVE) ; -Main $(OUT_NATIVE) : $(NATIVE_CORE_MODULES) $(NATIVE_MODULES) $(LIB_MODULES) $(PROJECT_MODULES) ; - -Depends native : $(OUT_NATIVE) ; - diff --git a/tests/native/pingpair_irq.pde b/tests/native/pingpair_irq.pde deleted file mode 100644 index 8bce21be7..000000000 --- a/tests/native/pingpair_irq.pde +++ /dev/null @@ -1,223 +0,0 @@ -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Interrupt-driven test for native target - * - * This example is the friendliest for the native target because it doesn't do - * any polling. Made a slight change to call done() at the end of setup. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 - -RF24 radio(8, 9); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const short role_pin = 7; - -// -// Topology -// - -// Single radio pipe address for the 2 nodes to communicate. -const uint64_t pipe = 0xE8E8F0F0E1LL; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes in this -// system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum{ - role_sender = 1, - role_receiver -} role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = {"invalid", "Sender", "Receiver"}; - -// The role of the current running sketch -role_e role; - -// Interrupt handler, check the radio because we got an IRQ -void check_radio(void); - -void setup(void){ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin, HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if (digitalRead(role_pin)){ - role = role_sender; - } else { - role = role_receiver; - } - - // - // Print preamble - // - - Serial.begin(115200); - printf_begin(); - printf("\n\rRF24/examples/pingpair_irq/\n\r"); - printf("ROLE: %s\n\r", role_friendly_name[role]); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // We will be using the Ack Payload feature, so please enable it - radio.enableAckPayload(); - radio.enableDynamicPayloads(); // needed for using ACK payloads - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens a single pipe for these two nodes to communicate - // back and forth. One listens on it, the other talks to it. - - if (role == role_sender) { - radio.openWritingPipe(pipe); - } else { - radio.openReadingPipe(1, pipe); - } - - // - // Start listening - // - - if (role == role_receiver) - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); - - // - // Attach interrupt handler to interrupt #0 (using pin 2) - // on BOTH the sender and receiver - // - - attachInterrupt(0, check_radio, FALLING); - - // - // On the native target, this is as far as we get - // - #if NATIVE - done(); - #endif -} - -static uint32_t message_count = 0; - -void loop(void) -{ - // - // Sender role. Repeatedly send the current time - // - - if (role == role_sender){ - // Take the time, and send it. - unsigned long time = millis(); - printf("Now sending %lu\n\r", time); - radio.startWrite(&time, sizeof(unsigned long)); - - // Try again soon - delay(2000); - } - - // - // Receiver role: Does nothing! All the work is in IRQ - // - -} - -void check_radio(void) -{ - // What happened? - bool tx, fail, rx; - radio.whatHappened(tx, fail, rx); - - // Have we successfully transmitted? - if (tx){ - if (role == role_sender){ - printf("Send:OK\n\r"); - } - - if (role == role_receiver){ - printf("Ack Payload:Sent\n\r"); - } - } - - // Have we failed to transmit? - if (fail){ - if (role == role_sender){ - printf("Send:Failed\n\r"); - } - - if (role == role_receiver){ - printf("Ack Payload:Failed\n\r"); - } - } - - // Transmitter can power down for now, because - // the transmission is done. - if ((tx || fail) && (role == role_sender)){ - radio.powerDown(); - } - - // Did we receive a message? - if (rx){ - // If we're the sender, we've received an ack payload - if (role == role_sender){ - radio.read(&message_count, sizeof(message_count)); - printf("Ack:%lu\n\r", (unsigned long) message_count); - } - - // If we're the receiver, we've received a time message - if (role == role_receiver){ - // Get this payload and dump it - static unsigned long got_time; - radio.read(&got_time, sizeof(got_time)); - printf("Got payload %lu\n\r", got_time); - - // Add an ack packet for the next time around. This is a simple - // packet counter - radio.writeAckPayload(1, &message_count, sizeof(message_count)); - ++message_count; - } - } -} - -// vim:ai:cin:sts=2 sw=2 ft=cpp diff --git a/tests/native/printf.h b/tests/native/printf.h deleted file mode 100644 index 0a507c121..000000000 --- a/tests/native/printf.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#include "WProgram.h" - -int serial_putc(char c, FILE*) -{ - Serial.write(c); - - return c; -} - -void printf_begin(void) -{ - fdevopen(&serial_putc, 0); -} - -#endif // __PRINTF_H__ diff --git a/tests/pingpair_blocking/Jamfile b/tests/pingpair_blocking/Jamfile deleted file mode 100644 index 18244ec84..000000000 --- a/tests/pingpair_blocking/Jamfile +++ /dev/null @@ -1,219 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = SPI RF24 ; -PROJECT_DIRS = $(PWD) ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= arduino ; -UPLOAD_SPEED ?= 115200 ; -MCU ?= atmega328p ; -F_CPU ?= 16000000 ; -CORE ?= arduino ; -VARIANT ?= standard ; -ARDUINO_VERSION ?= 100 ; - -# (3) USB Ports - -PORTS = p4 p6 p9 u0 u1 u2 ; -PORT_p6 = /dev/tty.usbserial-A600eHIs ; -PORT_p4 = /dev/tty.usbserial-A40081RP ; -PORT_p9 = /dev/tty.usbserial-A9007LmI ; -PORT_u0 = /dev/ttyUSB0 ; -PORT_u1 = /dev/ttyUSB1 ; -PORT_u2 = /dev/ttyUSB2 ; - -# (4) Location of AVR tools -# -# This configuration assumes using avr-tools that were obtained separate from the Arduino -# distribution. - -if $(OS) = MACOSX -{ - AVR_BIN ?= /usr/local/avrtools/bin ; - AVR_ETC = /usr/local/avrtools/etc ; - AVR_INCLUDE = /usr/local/avrtools/include ; -} -else -{ - AVR_BIN ?= /usr/bin ; - AVR_INCLUDE = /usr/lib/avr/include ; - AVR_ETC = /etc ; -} - -# (5) Directories where Arduino core and libraries are located - -ARDUINO_DIR ?= /opt/Arduino ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; - -# -# -------------------------------------------------- -# Below this line usually never needs to be modified -# - -# Tool locations - -CC = $(AVR_BIN)/avr-gcc ; -C++ = $(AVR_BIN)/avr-g++ ; -LINK = $(AVR_BIN)/avr-gcc ; -AR = $(AVR_BIN)/avr-ar rcs ; -RANLIB = ; -OBJCOPY = $(AVR_BIN)/avr-objcopy ; -AVRDUDE ?= $(AVR_BIN)/avrdude ; - -# Flags - -DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -OPTIM = -Os ; -CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ; -C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ; -LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ; -AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ; - -# Search everywhere for headers - -HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ; - -# Output locations - -LOCATE_TARGET = $(F_CPU) ; -LOCATE_SOURCE = $(F_CPU) ; - -# -# Custom rules -# - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule Pde -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; -} - -if ( $(ARDUINO_VERSION) < 100 ) -{ - ARDUINO_H = WProgram.h ; -} -else -{ - ARDUINO_H = Arduino.h ; -} - -actions Pde -{ - echo "#include <$(ARDUINO_H)>" > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule C++Pde -{ - local _CPP = $(>:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule UserObject -{ - switch $(>:S) - { - case .ino : C++Pde $(<) : $(>) ; - case .pde : C++Pde $(<) : $(>) ; - } -} - -rule Objects -{ - local _i ; - - for _i in [ FGristFiles $(<) ] - { - local _b = $(_i:B)$(SUFOBJ) ; - local _o = $(_b:G=$(SOURCE_GRIST:E)) ; - Object $(_o) : $(_i) ; - Depends obj : $(_o) ; - } -} - -rule Library -{ - LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Main -{ - MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Hex -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions Hex -{ - $(OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule Upload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - UploadAction $(2) : $(3) ; -} - -actions UploadAction -{ - $(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -rule Arduino -{ - LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ; - Main $(<) : $(>) ; - LinkLibraries $(<) : core libs ; - Hex $(<:B).hex : $(<) ; - for _p in $(PORTS) - { - Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ; - } -} - -# -# Targets -# - -# Grab everything from the core directory -Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# Main output executable -Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ; diff --git a/tests/pingpair_blocking/pingpair_blocking.pde b/tests/pingpair_blocking/pingpair_blocking.pde deleted file mode 100644 index 7bba359de..000000000 --- a/tests/pingpair_blocking/pingpair_blocking.pde +++ /dev/null @@ -1,272 +0,0 @@ -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Test version of RF24, exposes some protected interface -// - -class RF24Test : public RF24 { -public: - RF24Test(int a, int b) - :RF24(a, b) - { - } -}; - - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 - -RF24Test radio(48, 49); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const int role_pin = 5; - -// -// Topology -// - -// Radio pipe addresses for the 2 nodes to communicate. -const uint64_t pipes[2] = {0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL}; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes -// in this system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { - role_ping_out = 1, - role_pong_back -} role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = {"invalid", "Ping out", "Pong back"}; - -// The role of the current running sketch -role_e role; - -// -// Test state -// - -bool done; //*< Are we done with the test? */ -bool passed; //*< Have we passed the test? */ -bool notified; //*< Have we notified the user we're done? */ -const int num_needed = 10; //*< How many success/failures until we're done? */ -int receives_remaining = num_needed; //*< How many ack packets until we declare victory? */ -int failures_remaining = num_needed; //*< How many more failed sends until we declare failure? */ -const int interval = 100; //*< ms to wait between sends */ - -char configuration = '1'; //*< Configuration key, one char sent in by the test framework to tell us how to configure, this is the default */ - -void one_ok(void) -{ - // Have we received enough yet? - if (!--receives_remaining) { - done = true; - passed = true; - } -} - -void one_failed(void) -{ - // Have we failed enough yet? - if (!--failures_remaining) { - done = true; - passed = false; - } -} - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin, HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if (digitalRead(role_pin)) { - role = role_ping_out; - } else { - role = role_pong_back; - } - - // - // Print preamble - // - - Serial.begin(115200); - printf_begin(); - printf("\n\rRF24/tests/pingpair_blocking/\n\r"); - printf("ROLE: %s\n\r", role_friendly_name[role]); - - // - // get test config - // - - printf("+READY press any key to start\n\r\n\r"); - - while (!Serial.available()) { - } - configuration = Serial.read(); - printf("Configuration\t = %c\n\r", configuration); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens two pipes for these two nodes to communicate - // back and forth. - // Open 'our' pipe for writing - // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading) - - if (role == role_ping_out) { - radio.openWritingPipe(pipes[0]); - radio.openReadingPipe(1, pipes[1]); - } else { - radio.openWritingPipe(pipes[1]); - radio.openReadingPipe(1, pipes[0]); - } - - // - // Start listening - // - - radio.startListening(); - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); - - if (role == role_pong_back) { - printf("\n\r+OK "); - } -} - -void loop(void) -{ - // - // Ping out role. Repeatedly send the current time - // - - if (role == role_ping_out) { - // First, stop listening so we can talk. - radio.stopListening(); - - // Take the time, and send it. This will block until complete - unsigned long time = millis(); - printf("Now sending %lu...", time); - radio.write(&time, sizeof(unsigned long)); - - // Now, continue listening - radio.startListening(); - - // Wait here until we get a response, or timeout (250ms) - unsigned long started_waiting_at = millis(); - bool timeout = false; - while (!radio.available() && !timeout) { - if (millis() - started_waiting_at > 200) { - timeout = true; - } - } - - // Describe the results - if (timeout) { - printf("Failed, response timed out.\n\r"); - one_failed(); - } else { - // Grab the response, compare, and send to debugging spew - unsigned long got_time; - radio.read(&got_time, sizeof(unsigned long)); - - // Spew it - printf("Got response %lu, round-trip delay: %lu\n\r", got_time, millis() - got_time); - one_ok(); - } - - // Try again later - delay(250); - } - - // - // Pong back role. Receive each packet, dump it out, and send it back - // - - if (role == role_pong_back) { - // if there is data ready - if (radio.available()) { - // Dump the payloads until we've gotten everything - unsigned long got_time; - bool done = false; - while (radio.available()) { - // Fetch the payload, and see if this was the last one. - radio.read(&got_time, sizeof(unsigned long)); - } - // Delay just a little bit to let the other unit - // make the transition to receiver - //delay(20); - //} - - // First, stop listening so we can talk - radio.stopListening(); - - // Spew it - printf("Got payload %lu...", got_time); - - // Send the final one back. - radio.write(&got_time, sizeof(unsigned long)); - - // Now, resume listening so we catch the next packets. - radio.startListening(); - printf("Sent response.\n\r"); - - } - } - - // - // Stop the test if we're done and report results - // - if (done && !notified) { - notified = true; - - printf("\n\r+OK "); - if (passed) { - printf("PASS\n\r\n\r"); - } else { - printf("FAIL\n\r\n\r"); - } - } -} -// vim:cin:ai:sts=2 sw=2 ft=cpp diff --git a/tests/pingpair_blocking/printf.h b/tests/pingpair_blocking/printf.h deleted file mode 100644 index e460ff0ab..000000000 --- a/tests/pingpair_blocking/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else - #error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/tests/pingpair_blocking/runtest.py b/tests/pingpair_blocking/runtest.py deleted file mode 100755 index 4de29d83c..000000000 --- a/tests/pingpair_blocking/runtest.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/python - -import sys, serial - - -def read_until(token): - while 1: - line = ser.readline(None) - sys.stdout.write(line) - - if (line.startswith(token)): - break - return line - - -ser = serial.Serial(sys.argv[1], 57600, timeout=5, dsrdtr=False, rtscts=False) - -read_until("+READY") -ser.write(sys.argv[2]) - -line = read_until("+OK") -ser.close() -if (line.find("PASS") != -1): - sys.exit(0) -else: - sys.exit(1) diff --git a/tests/pingpair_blocking/runtests.sh b/tests/pingpair_blocking/runtests.sh deleted file mode 100755 index e10644879..000000000 --- a/tests/pingpair_blocking/runtests.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -# Connect u0 to receiver, u1 to sender - -jam u0 u1 && expect test.ex diff --git a/tests/pingpair_blocking/test.ex b/tests/pingpair_blocking/test.ex deleted file mode 100755 index ea992add3..000000000 --- a/tests/pingpair_blocking/test.ex +++ /dev/null @@ -1,11 +0,0 @@ -#/usr/bin/expect - -set timeout 100 -spawn picocom -b 57600 /dev/ttyUSB0 -expect "+READY" -send "1" -expect "+OK" -spawn picocom -b 57600 /dev/ttyUSB1 -expect "+READY" -send "1" -expect "+OK" diff --git a/tests/pingpair_test/Jamfile b/tests/pingpair_test/Jamfile deleted file mode 100644 index 18244ec84..000000000 --- a/tests/pingpair_test/Jamfile +++ /dev/null @@ -1,219 +0,0 @@ -# (1) Project Information - -PROJECT_LIBS = SPI RF24 ; -PROJECT_DIRS = $(PWD) ; - -# (2) Board Information - -UPLOAD_PROTOCOL ?= arduino ; -UPLOAD_SPEED ?= 115200 ; -MCU ?= atmega328p ; -F_CPU ?= 16000000 ; -CORE ?= arduino ; -VARIANT ?= standard ; -ARDUINO_VERSION ?= 100 ; - -# (3) USB Ports - -PORTS = p4 p6 p9 u0 u1 u2 ; -PORT_p6 = /dev/tty.usbserial-A600eHIs ; -PORT_p4 = /dev/tty.usbserial-A40081RP ; -PORT_p9 = /dev/tty.usbserial-A9007LmI ; -PORT_u0 = /dev/ttyUSB0 ; -PORT_u1 = /dev/ttyUSB1 ; -PORT_u2 = /dev/ttyUSB2 ; - -# (4) Location of AVR tools -# -# This configuration assumes using avr-tools that were obtained separate from the Arduino -# distribution. - -if $(OS) = MACOSX -{ - AVR_BIN ?= /usr/local/avrtools/bin ; - AVR_ETC = /usr/local/avrtools/etc ; - AVR_INCLUDE = /usr/local/avrtools/include ; -} -else -{ - AVR_BIN ?= /usr/bin ; - AVR_INCLUDE = /usr/lib/avr/include ; - AVR_ETC = /etc ; -} - -# (5) Directories where Arduino core and libraries are located - -ARDUINO_DIR ?= /opt/Arduino ; -ARDUINO_CORE = $(ARDUINO_DIR)/hardware/arduino/cores/$(CORE) $(ARDUINO_DIR)/hardware/arduino/variants/$(VARIANT) ; -ARDUINO_LIB = $(ARDUINO_DIR)/libraries ; -SKETCH_LIB = $(HOME)/Source/Arduino/libraries ; - -# -# -------------------------------------------------- -# Below this line usually never needs to be modified -# - -# Tool locations - -CC = $(AVR_BIN)/avr-gcc ; -C++ = $(AVR_BIN)/avr-g++ ; -LINK = $(AVR_BIN)/avr-gcc ; -AR = $(AVR_BIN)/avr-ar rcs ; -RANLIB = ; -OBJCOPY = $(AVR_BIN)/avr-objcopy ; -AVRDUDE ?= $(AVR_BIN)/avrdude ; - -# Flags - -DEFINES += F_CPU=$(F_CPU)L ARDUINO=$(ARDUINO_VERSION) VERSION_H ; -OPTIM = -Os ; -CCFLAGS = -Wall -Wextra -Wno-strict-aliasing -mmcu=$(MCU) -ffunction-sections -fdata-sections ; -C++FLAGS = $(CCFLAGS) -fno-exceptions -fno-strict-aliasing ; -LINKFLAGS = $(OPTIM) -lm -Wl,--gc-sections -mmcu=$(MCU) ; -AVRDUDEFLAGS = -V -F -D -C $(AVR_ETC)/avrdude.conf -p $(MCU) -c $(UPLOAD_PROTOCOL) -b $(UPLOAD_SPEED) ; - -# Search everywhere for headers - -HDRS = $(PROJECT_DIRS) $(AVR_INCLUDE) $(ARDUINO_CORE) $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) ; - -# Output locations - -LOCATE_TARGET = $(F_CPU) ; -LOCATE_SOURCE = $(F_CPU) ; - -# -# Custom rules -# - -rule GitVersion -{ - Always $(<) ; - Depends all : $(<) ; -} - -actions GitVersion -{ - echo "const char program_version[] = \"\\" > $(<) - git log -1 --pretty=format:%h >> $(<) - echo "\";" >> $(<) -} - -GitVersion version.h ; - -rule Pde -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_SOURCE) ; - Clean clean : $(<) ; -} - -if ( $(ARDUINO_VERSION) < 100 ) -{ - ARDUINO_H = WProgram.h ; -} -else -{ - ARDUINO_H = Arduino.h ; -} - -actions Pde -{ - echo "#include <$(ARDUINO_H)>" > $(<) - echo "#line 1 \"$(>)\"" >> $(<) - cat $(>) >> $(<) -} - -rule C++Pde -{ - local _CPP = $(>:B).cpp ; - Pde $(_CPP) : $(>) ; - C++ $(<) : $(_CPP) ; -} - -rule UserObject -{ - switch $(>:S) - { - case .ino : C++Pde $(<) : $(>) ; - case .pde : C++Pde $(<) : $(>) ; - } -} - -rule Objects -{ - local _i ; - - for _i in [ FGristFiles $(<) ] - { - local _b = $(_i:B)$(SUFOBJ) ; - local _o = $(_b:G=$(SOURCE_GRIST:E)) ; - Object $(_o) : $(_i) ; - Depends obj : $(_o) ; - } -} - -rule Library -{ - LibraryFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Main -{ - MainFromObjects $(<) : $(>:B)$(SUFOBJ) ; - Objects $(>) ; -} - -rule Hex -{ - Depends $(<) : $(>) ; - MakeLocate $(<) : $(LOCATE_TARGET) ; - Depends hex : $(<) ; - Clean clean : $(<) ; -} - -actions Hex -{ - $(OBJCOPY) -O ihex -R .eeprom $(>) $(<) -} - -rule Upload -{ - Depends $(1) : $(2) ; - Depends $(2) : $(3) ; - NotFile $(1) ; - Always $(1) ; - Always $(2) ; - UploadAction $(2) : $(3) ; -} - -actions UploadAction -{ - $(AVRDUDE) $(AVRDUDEFLAGS) -P $(<) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(>):i -} - -rule Arduino -{ - LINKFLAGS on $(<) = $(LINKFLAGS) -Wl,-Map=$(LOCATE_TARGET)/$(<:B).map ; - Main $(<) : $(>) ; - LinkLibraries $(<) : core libs ; - Hex $(<:B).hex : $(<) ; - for _p in $(PORTS) - { - Upload $(_p) : $(PORT_$(_p)) : $(<:B).hex ; - } -} - -# -# Targets -# - -# Grab everything from the core directory -Library core : [ GLOB $(ARDUINO_CORE) : *.c *.cpp ] ; - -# Grab everything from libraries. To avoid this "grab everything" behaviour, you -# can specify specific modules to pick up in PROJECT_MODULES -Library libs : [ GLOB $(ARDUINO_LIB)/$(PROJECT_LIBS) $(ARDUINO_LIB)/$(PROJECT_LIBS)/utility $(SKETCH_LIB)/$(PROJECT_LIBS) : *.cpp *.c ] ; - -# Main output executable -Arduino $(PWD:B).elf : $(PROJECT_MODULES) [ GLOB $(PROJECT_DIRS) : *.c *.cpp *.pde *.ino ] ; diff --git a/tests/pingpair_test/pingpair_test.pde b/tests/pingpair_test/pingpair_test.pde deleted file mode 100644 index 189298fed..000000000 --- a/tests/pingpair_test/pingpair_test.pde +++ /dev/null @@ -1,417 +0,0 @@ -/* - Copyright (C) 2011 James Coliz, Jr. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * Full test on single RF pair - * - * This sketches uses as many RF24 methods as possible in a single test. - * - * To operate: - * Upload this sketch on two nodes, each with IRQ -> pin 2 - * One node needs pin 7 -> GND, the other NC. That's the receiving node - * Monitor the sending node's serial output - * Look for "+OK PASS" or "+OK FAIL" - */ - -#include -#include "nRF24L01.h" -#include "RF24.h" -#include "printf.h" - -// -// Hardware configuration -// - -// Set up nRF24L01 radio on SPI bus plus pins 8 & 9 - -RF24 radio(7, 8); - -// sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver -// Leave open to be the 'ping' transmitter -const short role_pin = 5; - -// -// Topology -// - -// Single radio pipe address for the 2 nodes to communicate. -const uint64_t pipe = 0xE8E8F0F0E1LL; - -// -// Role management -// -// Set up role. This sketch uses the same software for all the nodes in this -// system. Doing so greatly simplifies testing. The hardware itself specifies -// which node it is. -// -// This is done through the role_pin -// - -// The various roles supported by this sketch -typedef enum { - role_sender = 1, - role_receiver -} role_e; - -// The debug-friendly names of those roles -const char* role_friendly_name[] = {"invalid", "Sender", "Receiver"}; - -// The role of the current running sketch -role_e role; - -// Interrupt handler, check the radio because we got an IRQ -void check_radio(void); - -// -// Payload -// - -const int min_payload_size = 4; -const int max_payload_size = 32; -int payload_size_increments_by = 2; -int next_payload_size = min_payload_size; - -char receive_payload[max_payload_size + 1]; // +1 to allow room for a terminating NULL char - -// -// Test state -// - -bool done; //*< Are we done with the test? */ -bool passed; //*< Have we passed the test? */ -bool notified; //*< Have we notified the user we're done? */ -const int num_needed = 10; //*< How many success/failures until we're done? */ -int receives_remaining = num_needed; //*< How many ack packets until we declare victory? */ -int failures_remaining = num_needed; //*< How many more failed sends until we declare failure? */ -const int interval = 100; //*< ms to wait between sends */ - -char configuration = '1'; //*< Configuration key, one char sent in by the test framework to tell us how to configure, this is the default */ - -uint8_t pipe_number = 1; // Which pipe to send on. - -void one_ok(void) -{ - // Have we received enough yet? - if (!--receives_remaining) { - done = true; - passed = true; - } -} - -void one_failed(void) -{ - // Have we failed enough yet? - if (!--failures_remaining) { - done = true; - passed = false; - } -} - -// -// Setup -// - -void setup(void) -{ - // - // Role - // - - // set up the role pin - pinMode(role_pin, INPUT); - digitalWrite(role_pin, HIGH); - delay(20); // Just to get a solid reading on the role pin - - // read the address pin, establish our role - if (digitalRead(role_pin)) { - role = role_sender; - } else { - role = role_receiver; - } - - // - // Print preamble - // - - Serial.begin(115200); - printf_begin(); - printf("\n\rRF24/tests/pingpair_test/\n\r"); - printf("ROLE: %s\n\r", role_friendly_name[role]); - - // - // Read configuration from serial - // - // It would be a much better test if this program could accept configuration - // from the serial port. Then it would be possible to run the same test under - // lots of different circumstances. - // - // The idea is that we will print "+READY" at this point. The python script - // will wait for it, and then send down a configuration script that we - // execute here and then run with. - // - // The test controller will need to configure the receiver first, then go run - // the test on the sender. - // - - printf("+READY press any key to start\n\r\n\r"); - - while (!Serial.available()) { - } - configuration = Serial.read(); - printf("Configuration\t = %c\n\r", configuration); - - // - // Setup and configure rf radio - // - - radio.begin(); - - // We will be using the Ack Payload feature, so please enable it - radio.enableAckPayload(); - radio.enableDynamicPayloads(); // needed for using ACK payloads - - // Config 2 is special radio config - if (configuration == '2'){ - radio.setCRCLength(RF24_CRC_8); - radio.setDataRate(RF24_250KBPS); - radio.setChannel(10); - }else{ - //Otherwise, default radio config - - // Optional: Increase CRC length for improved reliability - radio.setCRCLength(RF24_CRC_16); - - // Optional: Decrease data rate for improved reliability - radio.setDataRate(RF24_1MBPS); - - // Optional: Pick a high channel - radio.setChannel(90); - } - - // Config 3 is static payloads only - if (configuration == '3'){ - next_payload_size = 16; - payload_size_increments_by = 0; - radio.setPayloadSize(next_payload_size); - }else{ - // enable dynamic payloads - radio.enableDynamicPayloads(); - } - - // Config 4 tests out a higher pipe ## - if (configuration == '4' && role == role_sender){ - // Set top 4 bytes of the address in pipe 1 - radio.openReadingPipe(1, pipe & 0xFFFFFFFF00ULL); - - // indicate the pipe to use - pipe_number = 5; - }else if (role == role_sender){ - radio.openReadingPipe(5, 0); - } - - // - // Open pipes to other nodes for communication - // - - // This simple sketch opens a single pipe for these two nodes to communicate - // back and forth. One listens on it, the other talks to it. - - if (role == role_sender){ - radio.openWritingPipe(pipe); - }else{ - radio.openReadingPipe(pipe_number, pipe); - } - - // - // Start listening - // - - if (role == role_receiver){ - radio.startListening(); - } - - // - // Dump the configuration of the rf unit for debugging - // - - radio.printDetails(); - - // - // Attach interrupt handler to interrupt #0 (using pin 2) - // on BOTH the sender and receiver - // - - attachInterrupt(0, check_radio, FALLING); - delay(50); - if (role == role_receiver){ - printf("\n\r+OK "); - } -} - -// -// Print buffer -// -// Printing from the interrupt handler is a bad idea, so we print from there -// to this intermediate buffer -// - -char prbuf[1000]; -char* prbuf_end = prbuf + sizeof(prbuf); -char* prbuf_in = prbuf; -char* prbuf_out = prbuf; - -// -// Loop -// - -static uint32_t message_count = 0; -static uint32_t last_message_count = 0; - -void loop(void){ - // - // Sender role. Repeatedly send the current time - // - - if (role == role_sender && !done){ - // The payload will always be the same, what will change is how much of it we send. - static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012"; - - // First, stop listening so we can talk. - radio.stopListening(); - - // Send it. This will block until complete - printf("\n\rNow sending length %i...", next_payload_size); - radio.startWrite(send_payload, next_payload_size, 0); - - // Update size for next time. - next_payload_size += payload_size_increments_by; - if (next_payload_size > max_payload_size){ - next_payload_size = min_payload_size; - } - - // Try again soon - delay(interval); - - // Timeout if we have not received anything back ever - if (!last_message_count && millis() > interval * 100){ - printf("No responses received. Are interrupts connected??\n\r"); - done = true; - } - } - - // - // Receiver role: Does nothing! All the work is in IRQ - // - - // - // Spew print buffer - // - - size_t write_length = prbuf_in - prbuf_out; - if (write_length){ - Serial.write(reinterpret_cast(prbuf_out), write_length); - prbuf_out += write_length; - } - - // - // Stop the test if we're done and report results - // - if (done && !notified){ - notified = true; - - printf("\n\r+OK "); - if (passed){ - printf("PASS\n\r\n\r"); - }else{ - printf("FAIL\n\r\n\r"); - } - } -} - -void check_radio(void) -{ - // What happened? - bool tx, fail, rx; - radio.whatHappened(tx, fail, rx); - - // Have we successfully transmitted? - if (tx){ - if (role == role_sender){ - prbuf_in += sprintf(prbuf_in, "Send:OK "); - } - - if (role == role_receiver){ - prbuf_in += sprintf(prbuf_in, "Ack Payload:Sent\n\r"); - } - } - - // Have we failed to transmit? - if (fail){ - if (role == role_sender){ - prbuf_in += sprintf(prbuf_in, "Send:Failed "); - - // log status of this line - one_failed(); - } - - if (role == role_receiver){ - prbuf_in += sprintf(prbuf_in, "Ack Payload:Failed\n\r"); - } - } - - // Not powering down since radio is in standby mode - //if (( tx || fail ) && ( role == role_sender )){ radio.powerDown(); } - - // Did we receive a message? - if (rx){ - // If we're the sender, we've received an ack payload - if (role == role_sender){ - radio.read(&message_count, sizeof(message_count)); - prbuf_in += sprintf(prbuf_in, "Ack:%lu ", message_count); - - // is this ack what we were expecting? to account - // for failures, we simply want to make sure we get a - // DIFFERENT ack every time. - if ((message_count != last_message_count) || (configuration == '3' && message_count == 16)){ - prbuf_in += sprintf(prbuf_in, "OK "); - one_ok(); - }else{ - prbuf_in += sprintf(prbuf_in, "FAILED "); - one_failed(); - } - last_message_count = message_count; - } - - // If we're the receiver, we've received a time message - if (role == role_receiver){ - // Get this payload and dump it - size_t len = max_payload_size; - memset(receive_payload, 0, max_payload_size); - - if (configuration == '3'){ - len = next_payload_size; - }else{ - len = radio.getDynamicPayloadSize(); - } - - radio.read(receive_payload, len); - - // Put a zero at the end for easy printing - receive_payload[len] = 0; - - // Spew it - prbuf_in += sprintf(prbuf_in, "Recv size=%i val=%s len=%u\n\r", len, receive_payload, strlen(receive_payload)); - - // Add an ack packet for the next time around. - // Here we will report back how many bytes we got this time. - radio.writeAckPayload(pipe_number, &len, sizeof(len)); - - ++message_count; - } - } -} diff --git a/tests/pingpair_test/printf.h b/tests/pingpair_test/printf.h deleted file mode 100644 index e460ff0ab..000000000 --- a/tests/pingpair_test/printf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2011 J. Coliz - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - */ - -/** - * @file printf.h - * - * Setup necessary to direct stdout to the Arduino Serial library, which - * enables 'printf' - */ - -#ifndef __PRINTF_H__ -#define __PRINTF_H__ - -#ifdef ARDUINO - -int serial_putc( char c, FILE * ) -{ - Serial.write( c ); - - return c; -} - -void printf_begin(void) -{ - fdevopen( &serial_putc, 0 ); -} - -#else - #error This example is only for use on Arduino. -#endif // ARDUINO - -#endif // __PRINTF_H__ diff --git a/tests/pingpair_test/runtest.py b/tests/pingpair_test/runtest.py deleted file mode 100755 index d9d2e0858..000000000 --- a/tests/pingpair_test/runtest.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/opt/local/bin/python - -import sys, serial - - -def read_until(token): - while 1: - line = ser.readline(None, "\r") - sys.stdout.write(line) - - if (line.startswith(token)): - break - return line - - -ser = serial.Serial(sys.argv[1], 57600, timeout=5, dsrdtr=False, rtscts=False) - -read_until("+READY") -ser.write(sys.argv[2]) - -line = read_until("+OK") -ser.close() -if (line.find("PASS") != -1): - sys.exit(0) -else: - sys.exit(1) diff --git a/tests/pingpair_test/runtests.sh b/tests/pingpair_test/runtests.sh deleted file mode 100755 index 4d02310b9..000000000 --- a/tests/pingpair_test/runtests.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -# Connect u0 to receiver, u0 to sender -# WARNING: Test config 2 only works with PLUS units. - -jam u0 u1 && expect test.ex 1 -sleep 1 -stty 57600 raw ignbrk hup < /dev/ttyUSB0 -sleep 1 -stty 57600 raw ignbrk hup < /dev/ttyUSB1 -expect test.ex 2 -sleep 1 -stty 57600 raw ignbrk hup < /dev/ttyUSB0 -sleep 1 -stty 57600 raw ignbrk hup < /dev/ttyUSB1 -expect test.ex 3 -sleep 1 -stty 57600 raw ignbrk hup < /dev/ttyUSB0 -sleep 1 -stty 57600 raw ignbrk hup < /dev/ttyUSB1 -expect test.ex 4 diff --git a/tests/pingpair_test/test.ex b/tests/pingpair_test/test.ex deleted file mode 100755 index a14ffef07..000000000 --- a/tests/pingpair_test/test.ex +++ /dev/null @@ -1,11 +0,0 @@ -#/usr/bin/expect - -set timeout 100 -spawn picocom -b 57600 /dev/ttyUSB0 -expect "+READY" -send [lindex $argv 0] -expect "+OK" -spawn picocom -b 57600 /dev/ttyUSB1 -expect "+READY" -send [lindex $argv 0] -expect "+OK" diff --git a/utility/CMakeLists.txt b/utility/CMakeLists.txt new file mode 100644 index 000000000..0ad11f50a --- /dev/null +++ b/utility/CMakeLists.txt @@ -0,0 +1,102 @@ +########################### +### declare the appropriate sources and install rules based on driver selected +########################### +if ("${RF24_DRIVER}" STREQUAL "wiringPi") # Use wiringPi + set(RF24_LINKED_DRIVER ${LibWiringPi} PARENT_SCOPE) + add_compile_options(-pthread) + set(RF24_DRIVER_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/spi.cpp + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/RF24_arch_config.h + PARENT_SCOPE + ) + install(FILES + ${RF24_DRIVER}/includes.h + ${RF24_DRIVER}/spi.h + ${RF24_DRIVER}/RF24_arch_config.h + DESTINATION include/RF24/utility/${RF24_DRIVER} + ) +elseif("${RF24_DRIVER}" STREQUAL "RPi") # use RPi + set(RF24_DRIVER_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/bcm2835.c + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/spi.cpp + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/compatibility.cpp + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/RF24_arch_config.h + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/interrupt.cpp + PARENT_SCOPE + ) + install(FILES + ${RF24_DRIVER}/includes.h + ${RF24_DRIVER}/bcm2835.h + ${RF24_DRIVER}/spi.h + ${RF24_DRIVER}/compatibility.h + ${RF24_DRIVER}/RF24_arch_config.h + ${RF24_DRIVER}/interrupt.h + DESTINATION include/RF24/utility/${RF24_DRIVER} + ) +elseif("${RF24_DRIVER}" STREQUAL "SPIDEV") # use SPIDEV + if(NOT SPIDEV_EXISTS) + message(WARNING "Detecting /dev/spidev0.0 failed - continuing anyway. Please make sure SPI is enabled.") + endif() + set(RF24_DRIVER_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/gpio.cpp + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/spi.cpp + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/compatibility.cpp + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/RF24_arch_config.h + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/interrupt.cpp + PARENT_SCOPE + ) + install(FILES + ${RF24_DRIVER}/includes.h + ${RF24_DRIVER}/gpio.h + ${RF24_DRIVER}/spi.h + ${RF24_DRIVER}/compatibility.h + ${RF24_DRIVER}/RF24_arch_config.h + ${RF24_DRIVER}/interrupt.h + DESTINATION include/RF24/utility/${RF24_DRIVER} + ) +elseif("${RF24_DRIVER}" STREQUAL "MRAA") # use MRAA + set(RF24_LINKED_DRIVER ${LibMRAA} PARENT_SCOPE) + set(RF24_DRIVER_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/gpio.cpp + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/spi.cpp + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/compatibility.cpp + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/RF24_arch_config.h + PARENT_SCOPE + ) + install(FILES + ${RF24_DRIVER}/includes.h + ${RF24_DRIVER}/gpio.h + ${RF24_DRIVER}/spi.h + ${RF24_DRIVER}/compatibility.h + ${RF24_DRIVER}/RF24_arch_config.h + DESTINATION include/RF24/utility/${RF24_DRIVER} + ) +elseif("${RF24_DRIVER}" STREQUAL "LittleWire") # use LittleWire + set(RF24_LINKED_DRIVER ${LibLittleWire} PARENT_SCOPE) + set(RF24_DRIVER_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/RF24_arch_config.h + PARENT_SCOPE + ) + install(FILES + ${RF24_DRIVER}/includes.h + ${RF24_DRIVER}/RF24_arch_config.h + DESTINATION include/RF24/utility/${RF24_DRIVER} + ) +else() # No valid/supported driver selected nor detected... this is vital + message(FATAL_ERROR "No valid/supported driver selected or auto-detection failed to resolve one. + Please specify 1 of the following supported drivers (ie `-D RF24_DRIVER=SPIDEV`): + \twiringPi + \tRPi + \tSPIDEV + \tMRAA + \tLittleWire" + ) +endif() + +# copy the includes file to the project source directory's utility folder +execute_process(COMMAND cp ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h ${CMAKE_CURRENT_LIST_DIR}/includes.h) diff --git a/utility/MRAA/gpio.cpp b/utility/MRAA/gpio.cpp index f5c7c3c6c..12c01d87f 100644 --- a/utility/MRAA/gpio.cpp +++ b/utility/MRAA/gpio.cpp @@ -1,6 +1,6 @@ -/* +/* * TMRh20 2015 - * + * */ #include "gpio.h" @@ -36,7 +36,8 @@ void GPIO::open(int port, int DDR) { if (port == gpio_ce_pin) { gpio_0 = new mraa::Gpio(port, 0); - gpio_0->useMmap(true); + // WARNING: use of memory mapped file system is deprecated in MRAA lib + gpio_0->useMmap(true); // `false` (or just not calling `useMmap()`) uses default file system? gpio_0->dir((mraa::Dir) DDR); }/*else if(port == gpio_cs_pin){ diff --git a/utility/MRAA/gpio.h b/utility/MRAA/gpio.h index e30935a6a..e00624ecb 100644 --- a/utility/MRAA/gpio.h +++ b/utility/MRAA/gpio.h @@ -50,10 +50,10 @@ class GPIO { int read(int port); /** - * - * @param port - * @param value - */ + * + * @param port + * @param value + */ void write(int port, int value); private: @@ -66,4 +66,3 @@ class GPIO { * @endcond */ #endif /* RF24_ARCH_GPIO_H */ - diff --git a/utility/RPi/interrupt.c b/utility/RPi/interrupt.cpp similarity index 100% rename from utility/RPi/interrupt.c rename to utility/RPi/interrupt.cpp diff --git a/utility/SPIDEV/compatibility.cpp b/utility/SPIDEV/compatibility.cpp index b1b9cee36..6ba649233 100644 --- a/utility/SPIDEV/compatibility.cpp +++ b/utility/SPIDEV/compatibility.cpp @@ -32,7 +32,7 @@ void __usleep(int microsec) * This function is added in order to simulate arduino millis() function */ -bool timerStarted = false; +bool timerStarted = false; void __start_timer() { @@ -43,9 +43,8 @@ auto start = std::chrono::steady_clock::now(); uint32_t __millis() { - + auto end = std::chrono::steady_clock::now(); - + return std::chrono::duration_cast(end - start).count(); } - diff --git a/utility/SPIDEV/gpio.h b/utility/SPIDEV/gpio.h index 2209dc555..cc5a7b208 100644 --- a/utility/SPIDEV/gpio.h +++ b/utility/SPIDEV/gpio.h @@ -10,7 +10,7 @@ */ #ifndef H -#define H +#define H #include #include diff --git a/utility/SPIDEV/interrupt.c b/utility/SPIDEV/interrupt.cpp similarity index 100% rename from utility/SPIDEV/interrupt.c rename to utility/SPIDEV/interrupt.cpp diff --git a/utility/Template/gpio.h b/utility/Template/gpio.h index 47a954c07..1f03a0ab3 100644 --- a/utility/Template/gpio.h +++ b/utility/Template/gpio.h @@ -15,7 +15,11 @@ #include -// class GPIO { +#ifndef DOXYGEN_FORCED +// exclude this line from the docs to prevent displaying in the list of classes +class GPIO +#endif +{ public: /* Constants */ static const int DIRECTION_OUT = 1; @@ -52,7 +56,10 @@ */ static void write(int port, int value); +#ifndef DOXYGEN_FORCED +// exclude this line from the docs to prevent warnings docs generators virtual ~ GPIO(); +#endif }; -/**@}*/ \ No newline at end of file +/**@}*/ diff --git a/utility/Template/spi.h b/utility/Template/spi.h index 8b1ce7eaf..d0813a120 100644 --- a/utility/Template/spi.h +++ b/utility/Template/spi.h @@ -24,7 +24,11 @@ using namespace std; -// class SPI { +#ifndef DOXYGEN_FORCED +// exclude this line from the docs to prevent displaying in the list of classes +class SPI +#endif +{ public: /** @@ -59,8 +63,10 @@ using namespace std; */ void transfern(char* buf, uint32_t len); +#ifndef DOXYGEN_FORCED +// exclude this line from the docs to prevent warnings docs generators virtual ~ SPI(); - +#endif private: /** Default SPI device */ @@ -77,4 +83,4 @@ using namespace std; }; -/**@}*/ \ No newline at end of file +/**@}*/ diff --git a/utility/rp2/CMakeLists.txt b/utility/rp2/CMakeLists.txt new file mode 100644 index 000000000..ccc115cf5 --- /dev/null +++ b/utility/rp2/CMakeLists.txt @@ -0,0 +1,21 @@ +## Include this file if you want to use the RF24 library +## in YOUR (Pico) project. +## See examples_pico/CMakeLists.txt to see how it could be done + +cmake_minimum_required(VERSION 3.12) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + +# Define the RF24 core library +add_library(RF24 INTERFACE) + +target_sources(RF24 INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/../../RF24.cpp + ${CMAKE_CURRENT_LIST_DIR}/gpio.cpp + ${CMAKE_CURRENT_LIST_DIR}/spi.cpp +) + +target_include_directories(RF24 INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/../../ +) diff --git a/utility/rp2/RF24_arch_config.h b/utility/rp2/RF24_arch_config.h new file mode 100644 index 000000000..13c16aa49 --- /dev/null +++ b/utility/rp2/RF24_arch_config.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) + * 2021 Jannis Achstetter (kripton) + * 2021 Brendan Doherty (2bndy5) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +/** + * @file RF24_arch_config.h + * General defines and includes for RF24 using The Pico SDK + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +#include "spi.h" +#include "gpio.h" +#include + +/** Define a specific platform name for this configuration */ +#define RF24_RP2 + +#define _BV(x) (1 << (x)) +#define _SPI SPI +#define RF24_SPI_PTR + +static SPI spi; + +#ifdef SERIAL_DEBUG + #define IF_SERIAL_DEBUG(x) ({x;}) +#else + #define IF_SERIAL_DEBUG(x) +#endif + +typedef uint16_t prog_uint16_t; +#define PSTR(x) (x) +#define printf_P printf +#define strlen_P strlen +#define PROGMEM +#define pgm_read_word(p) (*(p)) +#define PRIPSTR "%s" +#define pgm_read_byte(p) (*(p)) + +#define pgm_read_ptr(p) (*(p)) + +// Function, constant map as a result of migrating from Arduino +#define LOW GPIO::OUTPUT_LOW +#define HIGH GPIO::OUTPUT_HIGH +#define INPUT GPIO::DIRECTION_IN +#define OUTPUT GPIO::DIRECTION_OUT +#define digitalWrite(pin, value) GPIO::write(pin, value) +#define pinMode(pin, direction) GPIO::open(pin, direction) +#define delay(milisec) sleep_ms(milisec) +#define delayMicroseconds(usec) sleep_us(usec) +#define millis() to_ms_since_boot(get_absolute_time()) + +#endif // __ARCH_CONFIG_H__ + +/**@}*/ diff --git a/utility/rp2/gpio.cpp b/utility/rp2/gpio.cpp new file mode 100644 index 000000000..b6d11d4fe --- /dev/null +++ b/utility/rp2/gpio.cpp @@ -0,0 +1,26 @@ +#include "gpio.h" + +GPIO::GPIO() +{ +} + +void GPIO::open(int port, int DDR) { + gpio_init(port); + gpio_set_dir(port, DDR); +} + +void GPIO::close(int port) { + gpio_init(port); +} + +int GPIO::read(int port) { + return gpio_get(port); +} + +void GPIO::write(int port, int value) { + gpio_put(port, value); +} + +GPIO::~GPIO() +{ +} diff --git a/utility/rp2/gpio.h b/utility/rp2/gpio.h new file mode 100644 index 000000000..3ef265f64 --- /dev/null +++ b/utility/rp2/gpio.h @@ -0,0 +1,57 @@ +/** + * @file gpio.h + * Class declaration for SPI helper files + */ + +/** + * Example of gpio.h class declaration for GPIO portability + * + * @defgroup Porting_GPIO Porting: GPIO + * + * @{ + */ + +#include +#include "pico/stdlib.h" + +class GPIO { +public: + /* Constants */ + static const int DIRECTION_OUT = 1; + static const int DIRECTION_IN = 0; + + static const int OUTPUT_HIGH = 1; + static const int OUTPUT_LOW = 0; + + GPIO(); + + /** + * Similar to Arduino pinMode(pin,mode); + * @param port + * @param DDR + */ + static void open(int port, int DDR); + + /** + * + * @param port + */ + static void close(int port); + + /** + * Similar to Arduino digitalRead(pin); + * @param port + */ + static int read(int port); + + /** + * Similar to Arduino digitalWrite(pin,state); + * @param port + * @param value + */ + static void write(int port, int value); + + virtual ~ GPIO(); +}; + +/**@}*/ diff --git a/utility/rp2/spi.cpp b/utility/rp2/spi.cpp new file mode 100644 index 000000000..f60945198 --- /dev/null +++ b/utility/rp2/spi.cpp @@ -0,0 +1,52 @@ +#include "spi.h" + +spi_inst_t* SPI::_hw_id; + +SPI::SPI() +{ +} + +void SPI::begin(spi_inst_t* hw_id) +{ + begin(hw_id, PICO_DEFAULT_SPI_SCK_PIN, PICO_DEFAULT_SPI_TX_PIN, PICO_DEFAULT_SPI_RX_PIN); +} + +void SPI::begin(spi_inst_t* hw_id, uint8_t _sck, uint8_t _tx, uint8_t _rx) +{ + _hw_id = hw_id; + gpio_set_function(_sck, GPIO_FUNC_SPI); + gpio_set_function(_tx, GPIO_FUNC_SPI); + gpio_set_function(_rx, GPIO_FUNC_SPI); +} + +uint8_t SPI::transfer(uint8_t tx_) +{ + uint8_t recv = 0; + spi_write_read_blocking(_hw_id, &tx_, &recv, 1); + return recv; +} + +void SPI::transfernb(const uint8_t* tbuf, uint8_t* rbuf, uint32_t len) +{ + spi_write_read_blocking(_hw_id, tbuf, rbuf, len); +} + +void SPI::transfern(const uint8_t* buf, uint32_t len) +{ + spi_write_blocking(_hw_id, buf, len); +} + +void SPI::beginTransaction(uint32_t _spi_speed) +{ + spi_init(_hw_id, _spi_speed); + spi_set_format(_hw_id, RF24_SPI_BYTE_SIZE, RF24_SPI_CPOL, RF24_SPI_CPHA, RF24_SPI_ENDIAN); +} + +void SPI::endTransaction() +{ + spi_deinit(_hw_id); +} + +SPI::~SPI() +{ +} diff --git a/utility/rp2/spi.h b/utility/rp2/spi.h new file mode 100644 index 000000000..4c545a692 --- /dev/null +++ b/utility/rp2/spi.h @@ -0,0 +1,91 @@ +/** + * @file spi.h + * Class declaration for SPI wrapping the Pico SDK + */ +#include +#include "pico/stdlib.h" +#include "hardware/spi.h" + +#define RF24_SPI_BYTE_SIZE 8 +#define RF24_SPI_ENDIAN SPI_MSB_FIRST +#define RF24_SPI_CPHA SPI_CPHA_0 +#define RF24_SPI_CPOL SPI_CPOL_0 + +// this SPI class uses beginTransaction() & endTransaction() to +// implement spi_init() & spi_deinit() +#define SPI_HAS_TRANSACTION 1 + +class SPI { +public: + + /** + * SPI constructor + */ + SPI(); + + /** + * Start SPI + * @param hw_id This is either `spi0` or `spi1` (provided by the Pico SDK) + * + * @note this function assumes using the default SPI pins defined for your + * board in "pico-sdk/src/boards/include/boards/*.h" files of the Pico SDK. + * @see begin(spi_inst_t, uint8_t, uint8_t, uint8_t) for using other pins as + * your SPI bus. + */ + static void begin(spi_inst_t* hw_id); + + /** + * Start SPI + * @param hw_id This is either `spi0` or `spi1` (provided by the Pico SDK) + * @param _sck The pin to be used as the SPI bus' sck + * @param _tx The pin to be used as the SPI bus' tx (MOSI) + * @param _rx The pin to be used as the SPI bus' rx (MISO) + * + * @note this function assumes using the default SPI pins defined for your + * board in "pico-sdk/src/boards/include/boards/*.h" files of the Pico SDK. + * @see The [Pico SDK has a chart of applicable pins](https://datasheets.raspberrypi.org/pico/raspberry-pi-pico-c-sdk.pdf#%5B%7B%22num%22%3A106%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C115%2C377.118%2Cnull%5D) + * that can be used for hardware driven SPI transactions. + */ + static void begin(spi_inst_t* hw_id, uint8_t _sck, uint8_t _tx, uint8_t _rx); + + /** + * Transfer a single byte + * @param tx_ Byte to send + * @return Data returned via spi + */ + static uint8_t transfer(uint8_t tx_); + + /** + * Transfer a buffer of data + * @param tbuf Transmit buffer + * @param rbuf Receive buffer + * @param len Length of the data + */ + static void transfernb(const uint8_t* tbuf, uint8_t* rbuf, uint32_t len); + + /** + * Transfer a buffer of data without an rx buffer + * @param buf Pointer to a buffer of data + * @param len Length of the data + */ + static void transfern(const uint8_t* buf, uint32_t len); + + /** + * init the SPI bus (using hw_id passed to begin()) + * @param _spi_speed The frequency to use for SPI transactions with the radio. + */ + static void beginTransaction(uint32_t _spi_speed); + + /** deinit the SPI bus (using hw_id passed to begin()) */ + static void endTransaction(); + + virtual ~ SPI(); + +private: + + /** the ID of the hardware driven SPI bus */ + static spi_inst_t* _hw_id; + +}; + +/**@}*/ diff --git a/wikidoc.xslt b/wikidoc.xslt deleted file mode 100644 index 6a3d61363..000000000 --- a/wikidoc.xslt +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - === === - - - - - - - '''' - - - Parameters: - - - * '''': - - - - - - - Returns: - - * - - - - Warning: - - - - <pre> - - </pre> - - - - - - -