diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 49d358d7..0258df19 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,7 +11,7 @@ assignees: '' Before submitting new issue, please check the [Wiki](https://github.com/jgromes/RadioLib/wiki) and the [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. **Describe the bug** -A clear and concise description of what the bug is. When applicable, please include debug mode output: uncomment [debug macro definitions in BuildOpt.h](https://github.com/jgromes/RadioLib/blob/master/src/BuildOpt.h#L135) and post the output. +A clear and concise description of what the bug is. When applicable, please include [debug mode output](https://github.com/jgromes/RadioLib/wiki/Debug-mode). **To Reproduce** Minimal Arduino sketch to reproduce the behavior. Please user Markdown to style the code to make it readable (see [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code)). @@ -24,6 +24,7 @@ If applicable, add screenshots to help explain your problem. **Additional info (please complete):** - MCU: [e.g. Arduino Uno, ESP8266 etc.] + - Link to Arduino core: [e.g. https://github.com/stm32duino/Arduino_Core_STM32 when using official STM32 core. See readme for links to all supported cores] - Wireless module type [e.g. CC1101, SX1268, etc.] - Arduino IDE version [e.g. 1.8.5] - Library version [e.g. 3.0.0] diff --git a/.github/ISSUE_TEMPLATE/module-not-working.md b/.github/ISSUE_TEMPLATE/module-not-working.md new file mode 100644 index 00000000..1b67e8d6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/module-not-working.md @@ -0,0 +1,34 @@ +--- +name: Module not working +about: Template to use when your module isn't working +title: '' +labels: '' +assignees: '' + +--- + +**IMPORTANT: Before submitting an issue, please check the following:** +1. **Read [CONTRIBUTING.md](https://github.com/jgromes/RadioLib/blob/master/CONTRIBUTING.md)!** Issues that do not follow this document will be closed/locked/deleted/ignored. +2. RadioLib has a [Wiki](https://github.com/jgromes/RadioLib/wiki) and an extensive [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. +3. Make sure you're using the latest release of the library! Releases can be found [here](https://github.com/jgromes/RadioLib/releases). +4. Use [Arduino forums](https://forum.arduino.cc/) to ask generic questions about wireless modules, wiring, usage, etc. Only create issues for problems specific to RadioLib! +5. Error codes, their meaning and how to fix them can be found on [this page](https://jgromes.github.io/RadioLib/group__status__codes.html). + +**Sketch that is causing the module fail** + +```c++ +paste the sketch here, even if it is an unmodified example code +``` + +**Hardware setup** +Wiring diagram, schematic, pictures etc. + +**Debug mode output** +Enable all [debug levels](https://github.com/jgromes/RadioLib/wiki/Debug-mode) and paste the Serial monitor output here. + +**Additional info (please complete):** + - MCU: [e.g. Arduino Uno, ESP8266 etc.] + - Link to Arduino core: [e.g. https://github.com/stm32duino/Arduino_Core_STM32 when using official STM32 core. See readme for links to all supported cores] + - Wireless module type [e.g. CC1101, SX1268, etc.] + - Arduino IDE version [e.g. 1.8.5] + - Library version [e.g. 3.0.0] diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..d95c71d9 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,66 @@ +name: "CodeQL" + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: ['cpp'] + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + + - name: Install arduino-cli + run: + | + mkdir -p ~/.local/bin + echo "~/.local/bin" >> $GITHUB_PATH + curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=~/.local/bin sh + + - name: Install platform + run: + | + arduino-cli core update-index + arduino-cli core install arduino:avr + + - name: Static link + run: + | + # static link fix from https://github.com/github/securitylab/discussions/171 + for i in ~/.arduino*/packages/arduino/tools/avr-gcc/*/bin/*; do + mv "$i" "$i.real"; + printf '#!/bin/bash\nexec "'"$i"'.real" ${1+"$@"}\n' > "$i"; + chmod +x "$i"; + done + + - name: Build example + run: + arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn arduino:avr:uno $PWD/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino --warnings=all + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml new file mode 100644 index 00000000..ae645667 --- /dev/null +++ b/.github/workflows/doxygen.yml @@ -0,0 +1,26 @@ +name: Doxygen + +on: + push: + branches: [ master ] + workflow_dispatch: + +jobs: + doxygen: + runs-on: ubuntu-latest + steps: + - name: Install Doxygen + run: | + sudo apt-get update + sudo apt-get install -y doxygen + - uses: actions/checkout@v2 + + - name: Generate docs + run: doxygen Doxyfile + + - name: Deploy to GitHub Pages + uses: JamesIves/github-pages-deploy-action@releases/v3 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: gh-pages + FOLDER: docs/html diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..cb291490 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,162 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + workflow_dispatch: + +jobs: + + build: + strategy: + matrix: + board: + - arduino:avr:uno + - arduino:avr:mega + - arduino:avr:leonardo + - arduino:mbed:nano33ble + - arduino:mbed:envie_m4 + - arduino:megaavr:uno2018 + - arduino:sam:arduino_due_x + - arduino:samd:arduino_zero_native + - adafruit:samd:adafruit_feather_m0 + - adafruit:nrf52:feather52832 + - esp32:esp32:esp32 + - esp8266:esp8266:generic + - Intel:arc32:arduino_101 + - SparkFun:apollo3:sfe_artemis + - STM32:stm32:GenF3 + - stm32duino:STM32F1:mapleMini + - MegaCoreX:megaavr:4809 + + runs-on: ubuntu-latest + name: ${{ matrix.board }} + env: + run-build: ${{ (matrix.board == 'arduino:avr:uno') || contains(github.event.head_commit.message, 'CI_BUILD_ALL') || contains(github.event.head_commit.message, 'Bump version to') || contains(github.event.head_commit.message, format('{0}', matrix.board)) }} + + steps: + - name: Install arduino-cli + if: ${{ env.run-build == 'true' }} + run: + | + mkdir -p ~/.local/bin + echo "~/.local/bin" >> $GITHUB_PATH + curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=~/.local/bin sh + + - name: Get platform name + if: ${{ env.run-build == 'true' }} + uses: jungwinter/split@v1 + id: split + with: + msg: ${{ matrix.board }} + seperator: ':' + + - name: Prepare platform-specific settings + if: ${{ env.run-build == 'true' }} + id: prep + run: + | + # common settings - no extra options, skip nothing, all warnings + echo "::set-output name=options::" + echo "::set-output name=skip-pattern::''" + echo "::set-output name=warnings::'all'" + + # platform-dependent settings - extra board options, board index URLs, skip patterns etc. + if [[ "${{ contains(matrix.board, 'arduino:avr:mega') }}" == "true" ]]; then + # Arduino Mega + echo "::set-output name=options:::cpu=atmega2560" + + elif [[ "${{ contains(matrix.board, 'arduino:mbed') }}" == "true" ]]; then + # Arduino Nano 33 BLE + echo "::set-output name=skip-pattern::(HTTP|MQTT).*ino" + + elif [[ "${{ contains(matrix.board, 'arduino-beta:mbed') }}" == "true" ]]; then + # Arduino Portenta H7 + echo "::set-output name=skip-pattern::(HTTP|MQTT).*ino" + + elif [[ "${{ contains(matrix.board, 'arduino:megaavr:uno2018') }}" == "true" ]]; then + # Arduino Uno WiFi + echo "::set-output name=options:::mode=on" + + elif [[ "${{ contains(matrix.board, 'adafruit:samd') }}" == "true" ]]; then + # Adafruit SAMD + echo "::set-output name=options:::usbstack=arduino,debug=off" + echo "::set-output name=index-url::--additional-urls https://www.adafruit.com/package_adafruit_index.json" + + elif [[ "${{ contains(matrix.board, 'adafruit:nrf52') }}" == "true" ]]; then + # Adafruit Feather nRF52 + sudo apt-get update + sudo apt-get install -y python3 python3-pip python3-setuptools + pip3 install wheel + pip3 install --user adafruit-nrfutil + echo "/home/runner/.local/bin" >> $GITHUB_PATH + echo "::set-output name=options:::softdevice=s132v6,debug=l0" + echo "::set-output name=index-url::--additional-urls https://www.adafruit.com/package_adafruit_index.json" + + elif [[ "${{ contains(matrix.board, 'esp32:esp32') }}" == "true" ]]; then + # ESP32 + python -m pip install pyserial + echo "::set-output name=index-url::--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" + + elif [[ "${{ contains(matrix.board, 'esp8266:esp8266') }}" == "true" ]]; then + # ESP8266 + echo "::set-output name=options:::xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K" + echo "::set-output name=index-url::--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" + echo "::set-output name=skip-pattern::(HTTP|MQTT).*ino" + + elif [[ "${{ contains(matrix.board, 'SparkFun:apollo3') }}" == "true" ]]; then + # SparkFun Apollo + echo "::set-output name=index-url::--additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json" + echo "::set-output name=warnings::'none'" + echo "::set-output name=skip-pattern::(HTTP|MQTT).*ino" + + elif [[ "${{ contains(matrix.board, 'STM32:stm32') }}" == "true" ]]; then + # STM32 (official core) + echo "::set-output name=options:::pnum=BLACKPILL_F303CC" + echo "::set-output name=index-url::--additional-urls https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json" + + elif [[ "${{ contains(matrix.board, 'stm32duino:STM32F1') }}" == "true" ]]; then + # STM32 (unofficial core) + echo "::set-output name=options:::bootloader_version=original,cpu_speed=speed_72mhz" + echo "::set-output name=index-url::--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" + + elif [[ "${{ contains(matrix.board, 'MegaCoreX:megaavr') }}" == "true" ]]; then + # MegaCoreX + echo "::set-output name=index-url::--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" + + fi + + - name: Install platform + if: ${{ env.run-build == 'true' }} + run: + | + arduino-cli core update-index ${{ format('{0}', steps.prep.outputs.index-url) }} + arduino-cli core install ${{ format('{0}:{1} {2}', steps.split.outputs._0, steps.split.outputs._1, steps.prep.outputs.index-url) }} + + - name: Checkout repository + if: ${{ env.run-build == 'true' }} + uses: actions/checkout@v2 + + - name: Build examples + if: ${{ env.run-build == 'true' }} + run: + | + for example in $(find $PWD/examples -name '*.ino' | sort); do + # check whether to skip this sketch + if [ ! -z '${{ steps.prep.outputs.skip-pattern }}' ] && [[ ${example} =~ ${{ steps.prep.outputs.skip-pattern }} ]]; then + # skip sketch + echo -e "\n\033[1;33mSkipped ${example##*/} (matched with ${{ steps.prep.outputs.skip-pattern }})\033[0m"; + else + # build sketch + echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m"; + arduino-cli compile --libraries /home/runner/work/RadioLib --fqbn ${{ matrix.board }}${{ steps.prep.outputs.options }} $example --warnings=${{ steps.prep.outputs.warnings }} + if [ $? -ne 0 ]; then + echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n"; + exit 1; + else + echo -e "\033[1;32m${example##*/} build PASSED\033[0m\n"; + fi + fi + done diff --git a/.gitignore b/.gitignore index 3f9ff239..591da307 100644 --- a/.gitignore +++ b/.gitignore @@ -1,42 +1,10 @@ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - # Arduino Library Development file .development -# Arduino testing sketches -examples/test/ - # Atom *.tags *.tags1 + +# Debug decoder +extras/decoder/log.txt +extras/decoder/out.txt diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8e36b9cb..00000000 --- a/.travis.yml +++ /dev/null @@ -1,95 +0,0 @@ -env: - global: - - ARDUINO_IDE_VERSION="1.8.9" - matrix: - # see https://github.com/arduino/Arduino/blob/master/build/shared/manpage.adoc#options - # and https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5-3rd-party-Hardware-specification#boardstxt - - BOARD="esp32:esp32:esp32" - - BOARD="STM32:stm32:GenF3:pnum=BLACKPILL_F303CC" - - BOARD="esp8266:esp8266:generic:xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K" - # - BOARD="SparkFun:apollo3:amap3redboard" - - BOARD="arduino:samd:arduino_zero_native" - - BOARD="arduino:sam:arduino_due_x" - - BOARD="arduino:avr:uno" - - BOARD="arduino:avr:leonardo" - - BOARD="arduino:avr:mega:cpu=atmega2560" - -before_install: - # install Arduino IDE - - wget https://downloads.arduino.cc/arduino-$ARDUINO_IDE_VERSION-linux64.tar.xz - - tar xf arduino-$ARDUINO_IDE_VERSION-linux64.tar.xz - - mv arduino-$ARDUINO_IDE_VERSION $HOME/arduino-ide - - export PATH=$PATH:$HOME/arduino-ide - - # firewall Arduino IDE noise (https://github.com/per1234/arduino-ci-script/issues/1#issuecomment-504158113) - - sudo iptables -P INPUT DROP - - sudo iptables -P FORWARD DROP - - sudo iptables -P OUTPUT ACCEPT - - sudo iptables -A INPUT -i lo -j ACCEPT - - sudo iptables -A OUTPUT -o lo -j ACCEPT - - sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT - - # install 3rd party boards - - arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json,https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json,https://raw.githubusercontent.com/sparkfun/Arduino_Boards/master/IDE_Board_Manager/package_sparkfun_index.json" --save-prefs 2>&1 - - if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then - arduino --install-boards esp8266:esp8266; - export SKIP_PAT='(HTTP|MQTT).*ino'; - elif [[ "$BOARD" =~ "esp32:esp32:" ]]; then - arduino --install-boards esp32:esp32; - elif [[ "$BOARD" =~ "STM32:stm32:" ]]; then - arduino --install-boards STM32:stm32; - elif [[ "$BOARD" =~ "arduino:samd:" ]]; then - arduino --install-boards arduino:samd; - elif [[ "$BOARD" =~ "arduino:sam:" ]]; then - arduino --install-boards arduino:sam; - elif [[ "$BOARD" =~ "SparkFun:apollo3:" ]]; then - arduino --install-boards SparkFun:apollo3; - fi - -# create directory to save the library and create symbolic link -install: - - mkdir -p $HOME/Arduino/libraries - - ln -s $PWD $HOME/Arduino/libraries/RadioLib - -# only build the master branch -branches: - only: - - master - -script: - # build all example sketches - - | - for example in $(find $PWD/examples -name '*.ino' | sort); do - # check whether to skip this sketch - if [ ! -z "$SKIP_PAT" ] && [[ ${example} =~ $SKIP_PAT ]]; then - # skip sketch - echo -e "\n\033[1;33mSkipped ${example##*/} (matched with $SKIP_PAT)\033[0m"; - else - # build sketch - echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m"; - arduino --verify --board $BOARD $example; - if [ $? -ne 0 ]; then - echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n"; - exit 1; - else - echo -e "\033[1;32m${example##*/} build PASSED\033[0m\n"; - fi - fi - done - - # generate Doxygen documentation (only for Arduino UNO) - - if [ $BOARD = "arduino:avr:uno" ]; then - sudo apt-get update; - sudo apt-get install -y doxygen; - doxygen Doxyfile; - fi - -# deploy Doxygen docs on master branch and only when building for Arduino UNO -deploy: - provider: pages - skip_cleanup: true - local_dir: docs/html - github_token: $GH_REPO_TOKEN - on: - branch: master - condition: $BOARD = "arduino:avr:uno" diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..1a32eacc --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Code of Conduct + +Don't be an a*shole. diff --git a/README.md b/README.md index 68122780..08c28fa7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# RadioLib ![Build Status](https://github.com/jgromes/RadioLib/workflows/CI/badge.svg) + ### _One radio library to rule them all!_ ## Universal wireless communication library for Arduino @@ -26,41 +28,65 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __XBee__ modules (S2B) ### Supported protocols and digital modes: -* __MQTT__ for modules: ESP8266 -* __HTTP__ for modules: ESP8266 -* __AX.25__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x -* [__RTTY__](https://www.sigidwiki.com/wiki/RTTY) for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x -* [__Morse Code__](https://www.sigidwiki.com/wiki/Morse_Code_(CW)) for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x -* [__SSTV__](https://www.sigidwiki.com/wiki/SSTV) for modules: SX127x, RFM9x, SX126x, RF69 and SX1231 -* [__Hellschreiber__](https://www.sigidwiki.com/wiki/Hellschreiber) for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +* __MQTT__ for modules: +ESP8266 +* __HTTP__ for modules: +ESP8266 +* __AX.25__ using 2-FSK or AFSK for modules: +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x +* [__RTTY__](https://www.sigidwiki.com/wiki/RTTY) using 2-FSK or AFSK for modules: +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +* [__Morse Code__](https://www.sigidwiki.com/wiki/Morse_Code_(CW)) using 2-FSK or AFSK for modules: +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +* [__SSTV__](https://www.sigidwiki.com/wiki/SSTV) using 2-FSK or AFSK for modules: +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x +* [__Hellschreiber__](https://www.sigidwiki.com/wiki/Hellschreiber) using 2-FSK or AFSK for modules: +SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x ### Supported platforms: -* __Arduino AVR__ - tested with hardware on Uno, Mega and Leonardo -* __ESP8266__ - tested with hardware on NodeMCU and Wemos D1 -* __ESP32__ - tested with hardware on ESP-WROOM-32 -* __STM32__ - tested with hardware on Nucleo L452RE-P -* __Arduino SAMD__ - Arduino Zero, Arduino MKR boards, M0 Pro etc. -* __Arduino SAM__ - Arduino Due -* __Adafruit nRF52__ - Adafruit Bluefruit Feather etc. -* _Intel Curie_ - Arduino 101 -* _Arduino megaAVR_ - Arduino Uno WiFi Rev.2 etc. -* _Apollo3_ - SparkFun Artemis Redboard etc. -* _Arduino nRF52_ - Arduino Nano 33 BLE +* __Arduino__ + * [__AVR__](https://github.com/arduino/ArduinoCore-avr) - Arduino Uno, Mega, Leonardo, Pro Mini, Nano etc. + * [__mbed__](https://github.com/arduino/ArduinoCore-mbed) - Arduino Nano 33 BLE and Arduino Portenta H7 + * [__megaAVR__](https://github.com/arduino/ArduinoCore-megaavr) - Arduino Uno WiFi Rev.2 and Nano Every + * [__SAM__](https://github.com/arduino/ArduinoCore-sam) - Arduino Due + * [__SAMD__](https://github.com/arduino/ArduinoCore-samd) - Arduino Zero, MKR boards, M0 Pro etc. -The list above is by no means exhaustive. Most of RadioLib code is independent of the used platform, so as long as your board is running some Arduino-compatible core, RadioLib should work. Compilation of all examples is tested for all platforms in __bold__ on each git push. Platforms in _italic_ are not tested on each push, but do compile and should be working. +* __Adafruit__ + * [__SAMD__](https://github.com/adafruit/ArduinoCore-samd) - Adafruit Feather M0 and M4 boards (Feather, Metro, Gemma, Trinket etc.) + * [__nRF52__](https://github.com/adafruit/Adafruit_nRF52_Arduino) - Adafruit Feather nRF528x, Bluefruit and CLUE + +* __Espressif__ + * [__ESP32__](https://github.com/espressif/arduino-esp32) - ESP32-based boards + * [__ESP8266__](https://github.com/esp8266/Arduino) - ESP8266-based boards + +* __Intel__ + * [__Curie__](https://github.com/arduino/ArduinoCore-arc32) - Arduino 101 + +* __SparkFun__ + * [__Apollo3__](https://github.com/sparkfun/Arduino_Apollo3) - Sparkfun Artemis Redboard + +* __ST Microelectronics__ + * [__STM32__ (official core)](https://github.com/stm32duino/Arduino_Core_STM32) - STM32 Nucleo, Discovery, Maple, BluePill, BlackPill etc. + * [__STM32__ (unofficial core)](https://github.com/rogerclarkmelbourne/Arduino_STM32) - STM32F1 and STM32F4-based boards + +* __MCUdude__ + * [__MegaCoreX__](https://github.com/MCUdude/MegaCoreX) - megaAVR-0 series (ATmega4809, ATmega3209 etc.) + +The list above is by no means exhaustive. Most of RadioLib code is independent of the used platform, so as long as your board is running some Arduino-compatible core, RadioLib should work. Compilation of all examples is tested for all platforms prior to releasing new version. ### In development: * __SIM800C__ GSM module * __LoRaWAN__ protocol for SX127x, RFM9x and SX126x modules +* __APRS__ protocol for all the modules that can transmit AX.25 * ___and more!___ ## Frequently Asked Questions ### Where should I start? -First of all, take a look at the [examples](https://github.com/jgromes/RadioLib/tree/master/examples) and the [Wiki](https://github.com/jgromes/RadioLib/wiki) - especially the [Basics](https://github.com/jgromes/RadioLib/wiki/Basics) page. There's a lot of useful information over there. Also, you should check out [RadioShield](https://github.com/jgromes/RadioShield) - open source Arduino shield that will allow you to easily connect any two wireless modules supported by RadioLib! +First of all, take a look at the [examples](https://github.com/jgromes/RadioLib/tree/master/examples) and the [Wiki](https://github.com/jgromes/RadioLib/wiki) - especially the [Basics](https://github.com/jgromes/RadioLib/wiki/Basics) page. There's a lot of useful information over there. If something isn't working as expected, try searching the [issues](https://github.com/jgromes/RadioLib/issues/). ### Help, my module isn't working! -The fastest way to get help is by creating an [issue](https://github.com/jgromes/RadioLib/issues/new?assignees=&labels=&template=bug_report.md&title=) using the appropriate template. It is also highly recommended to try running the examples first - their functionality is tested from time to time and they should work. Finally, RadioLib is still under development, which means that sometimes, backwards-incompatible changes might be introduced. Though these are kept at minimum, sometimes it is unavoidable. You can check the [release changelog](https://github.com/jgromes/RadioLib/releases) to find out if there's been such a major change recently. +The fastest way to get help is by creating an [issue](https://github.com/jgromes/RadioLib/issues/new/choose) using the appropriate template. It is also highly recommended to try running the examples first - their functionality is tested from time to time and they should work. Finally, RadioLib is still under development, which means that sometimes, backwards-incompatible changes might be introduced. Though these are kept at minimum, sometimes it is unavoidable. You can check the [release changelog](https://github.com/jgromes/RadioLib/releases) to find out if there's been such a major change recently. ### RadioLib doesn't support my module! What should I do? Start by creating new issue (if it doesn't exist yet). If you have some experience with Arduino and C/C++ in general, you can try to add the support yourself! Use the template files in `/extras/` folder to get started. This is by far the fastest way to implement new modules into RadioLib, since I can't be working on everything all the time. If you don't trust your programming skills enough to have a go at it yourself, don't worry. I will try to implement all requested modules, but it will take me a while. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..b43ea5c1 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +## Reporting a Vulnerability + +RadioLib is provided as-is without any warranty, and is not intended to be used in security-critical applications. However, if you discover a vulnerability within the library code, please report it to gromes.jan@gmail.com. diff --git a/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino b/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino new file mode 100644 index 00000000..29469f48 --- /dev/null +++ b/examples/AFSK/AFSK_Imperial_March/AFSK_Imperial_March.ino @@ -0,0 +1,94 @@ +/* + RadioLib AFSK Imperial March Example + + This example shows how to EXECUTE ORDER 66 + + Other modules that can be used for AFSK: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// include the melody +#include "melody.h" + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +AFSKClient audio(&radio, 5); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for AFSK + // (RF69, CC1101,, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[AFSK] Executing Order 66 ... ")); + + // calculate whole note duration + int wholenote = (60000 * 4) / 120; + + // iterate over the melody + for(unsigned int note = 0; note < sizeof(melody) / sizeof(melody[0]); note += 2) { + // calculate the duration of each note + int noteDuration = 0; + int divider = melody[note + 1]; + if(divider > 0) { + // regular note, just proceed + noteDuration = wholenote / divider; + } else if(divider < 0) { + // dotted notes are represented with negative durations!! + noteDuration = wholenote / abs(divider); + noteDuration *= 1.5; // increases the duration in half for dotted notes + } + + // we only play the note for 90% of the duration, leaving 10% as a pause + audio.tone(melody[note]); + delay(noteDuration*0.9); + audio.noTone(); + delay(noteDuration*0.1); + } + + Serial.println(F("done!")); + + // wait for a second + delay(1000); +} diff --git a/examples/AFSK/AFSK_Imperial_March/melody.h b/examples/AFSK/AFSK_Imperial_March/melody.h new file mode 100644 index 00000000..e4b15169 --- /dev/null +++ b/examples/AFSK/AFSK_Imperial_March/melody.h @@ -0,0 +1,128 @@ +/* + Note definitions, melody and melody-related functions + adapted from https://github.com/robsoncouto/arduino-songs + by Robson Couto, 2019 +*/ + +#define NOTE_B0 31 +#define NOTE_C1 33 +#define NOTE_CS1 35 +#define NOTE_D1 37 +#define NOTE_DS1 39 +#define NOTE_E1 41 +#define NOTE_F1 44 +#define NOTE_FS1 46 +#define NOTE_G1 49 +#define NOTE_GS1 52 +#define NOTE_A1 55 +#define NOTE_AS1 58 +#define NOTE_B1 62 +#define NOTE_C2 65 +#define NOTE_CS2 69 +#define NOTE_D2 73 +#define NOTE_DS2 78 +#define NOTE_E2 82 +#define NOTE_F2 87 +#define NOTE_FS2 93 +#define NOTE_G2 98 +#define NOTE_GS2 104 +#define NOTE_A2 110 +#define NOTE_AS2 117 +#define NOTE_B2 123 +#define NOTE_C3 131 +#define NOTE_CS3 139 +#define NOTE_D3 147 +#define NOTE_DS3 156 +#define NOTE_E3 165 +#define NOTE_F3 175 +#define NOTE_FS3 185 +#define NOTE_G3 196 +#define NOTE_GS3 208 +#define NOTE_A3 220 +#define NOTE_AS3 233 +#define NOTE_B3 247 +#define NOTE_C4 262 +#define NOTE_CS4 277 +#define NOTE_D4 294 +#define NOTE_DS4 311 +#define NOTE_E4 330 +#define NOTE_F4 349 +#define NOTE_FS4 370 +#define NOTE_G4 392 +#define NOTE_GS4 415 +#define NOTE_A4 440 +#define NOTE_AS4 466 +#define NOTE_B4 494 +#define NOTE_C5 523 +#define NOTE_CS5 554 +#define NOTE_D5 587 +#define NOTE_DS5 622 +#define NOTE_E5 659 +#define NOTE_F5 698 +#define NOTE_FS5 740 +#define NOTE_G5 784 +#define NOTE_GS5 831 +#define NOTE_A5 880 +#define NOTE_AS5 932 +#define NOTE_B5 988 +#define NOTE_C6 1047 +#define NOTE_CS6 1109 +#define NOTE_D6 1175 +#define NOTE_DS6 1245 +#define NOTE_E6 1319 +#define NOTE_F6 1397 +#define NOTE_FS6 1480 +#define NOTE_G6 1568 +#define NOTE_GS6 1661 +#define NOTE_A6 1760 +#define NOTE_AS6 1865 +#define NOTE_B6 1976 +#define NOTE_C7 2093 +#define NOTE_CS7 2217 +#define NOTE_D7 2349 +#define NOTE_DS7 2489 +#define NOTE_E7 2637 +#define NOTE_F7 2794 +#define NOTE_FS7 2960 +#define NOTE_G7 3136 +#define NOTE_GS7 3322 +#define NOTE_A7 3520 +#define NOTE_AS7 3729 +#define NOTE_B7 3951 +#define NOTE_C8 4186 +#define NOTE_CS8 4435 +#define NOTE_D8 4699 +#define NOTE_DS8 4978 +#define REST 0 + +// notes of the moledy followed by the duration. +// a 4 means a quarter note, 8 an eighteenth , 16 sixteenth, so on +// !!negative numbers are used to represent dotted notes, +// so -4 means a dotted quarter note, that is, a quarter plus an eighteenth!! +int melody[] = { + + // Darth Vader theme (Imperial March) - Star wars + // Score available at https://musescore.com/user/202909/scores/1141521 + // The tenor saxophone part was used + + NOTE_A4,-4, NOTE_A4,-4, NOTE_A4,16, NOTE_A4,16, NOTE_A4,16, NOTE_A4,16, NOTE_F4,8, REST,8, + NOTE_A4,-4, NOTE_A4,-4, NOTE_A4,16, NOTE_A4,16, NOTE_A4,16, NOTE_A4,16, NOTE_F4,8, REST,8, + NOTE_A4,4, NOTE_A4,4, NOTE_A4,4, NOTE_F4,-8, NOTE_C5,16, + + NOTE_A4,4, NOTE_F4,-8, NOTE_C5,16, NOTE_A4,2,//4 + NOTE_E5,4, NOTE_E5,4, NOTE_E5,4, NOTE_F5,-8, NOTE_C5,16, + NOTE_A4,4, NOTE_F4,-8, NOTE_C5,16, NOTE_A4,2, + + NOTE_A5,4, NOTE_A4,-8, NOTE_A4,16, NOTE_A5,4, NOTE_GS5,-8, NOTE_G5,16, //7 + NOTE_DS5,16, NOTE_D5,16, NOTE_DS5,8, REST,8, NOTE_A4,8, NOTE_DS5,4, NOTE_D5,-8, NOTE_CS5,16, + + NOTE_C5,16, NOTE_B4,16, NOTE_C5,16, REST,8, NOTE_F4,8, NOTE_GS4,4, NOTE_F4,-8, NOTE_A4,-16,//9 + NOTE_C5,4, NOTE_A4,-8, NOTE_C5,16, NOTE_E5,2, + + NOTE_A5,4, NOTE_A4,-8, NOTE_A4,16, NOTE_A5,4, NOTE_GS5,-8, NOTE_G5,16, //7 + NOTE_DS5,16, NOTE_D5,16, NOTE_DS5,8, REST,8, NOTE_A4,8, NOTE_DS5,4, NOTE_D5,-8, NOTE_CS5,16, + + NOTE_C5,16, NOTE_B4,16, NOTE_C5,16, REST,8, NOTE_F4,8, NOTE_GS4,4, NOTE_F4,-8, NOTE_A4,-16,//9 + NOTE_A4,4, NOTE_F4,-8, NOTE_C5,16, NOTE_A4,2, + +}; diff --git a/examples/AFSK/AFSK_Tone/AFSK_Tone.ino b/examples/AFSK/AFSK_Tone/AFSK_Tone.ino new file mode 100644 index 00000000..43286f84 --- /dev/null +++ b/examples/AFSK/AFSK_Tone/AFSK_Tone.ino @@ -0,0 +1,77 @@ +/* + RadioLib AFSK Example + + This example shows hot to send audio FSK tones + using SX1278's FSK modem. + + Other modules that can be used for AFSK: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create AFSK client instance using the FSK module +// this requires connection to the module direct +// input pin, here connected to Arduino pin 5 +// SX127x/RFM9x: DIO2 +// RF69: DIO2 +// SX1231: DIO2 +// CC1101: GDO2 +// Si443x/RFM2x: GPIO +AFSKClient audio(&radio, 5); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for AFSK + // (RF69, CC1101,, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + // AFSKClient can be used to transmit tones, + // same as Arduino tone() function + + // 400 Hz tone + audio.tone(400); + delay(1000); + + // silence + audio.noTone(); + delay(1000); + + // AFSKClient can also be used to transmit HAM-friendly + // RTTY, Morse code, Hellschreiber, SSTV and AX.25. + // Details on how to use AFSK are in the example + // folders for each of the above modes. +} diff --git a/examples/AX25/AX25_Frames/AX25_Frames.ino b/examples/AX25/AX25_Frames/AX25_Frames.ino index c6af0ad8..0167214c 100644 --- a/examples/AX25/AX25_Frames/AX25_Frames.ino +++ b/examples/AX25/AX25_Frames/AX25_Frames.ino @@ -19,6 +19,12 @@ Frames shown in this example are not exhaustive; all possible AX.25 frames should be supported. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -29,14 +35,14 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 fsk = new Module(10, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1278 fsk = RadioShield.ModuleA; +//SX1278 radio = RadioShield.ModuleA; // create AX.25 client instance using the FSK module -AX25Client ax25(&fsk); +AX25Client ax25(&radio); void setup() { Serial.begin(9600); @@ -44,13 +50,13 @@ void setup() { // initialize SX1278 Serial.print(F("[SX1278] Initializing ... ")); // carrier frequency: 434.0 MHz - // bit rate: 1.2 kbps (1200 baud AFSK AX.25) - // frequency deviation: 0.5 kHz (1200 baud AFSK AX.25) - int state = fsk.beginFSK(434.0, 1.2, 0.5); + // bit rate: 1.2 kbps (1200 baud 2-FSK AX.25) + // frequency deviation: 0.5 kHz (1200 baud 2-FSK AX.25) + int state = radio.beginFSK(434.0, 1.2, 0.5); // when using one of the non-LoRa modules for AX.25 // (RF69, CC1101, Si4432 etc.), use the basic begin() method - // int state = fsk.begin(); + // int state = radio.begin(); if(state == ERR_NONE) { Serial.println(F("success!")); diff --git a/examples/AX25/AX25_Transmit/AX25_Transmit.ino b/examples/AX25/AX25_Transmit/AX25_Transmit.ino index 0a462eff..2ed78875 100644 --- a/examples/AX25/AX25_Transmit/AX25_Transmit.ino +++ b/examples/AX25/AX25_Transmit/AX25_Transmit.ino @@ -12,6 +12,12 @@ - SX126x - nRF24 - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -22,14 +28,14 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 fsk = new Module(10, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1278 fsk = RadioShield.ModuleA; +//SX1278 radio = RadioShield.ModuleA; // create AX.25 client instance using the FSK module -AX25Client ax25(&fsk); +AX25Client ax25(&radio); void setup() { Serial.begin(9600); @@ -37,13 +43,13 @@ void setup() { // initialize SX1278 Serial.print(F("[SX1278] Initializing ... ")); // carrier frequency: 434.0 MHz - // bit rate: 1.2 kbps (1200 baud AFSK AX.25) - // frequency deviation: 0.5 kHz (1200 baud AFSK AX.25) - int state = fsk.beginFSK(434.0, 1.2, 0.5); + // bit rate: 1.2 kbps (1200 baud 2-FSK AX.25) + // frequency deviation: 0.5 kHz (1200 baud 2-FSK AX.25) + int state = radio.beginFSK(434.0, 1.2, 0.5); // when using one of the non-LoRa modules for AX.25 // (RF69, CC1101,, Si4432 etc.), use the basic begin() method - // int state = fsk.begin(); + // int state = radio.begin(); if(state == ERR_NONE) { Serial.println(F("success!")); diff --git a/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino b/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino new file mode 100644 index 00000000..703847af --- /dev/null +++ b/examples/AX25/AX25_Transmit_AFSK/AX25_Transmit_AFSK.ino @@ -0,0 +1,97 @@ +/* + RadioLib AX.25 Transmit AFSK Example + + This example sends AX.25 messages using + SX1278's FSK modem. The data is modulated + as AFSK at 1200 baud using Bell 202 tones. + + Other modules that can be used for AX.25 + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - nRF24 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// pin 5 is connected to SX1278 DIO2 +AFSKClient audio(&radio, 5); + +// create AX.25 client instance using the AFSK instance +AX25Client ax25(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for AX.25 + // (RF69, CC1101,, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize AX.25 client + Serial.print(F("[AX.25] Initializing ... ")); + // source station callsign: "N7LEM" + // source station SSID: 0 + // preamble length: 8 bytes + state = ax25.begin("N7LEM"); + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + // send AX.25 unnumbered information frame + Serial.print(F("[AX.25] Sending UI frame ... ")); + // destination station callsign: "NJ7P" + // destination station SSID: 0 + int state = ax25.transmit("Hello World!", "NJ7P"); + if (state == ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else { + // some error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + delay(1000); +} diff --git a/examples/CC1101/CC1101_Receive/CC1101_Receive.ino b/examples/CC1101/CC1101_Receive/CC1101_Receive.ino index fa8f3aa8..b51bdf20 100644 --- a/examples/CC1101/CC1101_Receive/CC1101_Receive.ino +++ b/examples/CC1101/CC1101_Receive/CC1101_Receive.ino @@ -9,6 +9,9 @@ - frequency deviation - sync word + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -21,23 +24,18 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc = new Module(10, 2, RADIOLIB_NC, 3); +CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//CC1101 cc = RadioShield.ModuleA; +//CC1101 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); - // carrier frequency: 868.0 MHz - // bit rate: 4.8 kbps - // frequency deviation: 48.0 kHz - // Rx bandwidth: 325.0 kHz - // sync word: 0xD391 - int state = cc.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -52,12 +50,12 @@ void loop() { // you can receive data as an Arduino String String str; - int state = cc.receive(str); + int state = radio.receive(str); // you can also receive data as byte array /* byte byteArr[8]; - int state = cc.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { @@ -71,13 +69,13 @@ void loop() { // print RSSI (Received Signal Strength Indicator) // of the last received packet Serial.print(F("[CC1101] RSSI:\t\t")); - Serial.print(cc.getRSSI()); + Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); // print LQI (Link Quality Indicator) // of the last received packet, lower is better Serial.print(F("[CC1101] LQI:\t\t")); - Serial.println(cc.getLQI()); + Serial.println(radio.getLQI()); } else if (state == ERR_CRC_MISMATCH) { // packet was received, but is malformed diff --git a/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino b/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino index 3e12b6d5..81eac67c 100644 --- a/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino +++ b/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino @@ -7,6 +7,9 @@ will automatically filter out any packets that do not contain either node address or broadcast addresses. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -19,23 +22,18 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc = new Module(10, 2, RADIOLIB_NC, 3); +CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//CC1101 cc = RadioShield.ModuleA; +//CC1101 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); - // carrier frequency: 868.0 MHz - // bit rate: 4.8 kbps - // frequency deviation: 48.0 kHz - // Rx bandwidth: 325.0 kHz - // sync word: 0xD391 - int state = cc.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -52,7 +50,7 @@ void setup() { // When setting two broadcast addresses, 0x00 and // 0xFF will be used. Serial.print(F("[CC1101] Setting node address ... ")); - state = cc.setNodeAddress(0x01, 1); + state = radio.setNodeAddress(0x01, 1); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -66,7 +64,7 @@ void setup() { // set node address /* Serial.print(F("[CC1101] Disabling address filtering ... ")); - state == cc.disableAddressFiltering(); + state == radio.disableAddressFiltering(); if(state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -82,12 +80,12 @@ void loop() { // you can receive data as an Arduino String String str; - int state = cc.receive(str); + int state = radio.receive(str); // you can also receive data as byte array /* byte byteArr[8]; - int state = cc.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { @@ -101,13 +99,13 @@ void loop() { // print RSSI (Received Signal Strength Indicator) // of the last received packet Serial.print(F("[CC1101] RSSI:\t\t")); - Serial.print(cc.getRSSI()); + Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); // print LQI (Link Quality Indicator) // of the last received packet, lower is better Serial.print(F("[CC1101] LQI:\t\t")); - Serial.println(cc.getLQI()); + Serial.println(radio.getLQI()); } else if (state == ERR_CRC_MISMATCH) { // packet was received, but is malformed diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino index b57c4102..a7228de4 100644 --- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino +++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -12,8 +12,11 @@ - frequency deviation - sync word - For full API reference, see the GitHub Pages - https://jgromes.github.io/RadioLib/ + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -24,23 +27,18 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc = new Module(5, 2, RADIOLIB_NC, 3); +CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//CC1101 cc = RadioShield.ModuleA; +//CC1101 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); - // carrier frequency: 868.0 MHz - // bit rate: 4.8 kbps - // frequency deviation: 48.0 kHz - // Rx bandwidth: 325.0 kHz - // sync word: 0xD391 - int state = cc.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -51,11 +49,11 @@ void setup() { // set the function that will be called // when new packet is received - cc.setGdo0Action(setFlag); + radio.setGdo0Action(setFlag); // start listening for packets Serial.print(F("[CC1101] Starting to listen ... ")); - state = cc.startReceive(); + state = radio.startReceive(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -67,11 +65,11 @@ void setup() { // if needed, 'listen' mode can be disabled by calling // any of the following methods: // - // cc.standby() - // cc.sleep() - // cc.transmit(); - // cc.receive(); - // cc.readData(); + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); } // flag to indicate that a packet was received @@ -105,36 +103,33 @@ void loop() { receivedFlag = false; // you can read received data as an Arduino String - //String str; - //int state = cc.readData(str); + String str; + int state = radio.readData(str); // you can also read received data as byte array - + /* byte byteArr[8]; - int state = cc.readData(byteArr, 8); - + int state = radio.readData(byteArr, 8); + */ if (state == ERR_NONE) { // packet was successfully received Serial.println(F("[CC1101] Received packet!")); // print data of the packet - Serial.println(F("[CC1101] Data:\t\t")); - //Serial.println(str); - for(uint8_t i = 0; i < 8; i++) { - Serial.println(byteArr[i], HEX); - } + Serial.print(F("[CC1101] Data:\t\t")); + Serial.println(str); // print RSSI (Received Signal Strength Indicator) // of the last received packet Serial.print(F("[CC1101] RSSI:\t\t")); - Serial.print(cc.getRSSI()); + Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); // print LQI (Link Quality Indicator) // of the last received packet, lower is better Serial.print(F("[CC1101] LQI:\t\t")); - Serial.println(cc.getLQI()); + Serial.println(radio.getLQI()); } else if (state == ERR_CRC_MISMATCH) { // packet was received, but is malformed @@ -148,7 +143,7 @@ void loop() { } // put module back to listen mode - cc.startReceive(); + radio.startReceive(); // we're ready to receive more packets, // enable interrupt service routine diff --git a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino index 02394da1..e724f7b6 100644 --- a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino +++ b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino @@ -11,6 +11,9 @@ - output power during transmission - sync word + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -23,30 +26,25 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc1 = new Module(10, 2, RADIOLIB_NC, 3); +CC1101 radio1 = new Module(10, 2, RADIOLIB_NC, 3); // second CC1101 has different connections: // CS pin: 9 // GDO0 pin: 4 // RST pin: unused // GDO2 pin: 5 (optional) -CC1101 cc2 = new Module(9, 4, RADIOLIB_NC, 53); +CC1101 radio2 = new Module(9, 4, RADIOLIB_NC, 53); // or using RadioShield // https://github.com/jgromes/RadioShield -//CC1101 cc3 = RadioShield.ModuleB; +//CC1101 radio3 = RadioShield.ModuleB; void setup() { Serial.begin(9600); // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); - // carrier frequency: 868.0 MHz - // bit rate: 4.8 kbps - // frequency deviation: 48.0 kHz - // Rx bandwidth: 325.0 kHz - // sync word: 0xD391 - int state = cc1.begin(); + int state = radio1.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -61,8 +59,9 @@ void setup() { // bit rate: 32.0 kbps // frequency deviation: 60.0 kHz // Rx bandwidth: 250.0 kHz - // sync word: 0xD391 - state = cc2.begin(434.0, 32.0, 60.0, 250.0); + // output power: 7 dBm + // preamble length: 32 bits + state = radio2.begin(434.0, 32.0, 60.0, 250.0, 7, 32); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -75,13 +74,13 @@ void setup() { // and check if the configuration was changed successfully // set carrier frequency to 433.5 MHz - if (cc1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { + if (radio1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { Serial.println(F("[CC1101] Selected frequency is invalid for this module!")); while (true); } // set bit rate to 100.0 kbps - state = cc1.setBitRate(100.0); + state = radio1.setBitRate(100.0); if (state == ERR_INVALID_BIT_RATE) { Serial.println(F("[CC1101] Selected bit rate is invalid for this module!")); while (true); @@ -92,25 +91,25 @@ void setup() { } // set receiver bandwidth to 250.0 kHz - if (cc1.setRxBandwidth(250.0) == ERR_INVALID_RX_BANDWIDTH) { + if (radio1.setRxBandwidth(250.0) == ERR_INVALID_RX_BANDWIDTH) { Serial.println(F("[CC1101] Selected receiver bandwidth is invalid for this module!")); while (true); } // set allowed frequency deviation to 10.0 kHz - if (cc1.setFrequencyDeviation(10.0) == ERR_INVALID_FREQUENCY_DEVIATION) { + if (radio1.setFrequencyDeviation(10.0) == ERR_INVALID_FREQUENCY_DEVIATION) { Serial.println(F("[CC1101] Selected frequency deviation is invalid for this module!")); while (true); } // set output power to 5 dBm - if (cc1.setOutputPower(5) == ERR_INVALID_OUTPUT_POWER) { + if (radio1.setOutputPower(5) == ERR_INVALID_OUTPUT_POWER) { Serial.println(F("[CC1101] Selected output power is invalid for this module!")); while (true); } // 2 bytes can be set as sync word - if (cc1.setSyncWord(0x01, 0x23) == ERR_INVALID_SYNC_WORD) { + if (radio1.setSyncWord(0x01, 0x23) == ERR_INVALID_SYNC_WORD) { Serial.println(F("[CC1101] Selected sync word is invalid for this module!")); while (true); } diff --git a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino b/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino index be530890..3463c6f1 100644 --- a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino +++ b/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino @@ -7,6 +7,9 @@ - null-terminated char array (C-string) - arbitrary binary data (byte array) + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -19,23 +22,18 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc = new Module(10, 2, RADIOLIB_NC, 3); +CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//CC1101 cc = RadioShield.ModuleA; +//CC1101 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); - // initialize CC1101 + // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); - // carrier frequency: 868.0 MHz - // bit rate: 4.8 kbps - // frequency deviation: 48.0 kHz - // Rx bandwidth: 325.0 kHz - // sync word: 0xD391 - int state = cc.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -49,12 +47,12 @@ void loop() { Serial.print(F("[CC1101] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to 63 characters long - int state = cc.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); // you can also transmit byte array up to 63 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = cc.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino index e584eb7c..430eafd8 100644 --- a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino +++ b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino @@ -7,6 +7,9 @@ will automatically filter out any packets that do not contain either node address or broadcast addresses. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -19,23 +22,18 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc = new Module(10, 2, RADIOLIB_NC, 3); +CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//CC1101 cc = RadioShield.ModuleA; +//CC1101 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); - // carrier frequency: 868.0 MHz - // bit rate: 4.8 kbps - // frequency deviation: 48.0 kHz - // Rx bandwidth: 325.0 kHz - // sync word: 0xD391 - int state = cc.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -52,7 +50,7 @@ void setup() { // When setting two broadcast addresses, 0x00 and // 0xFF will be used. Serial.print(F("[CC1101] Setting node address ... ")); - state = cc.setNodeAddress(0x01, 1); + state = radio.setNodeAddress(0x01, 1); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -66,7 +64,7 @@ void setup() { // set node address /* Serial.print(F("[CC1101] Disabling address filtering ... ")); - state == cc.disableAddressFiltering(); + state == radio.disableAddressFiltering(); if(state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -81,12 +79,12 @@ void loop() { Serial.print(F("[CC1101] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to 63 characters long - int state = cc.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); // you can also transmit byte array up to 63 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = cc.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index 47991677..c15652b6 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -8,6 +8,9 @@ - null-terminated char array (C-string) - arbitrary binary data (byte array) + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#cc1101 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -20,11 +23,11 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc = new Module(10, 2, RADIOLIB_NC, 3); +CC1101 radio = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//CC1101 cc = RadioShield.ModuleA; +//CC1101 radio = RadioShield.ModuleA; // save transmission state between loops int transmissionState = ERR_NONE; @@ -34,12 +37,7 @@ void setup() { // initialize CC1101 with default settings Serial.print(F("[CC1101] Initializing ... ")); - // carrier frequency: 868.0 MHz - // bit rate: 4.8 kbps - // frequency deviation: 48.0 kHz - // Rx bandwidth: 325.0 kHz - // sync word: 0xD391 - int state = cc.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -50,20 +48,20 @@ void setup() { // set the function that will be called // when packet transmission is finished - cc.setGdo0Action(setFlag); + radio.setGdo0Action(setFlag); // start transmitting the first packet Serial.print(F("[CC1101] Sending first packet ... ")); // you can transmit C-string or Arduino string up to // 64 characters long - transmissionState = cc.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World!"); // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; - state = cc.startTransmit(byteArr, 8); + state = radio.startTransmit(byteArr, 8); */ } @@ -119,13 +117,13 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = cc.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World!"); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = cc.startTransmit(byteArr, 8); + int state = radio.startTransmit(byteArr, 8); */ // we're ready to send more packets, diff --git a/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino b/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino index c1d74d31..edadc5d6 100644 --- a/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino +++ b/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino @@ -13,6 +13,12 @@ - nRF24 - Si443x/RFM2x - SX128x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -23,32 +29,25 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 fsk = new Module(10, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1278 fsk = RadioShield.ModuleA; +//SX1278 radio = RadioShield.ModuleA; // create Hellschreiber client instance using the FSK module -HellClient hell(&fsk); +HellClient hell(&radio); void setup() { Serial.begin(9600); - // initialize SX1278 + // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // current limit: 100 mA - // sync word: 0x2D 0x01 - int state = fsk.beginFSK(); + int state = radio.beginFSK(); // when using one of the non-LoRa modules for Morse code // (RF69, CC1101, Si4432 etc.), use the basic begin() method - // int state = fsk.begin(); + // int state = radio.begin(); if(state == ERR_NONE) { Serial.println(F("success!")); @@ -106,7 +105,7 @@ void loop() { float f = -3.1415; hell.println(f, 3); - // custom glyph - must be a 7 byte array of rows 7 pixels long + // custom glyph - must be a 7 byte array of rows 7 pixels long uint8_t customGlyph[] = { 0b0000000, 0b0010100, 0b0010100, 0b0000000, 0b0100010, 0b0011100, 0b0000000 }; hell.printGlyph(customGlyph); diff --git a/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino new file mode 100644 index 00000000..1938f34c --- /dev/null +++ b/examples/Hellschreiber/Hellschreiber_Transmit_AFSK/Hellschreiber_Transmit_AFSK.ino @@ -0,0 +1,119 @@ +/* + RadioLib Hellschreiber Transmit AFSK Example + + This example sends Hellschreiber message using + SX1278's FSK modem. The data is modulated + as AFSK. + + Other modules that can be used for Hellschreiber + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// pin 5 is connected to SX1278 DIO2 +AFSKClient audio(&radio, 5); + +// create Hellschreiber client instance using the AFSK instance +HellClient hell(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for Morse code + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize Hellschreiber client + Serial.print(F("[Hell] Initializing ... ")); + // AFSK tone frequency: 400 Hz + // speed: 122.5 Baud ("Feld Hell") + state = hell.begin(400); + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Hell] Sending Hellschreiber data ... ")); + + // HellClient supports all methods of the Serial class + // NOTE: Lower case letter will be capitalized. + + // Arduino String class + String aStr = "Arduino String"; + hell.print(aStr); + + // character array (C-String) + hell.print("C-String"); + + // string saved in flash + hell.print(F("Flash String")); + + // character + hell.print('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + hell.print(255, HEX); + + // integer number + int i = 1000; + hell.print(i); + + // floating point number + // NOTE: println() has no effect on the transmission, + // and is only kept for compatibility reasons. + float f = -3.1415; + hell.println(f, 3); + + // custom glyph - must be a 7 byte array of rows 7 pixels long + uint8_t customGlyph[] = { 0b0000000, 0b0010100, 0b0010100, 0b0000000, 0b0100010, 0b0011100, 0b0000000 }; + hell.printGlyph(customGlyph); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/examples/Morse/Morse_Transmit/Morse_Transmit.ino b/examples/Morse/Morse_Transmit/Morse_Transmit.ino index e0d6d1fe..9c39a3b7 100644 --- a/examples/Morse/Morse_Transmit/Morse_Transmit.ino +++ b/examples/Morse/Morse_Transmit/Morse_Transmit.ino @@ -13,6 +13,12 @@ - nRF24 - Si443x/RFM2x - SX128x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // include the library @@ -23,32 +29,25 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 fsk = new Module(10, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1278 fsk = RadioShield.ModuleA; +//SX1278 radio = RadioShield.ModuleA; // create Morse client instance using the FSK module -MorseClient morse(&fsk); +MorseClient morse(&radio); void setup() { Serial.begin(9600); - // initialize SX1278 + // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // current limit: 100 mA - // sync word: 0x2D 0x01 - int state = fsk.beginFSK(); - + int state = radio.beginFSK(); + // when using one of the non-LoRa modules for Morse code // (RF69, CC1101, Si4432 etc.), use the basic begin() method - // int state = fsk.begin(); + // int state = radio.begin(); if(state == ERR_NONE) { Serial.println(F("success!")); diff --git a/examples/Morse/Morse_Transmit_AFSK/Morse_Transmit_AFSK.ino b/examples/Morse/Morse_Transmit_AFSK/Morse_Transmit_AFSK.ino new file mode 100644 index 00000000..ad89cb49 --- /dev/null +++ b/examples/Morse/Morse_Transmit_AFSK/Morse_Transmit_AFSK.ino @@ -0,0 +1,120 @@ +/* + RadioLib Morse Transmit AFSK Example + + This example sends Morse code message using + SX1278's FSK modem. The data is modulated + as AFSK. + + Other modules that can be used for Morse Code + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// pin 5 is connected to SX1278 DIO2 +AFSKClient audio(&radio, 5); + +// create Morse client instance using the AFSK instance +MorseClient morse(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for Morse code + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize Morse client + Serial.print(F("[Morse] Initializing ... ")); + // AFSK tone frequency: 400 MHz + // speed: 20 words per minute + state = morse.begin(400); + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Morse] Sending Morse data ... ")); + + // MorseClient supports all methods of the Serial class + // NOTE: Characters that do not have ITU-R M.1677-1 + // representation will not be sent! Lower case + // letters will be capitalized. + + // send start signal first + morse.startSignal(); + + // Arduino String class + String aStr = "Arduino String"; + morse.print(aStr); + + // character array (C-String) + morse.print("C-String"); + + // string saved in flash + morse.print(F("Flash String")); + + // character + morse.print('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + morse.print(255, HEX); + + // integer number + int i = 1000; + morse.print(i); + + // floating point number + // NOTE: When using println(), the transmission will be + // terminated with end-of-work signal (...-.-). + float f = -3.1415; + morse.println(f, 3); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/examples/RF69/RF69_Receive/RF69_Receive.ino b/examples/RF69/RF69_Receive/RF69_Receive.ino index 597ee63e..fd924755 100644 --- a/examples/RF69/RF69_Receive/RF69_Receive.ino +++ b/examples/RF69/RF69_Receive/RF69_Receive.ino @@ -9,6 +9,9 @@ - frequency deviation - sync word + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -20,24 +23,18 @@ // CS pin: 10 // DIO0 pin: 2 // RESET pin: 3 -RF69 rf = new Module(10, 2, 3); +RF69 radio = new Module(10, 2, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//RF69 rf = RadioShield.ModuleA; +//RF69 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // sync word: 0x2D01 - int state = rf.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -52,12 +49,12 @@ void loop() { // you can receive data as an Arduino String String str; - int state = rf.receive(str); + int state = radio.receive(str); // you can also receive data as byte array /* byte byteArr[8]; - int state = rf.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { @@ -68,6 +65,12 @@ void loop() { Serial.print(F("[RF69] Data:\t\t")); Serial.println(str); + // print RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[RF69] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + } else if (state == ERR_RX_TIMEOUT) { // timeout occurred while waiting for a packet Serial.println(F("timeout!")); diff --git a/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino b/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino index 7c947cf0..c1fa2816 100644 --- a/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino +++ b/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino @@ -5,6 +5,9 @@ Packets are decrypted using hardware AES. NOTE: When using address filtering, the address byte is NOT encrypted! + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -16,24 +19,18 @@ // CS pin: 10 // DIO0 pin: 2 // RESET pin: 3 -RF69 rf = new Module(10, 2, 3); +RF69 radio = new Module(10, 2, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//RF69 rf = RadioShield.ModuleA; +//RF69 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // sync word: 0x2D01 - int state = rf.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -46,14 +43,14 @@ void setup() { // NOTE: the key must be exactly 16 bytes long! uint8_t key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; - rf.setAESKey(key); + radio.setAESKey(key); // enable AES encryption - rf.enableAES(); + radio.enableAES(); // AES encryption can also be disabled /* - rf.disableAES(); + radio.disableAES(); */ } @@ -62,12 +59,12 @@ void loop() { // you can receive data as an Arduino String String str; - int state = rf.receive(str); + int state = radio.receive(str); // you can also receive data as byte array /* byte byteArr[8]; - int state = rf.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino b/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino index 08242ec3..df20200c 100644 --- a/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino +++ b/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino @@ -7,6 +7,9 @@ automatically filter out any packets that do not contain either node address or broadcast address. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -18,24 +21,18 @@ // CS pin: 10 // DIO0 pin: 2 // RESET pin: 3 -RF69 rf = new Module(10, 2, 3); +RF69 radio = new Module(10, 2, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//RF69 rf = RadioShield.ModuleA; +//RF69 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // sync word: 0x2D01 - int state = rf.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -48,7 +45,7 @@ void setup() { // NOTE: calling this method will automatically enable // address filtering (node address only) Serial.print(F("[RF69] Setting node address ... ")); - state = rf.setNodeAddress(0x02); + state = radio.setNodeAddress(0x02); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -61,7 +58,7 @@ void setup() { // NOTE: calling this method will automatically enable // address filtering (node or broadcast address) Serial.print(F("[RF69] Setting broadcast address ... ")); - state = rf.setBroadcastAddress(0xFF); + state = radio.setBroadcastAddress(0xFF); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -75,7 +72,7 @@ void setup() { // node and broadcast address /* Serial.print(F("[RF69] Disabling address filtering ... ")); - state == rf.disableAddressFiltering(); + state == radio.disableAddressFiltering(); if(state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -91,12 +88,12 @@ void loop() { // you can receive data as an Arduino String String str; - int state = rf.receive(str); + int state = radio.receive(str); // you can also receive data as byte array /* byte byteArr[8]; - int state = rf.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino index 32aef55f..2a512783 100644 --- a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino +++ b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino @@ -5,6 +5,9 @@ receive them. Once a packet is received, an interrupt is triggered. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -16,24 +19,18 @@ // CS pin: 10 // DIO0 pin: 2 // RESET pin: 3 -RF69 rf = new Module(10, 2, 3); +RF69 radio = new Module(10, 2, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//RF69 rf = RadioShield.ModuleA; +//RF69 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // sync word: 0x2D01 - int state = rf.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -44,11 +41,11 @@ void setup() { // set the function that will be called // when new packet is received - rf.setDio0Action(setFlag); + radio.setDio0Action(setFlag); // start listening for packets Serial.print(F("[RF69] Starting to listen ... ")); - state = rf.startReceive(); + state = radio.startReceive(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -60,11 +57,11 @@ void setup() { // if needed, 'listen' mode can be disabled by calling // any of the following methods: // - // rf.standby() - // rf.sleep() - // rf.transmit(); - // rf.receive(); - // rf.readData(); + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); } // flag to indicate that a packet was received @@ -99,12 +96,12 @@ void loop() { // you can read received data as an Arduino String String str; - int state = rf.readData(str); + int state = radio.readData(str); // you can also read received data as byte array /* byte byteArr[8]; - int state = rf.readData(byteArr, 8); + int state = radio.readData(byteArr, 8); */ if (state == ERR_NONE) { @@ -112,9 +109,15 @@ void loop() { Serial.println(F("[RF69] Received packet!")); // print data of the packet - Serial.print(F("[RF69] Data:\t\t\t")); + Serial.print(F("[RF69] Data:\t\t")); Serial.println(str); + // print RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[RF69] RSSI:\t\t")); + Serial.print(radio.getRSSI()); + Serial.println(F(" dBm")); + } else if (state == ERR_CRC_MISMATCH) { // packet was received, but is malformed Serial.println(F("CRC error!")); @@ -127,7 +130,7 @@ void loop() { } // put module back to listen mode - rf.startReceive(); + radio.startReceive(); // we're ready to receive more packets, // enable interrupt service routine diff --git a/examples/RF69/RF69_Settings/RF69_Settings.ino b/examples/RF69/RF69_Settings/RF69_Settings.ino index 2fee90ba..f936ee2e 100644 --- a/examples/RF69/RF69_Settings/RF69_Settings.ino +++ b/examples/RF69/RF69_Settings/RF69_Settings.ino @@ -11,6 +11,9 @@ - output power during transmission - sync word + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -22,30 +25,24 @@ // CS pin: 10 // DIO0 pin: 2 // RESET pin: 3 -RF69 rf1 = new Module(10, 2, 3); +RF69 radio1 = new Module(10, 2, 3); // second CC1101 has different connections: // CS pin: 9 // DIO0 pin: 4 // RESET pin: 5 -RF69 rf2 = new Module(9, 4, 5); +RF69 radio2 = new Module(9, 4, 5); // or using RadioShield // https://github.com/jgromes/RadioShield -//RF69 rf3 = RadioShield.ModuleB; +//RF69 radio3 = RadioShield.ModuleB; void setup() { Serial.begin(9600); // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // sync word: 0x2D01 - int state = rf1.begin(); + int state = radio1.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -61,8 +58,8 @@ void setup() { // frequency deviation: 60.0 kHz // Rx bandwidth: 250.0 kHz // output power: 17 dBm - // sync word: 0x2D01 - state = rf2.begin(868.0, 300.0, 60.0, 250.0, 17); + // preamble length: 32 bits + state = radio2.begin(868.0, 300.0, 60.0, 250.0, 17, 32); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -75,13 +72,13 @@ void setup() { // and check if the configuration was changed successfully // set carrier frequency to 433.5 MHz - if (rf1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { + if (radio1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { Serial.println(F("[RF69] Selected frequency is invalid for this module!")); while (true); } // set bit rate to 100.0 kbps - state = rf1.setBitRate(100.0); + state = radio1.setBitRate(100.0); if (state == ERR_INVALID_BIT_RATE) { Serial.println(F("[RF69] Selected bit rate is invalid for this module!")); while (true); @@ -92,7 +89,7 @@ void setup() { } // set receiver bandwidth to 250.0 kHz - state = rf1.setRxBandwidth(250.0); + state = radio1.setRxBandwidth(250.0); if (state == ERR_INVALID_RX_BANDWIDTH) { Serial.println(F("[RF69] Selected receiver bandwidth is invalid for this module!")); while (true); @@ -103,13 +100,13 @@ void setup() { } // set allowed frequency deviation to 10.0 kHz - if (rf1.setFrequencyDeviation(10.0) == ERR_INVALID_FREQUENCY_DEVIATION) { + if (radio1.setFrequencyDeviation(10.0) == ERR_INVALID_FREQUENCY_DEVIATION) { Serial.println(F("[RF69] Selected frequency deviation is invalid for this module!")); while (true); } // set output power to 2 dBm - if (rf1.setOutputPower(2) == ERR_INVALID_OUTPUT_POWER) { + if (radio1.setOutputPower(2) == ERR_INVALID_OUTPUT_POWER) { Serial.println(F("[RF69] Selected output power is invalid for this module!")); while (true); } @@ -118,7 +115,7 @@ void setup() { // NOTE: sync word must not contain any zero bytes // set sync word to 0x0123456789ABCDEF uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - if (rf1.setSyncWord(syncWord, 8) == ERR_INVALID_SYNC_WORD) { + if (radio1.setSyncWord(syncWord, 8) == ERR_INVALID_SYNC_WORD) { Serial.println(F("[RF69] Selected sync word is invalid for this module!")); while (true); } @@ -128,13 +125,13 @@ void setup() { // RF69 can also measure temperature (roughly) // to get correct temperature measurements, the sensor must be calibrated // at ambient temperature - rf1.setAmbientTemperature(25); // replace 25 with your ambient temperature + radio1.setAmbientTemperature(25); // replace 25 with your ambient temperature } void loop() { // measure temperature Serial.print(F("[RF69] Measured temperature: ")); - Serial.print(rf1.getTemperature()); + Serial.print(radio1.getTemperature()); Serial.println(F(" deg C")); // wait 100 ms before the next measurement diff --git a/examples/RF69/RF69_Transmit/RF69_Transmit.ino b/examples/RF69/RF69_Transmit/RF69_Transmit.ino index 05879c0b..c57122b2 100644 --- a/examples/RF69/RF69_Transmit/RF69_Transmit.ino +++ b/examples/RF69/RF69_Transmit/RF69_Transmit.ino @@ -7,6 +7,9 @@ - null-terminated char array (C-string) - arbitrary binary data (byte array) + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -18,24 +21,18 @@ // CS pin: 10 // DIO0 pin: 2 // RESET pin: 3 -RF69 rf = new Module(10, 2, 3); +RF69 radio = new Module(10, 2, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//RF69 rf = RadioShield.ModuleA; +//RF69 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // sync word: 0x2D01 - int state = rf.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -43,18 +40,35 @@ void setup() { Serial.println(state); while (true); } + + // NOTE: some RF69 modules use high power output, + // those are usually marked RF69H(C/CW). + // To configure RadioLib for these modules, + // you must call setOutputPower() with + // second argument set to true. + /* + Serial.print(F("[RF69] Setting high power module ... ")); + state = radio.setOutputPower(20, true); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + */ } void loop() { Serial.print(F("[RF69] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to 64 characters long - int state = rf.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = rf.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino b/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino index 5df09c65..d5bc2de2 100644 --- a/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino +++ b/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino @@ -5,6 +5,9 @@ Packets are encrypted using hardware AES. NOTE: When using address filtering, the address byte is NOT encrypted! + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -16,24 +19,18 @@ // CS pin: 10 // DIO0 pin: 2 // RESET pin: 3 -RF69 rf = new Module(10, 2, 3); +RF69 radio = new Module(10, 2, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//RF69 rf = RadioShield.ModuleA; +//RF69 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // sync word: 0x2D01 - int state = rf.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -46,14 +43,14 @@ void setup() { // NOTE: the key must be exactly 16 bytes long! uint8_t key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; - rf.setAESKey(key); + radio.setAESKey(key); // enable AES encryption - rf.enableAES(); + radio.enableAES(); // AES encryption can also be disabled /* - rf.disableAES(); + radio.disableAES(); */ } @@ -61,12 +58,12 @@ void loop() { Serial.print(F("[RF69] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to 64 characters long - int state = rf.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = rf.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino b/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino index 7413822e..5f91e1f6 100644 --- a/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino +++ b/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino @@ -7,6 +7,9 @@ automatically filter out any packets that do not contain either node address or broadcast address. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -18,24 +21,18 @@ // CS pin: 10 // DIO0 pin: 2 // RESET pin: 3 -RF69 rf = new Module(10, 2, 3); +RF69 radio = new Module(10, 2, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//RF69 rf = RadioShield.ModuleA; +//RF69 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // sync word: 0x2D01 - int state = rf.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -48,7 +45,7 @@ void setup() { // NOTE: calling this method will automatically enable // address filtering (node address only) Serial.print(F("[RF69] Setting node address ... ")); - state = rf.setNodeAddress(0x01); + state = radio.setNodeAddress(0x01); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -61,7 +58,7 @@ void setup() { // NOTE: calling this method will automatically enable // address filtering (node or broadcast address) Serial.print(F("[RF69] Setting broadcast address ... ")); - state = rf.setBroadcastAddress(0xFF); + state = radio.setBroadcastAddress(0xFF); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -75,7 +72,7 @@ void setup() { // node and broadcast address /* Serial.print(F("[RF69] Disabling address filtering ... ")); - state = rf.disableAddressFiltering(); + state = radio.disableAddressFiltering(); if(state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -90,23 +87,23 @@ void loop() { Serial.print(F("[RF69] Transmitting packet ... ")); // transmit C-string or Arduino string to node with address 0x02 - int state = rf.transmit("Hello World!", 0x02); + int state = radio.transmit("Hello World!", 0x02); // transmit byte array to node with address 0x02 /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = rf.transmit(byteArr, 8, 0x02); + int state = radio.transmit(byteArr, 8, 0x02); */ // transmit C-string or Arduino string in broadcast mode /* - int state = rf.transmit("Hello World!", 0xFF); + int state = radio.transmit("Hello World!", 0xFF); */ // transmit byte array in broadcast mode /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = rf.transmit(byteArr, 8, 0xFF); + int state = radio.transmit(byteArr, 8, 0xFF); */ if (state == ERR_NONE) { diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index 3e83042a..0f03dad1 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -8,6 +8,9 @@ - null-terminated char array (C-string) - arbitrary binary data (byte array) + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -19,11 +22,11 @@ // CS pin: 10 // DIO0 pin: 2 // RESET pin: 3 -RF69 rf = new Module(10, 2, 3); +RF69 radio = new Module(10, 2, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//RF69 rf = RadioShield.ModuleA; +//RF69 radio = RadioShield.ModuleA; // save transmission state between loops int transmissionState = ERR_NONE; @@ -33,13 +36,7 @@ void setup() { // initialize RF69 with default settings Serial.print(F("[RF69] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // sync word: 0x2D01 - int state = rf.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -50,20 +47,37 @@ void setup() { // set the function that will be called // when packet transmission is finished - rf.setDio0Action(setFlag); + radio.setDio0Action(setFlag); + + // NOTE: some RF69 modules use high power output, + // those are usually marked RF69H(C/CW). + // To configure RadioLib for these modules, + // you must call setOutputPower() with + // second argument set to true. + /* + Serial.print(F("[RF69] Setting high power module ... ")); + state = radio.setOutputPower(20, true); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + */ // start transmitting the first packet Serial.print(F("[RF69] Sending first packet ... ")); // you can transmit C-string or Arduino string up to // 64 characters long - transmissionState = rf.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World!"); // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - state = rf.startTransmit(byteArr, 8); + state = radio.startTransmit(byteArr, 8); */ } @@ -119,13 +133,13 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = rf.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World!"); // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = rf.startTransmit(byteArr, 8); + int state = radio.startTransmit(byteArr, 8); */ // we're ready to send more packets, diff --git a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino index f565c6f0..80c3c67f 100644 --- a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino +++ b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino @@ -14,6 +14,9 @@ - Si443x/RFM2x - SX128x + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -26,32 +29,25 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 fsk = new Module(10, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1278 fsk = RadioShield.ModuleA; +//SX1278 radio = RadioShield.ModuleA; // create RTTY client instance using the FSK module -RTTYClient rtty(&fsk); +RTTYClient rtty(&radio); void setup() { Serial.begin(9600); - // initialize SX1278 + // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // current limit: 100 mA - // sync word: 0x2D 0x01 - int state = fsk.beginFSK(); + int state = radio.beginFSK(); // when using one of the non-LoRa modules for RTTY // (RF69, CC1101, Si4432 etc.), use the basic begin() method - // int state = fsk.begin(); + // int state = radio.begin(); if(state == ERR_NONE) { Serial.println(F("success!")); diff --git a/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino new file mode 100644 index 00000000..23a66598 --- /dev/null +++ b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino @@ -0,0 +1,130 @@ +/* + RadioLib RTTY Transmit AFSK Example + + This example sends RTTY message using SX1278's + FSK modem. The data is modulated as AFSK. + + Other modules that can be used for RTTY: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// pin 5 is connected to SX1278 DIO2 +AFSKClient audio(&radio, 5); + +// create RTTY client instance using the AFSK instance +RTTYClient rtty(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for RTTY + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize RTTY client + // NOTE: Unlike FSK RTTY, AFSK requires no rounding of + // the frequency shift. + Serial.print(F("[RTTY] Initializing ... ")); + // space frequency: 400 Hz + // frequency shift: 170 Hz + // baud rate: 45 baud + // encoding: ASCII (7-bit) + // stop bits: 1 + state = rtty.begin(400, 170, 45); + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + /* + // RadioLib also provides ITA2 ("Baudot") support + rtty.begin(400, 170, 45, ITA2); + + // All transmissions in loop() (strings and numbers) + // will now be encoded using ITA2 code + + // ASCII characters that do not have ITA2 equivalent + // will be sent as NUL (including lower case letters!) + */ +} + +void loop() { + Serial.print(F("[RTTY] Sending RTTY data ... ")); + + // send out idle condition for 500 ms + rtty.idle(); + delay(500); + + // RTTYClient supports all methods of the Serial class + + // Arduino String class + String aStr = "Arduino String"; + rtty.println(aStr); + + // character array (C-String) + rtty.println("C-String"); + + // string saved in flash + rtty.println(F("Flash String")); + + // character + rtty.println('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + rtty.println(255, HEX); + + // integer number + int i = 1000; + rtty.println(i); + + // floating point number + float f = -3.1415; + rtty.println(f, 3); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino b/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino index 92bdde6f..6b06bae3 100644 --- a/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino +++ b/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino @@ -25,6 +25,9 @@ lower speed modes such as Wrasse, Scottie1 or Martin1 are recommended. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -37,14 +40,14 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 fsk = new Module(10, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1278 fsk = RadioShield.ModuleA; +//SX1278 radio = RadioShield.ModuleA; // create SSTV client instance using the FSK module -SSTVClient sstv(&fsk); +SSTVClient sstv(&radio); // test "image" - actually just a single 320px line // will be sent over and over again, to create vertical color stripes at the receiver @@ -85,16 +88,9 @@ uint32_t line[320] = { void setup() { Serial.begin(9600); - // initialize SX1278 + // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // current limit: 100 mA - // sync word: 0x2D 0x01 - int state = fsk.beginFSK(); + int state = radio.beginFSK(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -105,7 +101,7 @@ void setup() { // when using one of the non-LoRa modules for SSTV // (RF69, SX1231 etc.), use the basic begin() method - // int state = fsk.begin(); + // int state = radio.begin(); // initialize SSTV client Serial.print(F("[SSTV] Initializing ... ")); @@ -152,7 +148,7 @@ void loop() { } // turn off transmitter - fsk.standby(); + radio.standby(); Serial.println(F("done!")); diff --git a/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino new file mode 100644 index 00000000..e27bf67e --- /dev/null +++ b/examples/SSTV/SSTV_Transmit_AFSK/SSTV_Transmit_AFSK.ino @@ -0,0 +1,152 @@ +/* + RadioLib SSTV Transmit AFSK Example + + The following example sends SSTV picture using + SX1278's FSK modem. The data is modulated + as AFSK. + + Other modules that can be used for SSTV: + with AFSK modulation: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - Si443x/RFM2x + + NOTE: Some platforms (such as Arduino Uno) + might not be fast enough to correctly + send pictures via high-speed modes + like Scottie2 or Martin2. For those, + lower speed modes such as Wrasse, + Scottie1 or Martin1 are recommended. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// pin 5 is connected to SX1278 DIO2 +AFSKClient audio(&radio, 5); + +// create SSTV client instance using the AFSK instance +SSTVClient sstv(&audio); + +// test "image" - actually just a single 320px line +// will be sent over and over again, to create vertical color stripes at the receiver +uint32_t line[320] = { + // black + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + + // blue + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + + // green + 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, + 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, + + // cyan + 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, + 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, + + // red + 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, + 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, + + // magenta + 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, + 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, + + // yellow + 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, + 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, + + // white + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF +}; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // when using one of the non-LoRa modules for SSTV + // (RF69, SX1231 etc.), use the basic begin() method + // int state = radio.begin(); + + // initialize SSTV client + Serial.print(F("[SSTV] Initializing ... ")); + // SSTV mode: Wrasse (SC2-180) + // correction factor: 0.95 + // NOTE: Due to different speeds of various platforms + // supported by RadioLib (Arduino Uno, ESP32 etc), + // and because SSTV is analog protocol, incorrect + // timing of pulses can lead to distortions. + // To compensate, correction factor can be used + // to adjust the length of timing pulses + // (lower number = shorter pulses). + // The value is usually around 0.95 (95%). + state = sstv.begin(Wrasse, 0.95); + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // to help tune the receiver, SSTVClient can send + // continuous 1900 Hz beep + /* + sstv.idle(); + while(true); + */ +} + +void loop() { + // send picture with 8 color stripes + Serial.print(F("[SSTV] Sending test picture ... ")); + + // send synchronization header first + sstv.sendHeader(); + + // send all picture lines + for(uint16_t i = 0; i < sstv.getPictureHeight(); i++) { + sstv.sendLine(line); + } + + // turn off transmitter + radio.standby(); + + Serial.println(F("done!")); + + delay(30000); +} diff --git a/examples/SX1231/SX1231_Receive/SX1231_Receive.ino b/examples/SX1231/SX1231_Receive/SX1231_Receive.ino index 727de1e5..18d0354c 100644 --- a/examples/SX1231/SX1231_Receive/SX1231_Receive.ino +++ b/examples/SX1231/SX1231_Receive/SX1231_Receive.ino @@ -7,6 +7,9 @@ interface. Please see RF69 examples for examples on AES, address filtering, interrupts and settings. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -18,24 +21,18 @@ // CS pin: 10 // DIO0 pin: 2 // RESET pin: 3 -SX1231 rf = new Module(10, 2, 3); +SX1231 radio = new Module(10, 2, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1231 rf = RadioShield.ModuleA; +//SX1231 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1231 with default settings Serial.print(F("[SX1231] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // Rx bandwidth: 125.0 kHz - // frequency deviation: 50.0 kHz - // output power: 13 dBm - // sync word: 0x2D01 - int state = rf.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -50,12 +47,12 @@ void loop() { // you can receive data as an Arduino String String str; - int state = rf.receive(str); + int state = radio.receive(str); // you can also receive data as byte array /* byte byteArr[8]; - int state = rf.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino b/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino index e651202a..0f8cd14b 100644 --- a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino +++ b/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino @@ -7,6 +7,9 @@ interface. Please see RF69 examples for examples on AES, address filtering, interrupts and settings. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#rf69sx1231 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -18,24 +21,18 @@ // CS pin: 10 // DIO0 pin: 2 // RESET pin: 3 -SX1231 rf = new Module(10, 2, 3); +SX1231 radio = new Module(10, 2, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1231 rf = RadioShield.ModuleA; +//SX1231 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1231 with default settings Serial.print(F("[SX1231] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // Rx bandwidth: 125.0 kHz - // frequency deviation: 50.0 kHz - // output power: 13 dBm - // sync word: 0x2D01 - int state = rf.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -49,12 +46,12 @@ void loop() { Serial.print(F("[SX1231] Transmitting packet ... ")); // you can transmit C-string or Arduino string up to 256 characters long - int state = rf.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = rf.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino index 99209b99..b888a95d 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino @@ -8,6 +8,9 @@ Other modules from SX126x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -20,29 +23,18 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1262 lora = new Module(10, 2, 3, 9); +SX1262 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1262 lora = RadioShield.ModuleA; +//SX1262 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bandwidth: 125.0 kHz - // spreading factor: 9 - // coding rate: 7 - // sync word: 0x12 (private network) - // output power: 14 dBm - // current limit: 60 mA - // preamble length: 8 symbols - // TCXO voltage: 1.6 V (set to 0 to not use TCXO) - // regulator: DC-DC (set to true to use LDO) - // CRC: enabled - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -56,7 +48,7 @@ void loop() { Serial.print(F("[SX1262] Scanning channel for LoRa transmission ... ")); // start scanning current channel - int state = lora.scanChannel(); + int state = radio.scanChannel(); if (state == LORA_DETECTED) { // LoRa preamble was detected diff --git a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino index 90730ed0..d450f9c6 100644 --- a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino +++ b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino @@ -9,6 +9,9 @@ modem and use the appropriate configuration methods. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---fsk-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -21,30 +24,18 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1262 fsk = new Module(10, 2, 3, 9); +SX1262 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1262 fsk = RadioShield.ModuleA; +//SX1262 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1262 FSK modem with default settings Serial.print(F("[SX1262] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 156.2 kHz - // output power: 14 dBm - // current limit: 60.0 mA - // preamble length: 16 bits - // data shaping: Gaussian, BT = 0.5 - // TCXO voltage: 1.6 V (set to 0 to not use TCXO) - // regulator: DC-DC (set to true to use LDO) - // sync word: 0x2D 0x01 - // CRC: enabled, CRC16 (CCIT) - int state = fsk.beginFSK(); + int state = radio.beginFSK(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -55,21 +46,21 @@ void setup() { // if needed, you can switch between LoRa and FSK modes // - // lora.begin() start LoRa mode (and disable FSK) - // lora.beginFSK() start FSK mode (and disable LoRa) + // radio.begin() start LoRa mode (and disable FSK) + // radio.beginFSK() start FSK mode (and disable LoRa) // the following settings can also // be modified at run-time - state = fsk.setFrequency(433.5); - state = fsk.setBitRate(100.0); - state = fsk.setFrequencyDeviation(10.0); - state = fsk.setRxBandwidth(250.0); - state = fsk.setOutputPower(10.0); - state = fsk.setCurrentLimit(100.0); - state = fsk.setDataShaping(1.0); + state = radio.setFrequency(433.5); + state = radio.setBitRate(100.0); + state = radio.setFrequencyDeviation(10.0); + state = radio.setRxBandwidth(250.0); + state = radio.setOutputPower(10.0); + state = radio.setCurrentLimit(100.0); + state = radio.setDataShaping(RADIOLIB_SHAPING_1_0); uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - state = fsk.setSyncWord(syncWord, 8); + state = radio.setSyncWord(syncWord, 8); if (state != ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); @@ -78,15 +69,15 @@ void setup() { // FSK modem on SX126x can handle the sync word setting in bits, not just // whole bytes. The value used is left-justified. - // This makes same result as fsk.setSyncWord(syncWord, 8): - state = fsk.setSyncBits(syncWord, 64); + // This makes same result as radio.setSyncWord(syncWord, 8): + state = radio.setSyncBits(syncWord, 64); // This will use 0x012 as sync word (12 bits only): - state = fsk.setSyncBits(syncWord, 12); + state = radio.setSyncBits(syncWord, 12); // FSK modem allows advanced CRC configuration // Default is CCIT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted) // Set CRC to IBM CRC (2 bytes, initial 0xFFFF, polynomial 0x8005, non-inverted) - state = fsk.setCRC(2, 0xFFFF, 0x8005, false); + state = radio.setCRC(2, 0xFFFF, 0x8005, false); // set CRC length to 0 to disable CRC #warning "This sketch is just an API guide! Read the note at line 6." @@ -97,11 +88,11 @@ void loop() { // as the LoRa modem, even their interrupt-driven versions // transmit FSK packet - int state = fsk.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = lora.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { Serial.println(F("[SX1262] Packet transmitted successfully!")); @@ -116,10 +107,10 @@ void loop() { // receive FSK packet String str; - state = fsk.receive(str); + state = radio.receive(str); /* byte byteArr[8]; - int state = lora.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { Serial.println(F("[SX1262] Received packet!")); @@ -139,13 +130,13 @@ void loop() { // to transmit packet to a particular address, // use the following methods: // - // fsk.transmit("Hello World!", address); - // fsk.startTransmit("Hello World!", address); + // radio.transmit("Hello World!", address); + // radio.startTransmit("Hello World!", address); // set node address to 0x02 - state = fsk.setNodeAddress(0x02); + state = radio.setNodeAddress(0x02); // set broadcast address to 0xFF - state = fsk.setBroadcastAddress(0xFF); + state = radio.setBroadcastAddress(0xFF); if (state != ERR_NONE) { Serial.println(F("[SX1262] Unable to set address filter, code ")); Serial.println(state); @@ -155,7 +146,7 @@ void loop() { // NOTE: calling this method will also erase previously set // node and broadcast address /* - state = fsk.disableAddressFiltering(); + state = radio.disableAddressFiltering(); if (state != ERR_NONE) { Serial.println(F("Unable to remove address filter, code ")); } diff --git a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino b/examples/SX126x/SX126x_Receive/SX126x_Receive.ino index c95592f0..23969cb1 100644 --- a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino +++ b/examples/SX126x/SX126x_Receive/SX126x_Receive.ino @@ -13,6 +13,9 @@ Other modules from SX126x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -25,29 +28,18 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1262 lora = new Module(10, 2, 3, 9); +SX1262 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1262 lora = RadioShield.ModuleA; +//SX1262 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bandwidth: 125.0 kHz - // spreading factor: 9 - // coding rate: 7 - // sync word: 0x12 (private network) - // output power: 14 dBm - // current limit: 60 mA - // preamble length: 8 symbols - // TCXO voltage: 1.6 V (set to 0 to not use TCXO) - // regulator: DC-DC (set to true to use LDO) - // CRC: enabled - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -65,12 +57,12 @@ void loop() { // See example ReceiveInterrupt for details // on non-blocking reception method. String str; - int state = lora.receive(str); + int state = radio.receive(str); // you can also receive data as byte array /* byte byteArr[8]; - int state = lora.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { @@ -84,13 +76,13 @@ void loop() { // print the RSSI (Received Signal Strength Indicator) // of the last received packet Serial.print(F("[SX1262] RSSI:\t\t")); - Serial.print(lora.getRSSI()); + Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); // print the SNR (Signal-to-Noise Ratio) // of the last received packet Serial.print(F("[SX1262] SNR:\t\t")); - Serial.print(lora.getSNR()); + Serial.print(radio.getSNR()); Serial.println(F(" dB")); } else if (state == ERR_RX_TIMEOUT) { diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index 59d49f53..3932f7b0 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -12,7 +12,10 @@ - coding rate - sync word - Other modules from SX126x/RFM9x family can also be used. + Other modules from SX126x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ @@ -26,29 +29,18 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1262 lora = new Module(10, 2, 3, 9); +SX1262 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1262 lora = RadioShield.ModuleA; +//SX1262 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bandwidth: 125.0 kHz - // spreading factor: 9 - // coding rate: 7 - // sync word: 0x12 (private network) - // output power: 14 dBm - // current limit: 60 mA - // preamble length: 8 symbols - // TCXO voltage: 1.6 V (set to 0 to not use TCXO) - // regulator: DC-DC (set to true to use LDO) - // CRC: enabled - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -59,11 +51,11 @@ void setup() { // set the function that will be called // when new packet is received - lora.setDio1Action(setFlag); + radio.setDio1Action(setFlag); // start listening for LoRa packets Serial.print(F("[SX1262] Starting to listen ... ")); - state = lora.startReceive(); + state = radio.startReceive(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -75,12 +67,12 @@ void setup() { // if needed, 'listen' mode can be disabled by calling // any of the following methods: // - // lora.standby() - // lora.sleep() - // lora.transmit(); - // lora.receive(); - // lora.readData(); - // lora.scanChannel(); + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); + // radio.scanChannel(); } // flag to indicate that a packet was received @@ -115,12 +107,12 @@ void loop() { // you can read received data as an Arduino String String str; - int state = lora.readData(str); + int state = radio.readData(str); // you can also read received data as byte array /* byte byteArr[8]; - int state = lora.readData(byteArr, 8); + int state = radio.readData(byteArr, 8); */ if (state == ERR_NONE) { @@ -133,12 +125,12 @@ void loop() { // print RSSI (Received Signal Strength Indicator) Serial.print(F("[SX1262] RSSI:\t\t")); - Serial.print(lora.getRSSI()); + Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); // print SNR (Signal-to-Noise Ratio) Serial.print(F("[SX1262] SNR:\t\t")); - Serial.print(lora.getSNR()); + Serial.print(radio.getSNR()); Serial.println(F(" dB")); } else if (state == ERR_CRC_MISMATCH) { @@ -153,7 +145,7 @@ void loop() { } // put module back to listen mode - lora.startReceive(); + radio.startReceive(); // we're ready to receive more packets, // enable interrupt service routine diff --git a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino index 3da7d650..f485284f 100644 --- a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino +++ b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino @@ -17,6 +17,9 @@ Other modules from SX126x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -29,36 +32,25 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1262 loraSX1262 = new Module(10, 2, 3, 9); +SX1262 radio1 = new Module(10, 2, 3, 9); // SX12628 has different connections: // NSS pin: 8 // DIO1 pin: 4 // NRST pin: 5 // BUSY pin: 6 -SX1268 loraSX1268 = new Module(8, 4, 5, 6); +SX1268 radio2 = new Module(8, 4, 5, 6); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1261 loraSX1261 = RadioShield.ModuleB; +//SX1261 radio3 = RadioShield.ModuleB; void setup() { Serial.begin(9600); // initialize SX1268 with default settings Serial.print(F("[SX1262] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bandwidth: 125.0 kHz - // spreading factor: 9 - // coding rate: 7 - // sync word: 0x12 (private network) - // output power: 14 dBm - // current limit: 60 mA - // preamble length: 8 symbols - // TCXO voltage: 1.6 V (set to 0 to not use TCXO) - // regulator: DC-DC (set to true to use LDO) - // CRC: enabled - int state = loraSX1262.begin(); + int state = radio1.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -78,10 +70,8 @@ void setup() { // coding rate: 5 // sync word: 0x34 (public network/LoRaWAN) // output power: 2 dBm - // current limit: 50 mA // preamble length: 20 symbols - // CRC: enabled - state = loraSX1268.begin(915.0, 500.0, 6, 5, 0x34, 50, 20); + state = radio2.begin(915.0, 500.0, 6, 5, 0x34, 20); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -94,56 +84,56 @@ void setup() { // and check if the configuration was changed successfully // set carrier frequency to 433.5 MHz - if (loraSX1262.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { + if (radio1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { Serial.println(F("Selected frequency is invalid for this module!")); while (true); } // set bandwidth to 250 kHz - if (loraSX1262.setBandwidth(250.0) == ERR_INVALID_BANDWIDTH) { + if (radio1.setBandwidth(250.0) == ERR_INVALID_BANDWIDTH) { Serial.println(F("Selected bandwidth is invalid for this module!")); while (true); } // set spreading factor to 10 - if (loraSX1262.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) { + if (radio1.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) { Serial.println(F("Selected spreading factor is invalid for this module!")); while (true); } // set coding rate to 6 - if (loraSX1262.setCodingRate(6) == ERR_INVALID_CODING_RATE) { + if (radio1.setCodingRate(6) == ERR_INVALID_CODING_RATE) { Serial.println(F("Selected coding rate is invalid for this module!")); while (true); } // set LoRa sync word to 0xAB - if (loraSX1262.setSyncWord(0xAB) != ERR_NONE) { + if (radio1.setSyncWord(0xAB) != ERR_NONE) { Serial.println(F("Unable to set sync word!")); while (true); } // set output power to 10 dBm (accepted range is -17 - 22 dBm) - if (loraSX1262.setOutputPower(10) == ERR_INVALID_OUTPUT_POWER) { + if (radio1.setOutputPower(10) == ERR_INVALID_OUTPUT_POWER) { Serial.println(F("Selected output power is invalid for this module!")); while (true); } // set over current protection limit to 80 mA (accepted range is 45 - 240 mA) // NOTE: set value to 0 to disable overcurrent protection - if (loraSX1262.setCurrentLimit(80) == ERR_INVALID_CURRENT_LIMIT) { + if (radio1.setCurrentLimit(80) == ERR_INVALID_CURRENT_LIMIT) { Serial.println(F("Selected current limit is invalid for this module!")); while (true); } // set LoRa preamble length to 15 symbols (accepted range is 0 - 65535) - if (loraSX1262.setPreambleLength(15) == ERR_INVALID_PREAMBLE_LENGTH) { + if (radio1.setPreambleLength(15) == ERR_INVALID_PREAMBLE_LENGTH) { Serial.println(F("Selected preamble length is invalid for this module!")); while (true); } // disable CRC - if (loraSX1262.setCRC(false) == ERR_INVALID_CRC_CONFIGURATION) { + if (radio1.setCRC(false) == ERR_INVALID_CRC_CONFIGURATION) { Serial.println(F("Selected CRC is invalid for this module!")); while (true); } @@ -151,7 +141,7 @@ void setup() { // Some SX126x modules have TCXO (temperature compensated crystal // oscillator). To configure TCXO reference voltage, // the following method can be used. - if (loraSX1262.setTCXO(2.4) == ERR_INVALID_TCXO_VOLTAGE) { + if (radio1.setTCXO(2.4) == ERR_INVALID_TCXO_VOLTAGE) { Serial.println(F("Selected TCXO voltage is invalid for this module!")); while (true); } @@ -160,7 +150,7 @@ void setup() { // this feature, the following method can be used. // NOTE: As long as DIO2 is configured to control RF switch, // it can't be used as interrupt pin! - if (loraSX1262.setDio2AsRfSwitch() != ERR_NONE) { + if (radio1.setDio2AsRfSwitch() != ERR_NONE) { Serial.println(F("Failed to set DIO2 as RF switch!")); while (true); } diff --git a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino index 574fdff3..541645ee 100644 --- a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino +++ b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino @@ -9,6 +9,9 @@ Other modules from SX126x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -21,29 +24,18 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1262 lora = new Module(10, 2, 3, 9); +SX1262 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1262 lora = RadioShield.ModuleA; +//SX1262 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bandwidth: 125.0 kHz - // spreading factor: 9 - // coding rate: 7 - // sync word: 0x12 (private network) - // output power: 14 dBm - // current limit: 60 mA - // preamble length: 8 symbols - // TCXO voltage: 1.6 V (set to 0 to not use TCXO) - // regulator: DC-DC (set to true to use LDO) - // CRC: enabled - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -51,6 +43,16 @@ void setup() { Serial.println(state); while (true); } + + // some modules have an external RF switch + // controlled via two pins (RX enable, TX enable) + // to enable automatic control of the switch, + // call the following method + // RX enable: 4 + // TX enable: 5 + /* + radio.setRfSwitchPins(4, 5); + */ } void loop() { @@ -61,12 +63,12 @@ void loop() { // NOTE: transmit() is a blocking method! // See example SX126x_Transmit_Interrupt for details // on non-blocking transmission method. - int state = lora.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; - int state = lora.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { @@ -75,7 +77,7 @@ void loop() { // print measured data rate Serial.print(F("[SX1262] Datarate:\t")); - Serial.print(lora.getDataRate()); + Serial.print(radio.getDataRate()); Serial.println(F(" bps")); } else if (state == ERR_PACKET_TOO_LONG) { diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 724e05dc..20600a11 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -10,6 +10,9 @@ Other modules from SX126x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -22,7 +25,11 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1262 lora = new Module(10, 2, 3, 9); +SX1262 radio = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1262 radio = RadioShield.ModuleA; // save transmission state between loops int transmissionState = ERR_NONE; @@ -32,18 +39,7 @@ void setup() { // initialize SX1262 with default settings Serial.print(F("[SX1262] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bandwidth: 125.0 kHz - // spreading factor: 9 - // coding rate: 7 - // sync word: 0x12 (private network) - // output power: 14 dBm - // current limit: 60 mA - // preamble length: 8 symbols - // TCXO voltage: 1.6 V (set to 0 to not use TCXO) - // regulator: DC-DC (set to true to use LDO) - // CRC: enabled - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -54,20 +50,20 @@ void setup() { // set the function that will be called // when packet transmission is finished - lora.setDio1Action(setFlag); + radio.setDio1Action(setFlag); // start transmitting the first packet Serial.print(F("[SX1262] Sending first packet ... ")); // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = lora.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World!"); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - state = lora.startTransmit(byteArr, 8); + state = radio.startTransmit(byteArr, 8); */ } @@ -123,13 +119,13 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = lora.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World!"); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = lora.startTransmit(byteArr, 8); + int state = radio.startTransmit(byteArr, 8); */ // we're ready to send more packets, diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino b/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino index 4d946254..ececb747 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino @@ -9,6 +9,9 @@ Other modules from SX127x/RFM9x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -21,27 +24,18 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 lora = new Module(10, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1278 lora = RadioShield.ModuleA; +//SX1278 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bandwidth: 125.0 kHz - // spreading factor: 9 - // coding rate: 7 - // sync word: 0x12 - // output power: 17 dBm - // current limit: 100 mA - // preamble length: 8 symbols - // amplifier gain: 0 (automatic gain control) - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -55,7 +49,7 @@ void loop() { Serial.print(F("[SX1278] Scanning channel for LoRa preamble ... ")); // start scanning current channel - int state = lora.scanChannel(); + int state = radio.scanChannel(); if (state == PREAMBLE_DETECTED) { // LoRa preamble was detected diff --git a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino index 7727bcfe..d6294889 100644 --- a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino +++ b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino @@ -9,6 +9,9 @@ modem and use the appropriate configuration methods. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---fsk-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -21,7 +24,7 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 fsk = new Module(10, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield @@ -32,16 +35,7 @@ void setup() { // initialize SX1278 FSK modem with default settings Serial.print(F("[SX1278] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 125.0 kHz - // output power: 13 dBm - // current limit: 100 mA - // data shaping: Gaussian, BT = 0.5 - // sync word: 0x2D 0x01 - // OOK modulation: disabled - int state = fsk.beginFSK(); + int state = radio.beginFSK(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -52,21 +46,21 @@ void setup() { // if needed, you can switch between LoRa and FSK modes // - // lora.begin() start LoRa mode (and disable FSK) - // lora.beginFSK() start FSK mode (and disable LoRa) + // radio.begin() start LoRa mode (and disable FSK) + // radio.beginFSK() start FSK mode (and disable LoRa) // the following settings can also // be modified at run-time - state = fsk.setFrequency(433.5); - state = fsk.setBitRate(100.0); - state = fsk.setFrequencyDeviation(10.0); - state = fsk.setRxBandwidth(250.0); - state = fsk.setOutputPower(10.0); - state = fsk.setCurrentLimit(100); - state = fsk.setDataShaping(0.5); + state = radio.setFrequency(433.5); + state = radio.setBitRate(100.0); + state = radio.setFrequencyDeviation(10.0); + state = radio.setRxBandwidth(250.0); + state = radio.setOutputPower(10.0); + state = radio.setCurrentLimit(100); + state = radio.setDataShaping(RADIOLIB_SHAPING_0_5); uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - state = fsk.setSyncWord(syncWord, 8); + state = radio.setSyncWord(syncWord, 8); if (state != ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); @@ -78,8 +72,8 @@ void setup() { // Also, data shaping changes from Gaussian filter to // simple filter with cutoff frequency. Make sure to call // setDataShapingOOK() to set the correct shaping! - state = fsk.setOOK(true); - state = fsk.setDataShapingOOK(1); + state = radio.setOOK(true); + state = radio.setDataShapingOOK(1); if (state != ERR_NONE) { Serial.print(F("Unable to change modulation, code ")); Serial.println(state); @@ -95,11 +89,11 @@ void loop() { // NOTE: FSK modem maximum packet length is 63 bytes! // transmit FSK packet - int state = fsk.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = lora.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { Serial.println(F("[SX1278] Packet transmitted successfully!")); @@ -114,10 +108,10 @@ void loop() { // receive FSK packet String str; - state = fsk.receive(str); + state = radio.receive(str); /* byte byteArr[8]; - int state = lora.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { Serial.println(F("[SX1278] Received packet!")); @@ -137,13 +131,13 @@ void loop() { // to transmit packet to a particular address, // use the following methods: // - // fsk.transmit("Hello World!", address); - // fsk.startTransmit("Hello World!", address); + // radio.transmit("Hello World!", address); + // radio.startTransmit("Hello World!", address); // set node address to 0x02 - state = fsk.setNodeAddress(0x02); + state = radio.setNodeAddress(0x02); // set broadcast address to 0xFF - state = fsk.setBroadcastAddress(0xFF); + state = radio.setBroadcastAddress(0xFF); if (state != ERR_NONE) { Serial.println(F("[SX1278] Unable to set address filter, code ")); Serial.println(state); @@ -153,7 +147,7 @@ void loop() { // NOTE: calling this method will also erase previously set // node and broadcast address /* - state = fsk.disableAddressFiltering(); + state = radio.disableAddressFiltering(); if (state != ERR_NONE) { Serial.println(F("Unable to remove address filter, code ")); } @@ -164,7 +158,7 @@ void loop() { // sent to DIO1 (data) and DIO2 (clock) // activate direct mode transmitter - state = fsk.transmitDirect(); + state = radio.transmitDirect(); if (state != ERR_NONE) { Serial.println(F("[SX1278] Unable to start direct transmission mode, code ")); Serial.println(state); @@ -175,7 +169,7 @@ void loop() { // it is recommended to set data shaping to 0 // (no shaping) when transmitting audio - state = fsk.setDataShaping(0.0); + state = radio.setDataShaping(0.0); if (state != ERR_NONE) { Serial.println(F("[SX1278] Unable to set data shaping, code ")); Serial.println(state); @@ -199,7 +193,7 @@ void loop() { // direct mode transmissions can also be received // as bit stream on DIO1 (data) and DIO2 (clock) - state = fsk.receiveDirect(); + state = radio.receiveDirect(); if (state != ERR_NONE) { Serial.println(F("[SX1278] Unable to start direct reception mode, code ")); Serial.println(state); @@ -207,5 +201,5 @@ void loop() { // NOTE: you will not be able to send or receive packets // while direct mode is active! to deactivate it, call method - // fsk.packetMode() + // radio.packetMode() } diff --git a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino b/examples/SX127x/SX127x_Receive/SX127x_Receive.ino index 5627bdc3..0f839eec 100644 --- a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino +++ b/examples/SX127x/SX127x_Receive/SX127x_Receive.ino @@ -13,6 +13,9 @@ Other modules from SX127x/RFM9x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -25,27 +28,18 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 lora = new Module(10, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1278 lora = RadioShield.ModuleA; +//SX1278 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bandwidth: 125.0 kHz - // spreading factor: 9 - // coding rate: 7 - // sync word: 0x12 - // output power: 17 dBm - // current limit: 100 mA - // preamble length: 8 symbols - // amplifier gain: 0 (automatic gain control) - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -63,12 +57,12 @@ void loop() { // See example ReceiveInterrupt for details // on non-blocking reception method. String str; - int state = lora.receive(str); + int state = radio.receive(str); // you can also receive data as byte array /* byte byteArr[8]; - int state = lora.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { @@ -82,19 +76,19 @@ void loop() { // print the RSSI (Received Signal Strength Indicator) // of the last received packet Serial.print(F("[SX1278] RSSI:\t\t\t")); - Serial.print(lora.getRSSI()); + Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); // print the SNR (Signal-to-Noise Ratio) // of the last received packet Serial.print(F("[SX1278] SNR:\t\t\t")); - Serial.print(lora.getSNR()); + Serial.print(radio.getSNR()); Serial.println(F(" dB")); // print frequency error // of the last received packet Serial.print(F("[SX1278] Frequency error:\t")); - Serial.print(lora.getFrequencyError()); + Serial.print(radio.getFrequencyError()); Serial.println(F(" Hz")); } else if (state == ERR_RX_TIMEOUT) { diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index 7f192757..8a755bb8 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -14,6 +14,9 @@ Other modules from SX127x/RFM9x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -26,27 +29,18 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 lora = new Module(10, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1278 lora = RadioShield.ModuleA; +//SX1278 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bandwidth: 125.0 kHz - // spreading factor: 9 - // coding rate: 7 - // sync word: 0x12 - // output power: 17 dBm - // current limit: 100 mA - // preamble length: 8 symbols - // amplifier gain: 0 (automatic gain control) - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -57,11 +51,11 @@ void setup() { // set the function that will be called // when new packet is received - lora.setDio0Action(setFlag); + radio.setDio0Action(setFlag); // start listening for LoRa packets Serial.print(F("[SX1278] Starting to listen ... ")); - state = lora.startReceive(); + state = radio.startReceive(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -73,12 +67,12 @@ void setup() { // if needed, 'listen' mode can be disabled by calling // any of the following methods: // - // lora.standby() - // lora.sleep() - // lora.transmit(); - // lora.receive(); - // lora.readData(); - // lora.scanChannel(); + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); + // radio.scanChannel(); } // flag to indicate that a packet was received @@ -113,12 +107,12 @@ void loop() { // you can read received data as an Arduino String String str; - int state = lora.readData(str); + int state = radio.readData(str); // you can also read received data as byte array /* byte byteArr[8]; - int state = lora.readData(byteArr, 8); + int state = radio.readData(byteArr, 8); */ if (state == ERR_NONE) { @@ -131,17 +125,17 @@ void loop() { // print RSSI (Received Signal Strength Indicator) Serial.print(F("[SX1278] RSSI:\t\t")); - Serial.print(lora.getRSSI()); + Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); // print SNR (Signal-to-Noise Ratio) Serial.print(F("[SX1278] SNR:\t\t")); - Serial.print(lora.getSNR()); + Serial.print(radio.getSNR()); Serial.println(F(" dB")); // print frequency error Serial.print(F("[SX1278] Frequency error:\t")); - Serial.print(lora.getFrequencyError()); + Serial.print(radio.getFrequencyError()); Serial.println(F(" Hz")); } else if (state == ERR_CRC_MISMATCH) { @@ -156,7 +150,7 @@ void loop() { } // put module back to listen mode - lora.startReceive(); + radio.startReceive(); // we're ready to receive more packets, // enable interrupt service routine diff --git a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino index 76b26b10..84f31fac 100644 --- a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino +++ b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino @@ -13,6 +13,9 @@ Other modules from SX127x/RFM9x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -25,34 +28,25 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 loraSX1278 = new Module(10, 2, 9, 3); +SX1278 radio1 = new Module(10, 2, 9, 3); // SX1272 has different connections: // NSS pin: 9 // DIO0 pin: 4 // RESET pin: 5 // DIO1 pin: 6 -SX1272 loraSX1272 = new Module(9, 4, 5, 6); +SX1272 radio2 = new Module(9, 4, 5, 6); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1276 loraSX1276 = RadioShield.ModuleB; +//SX1276 radio3 = RadioShield.ModuleB; void setup() { Serial.begin(9600); // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bandwidth: 125.0 kHz - // spreading factor: 9 - // coding rate: 7 - // sync word: 0x12 - // output power: 17 dBm - // current limit: 100 mA - // preamble length: 8 symbols - // amplifier gain: 0 (automatic gain control) - int state = loraSX1278.begin(); + int state = radio1.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -76,10 +70,9 @@ void setup() { // coding rate: 5 // sync word: 0x14 // output power: 2 dBm - // current limit: 50 mA // preamble length: 20 symbols // amplifier gain: 1 (maximum gain) - state = loraSX1272.begin(915.0, 500.0, 6, 5, 0x14, 2); + state = radio2.begin(915.0, 500.0, 6, 5, 0x14, 2, 20, 1); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -92,32 +85,32 @@ void setup() { // and check if the configuration was changed successfully // set carrier frequency to 433.5 MHz - if (loraSX1278.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { + if (radio1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { Serial.println(F("Selected frequency is invalid for this module!")); while (true); } // set bandwidth to 250 kHz - if (loraSX1278.setBandwidth(250.0) == ERR_INVALID_BANDWIDTH) { + if (radio1.setBandwidth(250.0) == ERR_INVALID_BANDWIDTH) { Serial.println(F("Selected bandwidth is invalid for this module!")); while (true); } // set spreading factor to 10 - if (loraSX1278.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) { + if (radio1.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) { Serial.println(F("Selected spreading factor is invalid for this module!")); while (true); } // set coding rate to 6 - if (loraSX1278.setCodingRate(6) == ERR_INVALID_CODING_RATE) { + if (radio1.setCodingRate(6) == ERR_INVALID_CODING_RATE) { Serial.println(F("Selected coding rate is invalid for this module!")); while (true); } // set LoRa sync word to 0x14 // NOTE: value 0x34 is reserved for LoRaWAN networks and should not be used - if (loraSX1278.setSyncWord(0x14) != ERR_NONE) { + if (radio1.setSyncWord(0x14) != ERR_NONE) { Serial.println(F("Unable to set sync word!")); while (true); } @@ -125,20 +118,20 @@ void setup() { // set output power to 10 dBm (accepted range is -3 - 17 dBm) // NOTE: 20 dBm value allows high power operation, but transmission // duty cycle MUST NOT exceed 1% - if (loraSX1278.setOutputPower(10) == ERR_INVALID_OUTPUT_POWER) { + if (radio1.setOutputPower(10) == ERR_INVALID_OUTPUT_POWER) { Serial.println(F("Selected output power is invalid for this module!")); while (true); } // set over current protection limit to 80 mA (accepted range is 45 - 240 mA) // NOTE: set value to 0 to disable overcurrent protection - if (loraSX1278.setCurrentLimit(80) == ERR_INVALID_CURRENT_LIMIT) { + if (radio1.setCurrentLimit(80) == ERR_INVALID_CURRENT_LIMIT) { Serial.println(F("Selected current limit is invalid for this module!")); while (true); } // set LoRa preamble length to 15 symbols (accepted range is 6 - 65535) - if (loraSX1278.setPreambleLength(15) == ERR_INVALID_PREAMBLE_LENGTH) { + if (radio1.setPreambleLength(15) == ERR_INVALID_PREAMBLE_LENGTH) { Serial.println(F("Selected preamble length is invalid for this module!")); while (true); } @@ -146,7 +139,7 @@ void setup() { // set amplifier gain to 1 (accepted range is 1 - 6, where 1 is maximum gain) // NOTE: set value to 0 to enable automatic gain control // leave at 0 unless you know what you're doing - if (loraSX1278.setGain(1) == ERR_INVALID_GAIN) { + if (radio1.setGain(1) == ERR_INVALID_GAIN) { Serial.println(F("Selected gain is invalid for this module!")); while (true); } diff --git a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino index cd5ad220..6113046b 100644 --- a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino +++ b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino @@ -9,6 +9,9 @@ Other modules from SX127x/RFM9x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -21,27 +24,18 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 lora = new Module(10, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1278 lora = RadioShield.ModuleA; +//SX1278 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bandwidth: 125.0 kHz - // spreading factor: 9 - // coding rate: 7 - // sync word: 0x12 - // output power: 17 dBm - // current limit: 100 mA - // preamble length: 8 symbols - // amplifier gain: 0 (automatic gain control) - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -49,6 +43,16 @@ void setup() { Serial.println(state); while (true); } + + // some modules have an external RF switch + // controlled via two pins (RX enable, TX enable) + // to enable automatic control of the switch, + // call the following method + // RX enable: 4 + // TX enable: 5 + /* + radio.setRfSwitchPins(4, 5); + */ } void loop() { @@ -59,12 +63,12 @@ void loop() { // NOTE: transmit() is a blocking method! // See example SX127x_Transmit_Interrupt for details // on non-blocking transmission method. - int state = lora.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = lora.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { @@ -73,7 +77,7 @@ void loop() { // print measured data rate Serial.print(F("[SX1278] Datarate:\t")); - Serial.print(lora.getDataRate()); + Serial.print(radio.getDataRate()); Serial.println(F(" bps")); } else if (state == ERR_PACKET_TOO_LONG) { diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index 0290e54b..7f4b33be 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -10,6 +10,9 @@ Other modules from SX127x/RFM9x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -22,11 +25,11 @@ // DIO0 pin: 2 // RESET pin: 9 // DIO1 pin: 3 -SX1278 lora = new Module(10, 2, 9, 3); +SX1278 radio = new Module(10, 2, 9, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1278 lora = RadioShield.ModuleA; +//SX1278 radio = RadioShield.ModuleA; // save transmission state between loops int transmissionState = ERR_NONE; @@ -36,16 +39,7 @@ void setup() { // initialize SX1278 with default settings Serial.print(F("[SX1278] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bandwidth: 125.0 kHz - // spreading factor: 9 - // coding rate: 7 - // sync word: 0x12 - // output power: 17 dBm - // current limit: 100 mA - // preamble length: 8 symbols - // amplifier gain: 0 (automatic gain control) - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -56,20 +50,20 @@ void setup() { // set the function that will be called // when packet transmission is finished - lora.setDio0Action(setFlag); + radio.setDio0Action(setFlag); // start transmitting the first packet Serial.print(F("[SX1278] Sending first packet ... ")); // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = lora.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World!"); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - state = lora.startTransmit(byteArr, 8); + state = radio.startTransmit(byteArr, 8); */ } @@ -125,13 +119,13 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = lora.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World!"); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = lora.startTransmit(byteArr, 8); + int state = radio.startTransmit(byteArr, 8); */ // we're ready to send more packets, diff --git a/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino b/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino index 166215b7..96a96ffa 100644 --- a/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino +++ b/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino @@ -11,6 +11,9 @@ modem and use the appropriate configuration methods. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---ble-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -23,25 +26,18 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1280 ble = new Module(10, 2, 3, 9); +SX1280 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1280 ble = RadioShield.ModuleA; +//SX1280 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); - // carrier frequency: 2400.0 MHz - // bit rate: 800 kbps - // frequency deviation: 400.0 kHz - // output power: 10 dBm - // preamble length: 16 bits - // data shaping: Gaussian, BT = 0.5 - // CRC: enabled, CRC16 (CCIT) - int state = ble.beginBLE(); + int state = radio.beginBLE(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -50,19 +46,19 @@ void setup() { while (true); } - // if needed, you can switch between LoRa and FSK modes + // if needed, you can switch between any of the modems // - // ble.begin() start LoRa mode (and disable BLE) - // lora.beginBLE() start BLE mode (and disable LoRa) + // radio.begin() start LoRa modem (and disable BLE) + // radio.beginBLE() start BLE modem (and disable LoRa) // the following settings can also // be modified at run-time - state = ble.setFrequency(2410.5); - state = ble.setBitRate(200); - state = ble.setFrequencyDeviation(100.0); - state = ble.setOutputPower(5); - state = ble.setDataShaping(1.0); - state = ble.setAccessAddress(0x12345678); + state = radio.setFrequency(2410.5); + state = radio.setBitRate(250); + state = radio.setFrequencyDeviation(100.0); + state = radio.setOutputPower(5); + state = radio.setDataShaping(1.0); + state = radio.setAccessAddress(0x12345678); if (state != ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); @@ -77,11 +73,11 @@ void loop() { // as the LoRa modem, even their interrupt-driven versions // transmit BLE packet - int state = ble.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = ble.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { Serial.println(F("[SX1280] Packet transmitted successfully!")); @@ -90,16 +86,16 @@ void loop() { } else if (state == ERR_TX_TIMEOUT) { Serial.println(F("[SX1280] Timed out while transmitting!")); } else { - Serial.println(F("[SX1280] Failed to transmit packet, code ")); + Serial.print(F("[SX1280] Failed to transmit packet, code ")); Serial.println(state); } // receive BLE packet String str; - state = ble.receive(str); + state = radio.receive(str); /* byte byteArr[8]; - int state = ble.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { Serial.println(F("[SX1280] Received packet!")); diff --git a/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino b/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino index 6ec30377..cec1560a 100644 --- a/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino +++ b/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino @@ -6,6 +6,9 @@ Other modules from SX128x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -18,25 +21,18 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1280 lora = new Module(10, 2, 3, 9); +SX1280 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1280 lora = RadioShield.ModuleA; +//SX1280 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); - // carrier frequency: 2400.0 MHz - // bandwidth: 812.5 kHz - // spreading factor: 9 - // coding rate: 7 - // output power: 10 dBm - // preamble length: 12 symbols - // CRC: enabled - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -50,7 +46,7 @@ void loop() { Serial.print(F("[SX1280] Scanning channel for LoRa transmission ... ")); // start scanning current channel - int state = lora.scanChannel(); + int state = radio.scanChannel(); if (state == LORA_DETECTED) { // LoRa preamble was detected diff --git a/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino b/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino index 1f28b834..cf2d0e7c 100644 --- a/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino +++ b/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino @@ -9,6 +9,9 @@ modem and use the appropriate configuration methods. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---flrc-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -21,26 +24,18 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1280 flrc = new Module(10, 2, 3, 9); +SX1280 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1280 flrc = RadioShield.ModuleA; +//SX1280 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); - // carrier frequency: 2400.0 MHz - // bit rate: 650 kbps - // coding rate: 3 - // output power: 10 dBm - // preamble length: 16 bits - // data shaping: Gaussian, BT = 0.5 - // sync word: 0x2D 0x01 0x4B 0x1D - // CRC: enabled - int state = flrc.beginFLRC(); + int state = radio.beginFLRC(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -49,20 +44,20 @@ void setup() { while (true); } - // if needed, you can switch between LoRa and FLRC modes + // if needed, you can switch between any of the modems // - // flrc.begin() start LoRa mode (and disable FLRC) - // lora.beginFLRC() start FLRC mode (and disable LoRa) + // radio.begin() start LoRa modem (and disable FLRC) + // radio.beginFLRC() start FLRC modem (and disable LoRa) // the following settings can also // be modified at run-time - state = flrc.setFrequency(2410.5); - state = flrc.setBitRate(200); - state = flrc.setCodingRate(2); - state = flrc.setOutputPower(5); - state = flrc.setDataShaping(1.0); + state = radio.setFrequency(2410.5); + state = radio.setBitRate(520); + state = radio.setCodingRate(2); + state = radio.setOutputPower(5); + state = radio.setDataShaping(1.0); uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; - state = flrc.setSyncWord(syncWord, 4); + state = radio.setSyncWord(syncWord, 4); if (state != ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); @@ -77,11 +72,11 @@ void loop() { // as the LoRa modem, even their interrupt-driven versions // transmit FLRC packet - int state = flrc.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = flrc.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { Serial.println(F("[SX1280] Packet transmitted successfully!")); @@ -94,12 +89,12 @@ void loop() { Serial.println(state); } - // receive GFSK packet + // receive FLRC packet String str; - state = flrc.receive(str); + state = radio.receive(str); /* byte byteArr[8]; - int state = flrc.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { Serial.println(F("[SX1280] Received packet!")); diff --git a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino index adfc5320..2df0d6ac 100644 --- a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino +++ b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino @@ -9,6 +9,9 @@ modem and use the appropriate configuration methods. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---gfsk-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -21,26 +24,18 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1280 gfsk = new Module(10, 2, 3, 9); +SX1280 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1280 lora = RadioShield.ModuleA; +//SX1280 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); - // carrier frequency: 2400.0 MHz - // bit rate: 800 kbps - // frequency deviation: 400.0 kHz - // output power: 10 dBm - // preamble length: 16 bits - // data shaping: Gaussian, BT = 0.5 - // sync word: 0x2D 0x01 - // CRC: enabled, CRC16 (CCIT) - int state = gfsk.beginGFSK(); + int state = radio.beginGFSK(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -49,20 +44,20 @@ void setup() { while (true); } - // if needed, you can switch between LoRa and FSK modes + // if needed, you can switch between any of the modems // - // gfsk.begin() start LoRa mode (and disable GFSK) - // lora.beginGFSK() start GFSK mode (and disable LoRa) + // radio.begin() start LoRa modem (and disable GFSK) + // radio.beginGFSK() start GFSK modem (and disable LoRa) // the following settings can also // be modified at run-time - state = gfsk.setFrequency(2410.5); - state = gfsk.setBitRate(200); - state = gfsk.setFrequencyDeviation(100.0); - state = gfsk.setOutputPower(5); - state = gfsk.setDataShaping(1.0); + state = radio.setFrequency(2410.5); + state = radio.setBitRate(200); + state = radio.setFrequencyDeviation(100.0); + state = radio.setOutputPower(5); + state = radio.setDataShaping(RADIOLIB_SHAPING_1_0); uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89}; - state = gfsk.setSyncWord(syncWord, 5); + state = radio.setSyncWord(syncWord, 5); if (state != ERR_NONE) { Serial.print(F("Unable to set configuration, code ")); Serial.println(state); @@ -77,11 +72,11 @@ void loop() { // as the LoRa modem, even their interrupt-driven versions // transmit GFSK packet - int state = gfsk.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = gfsk.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { Serial.println(F("[SX1280] Packet transmitted successfully!")); @@ -96,10 +91,10 @@ void loop() { // receive GFSK packet String str; - state = gfsk.receive(str); + state = radio.receive(str); /* byte byteArr[8]; - int state = gfsk.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { Serial.println(F("[SX1280] Received packet!")); diff --git a/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino b/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino index 585f948b..f53b1a2d 100644 --- a/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino +++ b/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino @@ -8,6 +8,9 @@ Only SX1280 and SX1282 support ranging! + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -20,25 +23,18 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1280 lora = new Module(10, 2, 3, 9); +SX1280 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1280 lora = RadioShield.ModuleA; +//SX1280 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); - // carrier frequency: 2400.0 MHz - // bandwidth: 812.5 kHz - // spreading factor: 9 - // coding rate: 7 - // output power: 10 dBm - // preamble length: 12 symbols - // CRC: enabled - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -54,18 +50,18 @@ void loop() { // start ranging exchange // range as master: true // slave address: 0x12345678 - int state = lora.range(true, 0x12345678); + int state = radio.range(true, 0x12345678); // the other module must be configured as slave with the same address /* - int state = lora.range(false, 0x12345678); + int state = radio.range(false, 0x12345678); */ if (state == ERR_NONE) { // ranging finished successfully Serial.println(F("success!")); Serial.print(F("[SX1280] Distance:\t\t\t")); - Serial.print(lora.getRangingResult()); + Serial.print(radio.getRangingResult()); Serial.println(F(" meters")); } else if (state == ERR_RANGING_TIMEOUT) { diff --git a/examples/SX128x/SX128x_Receive/SX128x_Receive.ino b/examples/SX128x/SX128x_Receive/SX128x_Receive.ino index 0427cf41..ff5adc41 100644 --- a/examples/SX128x/SX128x_Receive/SX128x_Receive.ino +++ b/examples/SX128x/SX128x_Receive/SX128x_Receive.ino @@ -13,6 +13,9 @@ Other modules from SX128x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -25,25 +28,18 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1280 lora = new Module(10, 2, 3, 9); +SX1280 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1280 lora = RadioShield.ModuleA; +//SX1280 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); - // carrier frequency: 2400.0 MHz - // bandwidth: 812.5 kHz - // spreading factor: 9 - // coding rate: 7 - // output power: 10 dBm - // preamble length: 12 symbols - // CRC: enabled - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -61,12 +57,12 @@ void loop() { // See example ReceiveInterrupt for details // on non-blocking reception method. String str; - int state = lora.receive(str); + int state = radio.receive(str); // you can also receive data as byte array /* byte byteArr[8]; - int state = lora.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { @@ -80,13 +76,13 @@ void loop() { // print the RSSI (Received Signal Strength Indicator) // of the last received packet Serial.print(F("[SX1280] RSSI:\t\t")); - Serial.print(lora.getRSSI()); + Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); // print the SNR (Signal-to-Noise Ratio) // of the last received packet Serial.print(F("[SX1280] SNR:\t\t")); - Serial.print(lora.getSNR()); + Serial.print(radio.getSNR()); Serial.println(F(" dB")); } else if (state == ERR_RX_TIMEOUT) { diff --git a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino index 2d6f1664..65e03f7d 100644 --- a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino +++ b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -14,6 +14,9 @@ Other modules from SX128x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -26,25 +29,18 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1280 lora = new Module(10, 2, 3, 9); +SX1280 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1280 lora = RadioShield.ModuleA; +//SX1280 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); - // carrier frequency: 2400.0 MHz - // bandwidth: 812.5 kHz - // spreading factor: 9 - // coding rate: 7 - // output power: 10 dBm - // preamble length: 12 symbols - // CRC: enabled - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -55,11 +51,11 @@ void setup() { // set the function that will be called // when new packet is received - lora.setDio1Action(setFlag); + radio.setDio1Action(setFlag); // start listening for LoRa packets Serial.print(F("[SX1280] Starting to listen ... ")); - state = lora.startReceive(); + state = radio.startReceive(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -71,12 +67,12 @@ void setup() { // if needed, 'listen' mode can be disabled by calling // any of the following methods: // - // lora.standby() - // lora.sleep() - // lora.transmit(); - // lora.receive(); - // lora.readData(); - // lora.scanChannel(); + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); + // radio.scanChannel(); } // flag to indicate that a packet was received @@ -111,12 +107,12 @@ void loop() { // you can read received data as an Arduino String String str; - int state = lora.readData(str); + int state = radio.readData(str); // you can also read received data as byte array /* byte byteArr[8]; - int state = lora.readData(byteArr, 8); + int state = radio.readData(byteArr, 8); */ if (state == ERR_NONE) { @@ -129,12 +125,12 @@ void loop() { // print RSSI (Received Signal Strength Indicator) Serial.print(F("[SX1280] RSSI:\t\t")); - Serial.print(lora.getRSSI()); + Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); // print SNR (Signal-to-Noise Ratio) Serial.print(F("[SX1280] SNR:\t\t")); - Serial.print(lora.getSNR()); + Serial.print(radio.getSNR()); Serial.println(F(" dB")); } else if (state == ERR_CRC_MISMATCH) { @@ -149,7 +145,7 @@ void loop() { } // put module back to listen mode - lora.startReceive(); + radio.startReceive(); // we're ready to receive more packets, // enable interrupt service routine diff --git a/examples/SX128x/SX128x_Settings/SX128x_Settings.ino b/examples/SX128x/SX128x_Settings/SX128x_Settings.ino index 49d218d6..0963d85a 100644 --- a/examples/SX128x/SX128x_Settings/SX128x_Settings.ino +++ b/examples/SX128x/SX128x_Settings/SX128x_Settings.ino @@ -14,6 +14,9 @@ Other modules from SX128x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -26,32 +29,25 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1280 loraSX1280 = new Module(10, 2, 3, 9); +SX1280 radio1 = new Module(10, 2, 3, 9); // SX1280 has the following connections: // NSS pin: 8 // DIO1 pin: 4 // NRST pin: 5 // BUSY pin: 6 -SX1281 loraSX1281 = new Module(8, 4, 5, 6); +SX1281 radio2 = new Module(8, 4, 5, 6); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1282 loraSX1282 = RadioShield.ModuleB; +//SX1282 radio3 = RadioShield.ModuleB; void setup() { Serial.begin(9600); // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); - // carrier frequency: 2400.0 MHz - // bandwidth: 812.5 kHz - // spreading factor: 9 - // coding rate: 7 - // output power: 10 dBm - // preamble length: 12 symbols - // CRC: enabled - int state = loraSX1280.begin(); + int state = radio1.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -71,8 +67,7 @@ void setup() { // coding rate: 5 // output power: 2 dBm // preamble length: 20 symbols - // CRC: enabled - state = loraSX1281.begin(2450.0, 1625.0, 7, 5, 2, 20); + state = radio2.begin(2450.0, 1625.0, 7, 5, 2, 20); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -85,43 +80,43 @@ void setup() { // and check if the configuration was changed successfully // set carrier frequency to 2410.5 MHz - if (loraSX1280.setFrequency(2410.5) == ERR_INVALID_FREQUENCY) { + if (radio1.setFrequency(2410.5) == ERR_INVALID_FREQUENCY) { Serial.println(F("Selected frequency is invalid for this module!")); while (true); } // set bandwidth to 203.125 kHz - if (loraSX1280.setBandwidth(203.125) == ERR_INVALID_BANDWIDTH) { + if (radio1.setBandwidth(203.125) == ERR_INVALID_BANDWIDTH) { Serial.println(F("Selected bandwidth is invalid for this module!")); while (true); } // set spreading factor to 10 - if (loraSX1280.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) { + if (radio1.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) { Serial.println(F("Selected spreading factor is invalid for this module!")); while (true); } // set coding rate to 6 - if (loraSX1280.setCodingRate(6) == ERR_INVALID_CODING_RATE) { + if (radio1.setCodingRate(6) == ERR_INVALID_CODING_RATE) { Serial.println(F("Selected coding rate is invalid for this module!")); while (true); } // set output power to -2 dBm - if (loraSX1280.setOutputPower(-2) == ERR_INVALID_OUTPUT_POWER) { + if (radio1.setOutputPower(-2) == ERR_INVALID_OUTPUT_POWER) { Serial.println(F("Selected output power is invalid for this module!")); while (true); } // set LoRa preamble length to 16 symbols (accepted range is 2 - 65535) - if (loraSX1280.setPreambleLength(16) == ERR_INVALID_PREAMBLE_LENGTH) { + if (radio1.setPreambleLength(16) == ERR_INVALID_PREAMBLE_LENGTH) { Serial.println(F("Selected preamble length is invalid for this module!")); while (true); } // disable CRC - if (loraSX1280.setCRC(false) == ERR_INVALID_CRC_CONFIGURATION) { + if (radio1.setCRC(false) == ERR_INVALID_CRC_CONFIGURATION) { Serial.println(F("Selected CRC is invalid for this module!")); while (true); } diff --git a/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino b/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino index e8e777dc..a4037def 100644 --- a/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino +++ b/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino @@ -9,6 +9,9 @@ Other modules from SX128x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -21,11 +24,11 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1280 lora = new Module(10, 2, 3, 9); +SX1280 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1280 lora = RadioShield.ModuleA; +//SX1280 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); @@ -39,7 +42,7 @@ void setup() { // output power: 10 dBm // preamble length: 12 symbols // CRC: enabled - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -47,6 +50,16 @@ void setup() { Serial.println(state); while (true); } + + // some modules have an external RF switch + // controlled via two pins (RX enable, TX enable) + // to enable automatic control of the switch, + // call the following method + // RX enable: 4 + // TX enable: 5 + /* + radio.setRfSwitchPins(4, 5); + */ } void loop() { @@ -57,12 +70,12 @@ void loop() { // NOTE: transmit() is a blocking method! // See example SX128x_Transmit_Interrupt for details // on non-blocking transmission method. - int state = lora.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; - int state = lora.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino index 284244e8..ecdd9312 100644 --- a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -10,6 +10,9 @@ Other modules from SX128x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -22,11 +25,11 @@ // DIO1 pin: 2 // NRST pin: 3 // BUSY pin: 9 -SX1280 lora = new Module(10, 2, 3, 9); +SX1280 radio = new Module(10, 2, 3, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//SX1280 lora = RadioShield.ModuleA; +//SX1280 radio = RadioShield.ModuleA; // save transmission state between loops int transmissionState = ERR_NONE; @@ -36,14 +39,7 @@ void setup() { // initialize SX1280 with default settings Serial.print(F("[SX1280] Initializing ... ")); - // carrier frequency: 2400.0 MHz - // bandwidth: 812.5 kHz - // spreading factor: 9 - // coding rate: 7 - // output power: 10 dBm - // preamble length: 12 symbols - // CRC: enabled - int state = lora.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -54,20 +50,20 @@ void setup() { // set the function that will be called // when packet transmission is finished - lora.setDio1Action(setFlag); + radio.setDio1Action(setFlag); // start transmitting the first packet Serial.print(F("[SX1280] Sending first packet ... ")); // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = lora.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World!"); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - state = lora.startTransmit(byteArr, 8); + state = radio.startTransmit(byteArr, 8); */ } @@ -119,13 +115,13 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = lora.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World!"); // you can also transmit byte array up to 256 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = lora.startTransmit(byteArr, 8); + int state = radio.startTransmit(byteArr, 8); */ // we're ready to send more packets, diff --git a/examples/Si443x/Si443x_Receive/Si443x_Receive.ino b/examples/Si443x/Si443x_Receive/Si443x_Receive.ino index 345fb8a6..846e46e3 100644 --- a/examples/Si443x/Si443x_Receive/Si443x_Receive.ino +++ b/examples/Si443x/Si443x_Receive/Si443x_Receive.ino @@ -11,6 +11,9 @@ Other modules from Si443x/RFM2x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -22,24 +25,18 @@ // nSEL pin: 10 // nIRQ pin: 2 // SDN pin: 9 -Si4432 fsk = new Module(10, 2, 9); +Si4432 radio = new Module(10, 2, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//Si4432 fsk = RadioShield.ModuleA; +//Si4432 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize Si4432 with default settings Serial.print(F("[Si4432] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 225.1 kHz - // output power: 11 dBm - // sync word: 0x2D 0x01 - int state = fsk.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -54,12 +51,12 @@ void loop() { // you can receive data as an Arduino String String str; - int state = fsk.receive(str); + int state = radio.receive(str); // you can also receive data as byte array /* byte byteArr[8]; - int state = rf.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino index a514980e..e890b08d 100644 --- a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino +++ b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino @@ -7,6 +7,9 @@ Other modules from Si443x/RFM2x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -18,24 +21,18 @@ // nSEL pin: 10 // nIRQ pin: 2 // SDN pin: 9 -Si4432 fsk = new Module(10, 2, 9); +Si4432 radio = new Module(10, 2, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//Si4432 fsk = RadioShield.ModuleA; +//Si4432 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize Si4432 with default settings Serial.print(F("[Si4432] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 225.1 kHz - // output power: 11 dBm - // sync word: 0x2D 0x01 - int state = fsk.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -46,11 +43,11 @@ void setup() { // set the function that will be called // when new packet is received - fsk.setIrqAction(setFlag); + radio.setIrqAction(setFlag); // start listening for packets Serial.print(F("[Si4432] Starting to listen ... ")); - state = fsk.startReceive(); + state = radio.startReceive(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -62,11 +59,11 @@ void setup() { // if needed, 'listen' mode can be disabled by calling // any of the following methods: // - // fsk.standby() - // fsk.sleep() - // fsk.transmit(); - // fsk.receive(); - // fsk.readData(); + // radio.standby() + // radio.sleep() + // radio.transmit(); + // radio.receive(); + // radio.readData(); } // flag to indicate that a packet was received @@ -101,12 +98,12 @@ void loop() { // you can read received data as an Arduino String String str; - int state = fsk.readData(str); + int state = radio.readData(str); // you can also read received data as byte array /* byte byteArr[8]; - int state = fsk.readData(byteArr, 8); + int state = radio.readData(byteArr, 8); */ if (state == ERR_NONE) { @@ -129,7 +126,7 @@ void loop() { } // put module back to listen mode - fsk.startReceive(); + radio.startReceive(); // we're ready to receive more packets, // enable interrupt service routine diff --git a/examples/Si443x/Si443x_Settings/Si443x_Settings.ino b/examples/Si443x/Si443x_Settings/Si443x_Settings.ino index b3d1ab82..cd420505 100644 --- a/examples/Si443x/Si443x_Settings/Si443x_Settings.ino +++ b/examples/Si443x/Si443x_Settings/Si443x_Settings.ino @@ -11,6 +11,9 @@ - output power during transmission - sync word + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -22,30 +25,24 @@ // nSEL pin: 10 // nIRQ pin: 2 // SDN pin: 9 -Si4432 fsk1 = new Module(10, 2, 9); +Si4432 radio1 = new Module(10, 2, 9); // Si4432 has the following connections: // nSEL pin: 8 // nIRQ pin: 3 // SDN pin: 7 -Si4432 fsk2 = new Module(8, 3, 7); +Si4432 radio2 = new Module(8, 3, 7); // or using RadioShield // https://github.com/jgromes/RadioShield -//Si4432 fsk3 = RadioShield.ModuleB; +//Si4432 radio3 = RadioShield.ModuleB; void setup() { Serial.begin(9600); // initialize Si4432 with default settings Serial.print(F("[Si4432] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 225.1 kHz - // output power: 11 dBm - // sync word: 0x2D 0x01 - int state = fsk1.begin(); + int state = radio1.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -61,8 +58,8 @@ void setup() { // frequency deviation: 60.0 kHz // Rx bandwidth: 335.5 kHz // output power: 17 dBm - // sync word: 0x2D 0x01 - state = fsk2.begin(868.0, 200.0, 60.0, 335.5, 17); + // preamble length: 32 bits + state = radio2.begin(868.0, 200.0, 60.0, 335.5, 17, 32); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -75,13 +72,13 @@ void setup() { // and check if the configuration was changed successfully // set carrier frequency to 433.5 MHz - if (fsk1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { + if (radio1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { Serial.println(F("[Si4432] Selected frequency is invalid for this module!")); while (true); } // set bit rate to 100.0 kbps - state = fsk1.setBitRate(100.0); + state = radio1.setBitRate(100.0); if (state == ERR_INVALID_BIT_RATE) { Serial.println(F("[Si4432] Selected bit rate is invalid for this module!")); while (true); @@ -92,20 +89,20 @@ void setup() { } // set receiver bandwidth to 284.8 kHz - state = fsk1.setRxBandwidth(284.8); + state = radio1.setRxBandwidth(284.8); if (state == ERR_INVALID_RX_BANDWIDTH) { Serial.println(F("[Si4432] Selected receiver bandwidth is invalid for this module!")); while (true); } // set frequency deviation to 10.0 kHz - if (fsk1.setFrequencyDeviation(10.0) == ERR_INVALID_FREQUENCY_DEVIATION) { + if (radio1.setFrequencyDeviation(10.0) == ERR_INVALID_FREQUENCY_DEVIATION) { Serial.println(F("[Si4432] Selected frequency deviation is invalid for this module!")); while (true); } // set output power to 2 dBm - if (fsk1.setOutputPower(2) == ERR_INVALID_OUTPUT_POWER) { + if (radio1.setOutputPower(2) == ERR_INVALID_OUTPUT_POWER) { Serial.println(F("[Si4432] Selected output power is invalid for this module!")); while (true); } @@ -113,7 +110,7 @@ void setup() { // up to 4 bytes can be set as sync word // set sync word to 0x01234567 uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; - if (fsk1.setSyncWord(syncWord, 4) == ERR_INVALID_SYNC_WORD) { + if (radio1.setSyncWord(syncWord, 4) == ERR_INVALID_SYNC_WORD) { Serial.println(F("[Si4432] Selected sync word is invalid for this module!")); while (true); } diff --git a/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino b/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino index 34a278da..ca267624 100644 --- a/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino +++ b/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino @@ -9,6 +9,9 @@ Other modules from Si443x/RFM2x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -20,24 +23,18 @@ // nSEL pin: 10 // nIRQ pin: 2 // SDN pin: 9 -Si4432 fsk = new Module(10, 2, 9); +Si4432 radio = new Module(10, 2, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//Si4432 fsk = RadioShield.ModuleA; +//Si4432 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); // initialize Si4432 with default settings Serial.print(F("[Si4432] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 225.1 kHz - // output power: 11 dBm - // sync word: 0x2D 0x01 - int state = fsk.begin(); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -55,12 +52,12 @@ void loop() { // NOTE: transmit() is a blocking method! // See example Si443x_Transmit_Interrupt for details // on non-blocking transmission method. - int state = fsk.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; - int state = fsk.transmit(byteArr, 8); + int state = radio.transmit(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino index e4c56c18..82c5364d 100644 --- a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -9,6 +9,9 @@ Other modules from Si443x/RFM2x family can also be used. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#si443xrfm2x + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -20,11 +23,11 @@ // nSEL pin: 10 // nIRQ pin: 2 // SDN pin: 9 -Si4432 fsk = new Module(10, 2, 9); +Si4432 radio = new Module(10, 2, 9); // or using RadioShield // https://github.com/jgromes/RadioShield -//Si4432 fsk = RadioShield.ModuleA; +//Si4432 radio = RadioShield.ModuleA; // save transmission state between loops int transmissionState = ERR_NONE; @@ -34,14 +37,7 @@ void setup() { // initialize Si4432 with default settings Serial.print(F("[Si4432] Initializing ... ")); - // carrier frequency: 434.0 MHz - // bit rate: 48.0 kbps - // frequency deviation: 50.0 kHz - // Rx bandwidth: 225.1 kHz - // output power: 11 dBm - // sync word: 0x2D 0x01 - int state = fsk.begin(); - fsk.setOutputPower(13); + int state = radio.begin(); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -52,20 +48,20 @@ void setup() { // set the function that will be called // when packet transmission is finished - fsk.setIrqAction(setFlag); + radio.setIrqAction(setFlag); // start transmitting the first packet Serial.print(F("[Si4432] Sending first packet ... ")); // you can transmit C-string or Arduino string up to // 64 characters long - transmissionState = fsk.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World!"); // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - state = fsk.startTransmit(byteArr, 8); + state = radio.startTransmit(byteArr, 8); */ } @@ -117,13 +113,13 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long - transmissionState = fsk.startTransmit("Hello World!"); + transmissionState = radio.startTransmit("Hello World!"); // you can also transmit byte array up to 64 bytes long /* byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - int state = fsk.startTransmit(byteArr, 8); + int state = radio.startTransmit(byteArr, 8); */ // we're ready to send more packets, diff --git a/examples/nRF24/nRF24_Receive/nRF24_Receive.ino b/examples/nRF24/nRF24_Receive/nRF24_Receive.ino index b5b5571e..2c036fd6 100644 --- a/examples/nRF24/nRF24_Receive/nRF24_Receive.ino +++ b/examples/nRF24/nRF24_Receive/nRF24_Receive.ino @@ -9,6 +9,9 @@ - transmit pipe on transmitter must match receive pipe on receiver + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -20,22 +23,18 @@ // CS pin: 10 // IRQ pin: 2 // CE pin: 3 -nRF24 nrf = new Module(10, 2, 3); +nRF24 radio = new Module(10, 2, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//nRF24 nrf = RadioShield.ModuleA; +//nRF24 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); - // initialize nRF24 + // initialize nRF24 with default settings Serial.print(F("[nRF24] Initializing ... ")); - // carrier frequency: 2400 MHz - // data rate: 1000 kbps - // output power: -12 dBm - // address width: 5 bytes - int state = nrf.begin(); + int state = radio.begin(); if(state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -50,7 +49,7 @@ void setup() { // methods (5 by default) Serial.print(F("[nRF24] Setting address for receive pipe 0 ... ")); byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89}; - state = nrf.setReceivePipe(0, addr); + state = radio.setReceivePipe(0, addr); if(state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -68,12 +67,12 @@ void loop() { // See example ReceiveInterrupt for details // on non-blocking reception method. String str; - int state = nrf.receive(str); + int state = radio.receive(str); // you can also receive data as byte array /* byte byteArr[8]; - int state = nrf.receive(byteArr, 8); + int state = radio.receive(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino b/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino index 89006b38..c692e8a8 100644 --- a/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino +++ b/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino @@ -9,6 +9,9 @@ Packet delivery is automatically acknowledged by the receiver. + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#nrf24 + For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ */ @@ -20,22 +23,18 @@ // CS pin: 10 // IRQ pin: 2 // CE pin: 3 -nRF24 nrf = new Module(10, 2, 3); +nRF24 radio = new Module(10, 2, 3); // or using RadioShield // https://github.com/jgromes/RadioShield -//nRF24 nrf = RadioShield.ModuleA; +//nRF24 radio = RadioShield.ModuleA; void setup() { Serial.begin(9600); - // initialize nRF24 + // initialize nRF24 with default settings Serial.print(F("[nRF24] Initializing ... ")); - // carrier frequency: 2400 MHz - // data rate: 1000 kbps - // output power: -12 dBm - // address width: 5 bytes - int state = nrf.begin(); + int state = radio.begin(); if(state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -50,7 +49,7 @@ void setup() { // methods (5 by default) byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89}; Serial.print(F("[nRF24] Setting transmit pipe ... ")); - state = nrf.setTransmitPipe(addr); + state = radio.setTransmitPipe(addr); if(state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -65,7 +64,7 @@ void loop() { // you can transmit C-string or Arduino string up to // 32 characters long - int state = nrf.transmit("Hello World!"); + int state = radio.transmit("Hello World!"); if (state == ERR_NONE) { // the packet was successfully transmitted diff --git a/extras/AiThinker_ESP8266_DIO_32M_32M_20160615_V1.5.4.bin b/extras/bin/AiThinker_ESP8266_DIO_32M_32M_20160615_V1.5.4.bin similarity index 100% rename from extras/AiThinker_ESP8266_DIO_32M_32M_20160615_V1.5.4.bin rename to extras/bin/AiThinker_ESP8266_DIO_32M_32M_20160615_V1.5.4.bin diff --git a/extras/AiThinker_ESP8266_DIO_8M_8M_20160615_V1.5.4.bin b/extras/bin/AiThinker_ESP8266_DIO_8M_8M_20160615_V1.5.4.bin similarity index 100% rename from extras/AiThinker_ESP8266_DIO_8M_8M_20160615_V1.5.4.bin rename to extras/bin/AiThinker_ESP8266_DIO_8M_8M_20160615_V1.5.4.bin diff --git a/extras/decoder/DebugDecoder.py b/extras/decoder/DebugDecoder.py new file mode 100644 index 00000000..330326f6 --- /dev/null +++ b/extras/decoder/DebugDecoder.py @@ -0,0 +1,112 @@ +import re, sys, argparse +from pathlib import Path +from argparse import RawTextHelpFormatter + + +''' +TODO list: + 1. Parse macro values (the names of bits in all registers in header file) + 2. Failed SPI write handling + 3. SX126x/SX128x handling + 4. AT handling +''' + + +def get_macro_name(value, macros): + for macro in macros: + if macro[1] == value: + return macro[0] + return 'UNKNOWN_VALUE' + + +def get_macro_value(value): + return ' 0x{0:02X}\n'.format(int(value, 16)) + + +parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description=''' + RadioLib debug output decoder script. Turns RadioLib Serial dumps into readable text. + + Step-by-step guid on how to use the decoder: + 1. Uncomment lines 312 (#define RADIOLIB_DEBUG) and 313 (#define RADIOLIB_VERBOSE) in RadioLib/src/BuildOpt.h + 2. Recompile and upload the failing Arduino sketch + 3. Open Arduino IDE Serial Monitor and enable timestamps + 4. Copy the Serial output and save it into a .txt file + 5. Run this script + + Output will be saved in the file specified by --out and printed to the terminal +''') +parser.add_argument('file', metavar='file', type=str, help='Text file of the debug output') +parser.add_argument('--out', metavar='out', default='./out.txt', type=str, help='Where to save the decoded file (defaults to ./out.txt)') +args = parser.parse_args() + +# open the log file +log = open(args.file, 'r').readlines() + +# find modules that are in use +used_modules = [] +pattern_module = re.compile('(([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?.[0-9]{3} -> )?M\t') +for entry in log: + m = pattern_module.search(entry) + if m != None: + used_modules.append(entry[m.end():].rstrip()) + +# get paths to all relevant header files +header_files = [] +for path in Path('../../src').rglob('*.h'): + for module in used_modules: + if module in path.name: + header_files.append(path) + +# extract names of address macros from the header files +macro_addresses = [] +pattern_define = re.compile('#define \w* +\w*(\n| +\/\/){1}') +for path in header_files: + file = open(path, 'r').readlines() + for line in file: + m = pattern_define.search(line) + if m != None: + s = re.split(' +', m.group().rstrip()) + if (s.__len__() > 1) and ('_REG' in s[1]): + macro_addresses.append([s[1], int(s[2], 0)]) + +''' +# extract names of value macros for each adddress macro +macro_values = [] +for path in header_files: + file = open(path, 'r').readlines() + for line in file: + for module in used_modules: + pattern_addr_macro = re.compile('\/\/ SI443X_REG_\w+'.format(module.capitalize())) +''' + +# parse every line in the log file +out = [] +pattern_debug = re.compile('(([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?.[0-9]{3} -> )?[RWM]\t.+') +for entry in log: + m = pattern_debug.search(entry) + if m != None: + s = re.split('( |\t)+', entry.rstrip()) + cmd_len = int((s.__len__() - 7)/2) + new_entry = s[0] + s[1] + s[2] + s[3] + if s[4] == 'W': + macro_address = int(s[6], 16) + new_entry += 'write {0:>2} 0x{1:02X} {2}\n'.format(cmd_len, macro_address, get_macro_name(macro_address, macro_addresses)) + for i in range(cmd_len): + new_entry += get_macro_value(s[8 + 2*i]); + elif s[4] == 'R': + macro_address = int(s[6], 16) + new_entry += 'read {0:>2} 0x{1:02X} {2}\n'.format(cmd_len, macro_address, get_macro_name(macro_address, macro_addresses)) + for i in range(cmd_len): + new_entry += get_macro_value(s[8 + 2*i]); + elif s[4] == 'M': + new_entry += 'module {}\n'.format(s[6]) + out.append(new_entry) + else: + out.append(entry) + +# write the output file +out_file = open(args.out, 'w') +for line in out: + print(line, end='') + out_file.write(line) +out_file.close() diff --git a/extras/ModuleTemplate.cpp b/extras/template/ModuleTemplate.cpp similarity index 92% rename from extras/ModuleTemplate.cpp rename to extras/template/ModuleTemplate.cpp index 0ee26318..07267305 100644 --- a/extras/ModuleTemplate.cpp +++ b/extras/template/ModuleTemplate.cpp @@ -1,4 +1,5 @@ #include ".h" +#if !defined(RADIOLIB_EXCLUDE_) ::(Module* mod) { /* @@ -12,10 +13,10 @@ int16_t ::begin() { "begin" method implementation MUST call the "init" method with appropriate settings. */ _mod->init(); - + /* "begin" method SHOULD implement some sort of mechanism to verify the connection between Arduino and the module. - + For example, sending AT command for UART modules, or reading a version register for SPI/I2C modules */ } diff --git a/extras/ModuleTemplate.h b/extras/template/ModuleTemplate.h similarity index 90% rename from extras/ModuleTemplate.h rename to extras/template/ModuleTemplate.h index dcb7b0f9..4d957cb0 100644 --- a/extras/ModuleTemplate.h +++ b/extras/template/ModuleTemplate.h @@ -12,14 +12,16 @@ If at any point you are unsure about the required style, please refer to the rest of the modules. */ +#if !defined(_RADIOLIB__H) && !defined(RADIOLIB_EXCLUDE_) #ifndef _RADIOLIB__H #define _RADIOLIB__H /* - Header file for each module MUST include Module.h. + Header file for each module MUST include Module.h and TypeDef.h in the src folder. The header file MAY include additional header files. */ -#include "Module.h" +#include "../../Module.h" +#include "../../TypeDef.h" /* Only use the following include if the module implements methods for OSI transport layer control. @@ -29,7 +31,7 @@ You also MUST provide crystal oscillator frequency and frequency configuration divisor step resolution to the TransportLayer constructor. */ -//#include "../protocols/TransportLayer.h" +//#include "../../protocols/PhysicalLayer/TransportLayer.h" /* Only use the following include if the module implements methods for OSI physical layer control. @@ -37,7 +39,7 @@ In this case, your class MUST implement all virtual methods of PhysicalLayer class. */ -//#include "../protocols/PhysicalLayer.h" +//#include "../../protocols/PhysicalLayer/PhysicalLayer.h" /* Register map @@ -74,7 +76,7 @@ class { The class MAY implement additional overloaded constructors. */ // constructor - (Module* module); + (Module* mod); /* The class MUST implement at least one basic method called "begin". @@ -105,3 +107,5 @@ class { }; #endif + +#endif diff --git a/keywords.txt b/keywords.txt index 21e58818..e117eec2 100644 --- a/keywords.txt +++ b/keywords.txt @@ -53,6 +53,7 @@ AX25Client KEYWORD1 AX25Frame KEYWORD1 SSTVClient KEYWORD1 HellClient KEYWORD1 +AFSKClient KEYWORD1 # SSTV modes Scottie1 KEYWORD1 @@ -123,6 +124,13 @@ disableSyncWordFiltering KEYWORD2 setPromiscuous KEYWORD2 setRSSIConfig KEYWORD2 setEncoding KEYWORD2 +getIRQFlags KEYWORD2 +getModemStatus KEYWORD2 +getTempRaw KEYWORD2 +setRfSwitchPins KEYWORD2 +forceLDRO KEYWORD2 +autoLDRO KEYWORD2 +getChipVersion KEYWORD2 # RF69-specific setAESKey KEYWORD2 @@ -137,6 +145,7 @@ setGdo0Action KEYWORD2 setGdo2Action KEYWORD2 clearGdo0Action KEYWORD2 clearGdo2Action KEYWORD2 +setCrcFiltering KEYWORD2 # SX126x-specific setTCXO KEYWORD2 @@ -225,6 +234,10 @@ getRangingResult KEYWORD2 # Hellschreiber printGlyph KEYWORD2 +# AFSK +tone KEYWORD2 +noTone KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### @@ -232,6 +245,16 @@ printGlyph KEYWORD2 RADIOLIB_NC LITERAL1 RADIOLIB_VERSION LITERAL1 +RADIOLIB_SHAPING_NONE LITERAL1 +RADIOLIB_SHAPING_0_3 LITERAL1 +RADIOLIB_SHAPING_0_5 LITERAL1 +RADIOLIB_SHAPING_0_7 LITERAL1 +RADIOLIB_SHAPING_1_0 LITERAL1 + +RADIOLIB_ENCODING_NRZ LITERAL1 +RADIOLIB_ENCODING_MANCHESTER LITERAL1 +RADIOLIB_ENCODING_WHITENING LITERAL1 + ERR_NONE LITERAL1 ERR_UNKNOWN LITERAL1 diff --git a/library.properties b/library.properties index 21975e9d..1b97e255 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=RadioLib -version=3.4.0 +version=4.2.0 author=Jan Gromes maintainer=Jan Gromes sentence=Universal wireless communication library for Arduino diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 063a8e05..17c69cbc 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -10,118 +10,335 @@ /* * Platform-specific configuration. * + * RADIOLIB_PLATFORM - platform name, used in debugging to quickly check the correct platform is detected. * RADIOLIB_PIN_TYPE - which type should be used for pin numbers in functions like digitalRead(). * RADIOLIB_PIN_MODE - which type should be used for pin modes in functions like pinMode(). * RADIOLIB_PIN_STATUS - which type should be used for pin values in functions like digitalWrite(). + * RADIOLIB_INTERRUPT_STATUS - which type should be used for pin changes in functions like attachInterrupt(). + * RADIOLIB_DIGITAL_PIN_TO_INTERRUPT - function/macro to be used to convert digital pin number to interrupt pin number. * RADIOLIB_NC - alias for unused pin, usually the largest possible value of RADIOLIB_PIN_TYPE. + * RADIOLIB_DEFAULT_SPI - default SPIClass instance to use. + * RADIOLIB_PROGMEM - macro to place variable into program storage (usually Flash). + * RADIOLIB_PROGMEM_READ_BYTE - function/macro to read variables saved in program storage (usually Flash). * RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - defined if the specific platform does not support SoftwareSerial. * RADIOLIB_HARDWARE_SERIAL_PORT - which hardware serial port should be used on platform that do not have SoftwareSerial support. + * RADIOLIB_TONE_UNSUPPORTED - some platforms do not have tone()/noTone(), which is required for AFSK. * * In addition, some platforms may require RadioLib to disable specific drivers (such as ESP8266). + * + * Users may also specify their own configuration by uncommenting the RADIOLIB_CUSTOM_PLATFORM, + * and then specifying all platform parameters in the section below. This will override automatic + * platform detection. */ -#if defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY)) - // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_NC (0xFF) -#elif defined(ESP8266) - // ESP8266 boards - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_NC (0xFF) +// uncomment to enable custom platform definition +//#define RADIOLIB_CUSTOM_PLATFORM - // RadioLib has ESPS8266 driver, this must be disabled to use ESP8266 as platform - #define _RADIOLIB_ESP8266_H +#if defined(RADIOLIB_CUSTOM_PLATFORM) + // name for your platform + #define RADIOLIB_PLATFORM "Custom" -#elif defined(ESP32) - // ESP32 boards + // the following parameters must always be defined #define RADIOLIB_PIN_TYPE uint8_t #define RADIOLIB_PIN_MODE uint8_t #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) #define RADIOLIB_NC (0xFF) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) -#elif defined(ARDUINO_ARCH_STM32) - // STM32duino boards - #define RADIOLIB_PIN_TYPE uint32_t - #define RADIOLIB_PIN_MODE uint32_t - #define RADIOLIB_PIN_STATUS uint32_t - #define RADIOLIB_NC (0xFFFFFFFF) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + // the following must be defined if the Arduino core does not support SoftwareSerial library + //#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + //#define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 -#elif defined(SAMD_SERIES) - // Arduino SAMD boards - Zero, MKR, etc. - #define RADIOLIB_PIN_TYPE uint32_t - #define RADIOLIB_PIN_MODE uint32_t - #define RADIOLIB_PIN_STATUS uint32_t - #define RADIOLIB_NC (0xFFFFFFFF) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + // the following must be defined if the Arduino core does not support tone function + //#define RADIOLIB_TONE_UNSUPPORTED -#elif defined(__SAM3X8E__) - // Arduino Due - #define RADIOLIB_PIN_TYPE uint32_t - #define RADIOLIB_PIN_MODE uint32_t - #define RADIOLIB_PIN_STATUS uint32_t - #define RADIOLIB_NC (0xFFFFFFFF) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - -#elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) - // Adafruit nRF52 boards - #define RADIOLIB_PIN_TYPE uint32_t - #define RADIOLIB_PIN_MODE uint32_t - #define RADIOLIB_PIN_STATUS uint32_t - #define RADIOLIB_NC (0xFFFFFFFF) - -#elif defined(ARDUINO_ARC32_TOOLS) - // Intel Curie - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_NC (0xFF) - -#elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) - // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE PinMode - #define RADIOLIB_PIN_STATUS PinStatus - #define RADIOLIB_NC (0xFF) - -#elif defined(AM_PART_APOLLO3) - // Sparkfun Artemis boards - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - -#elif defined(ARDUINO_ARDUINO_NANO33BLE) - // Arduino Nano 33 BLE - #define RADIOLIB_PIN_TYPE pin_size_t - #define RADIOLIB_PIN_MODE PinMode - #define RADIOLIB_PIN_STATUS PinStatus - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - - // Nano 33 BLE uses mbed libraries, which already contain ESP8266 driver - #define _RADIOLIB_ESP8266_H + // some of RadioLib drivers may be excluded, to prevent collisions with platforms (or to speed up build process) + // the following is a complete list of all possible exclusion macros, uncomment any of them to disable that driver + // NOTE: Some of the exclusion macros are dependent on each other. For example, it is not possible to exclude RF69 + // while keeping SX1231 (because RF69 is the base class for SX1231). The dependency is always uni-directional, + // so excluding SX1231 and keeping RF69 is valid. + //#define RADIOLIB_EXCLUDE_CC1101 + //#define RADIOLIB_EXCLUDE_ESP8266 + //#define RADIOLIB_EXCLUDE_HC05 + //#define RADIOLIB_EXCLUDE_JDY08 + //#define RADIOLIB_EXCLUDE_NRF24 + //#define RADIOLIB_EXCLUDE_RF69 + //#define RADIOLIB_EXCLUDE_SX1231 // dependent on RADIOLIB_EXCLUDE_RF69 + //#define RADIOLIB_EXCLUDE_SI443X + //#define RADIOLIB_EXCLUDE_RFM2X // dependent on RADIOLIB_EXCLUDE_SI443X + //#define RADIOLIB_EXCLUDE_SX127X + //#define RADIOLIB_EXCLUDE_RFM9X // dependent on RADIOLIB_EXCLUDE_SX127X + //#define RADIOLIB_EXCLUDE_SX126X + //#define RADIOLIB_EXCLUDE_SX128X + //#define RADIOLIB_EXCLUDE_XBEE + //#define RADIOLIB_EXCLUDE_AFSK + //#define RADIOLIB_EXCLUDE_AX25 + //#define RADIOLIB_EXCLUDE_HELLSCHREIBER + //#define RADIOLIB_EXCLUDE_HTTP + //#define RADIOLIB_EXCLUDE_MORSE + //#define RADIOLIB_EXCLUDE_MQTT + //#define RADIOLIB_EXCLUDE_RTTY + //#define RADIOLIB_EXCLUDE_SSTV #else - // other platforms not covered by the above list - this may or may not work - #define RADIOLIB_UNKNOWN_PLATFORM - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_NC (0xFF) + #if defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) || defined(ARDUINO_ARCH_MEGAAVR)) + // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. + #define RADIOLIB_PLATFORM "Arduino AVR" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #elif defined(ESP8266) + // ESP8266 boards + #define RADIOLIB_PLATFORM "ESP8266" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + + // RadioLib has ESP8266 driver, this must be disabled to use ESP8266 as platform + #define RADIOLIB_EXCLUDE_ESP8266 + + #elif defined(ESP32) + // ESP32 boards + #define RADIOLIB_PLATFORM "ESP32" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + + // ESP32 doesn't support tone(), but it can be emulated via LED control peripheral + #define RADIOLIB_TONE_UNSUPPORTED + #define RADIOLIB_TONE_ESP32_CHANNEL (1) + + #elif defined(ARDUINO_ARCH_STM32) + // official STM32 Arduino core (https://github.com/stm32duino/Arduino_Core_STM32) + #define RADIOLIB_PLATFORM "Arduino STM32 (official)" + #define RADIOLIB_PIN_TYPE uint32_t + #define RADIOLIB_PIN_MODE uint32_t + #define RADIOLIB_PIN_STATUS uint32_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + + // slow down SX126x/8x SPI on this platform + #define RADIOLIB_SPI_SLOWDOWN + + #elif defined(SAMD_SERIES) + // Adafruit SAMD boards (M0 and M4) + #define RADIOLIB_PLATFORM "Adafruit SAMD" + #define RADIOLIB_PIN_TYPE uint32_t + #define RADIOLIB_PIN_MODE uint32_t + #define RADIOLIB_PIN_STATUS uint32_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + + // slow down SX126x/8x SPI on this platform + #define RADIOLIB_SPI_SLOWDOWN + + #elif defined(ARDUINO_ARCH_SAMD) + // Arduino SAMD (Zero, MKR, etc.) + #define RADIOLIB_PLATFORM "Arduino SAMD" + #define RADIOLIB_PIN_TYPE pin_size_t + #define RADIOLIB_PIN_MODE PinMode + #define RADIOLIB_PIN_STATUS PinStatus + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + + #elif defined(__SAM3X8E__) + // Arduino Due + #define RADIOLIB_PLATFORM "Arduino Due" + #define RADIOLIB_PIN_TYPE uint32_t + #define RADIOLIB_PIN_MODE uint32_t + #define RADIOLIB_PIN_STATUS uint32_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + #define RADIOLIB_TONE_UNSUPPORTED + + #elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) + // Adafruit nRF52 boards + #define RADIOLIB_PLATFORM "Adafruit nRF52" + #define RADIOLIB_PIN_TYPE uint32_t + #define RADIOLIB_PIN_MODE uint32_t + #define RADIOLIB_PIN_STATUS uint32_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + + #elif defined(ARDUINO_ARC32_TOOLS) + // Intel Curie + #define RADIOLIB_PLATFORM "Intel Curie" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + + #elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) + // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every + #define RADIOLIB_PLATFORM "Arduino megaAVR" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE PinMode + #define RADIOLIB_PIN_STATUS PinStatus + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + + #elif defined(ARDUINO_ARCH_APOLLO3) + // Sparkfun Apollo3 boards + #define RADIOLIB_PLATFORM "Sparkfun Apollo3" + #define RADIOLIB_PIN_TYPE pin_size_t + #define RADIOLIB_PIN_MODE Arduino_PinMode + #define RADIOLIB_PIN_STATUS PinStatus + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + + // Apollo3 uses mbed libraries, which already contain ESP8266 driver + #define RADIOLIB_EXCLUDE_ESP8266 + + // slow down SX126x/8x SPI on this platform + #define RADIOLIB_SPI_SLOWDOWN + + #elif defined(ARDUINO_ARDUINO_NANO33BLE) + // Arduino Nano 33 BLE + #define RADIOLIB_PLATFORM "Arduino Nano 33 BLE" + #define RADIOLIB_PIN_TYPE pin_size_t + #define RADIOLIB_PIN_MODE PinMode + #define RADIOLIB_PIN_STATUS PinStatus + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + + // Nano 33 BLE uses mbed libraries, which already contain ESP8266 driver + #define RADIOLIB_EXCLUDE_ESP8266 + + #elif defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) + // Arduino Portenta H7 + #define RADIOLIB_PLATFORM "Portenta H7" + #define RADIOLIB_PIN_TYPE pin_size_t + #define RADIOLIB_PIN_MODE PinMode + #define RADIOLIB_PIN_STATUS PinStatus + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + + // Arduino Portenta H7 uses mbed libraries, which already contain ESP8266 driver + #define RADIOLIB_EXCLUDE_ESP8266 + + #elif defined(__STM32F4__) || defined(__STM32F1__) + // Arduino STM32 core by Roger Clark (https://github.com/rogerclarkmelbourne/Arduino_STM32) + #define RADIOLIB_PLATFORM "STM32duino (unofficial)" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE WiringPinMode + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_INTERRUPT_STATUS ExtIntTriggerMode + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + + #elif defined(ARDUINO_ARCH_MEGAAVR) + // MegaCoreX by MCUdude (https://github.com/MCUdude/MegaCoreX) + #define RADIOLIB_PLATFORM "MegaCoreX" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + + #else + // other platforms not covered by the above list - this may or may not work + #define RADIOLIB_PLATFORM "Unknown" + #define RADIOLIB_UNKNOWN_PLATFORM + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_PROGMEM PROGMEM + #define RADIOLIB_PROGMEM_READ_BYTE(addr) pgm_read_byte(addr) + + #endif #endif /* @@ -138,7 +355,7 @@ // set which Serial port should be used for debug output #define RADIOLIB_DEBUG_PORT Serial -#ifdef RADIOLIB_DEBUG +#if defined(RADIOLIB_DEBUG) #define RADIOLIB_DEBUG_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); } #define RADIOLIB_DEBUG_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); } #else @@ -146,7 +363,7 @@ #define RADIOLIB_DEBUG_PRINTLN(...) {} #endif -#ifdef RADIOLIB_VERBOSE +#if defined(RADIOLIB_VERBOSE) #define RADIOLIB_VERBOSE_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); } #define RADIOLIB_VERBOSE_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); } #else @@ -174,7 +391,9 @@ //#define RADIOLIB_STATIC_ONLY // set the size of static arrays to use +#if !defined(RADIOLIB_STATIC_ARRAY_SIZE) #define RADIOLIB_STATIC_ARRAY_SIZE 256 +#endif /*! \brief A simple assert macro, will return on error. @@ -186,10 +405,9 @@ */ #define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) { if(!(((VAR) >= (MIN)) && ((VAR) <= (MAX)))) { return(ERR); } } - // version definitions -#define RADIOLIB_VERSION_MAJOR (0x03) -#define RADIOLIB_VERSION_MINOR (0x04) +#define RADIOLIB_VERSION_MAJOR (0x04) +#define RADIOLIB_VERSION_MINOR (0x02) #define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) diff --git a/src/ISerial.cpp b/src/ISerial.cpp index 8cd4c65a..7822e5c2 100644 --- a/src/ISerial.cpp +++ b/src/ISerial.cpp @@ -8,41 +8,10 @@ void ISerial::begin(long speed) { _mod->ModuleSerial->begin(speed); } -bool ISerial::listen() { -#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - return true; -#else - return(_mod->ModuleSerial->listen()); -#endif -} - void ISerial::end() { _mod->ModuleSerial->end(); } -bool ISerial::isListening() { -#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - return true; -#else - return(_mod->ModuleSerial->isListening()); -#endif -} - -bool ISerial::stopListening() { -#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - return true; -#else - return(_mod->ModuleSerial->stopListening()); -#endif -} - -bool ISerial::overflow() { -#ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - return false; -#else - return(_mod->ModuleSerial->overflow()); -#endif -} int ISerial::peek() { return(_mod->ModuleSerial->peek()); @@ -64,9 +33,11 @@ void ISerial::flush() { _mod->ModuleSerial->flush(); } +#ifndef ARDUINO_ARCH_MEGAAVR size_t ISerial::print(const __FlashStringHelper *ifsh) { return(_mod->ModuleSerial->print(ifsh)); } +#endif size_t ISerial::print(const String &s) { return(_mod->ModuleSerial->print(s)); @@ -108,9 +79,11 @@ size_t ISerial::print(const Printable& x) { return(_mod->ModuleSerial->print(x)); } +#ifndef ARDUINO_ARCH_MEGAAVR size_t ISerial::println(const __FlashStringHelper *ifsh) { return(_mod->ModuleSerial->println(ifsh)); } +#endif size_t ISerial::println(const String &s) { return(_mod->ModuleSerial->println(s)); diff --git a/src/ISerial.h b/src/ISerial.h index d086beaf..d34ff09d 100644 --- a/src/ISerial.h +++ b/src/ISerial.h @@ -3,11 +3,6 @@ #include "Module.h" -#include - -#include "WString.h" -#include "Printable.h" - /*! \class ISerial @@ -15,21 +10,19 @@ */ class ISerial { public: - ISerial(Module* mod); + explicit ISerial(Module* mod); void begin(long); - bool listen(); void end(); - bool isListening(); - bool stopListening(); - bool overflow(); int peek(); size_t write(uint8_t); int read(); int available(); void flush(); + #ifndef ARDUINO_ARCH_MEGAAVR size_t print(const __FlashStringHelper *); + #endif size_t print(const String &); size_t print(const char[]); size_t print(char); @@ -41,7 +34,9 @@ class ISerial { size_t print(double, int = 2); size_t print(const Printable&); + #ifndef ARDUINO_ARCH_MEGAAVR size_t println(const __FlashStringHelper *); + #endif size_t println(const String &s); size_t println(const char[]); size_t println(char); diff --git a/src/Module.cpp b/src/Module.cpp index 8482e32c..029d6934 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -1,83 +1,115 @@ #include "Module.h" -Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst) { - _cs = cs; - _rx = RADIOLIB_NC; - _tx = RADIOLIB_NC; - _irq = irq; - _rst = rst; - _spi = &SPI; - _spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0); +Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst): + _cs(cs), + _irq(irq), + _rst(rst), + _rx(RADIOLIB_NC), + _tx(RADIOLIB_NC), + _spiSettings(SPISettings(2000000, MSBFIRST, SPI_MODE0)) +{ + _spi = &RADIOLIB_DEFAULT_SPI; _initInterface = true; + ModuleSerial = NULL; } -Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio) { - _cs = cs; - _rx = gpio; - _tx = RADIOLIB_NC; - _irq = irq; - _rst = rst; - _spi = &SPI; - _spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0); +Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio): + _cs(cs), + _irq(irq), + _rst(rst), + _rx(gpio), + _tx(RADIOLIB_NC), + _spiSettings(SPISettings(2000000, MSBFIRST, SPI_MODE0)) +{ + _spi = &RADIOLIB_DEFAULT_SPI; _initInterface = true; + ModuleSerial = NULL; } -Module::Module(RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, HardwareSerial* useSer, RADIOLIB_PIN_TYPE rst) { - _cs = RADIOLIB_NC; - _rx = rx; - _tx = tx; - _irq = RADIOLIB_NC; - _rst = rst; +Module::Module(RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, HardwareSerial* serial, RADIOLIB_PIN_TYPE rst): + _cs(RADIOLIB_NC), + _irq(RADIOLIB_NC), + _rst(rst), + _rx(rx), + _tx(tx), + _spiSettings(SPISettings(2000000, MSBFIRST, SPI_MODE0)) +{ _initInterface = true; #ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - ModuleSerial = useSer; + ModuleSerial = serial; #else ModuleSerial = new SoftwareSerial(_rx, _tx); - (void)useSer; + (void)serial; #endif } -Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass& spi, SPISettings spiSettings) { - _cs = cs; - _rx = RADIOLIB_NC; - _tx = RADIOLIB_NC; - _irq = irq; - _rst = rst; +Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass& spi, SPISettings spiSettings): + _cs(cs), + _irq(irq), + _rst(rst), + _rx(RADIOLIB_NC), + _tx(RADIOLIB_NC), + _spiSettings(spiSettings) +{ _spi = &spi; - _spiSettings = spiSettings; _initInterface = false; + ModuleSerial = NULL; } -Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings) { - _cs = cs; - _rx = gpio; - _tx = RADIOLIB_NC; - _irq = irq; - _rst = rst; +Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings): + _cs(cs), + _irq(irq), + _rst(rst), + _rx(gpio), + _tx(RADIOLIB_NC), + _spiSettings(spiSettings) +{ _spi = &spi; - _spiSettings = spiSettings; _initInterface = false; + ModuleSerial = NULL; } -Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi, SPISettings spiSettings, HardwareSerial* useSer) { - _cs = cs; - _rx = rx; - _tx = tx; - _irq = irq; - _rst = rst; +Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi, SPISettings spiSettings, HardwareSerial* serial): + _cs(cs), + _irq(irq), + _rst(rst), + _rx(rx), + _tx(tx), + _spiSettings(spiSettings) +{ _spi = &spi; - _spiSettings = spiSettings; _initInterface = false; #ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - ModuleSerial = useSer; + ModuleSerial = serial; #else ModuleSerial = new SoftwareSerial(_rx, _tx); - (void)useSer; + (void)serial; #endif } +Module::Module(const Module& mod) { + *this = mod; +} + +Module& Module::operator=(const Module& mod) { + this->ModuleSerial = mod.ModuleSerial; + this->baudrate = mod.baudrate; + memcpy(this->AtLineFeed, mod.AtLineFeed, strlen(mod.AtLineFeed)); + this->SPIreadCommand = mod.SPIreadCommand; + this->SPIwriteCommand = mod.SPIwriteCommand; + this->_cs = mod.getCs(); + this->_irq = mod.getIrq(); + this->_rst = mod.getRst(); + this->_rx = mod.getRx(); + this->_tx = mod.getTx(); + this->_spiSettings = mod.getSpiSettings(); + this->_spi = mod.getSpi(); + + return(*this); +} + void Module::init(uint8_t interface) { // select interface switch(interface) { @@ -102,13 +134,17 @@ void Module::init(uint8_t interface) { } } -void Module::term() { - // stop hardware interfaces - if(_spi != nullptr) { +void Module::term(uint8_t interface) { + // stop hardware interfaces (if they were initialized by the library) + if(!_initInterface) { + return; + } + + if((interface == RADIOLIB_USE_SPI) && (_spi != nullptr)) { _spi->end(); } - if(ModuleSerial != nullptr) { + if(((interface == RADIOLIB_USE_UART) && ModuleSerial != nullptr)) { ModuleSerial->end(); } } @@ -139,8 +175,8 @@ bool Module::ATsendData(uint8_t* data, uint32_t len) { bool Module::ATgetResponse() { char data[128]; char* dataPtr = data; - uint32_t start = millis(); - while(millis() - start < _ATtimeout) { + uint32_t start = Module::millis(); + while(Module::millis() - start < _ATtimeout) { while(ModuleSerial->available() > 0) { char c = ModuleSerial->read(); RADIOLIB_VERBOSE_PRINT(c); @@ -182,9 +218,9 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t // check register value each millisecond until check interval is reached // some registers need a bit of time to process the change (e.g. SX127X_REG_OP_MODE) - uint32_t start = micros(); - uint8_t readValue = 0; - while(micros() - start < (checkInterval * 1000)) { + uint32_t start = Module::micros(); + uint8_t readValue = 0x00; + while(Module::micros() - start < (checkInterval * 1000)) { readValue = SPIreadRegister(reg); if(readValue == newValue) { // check passed, we can stop the loop @@ -255,16 +291,20 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da // send data or get response if(cmd == SPIwriteCommand) { - for(size_t n = 0; n < numBytes; n++) { - _spi->transfer(dataOut[n]); - RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); + if(dataOut != NULL) { + for(size_t n = 0; n < numBytes; n++) { + _spi->transfer(dataOut[n]); + RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + } } } else if (cmd == SPIreadCommand) { - for(size_t n = 0; n < numBytes; n++) { - dataIn[n] = _spi->transfer(0x00); - RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); - RADIOLIB_VERBOSE_PRINT('\t'); + if(dataIn != NULL) { + for(size_t n = 0; n < numBytes; n++) { + dataIn[n] = _spi->transfer(0x00); + RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + } } } RADIOLIB_VERBOSE_PRINTLN(); @@ -294,3 +334,81 @@ RADIOLIB_PIN_STATUS Module::digitalRead(RADIOLIB_PIN_TYPE pin) { } return(LOW); } + +void Module::tone(RADIOLIB_PIN_TYPE pin, uint16_t value) { + if(pin == RADIOLIB_NC) { + return; + } + + #if !defined(RADIOLIB_TONE_UNSUPPORTED) + ::tone(pin, value); + #else + #if defined(ESP32) + // ESP32 tone() emulation + ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL); + ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, value); + #endif + #endif +} + +void Module::noTone(RADIOLIB_PIN_TYPE pin) { + if(pin == RADIOLIB_NC) { + return; + } + + #if !defined(RADIOLIB_TONE_UNSUPPORTED) + ::noTone(pin); + #else + #if defined(ESP32) + ledcDetachPin(pin); + ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0); + #endif + #endif +} + +void Module::attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode) { + ::attachInterrupt(interruptNum, userFunc, mode); +} + +void Module::detachInterrupt(RADIOLIB_PIN_TYPE interruptNum) { + ::detachInterrupt(interruptNum); +} + +void Module::yield() { + ::yield(); +} + +void Module::delay(uint32_t ms) { + ::delay(ms); +} + +void Module::delayMicroseconds(uint32_t us) { + ::delayMicroseconds(us); +} + +uint32_t Module::millis() { + return(::millis()); +} + +uint32_t Module::micros() { + return(::micros()); +} + +void Module::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { + _useRfSwitch = true; + _rxEn = rxEn; + _txEn = txEn; + Module::pinMode(rxEn, OUTPUT); + Module::pinMode(txEn, OUTPUT); +} + +void Module::setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState) { + // check RF switch control is enabled + if(!_useRfSwitch) { + return; + } + + // set pins + Module::digitalWrite(_rxEn, rxPinState); + Module::digitalWrite(_txEn, txPinState); +} diff --git a/src/Module.h b/src/Module.h index ebc81986..685a2eb5 100644 --- a/src/Module.h +++ b/src/Module.h @@ -4,7 +4,6 @@ #include "TypeDef.h" #include -//#include #ifndef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #include #endif @@ -21,18 +20,18 @@ class Module { /*! \brief UART-based module constructor. - \param tx Arduino pin to be used as Tx pin for SoftwareSerial communication. - \param rx Arduino pin to be used as Rx pin for SoftwareSerial communication. + \param tx Arduino pin to be used as Tx pin for SoftwareSerial communication. + \param serial HardwareSerial to be used on platforms that do not support SoftwareSerial. Defaults to Serial1. \param rst Arduino pin to be used as hardware reset for the module. Defaults to NC (unused). */ #ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - Module(RADIOLIB_PIN_TYPE tx, RADIOLIB_PIN_TYPE rx, HardwareSerial* serial = &RADIOLIB_HARDWARE_SERIAL_PORT, RADIOLIB_PIN_TYPE rst = RADIOLIB_NC); + Module(RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, HardwareSerial* serial = &RADIOLIB_HARDWARE_SERIAL_PORT, RADIOLIB_PIN_TYPE rst = RADIOLIB_NC); #else - Module(RADIOLIB_PIN_TYPE tx, RADIOLIB_PIN_TYPE rx, HardwareSerial* serial = nullptr, RADIOLIB_PIN_TYPE rst = RADIOLIB_NC); + Module(RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, HardwareSerial* serial = nullptr, RADIOLIB_PIN_TYPE rst = RADIOLIB_NC); #endif /*! @@ -87,9 +86,9 @@ class Module { \param spi SPI interface to be used, can also use software SPI implementations. - \param spiSettings SPI interface settings. + \param spiSettings SPI interface settings. Defaults to 2 MHz clock, MSB first, mode 0. */ - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings); + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0)); /*! \brief Generic module constructor. @@ -111,11 +110,24 @@ class Module { \param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1 */ #ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = &RADIOLIB_HARDWARE_SERIAL_PORT); + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi = RADIOLIB_DEFAULT_SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = &RADIOLIB_HARDWARE_SERIAL_PORT); #else - Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = nullptr); + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi = RADIOLIB_DEFAULT_SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = nullptr); #endif + /*! + \brief Copy constructor. + + \param mod Module instance to copy. + */ + Module(const Module& mod); + + /*! + \brief Overload for assignment operator. + + \param frame rvalue Module. + */ + Module& operator=(const Module& mod); // public member variables @@ -136,7 +148,7 @@ class Module { /*! \brief Line feed to be used when sending AT commands. Defaults to CR+LF. */ - const char* AtLineFeed = "\r\n"; + char AtLineFeed[3] = {'\r', '\n'}; /*! \brief Basic SPI read command. Defaults to 0x00. @@ -159,8 +171,10 @@ class Module { /*! \brief Terminate low-level module control. + + \param interface Interface to be terminated. See \ref shield_config for details. */ - void term(); + void term(uint8_t interface); // AT methods @@ -341,6 +355,27 @@ class Module { */ SPISettings getSpiSettings() const { return(_spiSettings); } + /*! + \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. + When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! + + \param rxEn RX enable pin. + + \param txEn TX enable pin. + */ + void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + + /*! + \brief Set RF switch state. + + \param rxPinState Pin state to set on Tx enable pin (usually high to transmit). + + \param txPinState Pin state to set on Rx enable pin (usually high to receive). + */ + void setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState); + + // Arduino core overrides + /*! \brief Arduino core pinMode override that checks RADIOLIB_NC as alias for unused pin. @@ -368,18 +403,85 @@ class Module { */ static RADIOLIB_PIN_STATUS digitalRead(RADIOLIB_PIN_TYPE pin); + /*! + \brief Arduino core tone override that checks RADIOLIB_NC as alias for unused pin and RADIOLIB_TONE_UNSUPPORTED to make sure the platform does support tone. + + \param pin Pin to write to. + + \param value Frequency to output. + */ + static void tone(RADIOLIB_PIN_TYPE pin, uint16_t value); + + /*! + \brief Arduino core noTone override that checks RADIOLIB_NC as alias for unused pin and RADIOLIB_TONE_UNSUPPORTED to make sure the platform does support tone. + + \param pin Pin to write to. + */ + static void noTone(RADIOLIB_PIN_TYPE pin); + + /*! + \brief Arduino core attachInterrupt override. + + \param interruptNum Interrupt number. + + \param userFunc Interrupt service routine. + + \param mode Pin hcange direction. + */ + static void attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode); + + /*! + \brief Arduino core detachInterrupt override. + + \param interruptNum Interrupt number. + */ + static void detachInterrupt(RADIOLIB_PIN_TYPE interruptNum); + + /*! + \brief Arduino core yield override. + */ + static void yield(); + + /*! + \brief Arduino core delay override. + + \param ms Delay length in milliseconds. + */ + static void delay(uint32_t ms); + + /*! + \brief Arduino core delayMicroseconds override. + + \param us Delay length in microseconds. + */ + static void delayMicroseconds(uint32_t us); + + /*! + \brief Arduino core millis override. + */ + static uint32_t millis(); + + /*! + \brief Arduino core micros override. + */ + static uint32_t micros(); + #ifndef RADIOLIB_GODMODE private: #endif - RADIOLIB_PIN_TYPE _cs; - RADIOLIB_PIN_TYPE _tx; - RADIOLIB_PIN_TYPE _rx; - RADIOLIB_PIN_TYPE _irq; - RADIOLIB_PIN_TYPE _rst; + RADIOLIB_PIN_TYPE _cs = RADIOLIB_NC; + RADIOLIB_PIN_TYPE _irq = RADIOLIB_NC; + RADIOLIB_PIN_TYPE _rst = RADIOLIB_NC; + RADIOLIB_PIN_TYPE _rx = RADIOLIB_NC; + RADIOLIB_PIN_TYPE _tx = RADIOLIB_NC; - bool _initInterface; - SPIClass* _spi; - SPISettings _spiSettings; + SPISettings _spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0); + + bool _initInterface = false; + SPIClass* _spi = NULL; + + bool _useRfSwitch = false; + RADIOLIB_PIN_TYPE _rxEn = RADIOLIB_NC, _txEn = RADIOLIB_NC; uint32_t _ATtimeout = 15000; }; diff --git a/src/RadioLib.h b/src/RadioLib.h index 04ea18e7..c6afae7a 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -22,6 +22,7 @@ - Morse Code (MorseClient) - AX.25 (AX25Client) - SSTV (SSTVClient) + - Hellschreiber (HellClient) - TransportLayer protocols - HTTP (HTTPClient) - MQTT (MQTTClient) @@ -49,6 +50,11 @@ #warning "God mode active, I hope it was intentional. Buckle up, lads." #endif +// print debug info +#ifdef RADIOLIB_DEBUG + #pragma message "RADIOLIB_PLATFORM: " RADIOLIB_PLATFORM +#endif + // check unknown/unsupported platform #ifdef RADIOLIB_UNKNOWN_PLATFORM #warning "RadioLib might not be compatible with this Arduino board - check supported platforms at https://github.com/jgromes/RadioLib!" @@ -85,6 +91,7 @@ // physical layer protocols #include "protocols/PhysicalLayer/PhysicalLayer.h" +#include "protocols/AFSK/AFSK.h" #include "protocols/AX25/AX25.h" #include "protocols/Hellschreiber/Hellschreiber.h" #include "protocols/Morse/Morse.h" diff --git a/src/TypeDef.h b/src/TypeDef.h index f8254d3d..a2726ded 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -88,6 +88,66 @@ \} */ +/*! + \defgroup config_shaping Data shaping filter values aliases. + + \{ +*/ + +/*! + \brief No shaping. +*/ +#define RADIOLIB_SHAPING_NONE 0x00 + +/*! + \brief Gaussin shaping filter, BT = 0.3 +*/ +#define RADIOLIB_SHAPING_0_3 0x01 + +/*! + \brief Gaussin shaping filter, BT = 0.5 +*/ +#define RADIOLIB_SHAPING_0_5 0x02 + +/*! + \brief Gaussin shaping filter, BT = 0.7 +*/ +#define RADIOLIB_SHAPING_0_7 0x03 + +/*! + \brief Gaussin shaping filter, BT = 1.0 +*/ +#define RADIOLIB_SHAPING_1_0 0x04 + +/*! + \} +*/ + +/*! + \defgroup config_encoding Encoding type aliases. + + \{ +*/ + +/*! + \brief Non-return to zero - no encoding. +*/ +#define RADIOLIB_ENCODING_NRZ 0x00 + +/*! + \brief Manchester encoding. +*/ +#define RADIOLIB_ENCODING_MANCHESTER 0x01 + +/*! + \brief Whitening. +*/ +#define RADIOLIB_ENCODING_WHITENING 0x02 + +/*! + \} +*/ + /*! \defgroup status_codes Status Codes @@ -223,6 +283,11 @@ */ #define ERR_INVALID_ENCODING -23 +/*! + \brief LoRa packet header has been damaged. +*/ +#define ERR_LORA_HEADER_DAMAGED -24 + // RF69-specific status codes /*! diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index f05fa32e..1373c0ca 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -1,12 +1,8 @@ #include "CC1101.h" +#if !defined(RADIOLIB_EXCLUDE_CC1101) CC1101::CC1101(Module* module) : PhysicalLayer(CC1101_FREQUENCY_STEP_SIZE, CC1101_MAX_PACKET_LENGTH) { _mod = module; - _packetLengthQueried = false; - _packetLengthConfig = CC1101_LENGTH_CONFIG_VARIABLE; - _modulation = CC1101_MOD_FORMAT_2_FSK; - - _syncWordLength = 2; } int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLength) { @@ -20,8 +16,8 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po uint8_t i = 0; bool flagFound = false; while((i < 10) && !flagFound) { - uint8_t version = SPIreadRegister(CC1101_REG_VERSION); - if(version == 0x14) { + int16_t version = getChipVersion(); + if((version == CC1101_VERSION_CURRENT) || (version == CC1101_VERSION_LEGACY)) { flagFound = true; } else { #ifdef RADIOLIB_DEBUG @@ -32,20 +28,20 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po char buffHex[7]; sprintf(buffHex, "0x%04X", version); RADIOLIB_DEBUG_PRINT(buffHex); - RADIOLIB_DEBUG_PRINT(F(", expected 0x0014")); + RADIOLIB_DEBUG_PRINT(F(", expected 0x0004/0x0014")); RADIOLIB_DEBUG_PRINTLN(); #endif - delay(1000); + Module::delay(10); i++; } } if(!flagFound) { RADIOLIB_DEBUG_PRINTLN(F("No CC1101 found!")); - _mod->term(); + _mod->term(RADIOLIB_USE_SPI); return(ERR_CHIP_NOT_FOUND); } else { - RADIOLIB_DEBUG_PRINTLN(F("Found CC1101! (match by CC1101_REG_VERSION == 0x14)")); + RADIOLIB_DEBUG_PRINTLN(F("M\tCC1101")); } // configure settings not accessible by API @@ -81,11 +77,15 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po RADIOLIB_ASSERT(state); // set default data shaping - state = setDataShaping(0); + state = setDataShaping(RADIOLIB_ENCODING_NRZ); RADIOLIB_ASSERT(state); // set default encoding - state = setEncoding(2); + state = setEncoding(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + + // set default sync word + state = setSyncWord(0x12, 0xAD, 0, false); RADIOLIB_ASSERT(state); // flush FIFOs @@ -101,13 +101,13 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission start - while(!digitalRead(_mod->getIrq())) { - yield(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); } // wait for transmission end - while(digitalRead(_mod->getIrq())) { - yield(); + while(Module::digitalRead(_mod->getIrq())) { + Module::yield(); } // set mode to standby @@ -125,13 +125,13 @@ int16_t CC1101::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for sync word - while(!digitalRead(_mod->getIrq())) { - yield(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); } // wait for packet end - while(digitalRead(_mod->getIrq())) { - yield(); + while(Module::digitalRead(_mod->getIrq())) { + Module::yield(); } // read packet data @@ -139,11 +139,18 @@ int16_t CC1101::receive(uint8_t* data, size_t len) { } int16_t CC1101::standby() { + // set idle mode SPIsendCommand(CC1101_CMD_IDLE); + + // set RF switch (if present) + _mod->setRfSwitchState(LOW, LOW); return(ERR_NONE); } int16_t CC1101::transmitDirect(uint32_t frf) { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { SPIwriteRegister(CC1101_REG_FREQ2, (frf & 0xFF0000) >> 16); @@ -163,6 +170,9 @@ int16_t CC1101::transmitDirect(uint32_t frf) { } int16_t CC1101::receiveDirect() { + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // activate direct mode int16_t state = directMode(); RADIOLIB_ASSERT(state); @@ -179,27 +189,27 @@ int16_t CC1101::packetMode() { return(state); } -void CC1101::setGdo0Action(void (*func)(void), RADIOLIB_PIN_STATUS dir) { - attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, dir); +void CC1101::setGdo0Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { + Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, dir); } void CC1101::clearGdo0Action() { - detachInterrupt(digitalPinToInterrupt(_mod->getIrq())); + Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } -void CC1101::setGdo2Action(void (*func)(void), RADIOLIB_PIN_STATUS dir) { +void CC1101::setGdo2Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) { if(_mod->getGpio() != RADIOLIB_NC) { return; } Module::pinMode(_mod->getGpio(), INPUT); - attachInterrupt(digitalPinToInterrupt(_mod->getGpio()), func, dir); + Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, dir); } void CC1101::clearGdo2Action() { if(_mod->getGpio() != RADIOLIB_NC) { return; } - detachInterrupt(digitalPinToInterrupt(_mod->getGpio())); + Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); } int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -232,6 +242,9 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // write packet to FIFO SPIwriteRegisterBurst(CC1101_REG_FIFO, data, len); + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + // set mode to transmit SPIsendCommand(CC1101_CMD_TX); @@ -249,6 +262,9 @@ int16_t CC1101::startReceive() { int state = SPIsetRegValue(CC1101_REG_IOCFG0, CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED); RADIOLIB_ASSERT(state); + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // set mode to receive SPIsendCommand(CC1101_CMD_RX); @@ -492,28 +508,28 @@ int16_t CC1101::setPreambleLength(uint8_t preambleLength) { // check allowed values uint8_t value; switch(preambleLength){ - case 2: + case 16: value = CC1101_NUM_PREAMBLE_2; break; - case 3: + case 24: value = CC1101_NUM_PREAMBLE_3; break; - case 4: + case 32: value = CC1101_NUM_PREAMBLE_4; break; - case 6: + case 48: value = CC1101_NUM_PREAMBLE_6; break; - case 8: + case 64: value = CC1101_NUM_PREAMBLE_8; break; - case 12: + case 96: value = CC1101_NUM_PREAMBLE_12; break; - case 16: + case 128: value = CC1101_NUM_PREAMBLE_16; break; - case 24: + case 192: value = CC1101_NUM_PREAMBLE_24; break; default: @@ -538,7 +554,7 @@ int16_t CC1101::setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs) { int16_t CC1101::disableAddressFiltering() { // disable address filtering - int16_t state = _mod->SPIsetRegValue(CC1101_REG_PKTCTRL1, CC1101_ADR_CHK_NONE, 1, 0); + int16_t state = SPIsetRegValue(CC1101_REG_PKTCTRL1, CC1101_ADR_CHK_NONE, 1, 0); RADIOLIB_ASSERT(state); // set node address to default (0x00) @@ -577,7 +593,7 @@ int16_t CC1101::setOOK(bool enableOOK) { } -float CC1101::getRSSI() { +float CC1101::getRSSI() const { float rssi; if(_rawRSSI >= 128) { rssi = (((float)_rawRSSI - 256.0)/2.0) - 74.0; @@ -587,16 +603,16 @@ float CC1101::getRSSI() { return(rssi); } -uint8_t CC1101::getLQI() { +uint8_t CC1101::getLQI() const { return(_rawLQI); } size_t CC1101::getPacketLength(bool update) { if(!_packetLengthQueried && update) { if (_packetLengthConfig == CC1101_LENGTH_CONFIG_VARIABLE) { - _packetLength = _mod->SPIreadRegister(CC1101_REG_FIFO); + _packetLength = SPIreadRegister(CC1101_REG_FIFO); } else { - _packetLength = _mod->SPIreadRegister(CC1101_REG_PKTLEN); + _packetLength = SPIreadRegister(CC1101_REG_PKTLEN); } _packetLengthQueried = true; @@ -614,23 +630,20 @@ int16_t CC1101::variablePacketLengthMode(uint8_t maxLen) { } int16_t CC1101::enableSyncWordFiltering(uint8_t maxErrBits, bool requireCarrierSense) { - switch (maxErrBits){ + switch(maxErrBits){ case 0: // in 16 bit sync word, expect all 16 bits - return (SPIsetRegValue(CC1101_REG_MDMCFG2, - requireCarrierSense ? CC1101_SYNC_MODE_16_16_THR : CC1101_SYNC_MODE_16_16, 2, 0)); + return(SPIsetRegValue(CC1101_REG_MDMCFG2, (requireCarrierSense ? CC1101_SYNC_MODE_16_16_THR : CC1101_SYNC_MODE_16_16), 2, 0)); case 1: // in 16 bit sync word, expect at least 15 bits - return (SPIsetRegValue(CC1101_REG_MDMCFG2, - requireCarrierSense ? CC1101_SYNC_MODE_15_16_THR : CC1101_SYNC_MODE_15_16, 2, 0)); + return(SPIsetRegValue(CC1101_REG_MDMCFG2, (requireCarrierSense ? CC1101_SYNC_MODE_15_16_THR : CC1101_SYNC_MODE_15_16), 2, 0)); default: - return (ERR_INVALID_SYNC_WORD); + return(ERR_INVALID_SYNC_WORD); } } int16_t CC1101::disableSyncWordFiltering(bool requireCarrierSense) { - return(SPIsetRegValue(CC1101_REG_MDMCFG2, - requireCarrierSense ? CC1101_SYNC_MODE_NONE_THR : CC1101_SYNC_MODE_NONE, 2, 0)); + return(SPIsetRegValue(CC1101_REG_MDMCFG2, (requireCarrierSense ? CC1101_SYNC_MODE_NONE_THR : CC1101_SYNC_MODE_NONE), 2, 0)); } int16_t CC1101::setCrcFiltering(bool crcOn) { @@ -669,19 +682,21 @@ int16_t CC1101::setPromiscuousMode(bool promiscuous) { return(state); } -int16_t CC1101::setDataShaping(float sh) { +int16_t CC1101::setDataShaping(uint8_t sh) { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); // set data shaping - sh *= 10.0; - if(abs(sh - 0.0) <= 0.001) { - state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_2_FSK, 6, 4); - } else if(abs(sh - 5.0) <= 0.001) { - state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_GFSK, 6, 4); - } else { - return(ERR_INVALID_DATA_SHAPING); + switch(sh) { + case RADIOLIB_SHAPING_NONE: + state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_2_FSK, 6, 4); + break; + case RADIOLIB_SHAPING_0_5: + state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_GFSK, 6, 4); + break; + default: + return(ERR_INVALID_DATA_SHAPING); } return(state); } @@ -693,29 +708,57 @@ int16_t CC1101::setEncoding(uint8_t encoding) { // set encoding switch(encoding) { - case 0: - state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_OFF, 3, 3); + case RADIOLIB_ENCODING_NRZ: + state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_OFF, 3, 3); RADIOLIB_ASSERT(state); - return(_mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF, 6, 6)); - case 1: - state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_ON, 3, 3); + return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF, 6, 6)); + case RADIOLIB_ENCODING_MANCHESTER: + state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_ON, 3, 3); RADIOLIB_ASSERT(state); - return(_mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF, 6, 6)); - case 2: - state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_OFF, 3, 3); + return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF, 6, 6)); + case RADIOLIB_ENCODING_WHITENING: + state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_OFF, 3, 3); RADIOLIB_ASSERT(state); - return(_mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_ON, 6, 6)); + return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_ON, 6, 6)); default: return(ERR_INVALID_ENCODING); } } +void CC1101::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { + _mod->setRfSwitchPins(rxEn, txEn); +} + +uint8_t CC1101::random() { + // set mode to Rx + SPIsendCommand(CC1101_CMD_RX); + + // wait a bit for the RSSI reading to stabilise + Module::delay(10); + + // read RSSI value 8 times, always keep just the least significant bit + uint8_t randByte = 0x00; + for(uint8_t i = 0; i < 8; i++) { + randByte |= ((SPIreadRegister(CC1101_REG_RSSI) & 0x01) << i); + } + + // set mode to standby + SPIsendCommand(CC1101_CMD_IDLE); + + return(randByte); +} + + +int16_t CC1101::getChipVersion() { + return(SPIgetRegValue(CC1101_REG_VERSION)); +} + int16_t CC1101::config() { // Reset the radio. Registers may be dirty from previous usage. SPIsendCommand(CC1101_CMD_RESET); // Wait a ridiculous amount of time to be sure radio is ready. - delay(150); + Module::delay(150); // enable automatic frequency synthesizer calibration int16_t state = SPIsetRegValue(CC1101_REG_MCSM0, CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4); @@ -773,11 +816,11 @@ int16_t CC1101::setPacketMode(uint8_t mode, uint8_t len) { } // set PKTCTRL0.LENGTH_CONFIG - int16_t state = _mod->SPIsetRegValue(CC1101_REG_PKTCTRL0, mode, 1, 0); + int16_t state = SPIsetRegValue(CC1101_REG_PKTCTRL0, mode, 1, 0); RADIOLIB_ASSERT(state); // set length to register - state = _mod->SPIsetRegValue(CC1101_REG_PKTLEN, len); + state = SPIsetRegValue(CC1101_REG_PKTLEN, len); RADIOLIB_ASSERT(state); // update the cached value @@ -831,9 +874,22 @@ void CC1101::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len) { } void CC1101::SPIsendCommand(uint8_t cmd) { + // get pointer to used SPI interface and the settings + SPIClass* spi = _mod->getSpi(); + SPISettings spiSettings = _mod->getSpiSettings(); + + // pull NSS low Module::digitalWrite(_mod->getCs(), LOW); - SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); - SPI.transfer(cmd); - SPI.endTransaction(); + + // start transfer + spi->beginTransaction(spiSettings); + + // send the command byte + spi->transfer(cmd); + + // stop transfer + spi->endTransaction(); Module::digitalWrite(_mod->getCs(), HIGH); } + +#endif diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index c1969d27..51432c1a 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -1,4 +1,4 @@ -#ifndef _RADIOLIB_CC1101_H +#if !defined(_RADIOLIB_CC1101_H) && !defined(RADIOLIB_EXCLUDE_CC1101) #define _RADIOLIB_CC1101_H #include "../../TypeDef.h" @@ -455,7 +455,8 @@ #define CC1101_PARTNUM 0x00 // CC1101_REG_VERSION -#define CC1101_VERSION 0x14 +#define CC1101_VERSION_CURRENT 0x14 +#define CC1101_VERSION_LEGACY 0x04 // CC1101_REG_MARCSTATE #define CC1101_MARC_STATE_SLEEP 0x00 // 4 0 main radio control state: sleep @@ -521,21 +522,21 @@ class CC1101: public PhysicalLayer { /*! \brief Initialization method. - \param freq Carrier frequency in MHz. Defaults to 868.0 MHz. + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. - \param br Bit rate to be used in kbps. Defaults to 4.8 kbps. + \param br Bit rate to be used in kbps. Defaults to 48.0 kbps. \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 48.0 kHz. - \param rxBw Receiver bandwidth in kHz. Defaults to 325.0 kHz. + \param rxBw Receiver bandwidth in kHz. Defaults to 135.0 kHz. - \param power Output power in dBm. Defaults to 0 dBm. + \param power Output power in dBm. Defaults to 10 dBm. - \param preambleLength Preamble Length in bytes. Defaults to 4 bytes. + \param preambleLength Preamble Length in bits. Defaults to 16 bits. \returns \ref status_codes */ - int16_t begin(float freq = 868.0, float br = 4.8, float freqDev = 48.0, float rxBw = 325.0, int8_t power = 0, uint8_t preambleLength = 4); + int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 48.0, float rxBw = 135.0, int8_t power = 10, uint8_t preambleLength = 16); /*! \brief Blocking binary transmit method. @@ -549,7 +550,7 @@ class CC1101: public PhysicalLayer { \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Blocking binary receive method. @@ -561,14 +562,14 @@ class CC1101: public PhysicalLayer { \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len); + int16_t receive(uint8_t* data, size_t len) override; /*! \brief Sets the module to standby mode. \returns \ref status_codes */ - int16_t standby(); + int16_t standby() override; /*! \brief Starts direct mode transmission. @@ -577,14 +578,14 @@ class CC1101: public PhysicalLayer { \returns \ref status_codes */ - int16_t transmitDirect(uint32_t frf = 0); + int16_t transmitDirect(uint32_t frf = 0) override; /*! \brief Starts direct mode reception. \returns \ref status_codes */ - int16_t receiveDirect(); + int16_t receiveDirect() override; /*! \brief Stops direct mode. It is required to call this method to switch from direct transmissions to packet-based transmissions. @@ -600,7 +601,7 @@ class CC1101: public PhysicalLayer { \param dir Signal change direction. Defaults to FALLING. */ - void setGdo0Action(void (*func)(void), RADIOLIB_PIN_STATUS dir = FALLING); + void setGdo0Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir = FALLING); /*! \brief Clears interrupt service routine to call when GDO0 activates. @@ -614,7 +615,7 @@ class CC1101: public PhysicalLayer { \param dir Signal change direction. Defaults to FALLING. */ - void setGdo2Action(void (*func)(void), RADIOLIB_PIN_STATUS dir = FALLING); + void setGdo2Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir = FALLING); /*! \brief Clears interrupt service routine to call when GDO0 activates. @@ -633,7 +634,7 @@ class CC1101: public PhysicalLayer { \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Interrupt-driven receive method. GDO0 will be activated when full packet is received. @@ -651,7 +652,7 @@ class CC1101: public PhysicalLayer { \returns \ref status_codes */ - int16_t readData(uint8_t* data, size_t len); + int16_t readData(uint8_t* data, size_t len) override; // configuration methods @@ -689,7 +690,7 @@ class CC1101: public PhysicalLayer { \returns \ref status_codes */ - int16_t setFrequencyDeviation(float freqDev); + int16_t setFrequencyDeviation(float freqDev) override; /*! \brief Sets output power. Allowed values are -30, -20, -15, -10, 0, 5, 7 or 10 dBm. @@ -733,7 +734,7 @@ class CC1101: public PhysicalLayer { /*! \brief Sets preamble length. - \param preambleLength Preamble length to be set (in bytes), allowed values: 2, 3, 4, 6, 8, 12, 16, 24 + \param preambleLength Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192. \returns \ref status_codes */ @@ -771,14 +772,14 @@ class CC1101: public PhysicalLayer { \returns Last packet RSSI in dBm. */ - float getRSSI(); + float getRSSI() const; /*! \brief Gets LQI (Link Quality Indicator) of the last received packet. \returns Last packet LQI (lower is better). */ - uint8_t getLQI(); + uint8_t getLQI() const; /*! \brief Query modem for the packet length of received payload. @@ -787,7 +788,7 @@ class CC1101: public PhysicalLayer { \returns Length of last received packet in bytes. */ - size_t getPacketLength(bool update = true); + size_t getPacketLength(bool update = true) override; /*! \brief Set modem in fixed packet length mode. @@ -847,46 +848,70 @@ class CC1101: public PhysicalLayer { /*! \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. - Allowed value is 0.5. Set to 0 to disable data shaping. + Allowed value is RADIOLIB_SHAPING_0_5. Set to RADIOLIB_SHAPING_NONE to disable data shaping. - \param sh Gaussian shaping bandwidth-time product that will be used for data shaping + \param sh Gaussian shaping bandwidth-time product that will be used for data shaping. \returns \ref status_codes */ - int16_t setDataShaping(float sh); + int16_t setDataShaping(uint8_t sh) override; /*! - \brief Sets transmission encoding. + \brief Sets transmission encoding. Allowed values are RADIOLIB_ENCODING_NRZ and RADIOLIB_ENCODING_WHITENING. - \param encoding Encoding to be used. Set to 0 for NRZ, 1 for Manchester and 2 for whitening. + \param encoding Encoding to be used. \returns \ref status_codes */ - int16_t setEncoding(uint8_t encoding); + int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. + When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! + + \param rxEn RX enable pin. + + \param txEn TX enable pin. + */ + void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + + /*! + \brief Get one truly random byte from RSSI noise. + + \returns TRNG byte. + */ + uint8_t random(); + + /*! + \brief Read version SPI register. Should return CC1101_VERSION_LEGACY (0x04) or CC1101_VERSION_CURRENT (0x14) if CC1101 is connected and working. + + \returns Version register contents or \ref status_codes + */ + int16_t getChipVersion(); #ifndef RADIOLIB_GODMODE private: #endif Module* _mod; - float _freq; - uint8_t _rawRSSI; - uint8_t _rawLQI; - uint8_t _modulation; + float _freq = 0; + uint8_t _rawRSSI = 0; + uint8_t _rawLQI = 0; + uint8_t _modulation = CC1101_MOD_FORMAT_2_FSK; - size_t _packetLength; - bool _packetLengthQueried; - uint8_t _packetLengthConfig; + size_t _packetLength = 0; + bool _packetLengthQueried = false; + uint8_t _packetLengthConfig = CC1101_LENGTH_CONFIG_VARIABLE; - bool _promiscuous; + bool _promiscuous = false; bool _crcOn = true; - uint8_t _syncWordLength; - int8_t _power; + uint8_t _syncWordLength = 2; + int8_t _power = 0; int16_t config(); int16_t directMode(); - void getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant); + static void getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant); int16_t setPacketMode(uint8_t mode, uint8_t len); // SPI read overrides to set bit for burst write and status registers access diff --git a/src/modules/ESP8266/ESP8266.cpp b/src/modules/ESP8266/ESP8266.cpp index 1aa959a9..fe62cc8e 100644 --- a/src/modules/ESP8266/ESP8266.cpp +++ b/src/modules/ESP8266/ESP8266.cpp @@ -1,5 +1,5 @@ -#if !defined(ESP8266) && !defined(ARDUINO_ARDUINO_NANO33BLE) #include "ESP8266.h" +#if !defined(RADIOLIB_EXCLUDE_ESP8266) && !defined(ESP8266) ESP8266::ESP8266(Module* module) { _mod = module; @@ -7,7 +7,8 @@ ESP8266::ESP8266(Module* module) { int16_t ESP8266::begin(long speed) { // set module properties - _mod->AtLineFeed = "\r\n"; + char lf[3] = "\r\n"; + memcpy(_mod->AtLineFeed, lf, strlen(lf)); _mod->baudrate = speed; _mod->init(RADIOLIB_USE_UART); @@ -29,13 +30,13 @@ int16_t ESP8266::reset() { } // wait for the module to start - delay(2000); + Module::delay(2000); // test AT setup - uint32_t start = millis(); - while (millis() - start < 3000) { + uint32_t start = Module::millis(); + while (Module::millis() - start < 3000) { if(!_mod->ATsendCommand("AT")) { - delay(100); + Module::delay(100); } else { return(ERR_NONE); } @@ -83,19 +84,19 @@ int16_t ESP8266::join(const char* ssid, const char* password) { int16_t ESP8266::openTransportConnection(const char* host, const char* protocol, uint16_t port, uint16_t tcpKeepAlive) { char portStr[6]; - itoa(port, portStr, 10); + sprintf(portStr, "%u", port); char tcpKeepAliveStr[6]; - itoa(tcpKeepAlive, tcpKeepAliveStr, 10); + sprintf(tcpKeepAliveStr, "%u", tcpKeepAlive); // build AT command const char* atStr = "AT+CIPSTART=\""; - uint8_t cmdLen = strlen(atStr) + strlen(protocol) + strlen(host) + strlen(portStr) + 5; - if((strcmp(protocol, "TCP") == 0) && (tcpKeepAlive > 0)) { - cmdLen += strlen(tcpKeepAliveStr) + 1; - } #ifdef RADIOLIB_STATIC_ONLY char cmd[RADIOLIB_STATIC_ARRAY_SIZE]; #else + uint8_t cmdLen = strlen(atStr) + strlen(protocol) + strlen(host) + strlen(portStr) + 5; + if((strcmp(protocol, "TCP") == 0) && (tcpKeepAlive > 0)) { + cmdLen += strlen(tcpKeepAliveStr) + 1; + } char* cmd = new char[cmdLen + 1]; #endif strcpy(cmd, atStr); @@ -131,8 +132,8 @@ int16_t ESP8266::closeTransportConnection() { int16_t ESP8266::send(const char* data) { // build AT command - char lenStr[8]; - itoa(strlen(data), lenStr, 10); + char lenStr[12]; + sprintf(lenStr, "%u", (uint16_t)strlen(data)); const char* atStr = "AT+CIPSEND="; #ifdef RADIOLIB_STATIC_ONLY char cmd[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -159,10 +160,10 @@ int16_t ESP8266::send(const char* data) { return(ERR_NONE); } -int16_t ESP8266::send(uint8_t* data, uint32_t len) { +int16_t ESP8266::send(uint8_t* data, size_t len) { // build AT command char lenStr[8]; - itoa(len, lenStr, 10); + sprintf(lenStr, "%u", (uint16_t)len); const char atStr[] = "AT+CIPSEND="; #ifdef RADIOLIB_STATIC_ONLY char cmd[RADIOLIB_STATIC_ARRAY_SIZE]; @@ -191,11 +192,11 @@ int16_t ESP8266::send(uint8_t* data, uint32_t len) { size_t ESP8266::receive(uint8_t* data, size_t len, uint32_t timeout) { size_t i = 0; - uint32_t start = millis(); + uint32_t start = Module::millis(); // wait until the required number of bytes is received or until timeout - while((millis() - start < timeout) && (i < len)) { - yield(); + while((Module::millis() - start < timeout) && (i < len)) { + Module::yield(); while(_mod->ModuleSerial->available() > 0) { uint8_t b = _mod->ModuleSerial->read(); RADIOLIB_DEBUG_PRINT(b); @@ -208,10 +209,10 @@ size_t ESP8266::receive(uint8_t* data, size_t len, uint32_t timeout) { size_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) { // wait for available data - uint32_t start = millis(); + uint32_t start = Module::millis(); while(_mod->ModuleSerial->available() < (int16_t)minBytes) { - yield(); - if(millis() - start >= timeout) { + Module::yield(); + if(Module::millis() - start >= timeout) { return(0); } } @@ -219,16 +220,16 @@ size_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) { // read response char rawStr[20]; uint8_t i = 0; - start = millis(); + start = Module::millis(); while(_mod->ModuleSerial->available() > 0) { - yield(); + Module::yield(); char c = _mod->ModuleSerial->read(); rawStr[i++] = c; if(c == ':') { rawStr[i++] = 0; break; } - if(millis() - start >= timeout) { + if(Module::millis() - start >= timeout) { rawStr[i++] = 0; break; } diff --git a/src/modules/ESP8266/ESP8266.h b/src/modules/ESP8266/ESP8266.h index e817038e..cc999500 100644 --- a/src/modules/ESP8266/ESP8266.h +++ b/src/modules/ESP8266/ESP8266.h @@ -1,6 +1,7 @@ -#if !defined(_RADIOLIB_ESP8266_H) +#if !defined(_RADIOLIB_ESP8266_H) && !defined(RADIOLIB_EXCLUDE_ESP8266) && !defined(ESP8266) #define _RADIOLIB_ESP8266_H +#include "../../TypeDef.h" #include "../../Module.h" #include "../../protocols/TransportLayer/TransportLayer.h" @@ -47,12 +48,12 @@ class ESP8266: public TransportLayer { int16_t join(const char* ssid, const char* password); // transport layer methods (implementations of purely virtual methods in TransportLayer class) - int16_t openTransportConnection(const char* host, const char* protocol, uint16_t port, uint16_t tcpKeepAlive = 0); - int16_t closeTransportConnection(); - int16_t send(const char* data); - int16_t send(uint8_t* data, uint32_t len); - size_t receive(uint8_t* data, size_t len, uint32_t timeout = 10000); - size_t getNumBytes(uint32_t timeout = 10000, size_t minBytes = 10); + int16_t openTransportConnection(const char* host, const char* protocol, uint16_t port, uint16_t tcpKeepAlive = 0) override; + int16_t closeTransportConnection() override; + int16_t send(const char* data) override; + int16_t send(uint8_t* data, size_t len) override; + size_t receive(uint8_t* data, size_t len, uint32_t timeout = 10000) override; + size_t getNumBytes(uint32_t timeout = 10000, size_t minBytes = 10) override; #ifndef RADIOLIB_GODMODE private: diff --git a/src/modules/HC05/HC05.cpp b/src/modules/HC05/HC05.cpp index 2aecab76..7a35ce71 100644 --- a/src/modules/HC05/HC05.cpp +++ b/src/modules/HC05/HC05.cpp @@ -1,4 +1,5 @@ #include "HC05.h" +#if !defined(RADIOLIB_EXCLUDE_HC05) HC05::HC05(Module* mod) : ISerial(mod) { @@ -9,3 +10,5 @@ void HC05::begin(long speed) { _mod->baudrate = speed; _mod->init(RADIOLIB_USE_UART); } + +#endif diff --git a/src/modules/HC05/HC05.h b/src/modules/HC05/HC05.h index 2bfacb48..7721a50a 100644 --- a/src/modules/HC05/HC05.h +++ b/src/modules/HC05/HC05.h @@ -1,4 +1,4 @@ -#ifndef _RADIOLIB_HC05_H +#if !defined(_RADIOLIB_HC05_H) && !defined(RADIOLIB_EXCLUDE_HC05) #define _RADIOLIB_HC05_H #include "../../ISerial.h" diff --git a/src/modules/JDY08/JDY08.cpp b/src/modules/JDY08/JDY08.cpp index 78bc596b..0179a142 100644 --- a/src/modules/JDY08/JDY08.cpp +++ b/src/modules/JDY08/JDY08.cpp @@ -1,3 +1,4 @@ +#if !defined(_RADIOLIB_JDY08_H) && !defined(RADIOLIB_EXCLUDE_JDY08) #include "JDY08.h" JDY08::JDY08(Module* mod) : ISerial(mod) { @@ -6,7 +7,10 @@ JDY08::JDY08(Module* mod) : ISerial(mod) { void JDY08::begin(long speed) { // set module properties - _mod->AtLineFeed = ""; + char lf[3] = ""; + memcpy(_mod->AtLineFeed, lf, strlen(lf)); _mod->baudrate = speed; _mod->init(RADIOLIB_USE_UART); } + +#endif diff --git a/src/modules/JDY08/JDY08.h b/src/modules/JDY08/JDY08.h index be01ef19..7bb64011 100644 --- a/src/modules/JDY08/JDY08.h +++ b/src/modules/JDY08/JDY08.h @@ -1,4 +1,4 @@ -#ifndef _RADIOLIB_JDY08_H +#if !defined(_RADIOLIB_JDY08_H) && !defined(RADIOLIB_EXCLUDE_JDY08) #define _RADIOLIB_JDY08_H #include "../../ISerial.h" diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index c9e9fa90..c5350fc8 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -1,18 +1,11 @@ #include "RF69.h" +#if !defined(RADIOLIB_EXCLUDE_RF69) RF69::RF69(Module* module) : PhysicalLayer(RF69_FREQUENCY_STEP_SIZE, RF69_MAX_PACKET_LENGTH) { _mod = module; - _tempOffset = 0; - - _packetLengthQueried = false; - _packetLengthConfig = RF69_PACKET_FORMAT_VARIABLE; - - _promiscuous = false; - - _syncWordLength = 2; } -int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t power) { +int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // set module properties _mod->init(RADIOLIB_USE_SPI); Module::pinMode(_mod->getIrq(), INPUT); @@ -25,8 +18,8 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe reset(); // check version register - uint8_t version = _mod->SPIreadRegister(RF69_REG_VERSION); - if(version == 0x24) { + int16_t version = getChipVersion(); + if(version == RF69_CHIP_VERSION) { flagFound = true; } else { #ifdef RADIOLIB_DEBUG @@ -40,17 +33,17 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe RADIOLIB_DEBUG_PRINT(F(", expected 0x0024")); RADIOLIB_DEBUG_PRINTLN(); #endif - delay(1000); + Module::delay(10); i++; } } if(!flagFound) { RADIOLIB_DEBUG_PRINTLN(F("No RF69 found!")); - _mod->term(); + _mod->term(RADIOLIB_USE_SPI); return(ERR_CHIP_NOT_FOUND); } else { - RADIOLIB_DEBUG_PRINTLN(F("Found RF69! (match by RF69_REG_VERSION == 0x24)")); + RADIOLIB_DEBUG_PRINTLN(F("M\tRF69")); } // configure settings not accessible by API @@ -78,32 +71,40 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe state = setOutputPower(power); RADIOLIB_ASSERT(state); + // configure default preamble length + state = setPreambleLength(preambleLen); + RADIOLIB_ASSERT(state); + // set default packet length mode state = variablePacketLengthMode(); RADIOLIB_ASSERT(state); - // default sync word values 0x2D01 is the same as the default in LowPowerLab RFM69 library - uint8_t syncWord[] = {0x2D, 0x01}; + // set default sync word + uint8_t syncWord[] = {0x12, 0xAD}; state = setSyncWord(syncWord, sizeof(syncWord)); RADIOLIB_ASSERT(state); // set default data shaping - state = setDataShaping(0); + state = setDataShaping(RADIOLIB_SHAPING_NONE); RADIOLIB_ASSERT(state); // set default encoding - state = setEncoding(0); + state = setEncoding(RADIOLIB_ENCODING_NRZ); RADIOLIB_ASSERT(state); - return(ERR_NONE); + // set CRC on by default + state = setCrcFiltering(true); + RADIOLIB_ASSERT(state); + + return(state); } void RF69::reset() { Module::pinMode(_mod->getRst(), OUTPUT); Module::digitalWrite(_mod->getRst(), HIGH); - delay(1); + Module::delay(1); Module::digitalWrite(_mod->getRst(), LOW); - delay(10); + Module::delay(10); } int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { @@ -115,11 +116,11 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission end or timeout - uint32_t start = micros(); - while(!digitalRead(_mod->getIrq())) { - yield(); + uint32_t start = Module::micros(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); - if(micros() - start > timeout) { + if(Module::micros() - start > timeout) { standby(); clearIRQFlags(); return(ERR_TX_TIMEOUT); @@ -144,11 +145,11 @@ int16_t RF69::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = micros(); - while(!digitalRead(_mod->getIrq())) { - yield(); - - if(micros() - start > timeout) { + uint32_t start = Module::micros(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); + + if(Module::micros() - start > timeout) { standby(); clearIRQFlags(); return(ERR_RX_TIMEOUT); @@ -160,16 +161,25 @@ int16_t RF69::receive(uint8_t* data, size_t len) { } int16_t RF69::sleep() { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, LOW); + // set module to sleep return(setMode(RF69_SLEEP)); } int16_t RF69::standby() { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, LOW); + // set module to standby return(setMode(RF69_STANDBY)); } int16_t RF69::transmitDirect(uint32_t frf) { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { _mod->SPIwriteRegister(RF69_REG_FRF_MSB, (frf & 0xFF0000) >> 16); @@ -188,6 +198,9 @@ int16_t RF69::transmitDirect(uint32_t frf) { } int16_t RF69::receiveDirect() { + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // activate direct mode int16_t state = directMode(); RADIOLIB_ASSERT(state); @@ -228,6 +241,7 @@ int16_t RF69::disableAES() { int16_t RF69::startReceive() { // set mode to standby int16_t state = setMode(RF69_STANDBY); + RADIOLIB_ASSERT(state); // set RX timeouts and DIO pin mapping state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO0_PACK_PAYLOAD_READY, 7, 4); @@ -238,35 +252,41 @@ int16_t RF69::startReceive() { // clear interrupt flags clearIRQFlags(); + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // set mode to receive - state = _mod->SPIsetRegValue(RF69_REG_TEST_PA1, RF69_PA1_NORMAL); + state = _mod->SPIsetRegValue(RF69_REG_OCP, RF69_OCP_ON | RF69_OCP_TRIM); + state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA1, RF69_PA1_NORMAL); state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA2, RF69_PA2_NORMAL); - state |= setMode(RF69_RX); + RADIOLIB_ASSERT(state); + + state = setMode(RF69_RX); return(state); } void RF69::setDio0Action(void (*func)(void)) { - attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, RISING); + Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); } void RF69::clearDio0Action() { - detachInterrupt(digitalPinToInterrupt(_mod->getIrq())); + Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } void RF69::setDio1Action(void (*func)(void)) { - if(_mod->getGpio() != RADIOLIB_NC) { + if(_mod->getGpio() == RADIOLIB_NC) { return; } Module::pinMode(_mod->getGpio(), INPUT); - attachInterrupt(digitalPinToInterrupt(_mod->getGpio()), func, RISING); + Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, RISING); } void RF69::clearDio1Action() { - if(_mod->getGpio() != RADIOLIB_NC) { + if(_mod->getGpio() == RADIOLIB_NC) { return; } - detachInterrupt(digitalPinToInterrupt(_mod->getGpio())); + Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); } int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -303,10 +323,19 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // write packet to FIFO _mod->SPIwriteRegisterBurst(RF69_REG_FIFO, data, len); + // enable +20 dBm operation + if(_power > 17) { + state = _mod->SPIsetRegValue(RF69_REG_OCP, RF69_OCP_OFF | 0x0F); + state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA1, RF69_PA1_20_DBM); + state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA2, RF69_PA2_20_DBM); + RADIOLIB_ASSERT(state); + } + + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + // set mode to transmit - state = _mod->SPIsetRegValue(RF69_REG_TEST_PA1, RF69_PA1_20_DBM); - state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA2, RF69_PA2_20_DBM); - state |= setMode(RF69_TX); + state = setMode(RF69_TX); return(state); } @@ -315,6 +344,7 @@ int16_t RF69::readData(uint8_t* data, size_t len) { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); + // get packet length size_t length = len; if(len == RF69_MAX_PACKET_LENGTH) { @@ -330,9 +360,6 @@ int16_t RF69::readData(uint8_t* data, size_t len) { // read packet data _mod->SPIreadRegisterBurst(RF69_REG_FIFO, length, data); - // update RSSI - lastPacketRSSI = -1.0 * (_mod->SPIgetRegValue(RF69_REG_RSSI_VALUE)/2.0); - // clear internal flag so getPacketLength can return the new packet length _packetLengthQueried = false; @@ -355,11 +382,10 @@ int16_t RF69::setFrequency(float freq) { //set carrier frequency uint32_t FRF = (freq * (uint32_t(1) << RF69_DIV_EXPONENT)) / RF69_CRYSTAL_FREQ; - int16_t state = _mod->SPIsetRegValue(RF69_REG_FRF_MSB, (FRF & 0xFF0000) >> 16, 7, 0); - state |= _mod->SPIsetRegValue(RF69_REG_FRF_MID, (FRF & 0x00FF00) >> 8, 7, 0); - state |= _mod->SPIsetRegValue(RF69_REG_FRF_LSB, FRF & 0x0000FF, 7, 0); - - return(state); + _mod->SPIwriteRegister(RF69_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); + _mod->SPIwriteRegister(RF69_REG_FRF_MID, (FRF & 0x00FF00) >> 8); + _mod->SPIwriteRegister(RF69_REG_FRF_LSB, FRF & 0x0000FF); + return(ERR_NONE); } int16_t RF69::setBitRate(float br) { @@ -496,22 +522,41 @@ int16_t RF69::setFrequencyDeviation(float freqDev) { return(state); } -int16_t RF69::setOutputPower(int8_t power) { - RADIOLIB_CHECK_RANGE(power, -18, 17, ERR_INVALID_OUTPUT_POWER); +int16_t RF69::setOutputPower(int8_t power, bool highPower) { + if(highPower) { + RADIOLIB_CHECK_RANGE(power, -2, 20, ERR_INVALID_OUTPUT_POWER); + } else { + RADIOLIB_CHECK_RANGE(power, -18, 13, ERR_INVALID_OUTPUT_POWER); + } // set mode to standby setMode(RF69_STANDBY); // set output power int16_t state; - if(power > 13) { - // requested output power is higher than 13 dBm, enable PA2 + PA1 on PA_BOOST - state = _mod->SPIsetRegValue(RF69_REG_PA_LEVEL, RF69_PA0_OFF | RF69_PA1_ON | RF69_PA2_ON | (power + 14), 7, 0); + if(highPower) { + // check if both PA1 and PA2 are needed + if(power <= 10) { + // -2 to 13 dBm, PA1 is enough + state = _mod->SPIsetRegValue(RF69_REG_PA_LEVEL, RF69_PA0_OFF | RF69_PA1_ON | RF69_PA2_OFF | (power + 18), 7, 0); + } else if(power <= 17) { + // 13 to 17 dBm, both PAs required + state = _mod->SPIsetRegValue(RF69_REG_PA_LEVEL, RF69_PA0_OFF | RF69_PA1_ON | RF69_PA2_ON | (power + 14), 7, 0); + } else { + // 18 - 20 dBm, both PAs and hig power settings required + state = _mod->SPIsetRegValue(RF69_REG_PA_LEVEL, RF69_PA0_OFF | RF69_PA1_ON | RF69_PA2_ON | (power + 11), 7, 0); + } + } else { - // requested output power is lower than 13 dBm, enable PA0 on RFIO + // low power module, use only PA0 state = _mod->SPIsetRegValue(RF69_REG_PA_LEVEL, RF69_PA0_ON | RF69_PA1_OFF | RF69_PA2_OFF | (power + 18), 7, 0); } + // cache the power value + if(state == ERR_NONE) { + _power = power; + } + return(state); } @@ -538,6 +583,17 @@ int16_t RF69::setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits) { return(ERR_NONE); } +int16_t RF69::setPreambleLength(uint8_t preambleLen) { + // RF69 configures preamble length in bytes + if(preambleLen % 8 != 0) { + return(ERR_INVALID_PREAMBLE_LENGTH); + } + + uint8_t preLenBytes = preambleLen / 8; + _mod->SPIwriteRegister(RF69_REG_PREAMBLE_MSB, 0x00); + return(_mod->SPIsetRegValue(RF69_REG_PREAMBLE_LSB, preLenBytes)); +} + int16_t RF69::setNodeAddress(uint8_t nodeAddr) { // enable address filtering (node only) int16_t state = _mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_ADDRESS_FILTERING_NODE, 2, 1); @@ -583,7 +639,7 @@ int16_t RF69::getTemperature() { // wait until measurement is finished while(_mod->SPIgetRegValue(RF69_REG_TEMP_1, 2, 2) == RF69_TEMP_MEAS_RUNNING) { // check every 10 us - delay(10); + Module::delay(10); } int8_t rawTemp = _mod->SPIgetRegValue(RF69_REG_TEMP_2); @@ -662,25 +718,24 @@ int16_t RF69::setPromiscuousMode(bool promiscuous) { return(state); } -int16_t RF69::setDataShaping(float sh) { +int16_t RF69::setDataShaping(uint8_t sh) { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); // set data shaping - sh *= 10.0; - if(abs(sh - 0.0) <= 0.001) { - state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_NO_SHAPING, 1, 0); - } else if(abs(sh - 3.0) <= 0.001) { - state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_0_3, 1, 0); - } else if(abs(sh - 5.0) <= 0.001) { - state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_0_5, 1, 0); - } else if(abs(sh - 10.0) <= 0.001) { - state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_1_0, 1, 0); - } else { - return(ERR_INVALID_DATA_SHAPING); + switch(sh) { + case RADIOLIB_SHAPING_NONE: + return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_NO_SHAPING, 1, 0)); + case RADIOLIB_SHAPING_0_3: + return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_0_3, 1, 0)); + case RADIOLIB_SHAPING_0_5: + return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_0_5, 1, 0)); + case RADIOLIB_SHAPING_1_0: + return(_mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK_GAUSSIAN_1_0, 1, 0)); + default: + return(ERR_INVALID_DATA_SHAPING); } - return(state); } int16_t RF69::setEncoding(uint8_t encoding) { @@ -690,17 +745,48 @@ int16_t RF69::setEncoding(uint8_t encoding) { // set encoding switch(encoding) { - case 0: + case RADIOLIB_ENCODING_NRZ: return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_DC_FREE_NONE, 6, 5)); - case 1: + case RADIOLIB_ENCODING_MANCHESTER: return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_DC_FREE_MANCHESTER, 6, 5)); - case 2: + case RADIOLIB_ENCODING_WHITENING: return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_1, RF69_DC_FREE_WHITENING, 6, 5)); default: return(ERR_INVALID_ENCODING); } } +float RF69::getRSSI() { + return(-1.0 * (_mod->SPIgetRegValue(RF69_REG_RSSI_VALUE)/2.0)); +} + +void RF69::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { + _mod->setRfSwitchPins(rxEn, txEn); +} + +uint8_t RF69::random() { + // set mode to Rx + setMode(RF69_RX); + + // wait a bit for the RSSI reading to stabilise + Module::delay(10); + + // read RSSI value 8 times, always keep just the least significant bit + uint8_t randByte = 0x00; + for(uint8_t i = 0; i < 8; i++) { + randByte |= ((_mod->SPIreadRegister(RF69_REG_RSSI_VALUE) & 0x01) << i); + } + + // set mode to standby + setMode(RF69_STANDBY); + + return(randByte); +} + +int16_t RF69::getChipVersion() { + return(_mod->SPIgetRegValue(RF69_REG_VERSION)); +} + int16_t RF69::config() { int16_t state = ERR_NONE; @@ -748,13 +834,13 @@ int16_t RF69::config() { // set Rx timeouts state = _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_1, RF69_TIMEOUT_RX_START, 7, 0); - state = _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_2, RF69_TIMEOUT_RSSI_THRESH, 7, 0); + state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_2, RF69_TIMEOUT_RSSI_THRESH, 7, 0); RADIOLIB_ASSERT(state); // enable improved fading margin state = _mod->SPIsetRegValue(RF69_REG_TEST_DAGC, RF69_CONTINUOUS_DAGC_LOW_BETA_OFF, 7, 0); - return(ERR_NONE); + return(state); } int16_t RF69::setPacketMode(uint8_t mode, uint8_t len) { @@ -784,3 +870,5 @@ void RF69::clearIRQFlags() { _mod->SPIwriteRegister(RF69_REG_IRQ_FLAGS_1, 0b11111111); _mod->SPIwriteRegister(RF69_REG_IRQ_FLAGS_2, 0b11111111); } + +#endif diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 1a40e5dc..e2c1d0a1 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_RF69_H +#if !defined(_RADIOLIB_RF69_H) #define _RADIOLIB_RF69_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_RF69) + #include "../../Module.h" #include "../../protocols/PhysicalLayer/PhysicalLayer.h" @@ -159,6 +162,9 @@ // RF69_REG_LISTEN_3 #define RF69_LISTEN_COEF_RX 0x20 // 7 0 duration of Rx phase in Listen mode +// RF69_REG_VERSION +#define RF69_CHIP_VERSION 0x24 // 7 0 + // RF69_REG_PA_LEVEL #define RF69_PA0_OFF 0b00000000 // 7 7 PA0 disabled #define RF69_PA0_ON 0b10000000 // 7 7 PA0 enabled (default) @@ -188,7 +194,7 @@ // RF69_REG_OCP #define RF69_OCP_OFF 0b00000000 // 4 4 PA overload current protection disabled -#define RF69_OCP_ON 0b00100000 // 4 4 PA overload current protection enabled +#define RF69_OCP_ON 0b00010000 // 4 4 PA overload current protection enabled #define RF69_OCP_TRIM 0b00001010 // 3 0 OCP current: I_max(OCP_TRIM = 0b1010) = 95 mA // RF69_REG_LNA @@ -441,11 +447,6 @@ class RF69: public PhysicalLayer { */ RF69(Module* module); - /*! - \brief RSSI value of the last received packet. - */ - float lastPacketRSSI; - // basic methods /*! @@ -459,11 +460,13 @@ class RF69: public PhysicalLayer { \param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz. - \param power Output power in dBm. Defaults to 13 dBm. + \param power Output power in dBm. Defaults to 10 dBm. + + \param preambleLen Preamble Length in bits. Defaults to 16 bits. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 13); + int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16); /*! \brief Reset method. Will reset the chip to the default state using RST pin. @@ -482,7 +485,7 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Blocking binary receive method. @@ -494,7 +497,7 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len); + int16_t receive(uint8_t* data, size_t len) override; /*! \brief Sets the module to sleep mode. @@ -508,7 +511,7 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t standby(); + int16_t standby() override; /*! \brief Starts direct mode transmission. @@ -517,14 +520,14 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t transmitDirect(uint32_t frf = 0); + int16_t transmitDirect(uint32_t frf = 0) override; /*! \brief Starts direct mode reception. \returns \ref status_codes */ - int16_t receiveDirect(); + int16_t receiveDirect() override; /*! \brief Stops direct mode. It is required to call this method to switch from direct transmissions to packet-based transmissions. @@ -592,7 +595,7 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Interrupt-driven receive method. GDO0 will be activated when full packet is received. @@ -610,7 +613,7 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t readData(uint8_t* data, size_t len); + int16_t readData(uint8_t* data, size_t len) override; // configuration methods @@ -648,16 +651,18 @@ class RF69: public PhysicalLayer { \returns \ref status_codes */ - int16_t setFrequencyDeviation(float freqDev); + int16_t setFrequencyDeviation(float freqDev) override; /*! - \brief Sets output power. Allowed values are -30, -20, -15, -10, 0, 5, 7 or 10 dBm. + \brief Sets output power. Allowed values range from -18 to 13 dBm for low power modules (RF69C/CW) or -2 to 20 dBm (RF69H/HC/HCW). \param power Output power to be set in dBm. + \param highPower Set to true when using modules high power port (RF69H/HC/HCW). Defaults to false (models without high power port - RF69C/CW). + \returns \ref status_codes */ - int16_t setOutputPower(int8_t power); + int16_t setOutputPower(int8_t power, bool highPower = false); /*! \brief Sets sync word. Up to 8 bytes can be set as sync word. @@ -670,6 +675,15 @@ class RF69: public PhysicalLayer { */ int16_t setSyncWord(uint8_t* syncWord, size_t len, uint8_t maxErrBits = 0); + /*! + \brief Sets preamble length. + + \param preambleLen Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192. + + \returns \ref status_codes + */ + int16_t setPreambleLength(uint8_t preambleLen); + /*! \brief Sets node address. Calling this method will also enable address filtering for node address only. @@ -718,7 +732,7 @@ class RF69: public PhysicalLayer { \returns Length of last received packet in bytes. */ - size_t getPacketLength(bool update = true); + size_t getPacketLength(bool update = true) override; /*! \brief Set modem in fixed packet length mode. @@ -774,39 +788,72 @@ class RF69: public PhysicalLayer { /*! \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. - Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. + Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. \param sh Gaussian shaping bandwidth-time product that will be used for data shaping \returns \ref status_codes */ - int16_t setDataShaping(float sh); + int16_t setDataShaping(uint8_t sh) override; /*! \brief Sets transmission encoding. + Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER and RADIOLIB_ENCODING_WHITENING. - \param encoding Encoding to be used. Set to 0 for NRZ, 1 for Manchester and 2 for whitening. + \param encoding Encoding to be used. \returns \ref status_codes */ - int16_t setEncoding(uint8_t encoding); + int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + + \returns Last packet RSSI in dBm. + */ + float getRSSI(); + + /*! + \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. + When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! + + \param rxEn RX enable pin. + + \param txEn TX enable pin. + */ + void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + + /*! + \brief Get one truly random byte from RSSI noise. + + \returns TRNG byte. + */ + uint8_t random(); + + /*! + \brief Read version SPI register. Should return RF69_CHIP_VERSION (0x24) if SX127x is connected and working. + + \returns Version register contents or \ref status_codes + */ + int16_t getChipVersion(); #ifndef RADIOLIB_GODMODE protected: #endif Module* _mod; - float _br; - float _rxBw; - int16_t _tempOffset; + float _br = 0; + float _rxBw = 0; + int16_t _tempOffset = 0; + int8_t _power = 0; - size_t _packetLength; - bool _packetLengthQueried; - uint8_t _packetLengthConfig; + size_t _packetLength = 0; + bool _packetLengthQueried = false; + uint8_t _packetLengthConfig = RF69_PACKET_FORMAT_VARIABLE; - bool _promiscuous; + bool _promiscuous = false; - uint8_t _syncWordLength; + uint8_t _syncWordLength = 2; int16_t config(); int16_t directMode(); @@ -820,3 +867,5 @@ class RF69: public PhysicalLayer { }; #endif + +#endif diff --git a/src/modules/RFM2x/RFM22.h b/src/modules/RFM2x/RFM22.h index e3cd4a4d..3204c7ca 100644 --- a/src/modules/RFM2x/RFM22.h +++ b/src/modules/RFM2x/RFM22.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_RFM22_H +#if !defined(_RADIOLIB_RFM22_H) #define _RADIOLIB_RFM22_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_RFM2X) + #include "../../Module.h" #include "../Si443x/Si443x.h" #include "../Si443x/Si4432.h" @@ -14,3 +17,5 @@ using RFM22 = Si4432; #endif + +#endif diff --git a/src/modules/RFM2x/RFM23.h b/src/modules/RFM2x/RFM23.h index 4f72557d..45a708a2 100644 --- a/src/modules/RFM2x/RFM23.h +++ b/src/modules/RFM2x/RFM23.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_RFM23_H +#if !defined(_RADIOLIB_RFM23_H) #define _RADIOLIB_RFM23_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_RFM2X) + #include "../../Module.h" #include "../Si443x/Si443x.h" #include "../Si443x/Si4431.h" @@ -14,3 +17,5 @@ using RFM23 = Si4431; #endif + +#endif diff --git a/src/modules/RFM9x/RFM95.cpp b/src/modules/RFM9x/RFM95.cpp index 49557190..ff614852 100644 --- a/src/modules/RFM9x/RFM95.cpp +++ b/src/modules/RFM9x/RFM95.cpp @@ -1,17 +1,23 @@ #include "RFM95.h" +#if !defined(RADIOLIB_EXCLUDE_RFM9X) RFM95::RFM95(Module* mod) : SX1278(mod) { } -int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) { +int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(RFM95_CHIP_VERSION, syncWord, currentLimit, preambleLength); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = config(); - RADIOLIB_ASSERT(state); + int16_t state = SX127x::begin(RFM9X_CHIP_VERSION_OFFICIAL, syncWord, preambleLength); + if(state == ERR_CHIP_NOT_FOUND) { + // SX127X_REG_VERSION might be set 0x12 + state = SX127x::begin(RFM9X_CHIP_VERSION_UNOFFICIAL, syncWord, preambleLength); + RADIOLIB_ASSERT(state); + } else if(state != ERR_NONE) { + // some other error + return(state); + } + RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278")); + RADIOLIB_DEBUG_PRINTLN(F("M\tRFM95")); // configure publicly accessible settings state = setFrequency(freq); @@ -35,8 +41,10 @@ int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW } int16_t RFM95::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 868.0, 915.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 862.0, 1020.0, ERR_INVALID_FREQUENCY); // set frequency return(SX127x::setFrequencyRaw(freq)); } + +#endif diff --git a/src/modules/RFM9x/RFM95.h b/src/modules/RFM9x/RFM95.h index 78758971..f6c02840 100644 --- a/src/modules/RFM9x/RFM95.h +++ b/src/modules/RFM9x/RFM95.h @@ -1,13 +1,17 @@ -#ifndef _RADIOLIB_RFM95_H +#if !defined(_RADIOLIB_RFM95_H) #define _RADIOLIB_RFM95_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_RFM9X) + #include "../../Module.h" #include "../SX127x/SX127x.h" #include "../SX127x/SX1278.h" // SX127X_REG_VERSION -#define RFM95_CHIP_VERSION 0x11 +#define RFM9X_CHIP_VERSION_OFFICIAL 0x11 +#define RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12 /*! \class RFM95 @@ -43,9 +47,6 @@ class RFM95: public SX1278 { \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. - Set to 0 to disable OCP (not recommended). - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. @@ -54,7 +55,7 @@ class RFM95: public SX1278 { \returns \ref status_codes */ - int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); // configuration methods @@ -74,3 +75,5 @@ class RFM95: public SX1278 { }; #endif + +#endif diff --git a/src/modules/RFM9x/RFM96.cpp b/src/modules/RFM9x/RFM96.cpp index cf81ca40..2d6978b9 100644 --- a/src/modules/RFM9x/RFM96.cpp +++ b/src/modules/RFM9x/RFM96.cpp @@ -1,18 +1,24 @@ #include "RFM96.h" +#if !defined(RADIOLIB_EXCLUDE_RFM9X) RFM96::RFM96(Module* mod) : SX1278(mod) { } -int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) { +int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(RFM9X_CHIP_VERSION, syncWord, currentLimit, preambleLength); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = config(); - RADIOLIB_ASSERT(state); - + int16_t state = SX127x::begin(RFM9X_CHIP_VERSION_OFFICIAL, syncWord, preambleLength); + if(state == ERR_CHIP_NOT_FOUND) { + // SX127X_REG_VERSION might be set 0x12 + state = SX127x::begin(RFM9X_CHIP_VERSION_UNOFFICIAL, syncWord, preambleLength); + RADIOLIB_ASSERT(state); + } else if(state != ERR_NONE) { + // some other error + return(state); + } + RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278")); + RADIOLIB_DEBUG_PRINTLN(F("M\tRFM96")); + // configure publicly accessible settings state = setFrequency(freq); RADIOLIB_ASSERT(state); @@ -30,13 +36,16 @@ int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW RADIOLIB_ASSERT(state); state = setGain(gain); + RADIOLIB_ASSERT(state); return(state); } int16_t RFM96::setFrequency(float freq) { - RADIOLIB_CHECK_RANGE(freq, 433.0, 470.0, ERR_INVALID_FREQUENCY); + RADIOLIB_CHECK_RANGE(freq, 410.0, 525.0, ERR_INVALID_FREQUENCY); // set frequency return(SX127x::setFrequencyRaw(freq)); } + +#endif diff --git a/src/modules/RFM9x/RFM96.h b/src/modules/RFM9x/RFM96.h index 1288c797..c18019b2 100644 --- a/src/modules/RFM9x/RFM96.h +++ b/src/modules/RFM9x/RFM96.h @@ -1,13 +1,17 @@ -#ifndef _RADIOLIB_RFM96_H +#if !defined(_RADIOLIB_RFM96_H) #define _RADIOLIB_RFM96_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_RFM9X) + #include "../../Module.h" #include "../SX127x/SX127x.h" #include "../SX127x/SX1278.h" // SX127X_REG_VERSION -#define RFM9X_CHIP_VERSION 0x12 // according to datasheet, this should be 0x11, but all modules seem to have 0x12 +#define RFM9X_CHIP_VERSION_OFFICIAL 0x11 +#define RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12 /*! \class RFM96 @@ -43,9 +47,6 @@ class RFM96: public SX1278 { \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. - Set to 0 to disable OCP (not recommended). - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. @@ -54,7 +55,7 @@ class RFM96: public SX1278 { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); // configuration methods @@ -81,3 +82,5 @@ class RFM96: public SX1278 { using RFM98 = RFM96; #endif + +#endif diff --git a/src/modules/RFM9x/RFM97.cpp b/src/modules/RFM9x/RFM97.cpp index 102fecf9..ccf19134 100644 --- a/src/modules/RFM9x/RFM97.cpp +++ b/src/modules/RFM9x/RFM97.cpp @@ -1,4 +1,5 @@ #include "RFM97.h" +#if !defined(RADIOLIB_EXCLUDE_RFM9X) RFM97::RFM97(Module* mod) : RFM95(mod) { @@ -37,3 +38,5 @@ int16_t RFM97::setSpreadingFactor(uint8_t sf) { } return(state); } + +#endif diff --git a/src/modules/RFM9x/RFM97.h b/src/modules/RFM9x/RFM97.h index b5dcbbdf..30454f91 100644 --- a/src/modules/RFM9x/RFM97.h +++ b/src/modules/RFM9x/RFM97.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_RFM97_H +#if !defined(_RADIOLIB_RFM97_H) #define _RADIOLIB_RFM97_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_RFM9X) + #include "../../Module.h" #include "../SX127x/SX127x.h" #include "../SX127x/SX1278.h" @@ -42,3 +45,5 @@ class RFM97: public RFM95 { }; #endif + +#endif diff --git a/src/modules/SX1231/SX1231.cpp b/src/modules/SX1231/SX1231.cpp index b7412bcb..3148556f 100644 --- a/src/modules/SX1231/SX1231.cpp +++ b/src/modules/SX1231/SX1231.cpp @@ -1,10 +1,11 @@ #include "SX1231.h" +#if !defined(RADIOLIB_EXCLUDE_SX1231) SX1231::SX1231(Module* mod) : RF69(mod) { } -int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t power) { +int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t preambleLen) { // set module properties _mod->init(RADIOLIB_USE_SPI); Module::pinMode(_mod->getIrq(), INPUT); @@ -14,38 +15,38 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po uint8_t i = 0; bool flagFound = false; while((i < 10) && !flagFound) { - uint8_t version = _mod->SPIreadRegister(RF69_REG_VERSION); + int16_t version = getChipVersion(); if((version == 0x21) || (version == 0x22) || (version == 0x23)) { flagFound = true; _chipRevision = version; } else { #ifdef RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINT(F("SX127x not found! (")); + RADIOLIB_DEBUG_PRINT(F("SX1231 not found! (")); RADIOLIB_DEBUG_PRINT(i + 1); - RADIOLIB_DEBUG_PRINT(F(" of 10 tries) SX127X_REG_VERSION == ")); + RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RF69_REG_VERSION == ")); - char buffHex[7]; + char buffHex[12]; sprintf(buffHex, "0x%04X", version); RADIOLIB_DEBUG_PRINT(buffHex); RADIOLIB_DEBUG_PRINT(F(", expected 0x0021 / 0x0022 / 0x0023")); RADIOLIB_DEBUG_PRINTLN(); #endif - delay(1000); + Module::delay(10); i++; } } if(!flagFound) { RADIOLIB_DEBUG_PRINTLN(F("No SX1231 found!")); - _mod->term(); + _mod->term(RADIOLIB_USE_SPI); return(ERR_CHIP_NOT_FOUND); - } else { - RADIOLIB_DEBUG_PRINTLN(F("Found SX1231!")); } + RADIOLIB_DEBUG_PRINTLN(F("M\tSX1231")); // configure settings not accessible by API int16_t state = config(); RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_PRINTLN(F("M\tRF69")); // configure publicly accessible settings state = setFrequency(freq); @@ -68,6 +69,10 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po state = setOutputPower(power); RADIOLIB_ASSERT(state); + // configure default preamble length + state = setPreambleLength(preambleLen); + RADIOLIB_ASSERT(state); + // default sync word values 0x2D01 is the same as the default in LowPowerLab RFM69 library uint8_t syncWord[] = {0x2D, 0x01}; state = setSyncWord(syncWord, 2); @@ -92,3 +97,5 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po return(ERR_NONE); } + +#endif diff --git a/src/modules/SX1231/SX1231.h b/src/modules/SX1231/SX1231.h index d048fd02..08cea4d4 100644 --- a/src/modules/SX1231/SX1231.h +++ b/src/modules/SX1231/SX1231.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX1231_H +#if !defined(_RADIOLIB_SX1231_H) #define _RADIOLIB_SX1231_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX1231) + #include "../../Module.h" #include "../RF69/RF69.h" @@ -40,16 +43,20 @@ class SX1231: public RF69 { \param freqDev Frequency deviation from carrier frequency in kHz Defaults to 50.0 kHz. - \param power Output power in dBm. Defaults to 13 dBm. + \param power Output power in dBm. Defaults to 10 dBm. + + \param preambleLen Preamble Length in bits. Defaults to 16 bits. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 13); + int16_t begin(float freq = 434.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 10, uint8_t preambleLen = 16); #ifndef RADIOLIB_GODMODE private: #endif - uint8_t _chipRevision; + uint8_t _chipRevision = 0; }; #endif + +#endif diff --git a/src/modules/SX126x/SX1261.cpp b/src/modules/SX126x/SX1261.cpp index a78d2578..1e035651 100644 --- a/src/modules/SX126x/SX1261.cpp +++ b/src/modules/SX126x/SX1261.cpp @@ -1,4 +1,5 @@ #include "SX1261.h" +#if !defined(RADIOLIB_EXCLUDE_SX126X) SX1261::SX1261(Module* mod): SX1262(mod) { @@ -17,10 +18,12 @@ int16_t SX1261::setOutputPower(int8_t power) { RADIOLIB_ASSERT(state); // set output power - // TODO power ramp time configuration + /// \todo power ramp time configuration state = SX126x::setTxParams(power); RADIOLIB_ASSERT(state); // restore OCP configuration return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); } + +#endif diff --git a/src/modules/SX126x/SX1261.h b/src/modules/SX126x/SX1261.h index 2dca7ed1..a52d4235 100644 --- a/src/modules/SX126x/SX1261.h +++ b/src/modules/SX126x/SX1261.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX1261_H +#if !defined(_RADIOLIB_SX1261_H) #define _RADIOLIB_SX1261_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX126X) + #include "../../Module.h" #include "SX126x.h" #include "SX1262.h" @@ -38,5 +41,6 @@ class SX1261 : public SX1262 { }; +#endif #endif diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 7d1f6efe..0d78eea5 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -1,12 +1,13 @@ #include "SX1262.h" +#if !defined(RADIOLIB_EXCLUDE_SX126X) SX1262::SX1262(Module* mod) : SX126x(mod) { } -int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, float currentLimit, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { +int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // execute common part - int16_t state = SX126x::begin(bw, sf, cr, syncWord, currentLimit, preambleLength, tcxoVoltage, useRegulatorLDO); + int16_t state = SX126x::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -17,13 +18,14 @@ int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync RADIOLIB_ASSERT(state); state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); return(state); } -int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, float currentLimit, uint16_t preambleLength, float dataShaping, float tcxoVoltage, bool useRegulatorLDO) { +int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // execute common part - int16_t state = SX126x::beginFSK(br, freqDev, rxBw, currentLimit, preambleLength, dataShaping, tcxoVoltage, useRegulatorLDO); + int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage, useRegulatorLDO); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -34,6 +36,7 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t RADIOLIB_ASSERT(state); state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); return(state); } @@ -41,8 +44,6 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t int16_t SX1262::setFrequency(float freq, bool calibrate) { RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, ERR_INVALID_FREQUENCY); - int16_t state = ERR_NONE; - // calibrate image if(calibrate) { uint8_t data[2]; @@ -62,7 +63,7 @@ int16_t SX1262::setFrequency(float freq, bool calibrate) { data[0] = SX126X_CAL_IMG_430_MHZ_1; data[1] = SX126X_CAL_IMG_430_MHZ_2; } - state = SX126x::calibrateImage(data); + int16_t state = SX126x::calibrateImage(data); RADIOLIB_ASSERT(state); } @@ -83,10 +84,12 @@ int16_t SX1262::setOutputPower(int8_t power) { RADIOLIB_ASSERT(state); // set output power - // TODO power ramp time configuration + /// \todo power ramp time configuration state = SX126x::setTxParams(power); RADIOLIB_ASSERT(state); // restore OCP configuration return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); } + +#endif diff --git a/src/modules/SX126x/SX1262.h b/src/modules/SX126x/SX1262.h index e33f568b..616cd407 100644 --- a/src/modules/SX126x/SX1262.h +++ b/src/modules/SX126x/SX1262.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX1262_H +#if !defined(_RADIOLIB_SX1262_H) #define _RADIOLIB_SX1262_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX126X) + #include "../../Module.h" #include "SX126x.h" @@ -37,17 +40,15 @@ class SX1262: public SX126x { \param syncWord 2-byte LoRa sync word. Defaults to SX126X_SYNC_WORD_PRIVATE (0x12). - \param power Output power in dBm. Defaults to 14 dBm. + \param power Output power in dBm. Defaults to 10 dBm. - \param currentLimit Current protection limit in mA. Defaults to 60.0 mA. - - \param preambleLength LoRa preamble length in symbols.Defaults to 8 symbols. + \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); /*! \brief Initialization method for FSK modem. @@ -60,19 +61,17 @@ class SX1262: public SX126x { \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. - \param power Output power in dBm. Defaults to 14 dBm. - - \param currentLimit Current protection limit in mA. Defaults to 60.0 mA. + \param power Output power in dBm. Defaults to 10 dBm. \parma preambleLength FSK preamble length in bits. Defaults to 16 bits. - \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 156.2, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 16, float dataShaping = 0.5, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); // configuration methods @@ -103,3 +102,5 @@ class SX1262: public SX126x { }; #endif + +#endif diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index 6b7f3ad2..0addddf8 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -1,12 +1,13 @@ #include "SX1268.h" +#if !defined(RADIOLIB_EXCLUDE_SX126X) SX1268::SX1268(Module* mod) : SX126x(mod) { } -int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, float currentLimit, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { +int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // execute common part - int16_t state = SX126x::begin(bw, sf, cr, syncWord, currentLimit, preambleLength, tcxoVoltage, useRegulatorLDO); + int16_t state = SX126x::begin(bw, sf, cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -17,12 +18,14 @@ int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync RADIOLIB_ASSERT(state); state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); return(state); } -int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, float currentLimit, uint16_t preambleLength, float dataShaping, float tcxoVoltage, bool useRegulatorLDO) { + +int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // execute common part - int16_t state = SX126x::beginFSK(br, freqDev, rxBw, currentLimit, preambleLength, dataShaping, tcxoVoltage, useRegulatorLDO); + int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, tcxoVoltage, useRegulatorLDO); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -33,15 +36,15 @@ int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t RADIOLIB_ASSERT(state); state = SX126x::fixPaClamping(); + RADIOLIB_ASSERT(state); return(state); } +/// \todo integers only (all modules - frequency, data rate, bandwidth etc.) int16_t SX1268::setFrequency(float freq, bool calibrate) { RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, ERR_INVALID_FREQUENCY); - int16_t state = ERR_NONE; - // calibrate image if(calibrate) { uint8_t data[2]; @@ -55,7 +58,7 @@ int16_t SX1268::setFrequency(float freq, bool calibrate) { data[0] = SX126X_CAL_IMG_430_MHZ_1; data[1] = SX126X_CAL_IMG_430_MHZ_2; } - state = SX126x::calibrateImage(data); + int16_t state = SX126x::calibrateImage(data); RADIOLIB_ASSERT(state); } @@ -76,10 +79,12 @@ int16_t SX1268::setOutputPower(int8_t power) { RADIOLIB_ASSERT(state); // set output power - // TODO power ramp time configuration + /// \todo power ramp time configuration state = SX126x::setTxParams(power); RADIOLIB_ASSERT(state); // restore OCP configuration return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); } + +#endif diff --git a/src/modules/SX126x/SX1268.h b/src/modules/SX126x/SX1268.h index 5b203b72..909dd334 100644 --- a/src/modules/SX126x/SX1268.h +++ b/src/modules/SX126x/SX1268.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX1268_H +#if !defined(_RADIOLIB_SX1268_H) #define _RADIOLIB_SX1268_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX126X) + #include "../../Module.h" #include "SX126x.h" @@ -37,9 +40,7 @@ class SX1268: public SX126x { \param syncWord 2-byte LoRa sync word. Defaults to SX126X_SYNC_WORD_PRIVATE (0x12). - \param power Output power in dBm. Defaults to 14 dBm. - - \param currentLimit Current protection limit in mA. Defaults to 60.0 mA. + \param power Output power in dBm. Defaults to 10 dBm. \param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols. @@ -47,7 +48,7 @@ class SX1268: public SX126x { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); /*! \brief Initialization method for FSK modem. @@ -56,23 +57,21 @@ class SX1268: public SX126x { \param br FSK bit rate in kbps. Defaults to 48.0 kbps. - \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 50.0 kHz. + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 50.0 kHz. \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. - \param power Output power in dBm. Defaults to 14 dBm. - - \param currentLimit Current protection limit in mA. Defaults to 60.0 mA. + \param power Output power in dBm. Defaults to 10 dBm. \parma preambleLength FSK preamble length in bits. Defaults to 16 bits. - \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. + \param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false. + \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 156.2, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 16, float dataShaping = 0.5, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); + int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false); // configuration methods @@ -103,3 +102,5 @@ class SX1268: public SX126x { }; #endif + +#endif diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 685163cf..8a1809ca 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -1,14 +1,16 @@ #include "SX126x.h" +#if !defined(RADIOLIB_EXCLUDE_SX126X) SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_FREQUENCY_STEP_SIZE, SX126X_MAX_PACKET_LENGTH) { _mod = mod; } -int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, float currentLimit, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { +int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // set module properties _mod->init(RADIOLIB_USE_SPI); Module::pinMode(_mod->getIrq(), INPUT); Module::pinMode(_mod->getGpio(), INPUT); + RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); // BW in kHz and SF are required in order to calculate LDRO for setModulationParams _bwKhz = bw; @@ -55,13 +57,13 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, float state = setSyncWord(syncWord); RADIOLIB_ASSERT(state); - state = setCurrentLimit(currentLimit); - RADIOLIB_ASSERT(state); - state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); // set publicly accessible settings that are not a part of begin method + state = setCurrentLimit(60.0); + RADIOLIB_ASSERT(state); + state = setDio2AsRfSwitch(true); RADIOLIB_ASSERT(state); @@ -74,11 +76,12 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, float return(state); } -int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, float currentLimit, uint16_t preambleLength, float dataShaping, float tcxoVoltage, bool useRegulatorLDO) { +int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) { // set module properties _mod->init(RADIOLIB_USE_SPI); Module::pinMode(_mod->getIrq(), INPUT); Module::pinMode(_mod->getGpio(), INPUT); + RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x")); // initialize configuration variables (will be overwritten during public settings configuration) _br = 21333; // 48.0 kbps @@ -118,34 +121,38 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, float currentLimit state = setRxBandwidth(rxBw); RADIOLIB_ASSERT(state); - state = setCurrentLimit(currentLimit); - RADIOLIB_ASSERT(state); - - state = setDataShaping(dataShaping); + state = setCurrentLimit(60.0); RADIOLIB_ASSERT(state); state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); - // set publicly accessible settings that are not a part of begin method - uint8_t sync[] = {0x2D, 0x01}; - state = setSyncWord(sync, 2); - RADIOLIB_ASSERT(state); - - state = setWhitening(true, 0x01FF); - RADIOLIB_ASSERT(state); - - state = variablePacketLengthMode(SX126X_MAX_PACKET_LENGTH); - RADIOLIB_ASSERT(state); - - state = setDio2AsRfSwitch(false); - RADIOLIB_ASSERT(state); - if(useRegulatorLDO) { state = setRegulatorLDO(); } else { state = setRegulatorDCDC(); } + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + uint8_t sync[] = {0x12, 0xAD}; + state = setSyncWord(sync, 2); + RADIOLIB_ASSERT(state); + + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + + state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + state = variablePacketLengthMode(SX126X_MAX_PACKET_LENGTH); + RADIOLIB_ASSERT(state); + + state = setCRC(2); + RADIOLIB_ASSERT(state); + + state = setDio2AsRfSwitch(false); + RADIOLIB_ASSERT(state); return(state); } @@ -154,7 +161,7 @@ int16_t SX126x::reset(bool verify) { // run the reset sequence Module::pinMode(_mod->getRst(), OUTPUT); Module::digitalWrite(_mod->getRst(), LOW); - delay(1); + Module::delay(1); Module::digitalWrite(_mod->getRst(), HIGH); // return immediately when verification is disabled @@ -163,7 +170,7 @@ int16_t SX126x::reset(bool verify) { } // set mode to standby - SX126x often refuses first few commands after reset - uint32_t start = millis(); + uint32_t start = Module::millis(); while(true) { // try to set mode to standby int16_t state = standby(); @@ -173,13 +180,13 @@ int16_t SX126x::reset(bool verify) { } // standby command failed, check timeout and try again - if(millis() - start >= 3000) { + if(Module::millis() - start >= 3000) { // timed out, possibly incorrect wiring return(state); } // wait a bit to not spam the module - delay(10); + Module::delay(10); } } @@ -218,16 +225,16 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = micros(); - while(!digitalRead(_mod->getIrq())) { - yield(); - if(micros() - start > timeout) { + uint32_t start = Module::micros(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); + if(Module::micros() - start > timeout) { clearIrqStatus(); standby(); return(ERR_TX_TIMEOUT); } } - uint32_t elapsed = micros() - start; + uint32_t elapsed = Module::micros() - start; // update data rate _dataRate = (len*8.0)/((float)elapsed/1000000.0); @@ -278,10 +285,10 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = micros(); - while(!digitalRead(_mod->getIrq())) { - yield(); - if(micros() - start > timeout) { + uint32_t start = Module::micros(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); + if(Module::micros() - start > timeout) { fixImplicitTimeout(); clearIrqStatus(); standby(); @@ -300,6 +307,9 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { } int16_t SX126x::transmitDirect(uint32_t frf) { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + // user requested to start transmitting immediately (required for RTTY) int16_t state = ERR_NONE; if(frf != 0) { @@ -313,6 +323,9 @@ int16_t SX126x::transmitDirect(uint32_t frf) { } int16_t SX126x::receiveDirect() { + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // SX126x is unable to output received data directly return(ERR_UNKNOWN); } @@ -327,6 +340,9 @@ int16_t SX126x::scanChannel() { int16_t state = standby(); RADIOLIB_ASSERT(state); + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // set DIO pin mapping state = setDioIrqParams(SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE); RADIOLIB_ASSERT(state); @@ -340,8 +356,8 @@ int16_t SX126x::scanChannel() { RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout - while(!digitalRead(_mod->getIrq())) { - yield(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); } // check CAD result @@ -360,6 +376,9 @@ int16_t SX126x::scanChannel() { } int16_t SX126x::sleep(bool retainConfig) { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, LOW); + uint8_t sleepMode = SX126X_SLEEP_START_WARM | SX126X_SLEEP_RTC_OFF; if(!retainConfig) { sleepMode = SX126X_SLEEP_START_COLD | SX126X_SLEEP_RTC_OFF; @@ -367,7 +386,7 @@ int16_t SX126x::sleep(bool retainConfig) { int16_t state = SPIwriteCommand(SX126X_CMD_SET_SLEEP, &sleepMode, 1, false); // wait for SX126x to safely enter sleep mode - delay(1); + Module::delay(1); return(state); } @@ -377,16 +396,19 @@ int16_t SX126x::standby() { } int16_t SX126x::standby(uint8_t mode) { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, LOW); + uint8_t data[] = {mode}; return(SPIwriteCommand(SX126X_CMD_SET_STANDBY, data, 1)); } void SX126x::setDio1Action(void (*func)(void)) { - attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, RISING); + Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); } void SX126x::clearDio1Action() { - detachInterrupt(digitalPinToInterrupt(_mod->getIrq())); + Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -435,13 +457,16 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { state = fixSensitivity(); RADIOLIB_ASSERT(state); + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + // start transmission state = setTx(SX126X_TX_TIMEOUT_NONE); RADIOLIB_ASSERT(state); // wait for BUSY to go low (= PA ramp up done) - while(digitalRead(_mod->getGpio())) { - yield(); + while(Module::digitalRead(_mod->getGpio())) { + Module::yield(); } return(state); @@ -451,6 +476,9 @@ int16_t SX126x::startReceive(uint32_t timeout) { int16_t state = startReceiveCommon(); RADIOLIB_ASSERT(state); + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // set mode to receive state = setRx(timeout); @@ -624,7 +652,7 @@ int16_t SX126x::setBandwidth(float bw) { // update modulation parameters _bwKhz = bw; - return(setModulationParams(_sf, _bw, _cr)); + return(setModulationParams(_sf, _bw, _cr, _ldro)); } int16_t SX126x::setSpreadingFactor(uint8_t sf) { @@ -637,7 +665,7 @@ int16_t SX126x::setSpreadingFactor(uint8_t sf) { // update modulation parameters _sf = sf; - return(setModulationParams(_sf, _bw, _cr)); + return(setModulationParams(_sf, _bw, _cr, _ldro)); } int16_t SX126x::setCodingRate(uint8_t cr) { @@ -650,7 +678,7 @@ int16_t SX126x::setCodingRate(uint8_t cr) { // update modulation parameters _cr = cr - 4; - return(setModulationParams(_sf, _bw, _cr)); + return(setModulationParams(_sf, _bw, _cr, _ldro)); } int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) { @@ -804,26 +832,31 @@ int16_t SX126x::setRxBandwidth(float rxBw) { return(setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev)); } -int16_t SX126x::setDataShaping(float sh) { +int16_t SX126x::setDataShaping(uint8_t sh) { // check active modem if(getPacketType() != SX126X_PACKET_TYPE_GFSK) { return(ERR_WRONG_MODEM); } - // check allowed values - sh *= 10.0; - if(abs(sh - 0.0) <= 0.001) { - _pulseShape = SX126X_GFSK_FILTER_NONE; - } else if(abs(sh - 3.0) <= 0.001) { - _pulseShape = SX126X_GFSK_FILTER_GAUSS_0_3; - } else if(abs(sh - 5.0) <= 0.001) { - _pulseShape = SX126X_GFSK_FILTER_GAUSS_0_5; - } else if(abs(sh - 7.0) <= 0.001) { - _pulseShape = SX126X_GFSK_FILTER_GAUSS_0_7; - } else if(abs(sh - 10.0) <= 0.001) { - _pulseShape = SX126X_GFSK_FILTER_GAUSS_1; - } else { - return(ERR_INVALID_DATA_SHAPING); + // set data shaping + switch(sh) { + case RADIOLIB_SHAPING_NONE: + _pulseShape = SX126X_GFSK_FILTER_NONE; + break; + case RADIOLIB_SHAPING_0_3: + _pulseShape = SX126X_GFSK_FILTER_GAUSS_0_3; + break; + case RADIOLIB_SHAPING_0_5: + _pulseShape = SX126X_GFSK_FILTER_GAUSS_0_5; + break; + case RADIOLIB_SHAPING_0_7: + _pulseShape = SX126X_GFSK_FILTER_GAUSS_0_7; + break; + case RADIOLIB_SHAPING_1_0: + _pulseShape = SX126X_GFSK_FILTER_GAUSS_1; + break; + default: + return(ERR_INVALID_DATA_SHAPING); } // update modulation parameters @@ -1020,7 +1053,7 @@ int16_t SX126x::setWhitening(bool enabled, uint16_t initial) { return(state); } -float SX126x::getDataRate() { +float SX126x::getDataRate() const { return(_dataRate); } @@ -1097,6 +1130,13 @@ uint32_t SX126x::getTimeOnAir(size_t len) { } } +float SX126x::getRSSIInst() { + uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU + SPIreadCommand(SX126X_CMD_GET_RSSI_INST, data, 3); + + return (float)data[0] / (-2.0); +} + int16_t SX126x::implicitHeader(size_t len) { return(setHeaderType(SX126X_LORA_HEADER_IMPLICIT, len)); } @@ -1117,6 +1157,52 @@ int16_t SX126x::setEncoding(uint8_t encoding) { return(setWhitening(encoding)); } +void SX126x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { + _mod->setRfSwitchPins(rxEn, txEn); +} + +int16_t SX126x::forceLDRO(bool enable) { + // check active modem + if(getPacketType() != SX126X_PACKET_TYPE_LORA) { + return(ERR_WRONG_MODEM); + } + + // update modulation parameters + _ldroAuto = false; + _ldro = (uint8_t)enable; + return(setModulationParams(_sf, _bw, _cr, _ldro)); +} + +int16_t SX126x::autoLDRO() { + if(getPacketType() != SX126X_PACKET_TYPE_LORA) { + return(ERR_WRONG_MODEM); + } + + _ldroAuto = true; + return(ERR_NONE); +} + +uint8_t SX126x::random() { + // set mode to Rx + setRx(SX126X_RX_TIMEOUT_INF); + + // wait a bit for the RSSI reading to stabilise + Module::delay(10); + + // read RSSI value 8 times, always keep just the least significant bit + uint8_t randByte = 0x00; + for(uint8_t i = 0; i < 8; i++) { + uint8_t val = 0x00; + readRegister(SX126X_REG_RANDOM_NUMBER_0, &val, sizeof(uint8_t)); + randByte |= ((val & 0x01) << i); + } + + // set mode to standby + standby(); + + return(randByte); +} + int16_t SX126x::setTCXO(float voltage, uint32_t delay) { // set mode to standby standby(); @@ -1126,6 +1212,11 @@ int16_t SX126x::setTCXO(float voltage, uint32_t delay) { clearDeviceErrors(); } + // check 0 V disable + if(abs(voltage - 0.0) <= 0.001) { + return(reset(true)); + } + // check alowed voltage values uint8_t data[4]; if(abs(voltage - 1.6) <= 0.001) { @@ -1281,8 +1372,8 @@ int16_t SX126x::setHeaderType(uint8_t headerType, size_t len) { } int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) { - // calculate symbol length and enable low data rate optimization, if needed - if(ldro == 0xFF) { + // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled + if(_ldroAuto) { float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz; RADIOLIB_DEBUG_PRINT("Symbol length: "); RADIOLIB_DEBUG_PRINT(symbolLength); @@ -1475,9 +1566,9 @@ int16_t SX126x::config(uint8_t modem) { RADIOLIB_ASSERT(state); // wait for calibration completion - delay(5); - while(digitalRead(_mod->getGpio())) { - yield(); + Module::delay(5); + while(Module::digitalRead(_mod->getGpio())) { + Module::yield(); } return(ERR_NONE); @@ -1509,14 +1600,14 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d #endif // pull NSS low - digitalWrite(_mod->getCs(), LOW); + Module::digitalWrite(_mod->getCs(), LOW); // ensure BUSY is low (state machine ready) - uint32_t start = millis(); - while(digitalRead(_mod->getGpio())) { - yield(); - if(millis() - start >= timeout) { - digitalWrite(_mod->getCs(), HIGH); + uint32_t start = Module::millis(); + while(Module::digitalRead(_mod->getGpio())) { + Module::yield(); + if(Module::millis() - start >= timeout) { + Module::digitalWrite(_mod->getCs(), HIGH); return(ERR_SPI_CMD_TIMEOUT); } } @@ -1576,15 +1667,15 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d // stop transfer spi->endTransaction(); - digitalWrite(_mod->getCs(), HIGH); + Module::digitalWrite(_mod->getCs(), HIGH); // wait for BUSY to go high and then low if(waitForBusy) { - delayMicroseconds(1); - start = millis(); - while(digitalRead(_mod->getGpio())) { - yield(); - if(millis() - start >= timeout) { + Module::delayMicroseconds(1); + start = Module::millis(); + while(Module::digitalRead(_mod->getGpio())) { + Module::yield(); + if(Module::millis() - start >= timeout) { status = SX126X_STATUS_CMD_TIMEOUT; break; } @@ -1633,8 +1724,8 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d // some faster platforms require a short delay here // not sure why, but it seems that long enough SPI transaction // (e.g. setPacketParams for GFSK) will fail without it - #if defined(ARDUINO_ARCH_STM32) - delay(1); + #if defined(RADIOLIB_SPI_SLOWDOWN) + Module::delay(1); #endif #endif @@ -1652,3 +1743,5 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d return(ERR_NONE); } } + +#endif diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index e6a7f078..ee99a27f 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX126X_H +#if !defined(_RADIOLIB_SX126X_H) #define _RADIOLIB_SX126X_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX126X) + #include "../../Module.h" #include "../../protocols/PhysicalLayer/PhysicalLayer.h" @@ -364,8 +367,6 @@ class SX126x: public PhysicalLayer { \param syncWord 1-byte LoRa sync word. - \param currentLimit Current protection limit in mA. - \param preambleLength LoRa preamble length in symbols. Allowed values range from 1 to 65535. \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. @@ -374,7 +375,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, float currentLimit, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false); + int16_t begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false); /*! \brief Initialization method for FSK modem. @@ -385,19 +386,15 @@ class SX126x: public PhysicalLayer { \param rxBw Receiver bandwidth in kHz. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz. - \param currentLimit Current protection limit in mA. - \param preambleLength FSK preamble length in bits. Allowed values range from 0 to 65535. - \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Allowed values are 0.3, 0.5, 0.7 and 1.0. Set to 0 to disable shaping. - \param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip. \param useRegulatorLDO use the LDO instead of DC-DC converter (default false). This is necessary for some modules such as the LAMBDA from RF solutions. \returns \ref status_codes */ - int16_t beginFSK(float br, float freqDev, float rxBw, float currentLimit, uint16_t preambleLength, float dataShaping, float tcxoVoltage, bool useRegulatorLDO = false); + int16_t beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false); /*! \brief Reset method. Will reset the chip to the default state using RST pin. @@ -421,7 +418,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Blocking binary receive method. @@ -433,7 +430,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len); + int16_t receive(uint8_t* data, size_t len) override; /*! \brief Starts direct mode transmission. @@ -442,7 +439,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t transmitDirect(uint32_t frf = 0); + int16_t transmitDirect(uint32_t frf = 0) override; /*! \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, as %SX126x series does not support direct mode reception. @@ -450,7 +447,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t receiveDirect(); + int16_t receiveDirect() override; /*! \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. @@ -473,7 +470,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t standby(); + int16_t standby() override; /*! \brief Sets the module to standby mode. @@ -510,7 +507,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. @@ -555,7 +552,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t readData(uint8_t* data, size_t len); + int16_t readData(uint8_t* data, size_t len) override; // configuration methods @@ -629,7 +626,7 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t setFrequencyDeviation(float freqDev); + int16_t setFrequencyDeviation(float freqDev) override; /*! \brief Sets FSK bit rate. Allowed values range from 0.6 to 300.0 kbps. @@ -650,13 +647,15 @@ class SX126x: public PhysicalLayer { int16_t setRxBandwidth(float rxBw); /*! - \brief Sets time-bandwidth product of Gaussian filter applied for shaping. Allowed values are 0.3, 0.5, 0.7 and 1.0. Set to 0 to disable shaping. + \brief Sets time-bandwidth product of Gaussian filter applied for shaping. + Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5, RADIOLIB_SHAPING_0_7 or RADIOLIB_SHAPING_1_0. + Set to RADIOLIB_SHAPING_NONE to disable data shaping. \param sh Time-bandwidth product of Gaussian filter to be set. \returns \ref status_codes */ - int16_t setDataShaping(float sh); + int16_t setDataShaping(uint8_t sh) override; /*! \brief Sets FSK sync word in the form of array of up to 8 bytes. @@ -734,9 +733,12 @@ class SX126x: public PhysicalLayer { /*! \brief Sets TCXO (Temperature Compensated Crystal Oscillator) configuration. - \param TCXO reference voltage in volts. Allowed values are 1.6, 1.7, 1.8, 2.2. 2.4, 2.7, 3.0 and 3.3 V + \param TCXO reference voltage in volts. Allowed values are 1.6, 1.7, 1.8, 2.2. 2.4, 2.7, 3.0 and 3.3 V. Set to 0 to disable TCXO. + NOTE: After setting this parameter to 0, the module will be reset (since there's no other way to disable TCXO). \param TCXO timeout in us. Defaults to 5000 us. + + \returns \ref status_codes */ int16_t setTCXO(float voltage, uint32_t delay = 5000); @@ -752,7 +754,7 @@ class SX126x: public PhysicalLayer { \returns Effective data rate in bps. */ - float getDataRate(); + float getDataRate() const; /*! \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. @@ -775,7 +777,7 @@ class SX126x: public PhysicalLayer { \returns Length of last received packet in bytes. */ - size_t getPacketLength(bool update = true); + size_t getPacketLength(bool update = true) override; /*! \brief Set modem in fixed packet length mode. Available in FSK mode only. @@ -804,6 +806,13 @@ class SX126x: public PhysicalLayer { */ uint32_t getTimeOnAir(size_t len); + /*! + \brief Get instantaneous RSSI value during recption of the packet. Should switch to FSK receive mode for LBT implementation. + + \returns Instantaneous RSSI value in dBm, in steps of 0.5dBm + */ + float getRSSIInst(); + /*! \brief Set implicit header mode for future reception/transmission. @@ -841,7 +850,42 @@ class SX126x: public PhysicalLayer { \returns \ref status_codes */ - int16_t setEncoding(uint8_t encoding); + int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. + When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! + + \param rxEn RX enable pin. + + \param txEn TX enable pin. + */ + void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + + /*! + \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to + the provided value, regardless of symbol length. To re-enable automatic LDRO configuration, call SX126x::autoLDRO() + + \param enable Force LDRO to be always enabled (true) or disabled (false). + + \returns \ref status_codes + */ + int16_t forceLDRO(bool enable); + + /*! + \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. After calling this method, LDRO will be enabled automatically + when symbol length exceeds 16 ms. + + \returns \ref status_codes + */ + int16_t autoLDRO(); + + /*! + \brief Get one truly random byte from RSSI noise. + + \returns TRNG byte. + */ + uint8_t random(); #ifndef RADIOLIB_GODMODE protected: @@ -862,7 +906,7 @@ class SX126x: public PhysicalLayer { int16_t calibrateImage(uint8_t* data); uint8_t getPacketType(); int16_t setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_200U); - int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro = 0xFF); + int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro); int16_t setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev); int16_t setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ = SX126X_LORA_IQ_STANDARD); int16_t setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t whitening, uint8_t packetType = SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLength = 0xFF, uint8_t preambleDetectorLength = SX126X_GFSK_PREAMBLE_DETECT_16); @@ -889,20 +933,21 @@ class SX126x: public PhysicalLayer { #endif Module* _mod; - uint8_t _bw, _sf, _cr, _ldro, _crcType, _headerType; - uint16_t _preambleLength; - float _bwKhz; + uint8_t _bw = 0, _sf = 0, _cr = 0, _ldro = 0, _crcType = 0, _headerType = 0; + uint16_t _preambleLength = 0; + float _bwKhz = 0; + bool _ldroAuto = true; - uint32_t _br, _freqDev; - uint8_t _rxBw, _pulseShape, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType; - uint16_t _preambleLengthFSK; - float _rxBwKhz; + uint32_t _br = 0, _freqDev = 0; + uint8_t _rxBw = 0, _pulseShape = 0, _crcTypeFSK = 0, _syncWordLength = 0, _addrComp = 0, _whitening = 0, _packetType = 0; + uint16_t _preambleLengthFSK = 0; + float _rxBwKhz = 0; - float _dataRate; + float _dataRate = 0; - uint32_t _tcxoDelay; + uint32_t _tcxoDelay = 0; - size_t _implicitLen; + size_t _implicitLen = 0; int16_t config(uint8_t modem); @@ -915,3 +960,5 @@ class SX126x: public PhysicalLayer { }; #endif + +#endif diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 28fedba3..f6b23efc 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -1,16 +1,13 @@ #include "SX1272.h" +#if !defined(RADIOLIB_EXCLUDE_SX127X) SX1272::SX1272(Module* mod) : SX127x(mod) { } -int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) { +int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(SX1272_CHIP_VERSION, syncWord, currentLimit, preambleLength); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = config(); + int16_t state = SX127x::begin(SX1272_CHIP_VERSION, syncWord, preambleLength); RADIOLIB_ASSERT(state); // mitigation of receiver spurious response @@ -35,24 +32,25 @@ int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync RADIOLIB_ASSERT(state); state = setGain(gain); + RADIOLIB_ASSERT(state); return(state); } -int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK) { +int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, currentLimit, preambleLength, enableOOK); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = configFSK(); + int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure publicly accessible settings state = setFrequency(freq); RADIOLIB_ASSERT(state); + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); + state = setOutputPower(power); + RADIOLIB_ASSERT(state); return(state); } @@ -60,9 +58,9 @@ int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t void SX1272::reset() { Module::pinMode(_mod->getRst(), OUTPUT); Module::digitalWrite(_mod->getRst(), HIGH); - delay(1); + Module::delay(1); Module::digitalWrite(_mod->getRst(), LOW); - delay(5); + Module::delay(5); } int16_t SX1272::setFrequency(float freq) { @@ -100,15 +98,17 @@ int16_t SX1272::setBandwidth(float bw) { if(state == ERR_NONE) { SX127x::_bw = bw; - // calculate symbol length and set low data rate optimization, if needed - float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; - RADIOLIB_DEBUG_PRINT("Symbol length: "); - RADIOLIB_DEBUG_PRINT(symbolLength); - RADIOLIB_DEBUG_PRINTLN(" ms"); - if(symbolLength >= 16.0) { - state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); - } else { - state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); + // calculate symbol length and set low data rate optimization, if auto-configuration is enabled + if(_ldroAuto) { + float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; + RADIOLIB_DEBUG_PRINT("Symbol length: "); + RADIOLIB_DEBUG_PRINT(symbolLength); + RADIOLIB_DEBUG_PRINTLN(" ms"); + if(symbolLength >= 16.0) { + state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); + } else { + state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); + } } } return(state); @@ -154,15 +154,17 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) { if(state == ERR_NONE) { SX127x::_sf = sf; - // calculate symbol length and set low data rate optimization, if needed + // calculate symbol length and set low data rate optimization, if auto-configuration is enabled + if(_ldroAuto) { float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; - RADIOLIB_DEBUG_PRINT("Symbol length: "); - RADIOLIB_DEBUG_PRINT(symbolLength); - RADIOLIB_DEBUG_PRINTLN(" ms"); - if(symbolLength >= 16.0) { - state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); - } else { - state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); + RADIOLIB_DEBUG_PRINT("Symbol length: "); + RADIOLIB_DEBUG_PRINT(symbolLength); + RADIOLIB_DEBUG_PRINTLN(" ms"); + if(symbolLength >= 16.0) { + state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0); + } else { + state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0); + } } } return(state); @@ -217,7 +219,7 @@ int16_t SX1272::setOutputPower(int8_t power) { state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_RFO, 7, 7); state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power + 1), 3, 0); state |= _mod->SPIsetRegValue(SX1272_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); - } else if((power >= 2) && (power <= 17)) { + } else if(power <= 17) { // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, (power - 2), 3, 0); @@ -256,34 +258,34 @@ int16_t SX1272::setGain(uint8_t gain) { return(state); } -int16_t SX1272::setDataShaping(float sh) { +int16_t SX1272::setDataShaping(uint8_t sh) { // check active modem if(getActiveModem() != SX127X_FSK_OOK) { return(ERR_WRONG_MODEM); } // check modulation - if(!SX127x::_ook) { + if(SX127x::_ook) { return(ERR_INVALID_MODULATION); } // set mode to standby int16_t state = SX127x::standby(); + RADIOLIB_ASSERT(state); // set data shaping - sh *= 10.0; - if(abs(sh - 0.0) <= 0.001) { - state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_NO_SHAPING, 4, 3); - } else if(abs(sh - 3.0) <= 0.001) { - state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_3, 4, 3); - } else if(abs(sh - 5.0) <= 0.001) { - state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_5, 4, 3); - } else if(abs(sh - 10.0) <= 0.001) { - state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_1_0, 4, 3); - } else { - return(ERR_INVALID_DATA_SHAPING); + switch(sh) { + case RADIOLIB_SHAPING_NONE: + return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_NO_SHAPING, 4, 3)); + case RADIOLIB_SHAPING_0_3: + return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_3, 4, 3)); + case RADIOLIB_SHAPING_0_5: + return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_5, 4, 3)); + case RADIOLIB_SHAPING_1_0: + return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_1_0, 4, 3)); + default: + return(ERR_INVALID_DATA_SHAPING); } - return(state); } int16_t SX1272::setDataShapingOOK(uint8_t sh) { @@ -351,6 +353,7 @@ float SX1272::getRSSI() { int16_t SX1272::setCRC(bool enableCRC) { if(getActiveModem() == SX127X_LORA) { // set LoRa CRC + SX127x::_crcEnabled = enableCRC; if(enableCRC) { return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_RX_CRC_MODE_ON, 2, 2)); } else { @@ -366,6 +369,29 @@ int16_t SX1272::setCRC(bool enableCRC) { } } +int16_t SX1272::forceLDRO(bool enable) { + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + + _ldroAuto = false; + if(enable) { + return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0)); + } else { + return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0)); + } +} + +int16_t SX1272::autoLDRO() { + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + + _ldroAuto = true; + return(ERR_NONE); +} + + int16_t SX1272::setBandwidthRaw(uint8_t newBandwidth) { // set mode to standby int16_t state = SX127x::standby(); @@ -381,12 +407,12 @@ int16_t SX1272::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { // write registers if(newSpreadingFactor == SX127X_SF_6) { - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_HEADER_IMPL_MODE | SX1272_RX_CRC_MODE_ON, 2, 1); + state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_HEADER_IMPL_MODE | (SX127x::_crcEnabled ? SX1272_RX_CRC_MODE_ON : SX1272_RX_CRC_MODE_OFF), 2, 1); state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX127X_SF_6 | SX127X_TX_MODE_SINGLE, 7, 3); state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_6); } else { - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_HEADER_EXPL_MODE | SX1272_RX_CRC_MODE_ON, 2, 1); + state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_HEADER_EXPL_MODE | (SX127x::_crcEnabled ? SX1272_RX_CRC_MODE_ON : SX1272_RX_CRC_MODE_OFF), 2, 1); state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | SX127X_TX_MODE_SINGLE, 7, 3); state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_7_12); @@ -417,3 +443,5 @@ int16_t SX1272::configFSK() { return(state); } + +#endif diff --git a/src/modules/SX127x/SX1272.h b/src/modules/SX127x/SX1272.h index a0f64541..78e009d3 100644 --- a/src/modules/SX127x/SX1272.h +++ b/src/modules/SX127x/SX1272.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX1272_H +#if !defined(_RADIOLIB_SX1272_H) #define _RADIOLIB_SX1272_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX127X) + #include "../../Module.h" #include "SX127x.h" @@ -116,8 +119,6 @@ class SX1272: public SX127x { \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks. - \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. Set to 0 to disable OCP (not recommended). @@ -129,7 +130,7 @@ class SX1272: public SX127x { \returns \ref status_codes */ - int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. @@ -145,21 +146,18 @@ class SX1272: public SX127x { \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. - Set to 0 to disable OCP (not recommended). - \param preambleLength Length of FSK preamble in bits. \param enableOOK Use OOK modulation instead of FSK. \returns \ref status_codes */ - int16_t beginFSK(float freq = 915.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 13, uint8_t currentLimit = 100, uint16_t preambleLength = 16, bool enableOOK = false); - + int16_t beginFSK(float freq = 915.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); + /*! \brief Reset method. Will reset the chip to the default state using RST pin. */ - void reset(); + void reset() override; // configuration methods @@ -219,14 +217,14 @@ class SX1272: public SX127x { int16_t setGain(uint8_t gain); /*! - \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. - Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. Only available in FSK mode with FSK modulation. + \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. Only available in FSK mode with FSK modulation. + Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. \param sh Gaussian shaping bandwidth-time product that will be used for data shaping \returns \ref status_codes */ - int16_t setDataShaping(float sh); + int16_t setDataShaping(uint8_t sh) override; /*! \brief Sets filter cutoff frequency that will be used for data shaping. @@ -255,6 +253,24 @@ class SX1272: public SX127x { */ int16_t setCRC(bool enableCRC); + /*! + \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to + the provided value, regardless of symbol length. To re-enable automatic LDRO configuration, call SX1278::autoLDRO() + + \param enable Force LDRO to be always enabled (true) or disabled (false). + + \returns \ref status_codes + */ + int16_t forceLDRO(bool enable); + + /*! + \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. After calling this method, LDRO will be enabled automatically + when symbol length exceeds 16 ms. + + \returns \ref status_codes + */ + int16_t autoLDRO(); + #ifndef RADIOLIB_GODMODE protected: #endif @@ -267,7 +283,11 @@ class SX1272: public SX127x { #ifndef RADIOLIB_GODMODE private: #endif + bool _ldroAuto = true; + bool _ldroEnabled = false; }; #endif + +#endif diff --git a/src/modules/SX127x/SX1273.cpp b/src/modules/SX127x/SX1273.cpp index ee0a48fc..49e12e3c 100644 --- a/src/modules/SX127x/SX1273.cpp +++ b/src/modules/SX127x/SX1273.cpp @@ -1,16 +1,13 @@ #include "SX1273.h" +#if !defined(RADIOLIB_EXCLUDE_SX127X) SX1273::SX1273(Module* mod) : SX1272(mod) { } -int16_t SX1273::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) { +int16_t SX1273::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(SX1272_CHIP_VERSION, syncWord, currentLimit, preambleLength); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = config(); + int16_t state = SX127x::begin(SX1272_CHIP_VERSION, syncWord, preambleLength); RADIOLIB_ASSERT(state); // mitigation of receiver spurious response @@ -35,6 +32,7 @@ int16_t SX1273::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync RADIOLIB_ASSERT(state); state = setGain(gain); + RADIOLIB_ASSERT(state); return(state); } @@ -68,3 +66,5 @@ int16_t SX1273::setSpreadingFactor(uint8_t sf) { return(state); } + +#endif diff --git a/src/modules/SX127x/SX1273.h b/src/modules/SX127x/SX1273.h index 52ffafd1..83b43dd4 100644 --- a/src/modules/SX127x/SX1273.h +++ b/src/modules/SX127x/SX1273.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX1273_H +#if !defined(_RADIOLIB_SX1273_H) #define _RADIOLIB_SX1273_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX127X) + #include "SX1272.h" /*! @@ -38,9 +41,6 @@ class SX1273: public SX1272 { \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. - Set to 0 to disable OCP (not recommended). - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. @@ -49,7 +49,7 @@ class SX1273: public SX1272 { \returns \ref status_codes */ - int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); // configuration methods @@ -69,3 +69,5 @@ class SX1273: public SX1272 { }; #endif + +#endif diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index 2fecd63a..fa99cef2 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -1,16 +1,13 @@ #include "SX1276.h" +#if !defined(RADIOLIB_EXCLUDE_SX127X) SX1276::SX1276(Module* mod) : SX1278(mod) { } -int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) { +int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, currentLimit, preambleLength); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = config(); + int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -30,6 +27,25 @@ int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync RADIOLIB_ASSERT(state); state = setGain(gain); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1276::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { + // execute common part + int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); return(state); } @@ -103,3 +119,5 @@ int16_t SX1276::setFrequency(float freq) { // set frequency return(SX127x::setFrequencyRaw(freq)); } + +#endif diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index 8a320ec8..8c234a87 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX1276_H +#if !defined(_RADIOLIB_SX1276_H) #define _RADIOLIB_SX1276_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX127X) + #include "SX1278.h" /*! @@ -38,9 +41,6 @@ class SX1276: public SX1278 { \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. - Set to 0 to disable OCP (not recommended). - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. @@ -49,7 +49,29 @@ class SX1276: public SX1278 { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + + /*! + \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. + + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. + + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. + Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. + + \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. + + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + + \param preambleLength Length of FSK preamble in bits. + + \param enableOOK Use OOK modulation instead of FSK. + + \returns \ref status_codes + */ + int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); // configuration methods @@ -69,3 +91,5 @@ class SX1276: public SX1278 { }; #endif + +#endif diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 715d8853..284b7c87 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -1,16 +1,13 @@ #include "SX1277.h" +#if !defined(RADIOLIB_EXCLUDE_SX127X) SX1277::SX1277(Module* mod) : SX1278(mod) { } -int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) { +int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, currentLimit, preambleLength); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = config(); + int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -30,6 +27,25 @@ int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync RADIOLIB_ASSERT(state); state = setGain(gain); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1277::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { + // execute common part + int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); return(state); } @@ -133,3 +149,5 @@ int16_t SX1277::setSpreadingFactor(uint8_t sf) { return(state); } + +#endif diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index cee312a3..e0ea539e 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX1277_H +#if !defined(_RADIOLIB_SX1277_H) #define _RADIOLIB_SX1277_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX127X) + #include "SX1278.h" /*! @@ -38,9 +41,6 @@ class SX1277: public SX1278 { \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. - Set to 0 to disable OCP (not recommended). - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. @@ -49,7 +49,29 @@ class SX1277: public SX1278 { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + + /*! + \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. + + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. + + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. + Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. + + \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. + + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + + \param preambleLength Length of FSK preamble in bits. + + \param enableOOK Use OOK modulation instead of FSK. + + \returns \ref status_codes + */ + int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); // configuration methods @@ -78,3 +100,5 @@ class SX1277: public SX1278 { }; #endif + +#endif diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index af3fc0b3..efa065c6 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -1,16 +1,13 @@ #include "SX1278.h" +#if !defined(RADIOLIB_EXCLUDE_SX127X) SX1278::SX1278(Module* mod) : SX127x(mod) { } -int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) { +int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, currentLimit, preambleLength); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = config(); + int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -30,17 +27,14 @@ int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync RADIOLIB_ASSERT(state); state = setGain(gain); + RADIOLIB_ASSERT(state); return(state); } -int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK) { +int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, currentLimit, preambleLength, enableOOK); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = configFSK(); + int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -48,6 +42,10 @@ int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t RADIOLIB_ASSERT(state); state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); return(state); } @@ -55,9 +53,9 @@ int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t void SX1278::reset() { Module::pinMode(_mod->getRst(), OUTPUT); Module::digitalWrite(_mod->getRst(), LOW); - delay(1); + Module::delay(1); Module::digitalWrite(_mod->getRst(), HIGH); - delay(5); + Module::delay(5); } int16_t SX1278::setFrequency(float freq) { @@ -172,15 +170,17 @@ int16_t SX1278::setBandwidth(float bw) { if(state == ERR_NONE) { SX127x::_bw = bw; - // calculate symbol length and set low data rate optimization, if needed - float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; - RADIOLIB_DEBUG_PRINT("Symbol length: "); - RADIOLIB_DEBUG_PRINT(symbolLength); - RADIOLIB_DEBUG_PRINTLN(" ms"); - if(symbolLength >= 16.0) { - state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); - } else { - state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); + // calculate symbol length and set low data rate optimization, if auto-configuration is enabled + if(_ldroAuto) { + float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; + RADIOLIB_DEBUG_PRINT("Symbol length: "); + RADIOLIB_DEBUG_PRINT(symbolLength); + RADIOLIB_DEBUG_PRINTLN(" ms"); + if(symbolLength >= 16.0) { + state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); + } else { + state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); + } } } return(state); @@ -226,15 +226,17 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) { if(state == ERR_NONE) { SX127x::_sf = sf; - // calculate symbol length and set low data rate optimization, if needed - float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; - RADIOLIB_DEBUG_PRINT("Symbol length: "); - RADIOLIB_DEBUG_PRINT(symbolLength); - RADIOLIB_DEBUG_PRINTLN(" ms"); - if(symbolLength >= 16.0) { - state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); - } else { - state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); + // calculate symbol length and set low data rate optimization, if auto-configuration is enabled + if(_ldroAuto) { + float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw; + RADIOLIB_DEBUG_PRINT("Symbol length: "); + RADIOLIB_DEBUG_PRINT(symbolLength); + RADIOLIB_DEBUG_PRINTLN(" ms"); + if(symbolLength >= 16.0) { + state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3); + } else { + state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3); + } } } return(state); @@ -289,7 +291,7 @@ int16_t SX1278::setOutputPower(int8_t power) { state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_RFO, 7, 7); state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_LOW_POWER | (power + 3), 6, 0); state |= _mod->SPIsetRegValue(SX1278_REG_PA_DAC, SX127X_PA_BOOST_OFF, 2, 0); - } else if((power >= 2) && (power <= 17)) { + } else if(power <= 17) { // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST, 7, 7); state |= _mod->SPIsetRegValue(SX127X_REG_PA_CONFIG, SX1278_MAX_POWER | (power - 2), 6, 0); @@ -328,7 +330,7 @@ int16_t SX1278::setGain(uint8_t gain) { return(state); } -int16_t SX1278::setDataShaping(float sh) { +int16_t SX1278::setDataShaping(uint8_t sh) { // check active modem if(getActiveModem() != SX127X_FSK_OOK) { return(ERR_WRONG_MODEM); @@ -341,21 +343,21 @@ int16_t SX1278::setDataShaping(float sh) { // set mode to standby int16_t state = SX127x::standby(); + RADIOLIB_ASSERT(state); // set data shaping - sh *= 10.0; - if(abs(sh - 0.0) <= 0.001) { - state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_NO_SHAPING, 6, 5); - } else if(abs(sh - 3.0) <= 0.001) { - state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_3, 6, 5); - } else if(abs(sh - 5.0) <= 0.001) { - state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_5, 6, 5); - } else if(abs(sh - 10.0) <= 0.001) { - state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_1_0, 6, 5); - } else { - return(ERR_INVALID_DATA_SHAPING); + switch(sh) { + case RADIOLIB_SHAPING_NONE: + return(_mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_NO_SHAPING, 6, 5)); + case RADIOLIB_SHAPING_0_3: + return(_mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_3, 6, 5)); + case RADIOLIB_SHAPING_0_5: + return(_mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_5, 6, 5)); + case RADIOLIB_SHAPING_1_0: + return(_mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_1_0, 6, 5)); + default: + return(ERR_INVALID_DATA_SHAPING); } - return(state); } int16_t SX1278::setDataShapingOOK(uint8_t sh) { @@ -429,6 +431,7 @@ float SX1278::getRSSI() { int16_t SX1278::setCRC(bool enableCRC) { if(getActiveModem() == SX127X_LORA) { // set LoRa CRC + SX127x::_crcEnabled = enableCRC; if(enableCRC) { return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_ON, 2, 2)); } else { @@ -444,6 +447,28 @@ int16_t SX1278::setCRC(bool enableCRC) { } } +int16_t SX1278::forceLDRO(bool enable) { + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + + _ldroAuto = false; + if(enable) { + return(_mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3)); + } else { + return(_mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3)); + } +} + +int16_t SX1278::autoLDRO() { + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + + _ldroAuto = true; + return(ERR_NONE); +} + int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) { // set mode to standby int16_t state = SX127x::standby(); @@ -460,12 +485,12 @@ int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { // write registers if(newSpreadingFactor == SX127X_SF_6) { state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1278_HEADER_IMPL_MODE, 0, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX127X_SF_6 | SX127X_TX_MODE_SINGLE | SX1278_RX_CRC_MODE_ON, 7, 2); + state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX127X_SF_6 | SX127X_TX_MODE_SINGLE | (SX127x::_crcEnabled ? SX1278_RX_CRC_MODE_ON : SX1278_RX_CRC_MODE_OFF), 7, 2); state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_6); } else { state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1278_HEADER_EXPL_MODE, 0, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | SX127X_TX_MODE_SINGLE | SX1278_RX_CRC_MODE_ON, 7, 2); + state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | SX127X_TX_MODE_SINGLE | (SX127x::_crcEnabled ? SX1278_RX_CRC_MODE_ON : SX1278_RX_CRC_MODE_OFF), 7, 2); state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_7_12); } @@ -495,3 +520,5 @@ int16_t SX1278::configFSK() { return(state); } + +#endif diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 77318e15..cba8c635 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX1278_H +#if !defined(_RADIOLIB_SX1278_H) #define _RADIOLIB_SX1278_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX127X) + #include "../../Module.h" #include "SX127x.h" @@ -127,9 +130,6 @@ class SX1278: public SX127x { \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. - Set to 0 to disable OCP (not recommended). - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. @@ -138,7 +138,7 @@ class SX1278: public SX127x { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); /*! \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. @@ -154,22 +154,19 @@ class SX1278: public SX127x { \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. - Set to 0 to disable OCP (not recommended). - \param preambleLength Length of FSK preamble in bits. \param enableOOK Use OOK modulation instead of FSK. \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 13, uint8_t currentLimit = 100, uint16_t preambleLength = 16, bool enableOOK = false); + int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); /*! \brief Reset method. Will reset the chip to the default state using RST pin. */ - void reset(); - + void reset() override; + // configuration methods /*! @@ -228,14 +225,14 @@ class SX1278: public SX127x { int16_t setGain(uint8_t gain); /*! - \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. - Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. Only available in FSK mode with FSK modulation. + \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. Only available in FSK mode with FSK modulation. + Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. \param sh Gaussian shaping bandwidth-time product that will be used for data shaping \returns \ref status_codes */ - int16_t setDataShaping(float sh); + int16_t setDataShaping(uint8_t sh) override; /*! \brief Sets filter cutoff frequency that will be used for data shaping. @@ -264,6 +261,24 @@ class SX1278: public SX127x { */ int16_t setCRC(bool enableCRC); + /*! + \brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to + the provided value, regardless of symbol length. To re-enable automatic LDRO configuration, call SX1278::autoLDRO() + + \param enable Force LDRO to be always enabled (true) or disabled (false). + + \returns \ref status_codes + */ + int16_t forceLDRO(bool enable); + + /*! + \brief Re-enables automatic LDRO configuration. Only available in LoRa mode. After calling this method, LDRO will be enabled automatically + when symbol length exceeds 16 ms. + + \returns \ref status_codes + */ + int16_t autoLDRO(); + #ifndef RADIOLIB_GODMODE protected: #endif @@ -276,7 +291,11 @@ class SX1278: public SX127x { #ifndef RADIOLIB_GODMODE private: #endif + bool _ldroAuto = true; + bool _ldroEnabled = false; }; #endif + +#endif diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 1b45c9b7..ad580404 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -1,16 +1,13 @@ #include "SX1279.h" +#if !defined(RADIOLIB_EXCLUDE_SX127X) SX1279::SX1279(Module* mod) : SX1278(mod) { } -int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint8_t currentLimit, uint16_t preambleLength, uint8_t gain) { +int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) { // execute common part - int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, currentLimit, preambleLength); - RADIOLIB_ASSERT(state); - - // configure settings not accessible by API - state = config(); + int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, preambleLength); RADIOLIB_ASSERT(state); // configure publicly accessible settings @@ -30,6 +27,25 @@ int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync RADIOLIB_ASSERT(state); state = setGain(gain); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX1279::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) { + // execute common part + int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setDataShaping(RADIOLIB_SHAPING_NONE); + RADIOLIB_ASSERT(state); return(state); } @@ -40,3 +56,5 @@ int16_t SX1279::setFrequency(float freq) { // set frequency return(SX127x::setFrequencyRaw(freq)); } + +#endif diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index f0953ecd..ef6f29e3 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX1279_H +#if !defined(_RADIOLIB_SX1279_H) #define _RADIOLIB_SX1279_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX127X) + #include "SX1278.h" /*! @@ -38,9 +41,6 @@ class SX1279: public SX1278 { \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. - \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. - Set to 0 to disable OCP (not recommended). - \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. Allowed values range from 6 to 65535. @@ -49,7 +49,29 @@ class SX1279: public SX1278 { \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 10, uint16_t preambleLength = 8, uint8_t gain = 0); + + /*! + \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module. + + \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz. + + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps. + + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. + Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met. + + \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz. + + \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm. + + \param preambleLength Length of FSK preamble in bits. + + \param enableOOK Use OOK modulation instead of FSK. + + \returns \ref status_codes + */ + int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false); // configuration methods @@ -69,3 +91,5 @@ class SX1279: public SX1278 { }; #endif + +#endif diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 727cf2b1..fe22a1e7 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1,11 +1,11 @@ #include "SX127x.h" +#if !defined(RADIOLIB_EXCLUDE_SX127X) SX127x::SX127x(Module* mod) : PhysicalLayer(SX127X_FREQUENCY_STEP_SIZE, SX127X_MAX_PACKET_LENGTH) { _mod = mod; - _packetLengthQueried = false; } -int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimit, uint16_t preambleLength) { +int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLength) { // set module properties _mod->init(RADIOLIB_USE_SPI); Module::pinMode(_mod->getIrq(), INPUT); @@ -14,16 +14,19 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { RADIOLIB_DEBUG_PRINTLN(F("No SX127x found!")); - _mod->term(); + _mod->term(RADIOLIB_USE_SPI); return(ERR_CHIP_NOT_FOUND); - } else { - RADIOLIB_DEBUG_PRINTLN(F("Found SX127x!")); } + RADIOLIB_DEBUG_PRINTLN(F("M\tSX127x")); // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); + // configure settings not accessible by API + state = config(); + RADIOLIB_ASSERT(state); + // check active modem if(getActiveModem() != SX127X_LORA) { // set LoRa mode @@ -36,7 +39,7 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi RADIOLIB_ASSERT(state); // set over current protection - state = SX127x::setCurrentLimit(currentLimit); + state = SX127x::setCurrentLimit(60); RADIOLIB_ASSERT(state); // set preamble length @@ -49,7 +52,7 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi return(state); } -int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK) { +int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) { // set module properties _mod->init(RADIOLIB_USE_SPI); Module::pinMode(_mod->getIrq(), INPUT); @@ -57,14 +60,20 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { RADIOLIB_DEBUG_PRINTLN(F("No SX127x found!")); - _mod->term(); + _mod->term(RADIOLIB_USE_SPI); return(ERR_CHIP_NOT_FOUND); - } else { - RADIOLIB_DEBUG_PRINTLN(F("Found SX127x!")); } + RADIOLIB_DEBUG_PRINTLN(F("M\tSX127x")); + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = configFSK(); + RADIOLIB_ASSERT(state); // check currently active modem - int16_t state; if(getActiveModem() != SX127X_FSK_OOK) { // set FSK mode state = setActiveModem(SX127X_FSK_OOK); @@ -88,15 +97,15 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB RADIOLIB_ASSERT(state); // set over current protection - state = SX127x::setCurrentLimit(currentLimit); + state = SX127x::setCurrentLimit(60); RADIOLIB_ASSERT(state); // set preamble length state = SX127x::setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); - // default sync word value 0x2D01 is the same as the default in LowPowerLab RFM69 library - uint8_t syncWord[] = {0x2D, 0x01}; + // set default sync word + uint8_t syncWord[] = {0x12, 0xAD}; state = setSyncWord(syncWord, 2); RADIOLIB_ASSERT(state); @@ -109,7 +118,7 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB RADIOLIB_ASSERT(state); // set default encoding - state = setEncoding(0); + state = setEncoding(RADIOLIB_ENCODING_NRZ); RADIOLIB_ASSERT(state); // set default packet length mode @@ -121,6 +130,7 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { // set mode to standby int16_t state = setMode(SX127X_STANDBY); + RADIOLIB_ASSERT(state); int16_t modem = getActiveModem(); uint32_t start = 0; @@ -142,10 +152,10 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - start = micros(); - while(!digitalRead(_mod->getIrq())) { - yield(); - if(micros() - start > timeout) { + start = Module::micros(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); + if(Module::micros() - start > timeout) { clearIRQFlags(); return(ERR_TX_TIMEOUT); } @@ -160,10 +170,10 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission end or timeout - start = micros(); - while(!digitalRead(_mod->getIrq())) { - yield(); - if(micros() - start > timeout) { + start = Module::micros(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); + if(Module::micros() - start > timeout) { clearIRQFlags(); standby(); return(ERR_TX_TIMEOUT); @@ -174,7 +184,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { } // update data rate - uint32_t elapsed = micros() - start; + uint32_t elapsed = Module::micros() - start; _dataRate = (len*8.0)/((float)elapsed/1000000.0); // clear interrupt flags @@ -187,6 +197,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { int16_t SX127x::receive(uint8_t* data, size_t len) { // set mode to standby int16_t state = setMode(SX127X_STANDBY); + RADIOLIB_ASSERT(state); int16_t modem = getActiveModem(); if(modem == SX127X_LORA) { @@ -195,9 +206,9 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout (100 LoRa symbols) - while(!digitalRead(_mod->getIrq())) { - yield(); - if(digitalRead(_mod->getGpio())) { + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); + if(Module::digitalRead(_mod->getGpio())) { clearIRQFlags(); return(ERR_RX_TIMEOUT); } @@ -212,10 +223,10 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = micros(); - while(!digitalRead(_mod->getIrq())) { - yield(); - if(micros() - start > timeout) { + uint32_t start = Module::micros(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); + if(Module::micros() - start > timeout) { clearIRQFlags(); return(ERR_RX_TIMEOUT); } @@ -245,14 +256,17 @@ int16_t SX127x::scanChannel() { // clear interrupt flags clearIRQFlags(); + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // set mode to CAD state = setMode(SX127X_CAD); RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout - while(!digitalRead(_mod->getIrq())) { - yield(); - if(digitalRead(_mod->getGpio())) { + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); + if(Module::digitalRead(_mod->getGpio())) { clearIRQFlags(); return(PREAMBLE_DETECTED); } @@ -265,26 +279,35 @@ int16_t SX127x::scanChannel() { } int16_t SX127x::sleep() { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, LOW); + // set mode to sleep return(setMode(SX127X_SLEEP)); } int16_t SX127x::standby() { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, LOW); + // set mode to standby return(setMode(SX127X_STANDBY)); } -int16_t SX127x::transmitDirect(uint32_t FRF) { +int16_t SX127x::transmitDirect(uint32_t frf) { // check modem if(getActiveModem() != SX127X_FSK_OOK) { return(ERR_WRONG_MODEM); } + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + // user requested to start transmitting immediately (required for RTTY) - if(FRF != 0) { - _mod->SPIwriteRegister(SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16); - _mod->SPIwriteRegister(SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8); - _mod->SPIwriteRegister(SX127X_REG_FRF_LSB, FRF & 0x0000FF); + if(frf != 0) { + _mod->SPIwriteRegister(SX127X_REG_FRF_MSB, (frf & 0xFF0000) >> 16); + _mod->SPIwriteRegister(SX127X_REG_FRF_MID, (frf & 0x00FF00) >> 8); + _mod->SPIwriteRegister(SX127X_REG_FRF_LSB, frf & 0x0000FF); return(setMode(SX127X_TX)); } @@ -303,6 +326,9 @@ int16_t SX127x::receiveDirect() { return(ERR_WRONG_MODEM); } + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // activate direct mode int16_t state = directMode(); RADIOLIB_ASSERT(state); @@ -336,11 +362,12 @@ int16_t SX127x::packetMode() { int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { // set mode to standby int16_t state = setMode(SX127X_STANDBY); + RADIOLIB_ASSERT(state); int16_t modem = getActiveModem(); if(modem == SX127X_LORA) { // set DIO pin mapping - state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE | SX127X_DIO1_RX_TIMEOUT, 7, 4); + state = _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE | SX127X_DIO1_RX_TIMEOUT, 7, 4); // set expected packet length for SF6 if(_sf == 6) { @@ -357,7 +384,8 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { } else if(modem == SX127X_FSK_OOK) { // set DIO pin mapping - state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6); + state = _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6); + RADIOLIB_ASSERT(state); // clear interrupt flags clearIRQFlags(); @@ -368,30 +396,33 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { } } + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // set mode to receive return(setMode(mode)); } void SX127x::setDio0Action(void (*func)(void)) { - attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, RISING); + Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); } void SX127x::clearDio0Action() { - detachInterrupt(digitalPinToInterrupt(_mod->getIrq())); + Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } void SX127x::setDio1Action(void (*func)(void)) { - if(_mod->getGpio() != RADIOLIB_NC) { + if(_mod->getGpio() == RADIOLIB_NC) { return; } - attachInterrupt(digitalPinToInterrupt(_mod->getGpio()), func, RISING); + Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, RISING); } void SX127x::clearDio1Action() { - if(_mod->getGpio() != RADIOLIB_NC) { + if(_mod->getGpio() == RADIOLIB_NC) { return; } - detachInterrupt(digitalPinToInterrupt(_mod->getGpio())); + Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio())); } int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -418,15 +449,6 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_TX_BASE_ADDR, SX127X_FIFO_TX_BASE_ADDR_MAX); state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_TX_BASE_ADDR_MAX); - // write packet to FIFO - _mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len); - - // start transmission - state |= setMode(SX127X_TX); - RADIOLIB_ASSERT(state); - - return(ERR_NONE); - } else if(modem == SX127X_FSK_OOK) { // check packet length if(len >= SX127X_MAX_PACKET_LENGTH_FSK) { @@ -440,25 +462,28 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { clearIRQFlags(); // set packet length - _mod->SPIwriteRegister(SX127X_REG_FIFO, len); + if (_packetLengthConfig == SX127X_PACKET_VARIABLE) { + _mod->SPIwriteRegister(SX127X_REG_FIFO, len); + } // check address filtering uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1); if((filter == SX127X_ADDRESS_FILTERING_NODE) || (filter == SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { _mod->SPIwriteRegister(SX127X_REG_FIFO, addr); } - - // write packet to FIFO - _mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len); - - // start transmission - state |= setMode(SX127X_TX); - RADIOLIB_ASSERT(state); - - return(ERR_NONE); } - return(ERR_UNKNOWN); + // write packet to FIFO + _mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len); + + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + + // start transmission + state |= setMode(SX127X_TX); + RADIOLIB_ASSERT(state); + + return(ERR_NONE); } int16_t SX127x::readData(uint8_t* data, size_t len) { @@ -474,11 +499,18 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { length = getPacketLength(); } - // check integrity CRC + // check packet header integrity + if(_crcEnabled && (_mod->SPIgetRegValue(SX127X_REG_HOP_CHANNEL, 6, 6)) == 0) { + // CRC is disabled according to packet header and enabled according to user + // most likely damaged packet header + clearIRQFlags(); + return(ERR_LORA_HEADER_DAMAGED); + } + + // check payload CRC if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { // clear interrupt flags clearIRQFlags(); - return(ERR_CRC_MISMATCH); } @@ -567,9 +599,10 @@ int16_t SX127x::setPreambleLength(uint16_t preambleLength) { return(state); } else if(modem == SX127X_FSK_OOK) { - // set preamble length - state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, (uint8_t)((preambleLength >> 8) & 0xFF)); - state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, (uint8_t)(preambleLength & 0xFF)); + // set preamble length (in bytes) + uint16_t numBytes = preambleLength / 8; + state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, (uint8_t)((numBytes >> 8) & 0xFF)); + state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, (uint8_t)(numBytes & 0xFF)); return(state); } @@ -640,7 +673,7 @@ float SX127x::getSNR() { return(rawSNR / 4.0); } -float SX127x::getDataRate() { +float SX127x::getDataRate() const { return(_dataRate); } @@ -666,7 +699,7 @@ int16_t SX127x::setBitRate(float br) { state = _mod->SPIsetRegValue(SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); state |= _mod->SPIsetRegValue(SX127X_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); - // TODO fractional part of bit rate setting (not in OOK) + /// \todo fractional part of bit rate setting (not in OOK) if(state == ERR_NONE) { SX127x::_br = br; } @@ -739,7 +772,7 @@ int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) { RADIOLIB_CHECK_RANGE(len, 1, 8, ERR_INVALID_SYNC_WORD); // sync word must not contain value 0x00 - for(uint8_t i = 0; i < len; i++) { + for(size_t i = 0; i < len; i++) { if(syncWord[i] == 0x00) { return(ERR_INVALID_SYNC_WORD); } @@ -851,7 +884,11 @@ size_t SX127x::getPacketLength(bool update) { } else if(modem == SX127X_FSK_OOK) { // get packet length if(!_packetLengthQueried && update) { - _packetLength = _mod->SPIreadRegister(SX127X_REG_FIFO); + if (_packetLengthConfig == SX127X_PACKET_VARIABLE) { + _packetLength = _mod->SPIreadRegister(SX127X_REG_FIFO); + } else { + _packetLength = _mod->SPIreadRegister(SX127X_REG_PAYLOAD_LENGTH_FSK); + } _packetLengthQueried = true; } } @@ -898,17 +935,127 @@ int16_t SX127x::setEncoding(uint8_t encoding) { // set encoding switch(encoding) { - case 0: + case RADIOLIB_ENCODING_NRZ: return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_DC_FREE_NONE, 6, 5)); - case 1: + case RADIOLIB_ENCODING_MANCHESTER: return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_DC_FREE_MANCHESTER, 6, 5)); - case 2: + case RADIOLIB_ENCODING_WHITENING: return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_DC_FREE_WHITENING, 6, 5)); default: return(ERR_INVALID_ENCODING); } } +uint16_t SX127x::getIRQFlags() { + // check active modem + if(getActiveModem() == SX127X_LORA) { + // LoRa, just 8-bit value + return((uint16_t)_mod->SPIreadRegister(SX127X_REG_IRQ_FLAGS)); + + } else { + // FSK, the IRQ flags are 16 bits in total + uint16_t flags = ((uint16_t)_mod->SPIreadRegister(SX127X_REG_IRQ_FLAGS_2)) << 8; + flags |= (uint16_t)_mod->SPIreadRegister(SX127X_REG_IRQ_FLAGS_1); + return(flags); + } + +} + +uint8_t SX127x::getModemStatus() { + // check active modem + if(getActiveModem() != SX127X_LORA) { + return(0x00); + } + + // read the register + return(_mod->SPIreadRegister(SX127X_REG_MODEM_STAT)); +} + +void SX127x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { + _mod->setRfSwitchPins(rxEn, txEn); +} + +uint8_t SX127x::random() { + // check active modem + uint8_t rssiValueReg = SX127X_REG_RSSI_WIDEBAND; + if(getActiveModem() == SX127X_FSK_OOK) { + rssiValueReg = SX127X_REG_RSSI_VALUE_FSK; + } + + // set mode to Rx + setMode(SX127X_RX); + + // wait a bit for the RSSI reading to stabilise + Module::delay(10); + + // read RSSI value 8 times, always keep just the least significant bit + uint8_t randByte = 0x00; + for(uint8_t i = 0; i < 8; i++) { + randByte |= ((_mod->SPIreadRegister(rssiValueReg) & 0x01) << i); + } + + // set mode to standby + setMode(SX127X_STANDBY); + + return(randByte); +} + +int16_t SX127x::getChipVersion() { + return(_mod->SPIgetRegValue(SX127X_REG_VERSION)); +} + +int8_t SX127x::getTempRaw() { + int8_t temp = 0; + uint8_t previousOpMode; + uint8_t ival; + + // save current Op Mode + previousOpMode = _mod->SPIgetRegValue(SX127X_REG_OP_MODE); + + // check if we need to step out of LoRa mode first + if ((previousOpMode & SX127X_LORA) == SX127X_LORA) { + _mod->SPIsetRegValue(SX127X_REG_OP_MODE, (SX127X_LORA | SX127X_SLEEP)); + } + + // put device in FSK sleep + _mod->SPIsetRegValue(SX127X_REG_OP_MODE, (SX127X_FSK_OOK | SX127X_SLEEP)); + + // put device in FSK RxSynth + _mod->SPIsetRegValue(SX127X_REG_OP_MODE, (SX127X_FSK_OOK | SX127X_FSRX)); + + // enable temperature reading + _mod->SPIsetRegValue(SX127X_REG_IMAGE_CAL, SX127X_TEMP_MONITOR_ON, 0, 0); + + // wait + Module::delayMicroseconds(200); + + // disable temperature reading + _mod->SPIsetRegValue(SX127X_REG_IMAGE_CAL, SX127X_TEMP_MONITOR_OFF, 0, 0); + + // put device in FSK sleep + _mod->SPIsetRegValue(SX127X_REG_OP_MODE, (SX127X_FSK_OOK | SX127X_SLEEP)); + + // read temperature + ival = _mod->SPIgetRegValue(SX127X_REG_TEMP); + + // convert very raw value + if ((ival & 0x80) == 0x80) { + temp = 255 - ival; + } else { + temp = -1 * ival; + } + + // check if we need to step back into LoRa mode + if ((previousOpMode & SX127X_LORA) == SX127X_LORA) { + _mod->SPIsetRegValue(SX127X_REG_OP_MODE, (SX127X_LORA | SX127X_SLEEP)); + } + + // reload previous Op Mode + _mod->SPIsetRegValue(SX127X_REG_OP_MODE, previousOpMode); + + return(temp); +} + int16_t SX127x::config() { // turn off frequency hopping int16_t state = _mod->SPIsetRegValue(SX127X_REG_HOP_PERIOD, SX127X_HOP_PERIOD_OFF); @@ -924,7 +1071,7 @@ int16_t SX127x::configFSK() { _mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_2, SX127X_FLAG_FIFO_OVERRUN); // set packet configuration - state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_PACKET_VARIABLE | SX127X_DC_FREE_WHITENING | SX127X_CRC_ON | SX127X_CRC_AUTOCLEAR_ON | SX127X_ADDRESS_FILTERING_OFF | SX127X_CRC_WHITENING_TYPE_CCITT, 7, 0); + state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_PACKET_VARIABLE | SX127X_DC_FREE_NONE | SX127X_CRC_ON | SX127X_CRC_AUTOCLEAR_ON | SX127X_ADDRESS_FILTERING_OFF | SX127X_CRC_WHITENING_TYPE_CCITT, 7, 0); state |= _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_PACKET | SX127X_IO_HOME_OFF, 6, 5); RADIOLIB_ASSERT(state); @@ -943,10 +1090,8 @@ int16_t SX127x::configFSK() { state |= _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_3, SX127X_TIMEOUT_SIGNAL_SYNC_OFF); RADIOLIB_ASSERT(state); - // enable preamble detector and set preamble length + // enable preamble detector state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_DETECT, SX127X_PREAMBLE_DETECTOR_ON | SX127X_PREAMBLE_DETECTOR_2_BYTE | SX127X_PREAMBLE_DETECTOR_TOL); - state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, SX127X_PREAMBLE_SIZE_MSB); - state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, SX127X_PREAMBLE_SIZE_LSB); return(state); } @@ -983,7 +1128,7 @@ bool SX127x::findChip(uint8_t ver) { reset(); // check version register - uint8_t version = _mod->SPIreadRegister(SX127X_REG_VERSION); + int16_t version = getChipVersion(); if(version == ver) { flagFound = true; } else { @@ -992,13 +1137,13 @@ bool SX127x::findChip(uint8_t ver) { RADIOLIB_DEBUG_PRINT(i + 1); RADIOLIB_DEBUG_PRINT(F(" of 10 tries) SX127X_REG_VERSION == ")); - char buffHex[5]; - sprintf(buffHex, "0x%02X", version); + char buffHex[12]; + sprintf(buffHex, "0x%04X", version); RADIOLIB_DEBUG_PRINT(buffHex); RADIOLIB_DEBUG_PRINT(F(", expected 0x00")); RADIOLIB_DEBUG_PRINTLN(ver, HEX); #endif - delay(1000); + Module::delay(10); i++; } } @@ -1043,27 +1188,4 @@ void SX127x::clearFIFO(size_t count) { } } -#ifdef RADIOLIB_DEBUG -void SX127x::regDump() { - RADIOLIB_DEBUG_PRINTLN(); - RADIOLIB_DEBUG_PRINTLN(F("ADDR\tVALUE")); - for(uint16_t addr = 0x01; addr <= 0x70; addr++) { - if(addr <= 0x0F) { - RADIOLIB_DEBUG_PRINT(F("0x0")); - } else { - RADIOLIB_DEBUG_PRINT(F("0x")); - } - RADIOLIB_DEBUG_PRINT(addr, HEX); - RADIOLIB_DEBUG_PRINT('\t'); - uint8_t val = _mod->SPIreadRegister(addr); - if(val <= 0x0F) { - RADIOLIB_DEBUG_PRINT(F("0x0")); - } else { - RADIOLIB_DEBUG_PRINT(F("0x")); - } - RADIOLIB_DEBUG_PRINTLN(val, HEX); - - delay(50); - } -} #endif diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 1edf5917..98906354 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX127X_H +#if !defined(_RADIOLIB_SX127X_H) #define _RADIOLIB_SX127X_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX127X) + #include "../../Module.h" #include "../../protocols/PhysicalLayer/PhysicalLayer.h" @@ -459,8 +462,8 @@ #define SX127X_TEMP_THRESHOLD_10_DEG_C 0b00000010 // 2 1 10 deg. C (default) #define SX127X_TEMP_THRESHOLD_15_DEG_C 0b00000100 // 2 1 15 deg. C #define SX127X_TEMP_THRESHOLD_20_DEG_C 0b00000110 // 2 1 20 deg. C -#define SX127X_TEMP_MONITOR_OFF 0b00000000 // 0 0 temperature monitoring disabled (default) -#define SX127X_TEMP_MONITOR_ON 0b00000001 // 0 0 temperature monitoring enabled +#define SX127X_TEMP_MONITOR_ON 0b00000000 // 0 0 temperature monitoring enabled (default) +#define SX127X_TEMP_MONITOR_OFF 0b00000001 // 0 0 temperature monitoring disabled // SX127X_REG_LOW_BAT #define SX127X_LOW_BAT_OFF 0b00000000 // 3 3 low battery detector disabled @@ -556,13 +559,11 @@ class SX127x: public PhysicalLayer { \param syncWord %LoRa sync word. - \param currentLimit Trim value for OCP (over current protection) in mA. - \param preambleLength Length of %LoRa transmission preamble in symbols. \returns \ref status_codes */ - int16_t begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimit, uint16_t preambleLength); + int16_t begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLength); /*! \brief Reset method. Will reset the chip to the default state using RST pin. Declared pure virtual since SX1272 and SX1278 implementations differ. @@ -580,15 +581,13 @@ class SX127x: public PhysicalLayer { \param rxBw Receiver bandwidth in kHz. - \param currentLimit Trim value for OCP (over current protection) in mA. - \param preambleLength Length of FSK preamble in bits. \param enableOOK Flag to specify OOK mode. This modulation is similar to FSK. \returns \ref status_codes */ - int16_t beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK); + int16_t beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK); /*! \brief Binary transmit method. Will transmit arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. @@ -602,7 +601,7 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Binary receive method. Will attempt to receive arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. @@ -614,7 +613,7 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len); + int16_t receive(uint8_t* data, size_t len) override; /*! \brief Performs scan for valid %LoRa preamble in the current channel. @@ -636,17 +635,17 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t standby(); + int16_t standby() override; /*! \brief Enables direct transmission mode on pins DIO1 (clock) and DIO2 (data). While in direct mode, the module will not be able to transmit or receive packets. Can only be activated in FSK mode. - \param FRF 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY. + \param frf 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY. \returns \ref status_codes */ - int16_t transmitDirect(uint32_t FRF = 0); + int16_t transmitDirect(uint32_t frf = 0) override; /*! \brief Enables direct reception mode on pins DIO1 (clock) and DIO2 (data). @@ -654,7 +653,7 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t receiveDirect(); + int16_t receiveDirect() override; /*! \brief Disables direct mode and enables packet mode, allowing the module to receive packets. Can only be activated in FSK mode. @@ -700,7 +699,7 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received. @@ -722,7 +721,7 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t readData(uint8_t* data, size_t len); + int16_t readData(uint8_t* data, size_t len) override; // configuration methods @@ -746,9 +745,9 @@ class SX127x: public PhysicalLayer { int16_t setCurrentLimit(uint8_t currentLimit); /*! - \brief Sets %LoRa preamble length. Allowed values range from 6 to 65535. Only available in %LoRa mode. + \brief Sets %LoRa or FSK preamble length. Allowed values range from 6 to 65535 in %LoRa mode or 0 to 65535 in FSK mode. - \param preambleLength Preamble length to be set (in symbols). + \param preambleLength Preamble length to be set (in symbols when in LoRa mode or bits in FSK mode). \returns \ref status_codes */ @@ -775,7 +774,7 @@ class SX127x: public PhysicalLayer { \returns Last packet data rate in bps (bits per second). */ - float getDataRate(); + float getDataRate() const; /*! \brief Sets FSK bit rate. Allowed values range from 1.2 to 300 kbps. Only available in FSK mode. @@ -793,7 +792,7 @@ class SX127x: public PhysicalLayer { \returns \ref status_codes */ - int16_t setFrequencyDeviation(float freqDev); + int16_t setFrequencyDeviation(float freqDev) override; /*! \brief Sets FSK receiver bandwidth. Allowed values range from 2.6 to 250 kHz. Only available in FSK mode. @@ -856,7 +855,7 @@ class SX127x: public PhysicalLayer { \returns Length of last received packet in bytes. */ - size_t getPacketLength(bool update = true); + size_t getPacketLength(bool update = true) override; /*! \brief Set modem in fixed packet length mode. Available in FSK mode only. @@ -890,29 +889,75 @@ class SX127x: public PhysicalLayer { /*! \brief Sets transmission encoding. Only available in FSK mode. + Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER and RADIOLIB_ENCODING_WHITENING. - \param encoding Encoding to be used. Set to 0 for NRZ, 1 for Manchester and 2 for whitening. + \param encoding Encoding to be used. \returns \ref status_codes */ - int16_t setEncoding(uint8_t encoding); + int16_t setEncoding(uint8_t encoding) override; - #ifdef RADIOLIB_DEBUG - void regDump(); - #endif + /*! + \brief Reads currently active IRQ flags, can be used to check which event caused an interrupt. + In LoRa mode, this is the content of SX127X_REG_IRQ_FLAGS register. + In FSK mode, this is the contents of SX127X_REG_IRQ_FLAGS_2 (MSB) and SX127X_REG_IRQ_FLAGS_1 (LSB) registers. + + \returns IRQ flags. + */ + uint16_t getIRQFlags(); + + /*! + \brief Reads modem status. Only available in LoRa mode. + + \returns Modem status. + */ + uint8_t getModemStatus(); + + /*! + \brief Reads uncalibrated temperature value. This function will change operating mode + and should not be called during Tx, Rx or CAD. + + \returns Uncalibrated temperature sensor reading. + */ + int8_t getTempRaw(); + + /*! + \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. + When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! + + \param rxEn RX enable pin. + + \param txEn TX enable pin. + */ + void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + + /*! + \brief Get one truly random byte from RSSI noise. + + \returns TRNG byte. + */ + uint8_t random(); + + /*! + \brief Read version SPI register. Should return SX1278_CHIP_VERSION (0x12) or SX1272_CHIP_VERSION (0x22) if SX127x is connected and working. + + \returns Version register contents or \ref status_codes + */ + int16_t getChipVersion(); #ifndef RADIOLIB_GODMODE protected: #endif Module* _mod; - float _freq; - float _bw; - uint8_t _sf; - uint8_t _cr; - float _br; - float _rxBw; - bool _ook; + float _freq = 0; + float _bw = 0; + uint8_t _sf = 0; + uint8_t _cr = 0; + float _br = 0; + float _rxBw = 0; + bool _ook = false; + bool _crcEnabled = false; int16_t setFrequencyRaw(float newFreq); int16_t config(); @@ -924,10 +969,10 @@ class SX127x: public PhysicalLayer { #ifndef RADIOLIB_GODMODE private: #endif - float _dataRate; - size_t _packetLength; - bool _packetLengthQueried; // FSK packet length is the first byte in FIFO, length can only be queried once - uint8_t _packetLengthConfig; + float _dataRate = 0; + size_t _packetLength = 0; + bool _packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once + uint8_t _packetLengthConfig = SX127X_PACKET_VARIABLE; bool findChip(uint8_t ver); int16_t setMode(uint8_t mode); @@ -937,3 +982,5 @@ class SX127x: public PhysicalLayer { }; #endif + +#endif diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index 2c4d09ee..0bb5b139 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -1,4 +1,5 @@ #include "SX1280.h" +#if !defined(RADIOLIB_EXCLUDE_SX128X) SX1280::SX1280(Module* mod) : SX1281(mod) { @@ -10,10 +11,10 @@ int16_t SX1280::range(bool master, uint32_t addr) { RADIOLIB_ASSERT(state); // wait until ranging is finished - uint32_t start = millis(); - while(!digitalRead(_mod->getIrq())) { - yield(); - if(millis() - start > 10000) { + uint32_t start = Module::millis(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); + if(Module::millis() - start > 10000) { clearIrqStatus(); standby(); return(ERR_RANGING_TIMEOUT); @@ -111,3 +112,5 @@ float SX1280::getRangingResult() { memcpy(&raw, data, sizeof(uint32_t)); return((float)raw * (150.0/(4.096 * _bwKhz))); } + +#endif diff --git a/src/modules/SX128x/SX1280.h b/src/modules/SX128x/SX1280.h index ea8c5a18..3cd3184a 100644 --- a/src/modules/SX128x/SX1280.h +++ b/src/modules/SX128x/SX1280.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX1280_H +#if !defined(_RADIOLIB_SX1280_H) #define _RADIOLIB_SX1280_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX128X) + #include "../../Module.h" #include "SX128x.h" #include "SX1281.h" @@ -56,3 +59,5 @@ class SX1280: public SX1281 { }; #endif + +#endif diff --git a/src/modules/SX128x/SX1281.cpp b/src/modules/SX128x/SX1281.cpp index 4aa09b0d..c6b2b5eb 100644 --- a/src/modules/SX128x/SX1281.cpp +++ b/src/modules/SX128x/SX1281.cpp @@ -1,5 +1,8 @@ #include "SX1281.h" +#if !defined(RADIOLIB_EXCLUDE_SX128X) SX1281::SX1281(Module* mod) : SX128x(mod) { } + +#endif diff --git a/src/modules/SX128x/SX1281.h b/src/modules/SX128x/SX1281.h index 88037a09..67a0a323 100644 --- a/src/modules/SX128x/SX1281.h +++ b/src/modules/SX128x/SX1281.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX1281_H +#if !defined(_RADIOLIB_SX1281_H) #define _RADIOLIB_SX1281_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX128X) + #include "../../Module.h" #include "SX128x.h" @@ -26,3 +29,5 @@ class SX1281: public SX128x { }; #endif + +#endif diff --git a/src/modules/SX128x/SX1282.cpp b/src/modules/SX128x/SX1282.cpp index 847a36d1..33deee97 100644 --- a/src/modules/SX128x/SX1282.cpp +++ b/src/modules/SX128x/SX1282.cpp @@ -1,5 +1,9 @@ #include "SX1282.h" +#if !defined(RADIOLIB_EXCLUDE_SX128X) +/// \todo implement advanced ranging SX1282::SX1282(Module* mod) : SX1280(mod) { } + +#endif diff --git a/src/modules/SX128x/SX1282.h b/src/modules/SX128x/SX1282.h index 09f92075..f6cbdbd7 100644 --- a/src/modules/SX128x/SX1282.h +++ b/src/modules/SX128x/SX1282.h @@ -1,13 +1,14 @@ -#ifndef _RADIOLIB_SX1282_H +#if !defined(_RADIOLIB_SX1282_H) #define _RADIOLIB_SX1282_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX128X) + #include "../../Module.h" #include "SX128x.h" #include "SX1280.h" -// TODO implement advanced ranging - /*! \class SX1282 @@ -29,3 +30,5 @@ class SX1282: public SX1280 { }; #endif + +#endif diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index e4dae862..e2990218 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1,4 +1,5 @@ #include "SX128x.h" +#if !defined(RADIOLIB_EXCLUDE_SX128X) SX128x::SX128x(Module* mod) : PhysicalLayer(SX128X_FREQUENCY_STEP_SIZE, SX128X_MAX_PACKET_LENGTH) { _mod = mod; @@ -9,6 +10,7 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, int8_t power _mod->init(RADIOLIB_USE_SPI); Module::pinMode(_mod->getIrq(), INPUT); Module::pinMode(_mod->getGpio(), INPUT); + RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); // initialize LoRa modulation variables _bwKhz = bw; @@ -55,11 +57,12 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, int8_t power return(state); } -int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, uint16_t preambleLength, float dataShaping) { +int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, uint16_t preambleLength) { // set module properties _mod->init(RADIOLIB_USE_SPI); Module::pinMode(_mod->getIrq(), INPUT); Module::pinMode(_mod->getGpio(), INPUT); + RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); // initialize GFSK modulation variables _brKbps = br; @@ -103,22 +106,26 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); - state = setDataShaping(dataShaping); + state = setDataShaping(RADIOLIB_SHAPING_0_5); RADIOLIB_ASSERT(state); // set publicly accessible settings that are not a part of begin method - uint8_t sync[] = { 0x2D, 0x01 }; + uint8_t sync[] = { 0x12, 0xAD }; state = setSyncWord(sync, 2); RADIOLIB_ASSERT(state); + state = setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + return(state); } -int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, float dataShaping) { +int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, uint8_t dataShaping) { // set module properties _mod->init(RADIOLIB_USE_SPI); Module::pinMode(_mod->getIrq(), INPUT); Module::pinMode(_mod->getGpio(), INPUT); + RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); // initialize BLE modulation variables _brKbps = br; @@ -162,11 +169,12 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, f return(state); } -int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uint16_t preambleLength, float dataShaping) { +int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uint16_t preambleLength, uint8_t dataShaping) { // set module properties _mod->init(RADIOLIB_USE_SPI); Module::pinMode(_mod->getIrq(), INPUT); Module::pinMode(_mod->getGpio(), INPUT); + RADIOLIB_DEBUG_PRINTLN(F("M\tSX128x")); // initialize FLRC modulation variables _brKbps = br; @@ -224,7 +232,7 @@ int16_t SX128x::reset(bool verify) { // run the reset sequence - same as SX126x, as SX128x docs don't seem to mention this Module::pinMode(_mod->getRst(), OUTPUT); Module::digitalWrite(_mod->getRst(), LOW); - delay(1); + Module::delay(1); Module::digitalWrite(_mod->getRst(), HIGH); // return immediately when verification is disabled @@ -233,7 +241,7 @@ int16_t SX128x::reset(bool verify) { } // set mode to standby - uint32_t start = millis(); + uint32_t start = Module::millis(); while(true) { // try to set mode to standby int16_t state = standby(); @@ -243,13 +251,13 @@ int16_t SX128x::reset(bool verify) { } // standby command failed, check timeout and try again - if(millis() - start >= 3000) { + if(Module::millis() - start >= 3000) { // timed out, possibly incorrect wiring return(state); } // wait a bit to not spam the module - delay(10); + Module::delay(10); } } @@ -281,10 +289,10 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for packet transmission or timeout - uint32_t start = micros(); - while(!digitalRead(_mod->getIrq())) { - yield(); - if(micros() - start > timeout) { + uint32_t start = Module::micros(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); + if(Module::micros() - start > timeout) { clearIrqStatus(); standby(); return(ERR_TX_TIMEOUT); @@ -325,10 +333,10 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = micros(); - while(!digitalRead(_mod->getIrq())) { - yield(); - if(micros() - start > timeout) { + uint32_t start = Module::micros(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); + if(Module::micros() - start > timeout) { clearIrqStatus(); standby(); return(ERR_RX_TIMEOUT); @@ -340,6 +348,9 @@ int16_t SX128x::receive(uint8_t* data, size_t len) { } int16_t SX128x::transmitDirect(uint32_t frf) { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + // user requested to start transmitting immediately (required for RTTY) int16_t state = ERR_NONE; if(frf != 0) { @@ -352,6 +363,9 @@ int16_t SX128x::transmitDirect(uint32_t frf) { } int16_t SX128x::receiveDirect() { + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // SX128x is unable to output received data directly return(ERR_UNKNOWN); } @@ -374,13 +388,16 @@ int16_t SX128x::scanChannel() { state = clearIrqStatus(); RADIOLIB_ASSERT(state); + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // set mode to CAD state = setCad(); RADIOLIB_ASSERT(state); // wait for channel activity detected or timeout - while(!digitalRead(_mod->getIrq())) { - yield(); + while(!Module::digitalRead(_mod->getIrq())) { + Module::yield(); } // check CAD result @@ -399,6 +416,9 @@ int16_t SX128x::scanChannel() { } int16_t SX128x::sleep(bool retainConfig) { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, LOW); + uint8_t sleepConfig = SX128X_SLEEP_DATA_BUFFER_RETAIN | SX128X_SLEEP_DATA_RAM_RETAIN; if(!retainConfig) { sleepConfig = SX128X_SLEEP_DATA_BUFFER_FLUSH | SX128X_SLEEP_DATA_RAM_FLUSH; @@ -406,7 +426,7 @@ int16_t SX128x::sleep(bool retainConfig) { int16_t state = SPIwriteCommand(SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false); // wait for SX128x to safely enter sleep mode - delay(1); + Module::delay(1); return(state); } @@ -416,16 +436,19 @@ int16_t SX128x::standby() { } int16_t SX128x::standby(uint8_t mode) { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, LOW); + uint8_t data[] = { mode }; return(SPIwriteCommand(SX128X_CMD_SET_STANDBY, data, 1)); } void SX128x::setDio1Action(void (*func)(void)) { - attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, RISING); + Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING); } void SX128x::clearDio1Action() { - detachInterrupt(digitalPinToInterrupt(_mod->getIrq())); + Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -444,6 +467,8 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, len, _crcLoRa); } else if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_FLRC)) { state = setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening, len); + } else if(modem == SX128X_PACKET_TYPE_BLE) { + state = setPacketParamsBLE(_connectionState, _crcBLE, _bleTestPayload, _whitening); } else { return(ERR_WRONG_MODEM); } @@ -458,8 +483,14 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // write packet to buffer - state = writeBuffer(data, len); - RADIOLIB_ASSERT(state); + if(modem == SX128X_PACKET_TYPE_BLE) { + // first 2 bytes of BLE payload are PDU header + state = writeBuffer(data, len, 2); + RADIOLIB_ASSERT(state); + } else { + state = writeBuffer(data, len); + RADIOLIB_ASSERT(state); + } // set DIO mapping state = setDioIrqParams(SX128X_IRQ_TX_DONE | SX128X_IRQ_RX_TX_TIMEOUT, SX128X_IRQ_TX_DONE); @@ -469,13 +500,16 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { state = clearIrqStatus(); RADIOLIB_ASSERT(state); + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + // start transmission state = setTx(SX128X_TX_TIMEOUT_NONE); RADIOLIB_ASSERT(state); // wait for BUSY to go low (= PA ramp up done) - while(digitalRead(_mod->getGpio())) { - yield(); + while(Module::digitalRead(_mod->getGpio())) { + Module::yield(); } return(state); @@ -505,6 +539,9 @@ int16_t SX128x::startReceive(uint16_t timeout) { RADIOLIB_ASSERT(state); } + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // set mode to receive state = setRx(timeout); @@ -785,23 +822,26 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) { return(setModulationParams(_br, _modIndex, _shaping)); } -int16_t SX128x::setDataShaping(float dataShaping) { +int16_t SX128x::setDataShaping(uint8_t sh) { // check active modem uint8_t modem = getPacketType(); if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE) || (modem == SX128X_PACKET_TYPE_FLRC))) { return(ERR_WRONG_MODEM); } - // check allowed values - dataShaping *= 10.0; - if(abs(dataShaping - 0.0) <= 0.001) { - _shaping = SX128X_BLE_GFSK_BT_OFF; - } else if(abs(dataShaping - 5.0) <= 0.001) { - _shaping = SX128X_BLE_GFSK_BT_0_5; - } else if(abs(dataShaping - 10.0) <= 0.001) { - _shaping = SX128X_BLE_GFSK_BT_1_0; - } else { - return(ERR_INVALID_DATA_SHAPING); + // set data shaping + switch(sh) { + case RADIOLIB_SHAPING_NONE: + _shaping = SX128X_BLE_GFSK_BT_OFF; + break; + case RADIOLIB_SHAPING_0_5: + _shaping = SX128X_BLE_GFSK_BT_0_5; + break; + case RADIOLIB_SHAPING_1_0: + _shaping = SX128X_BLE_GFSK_BT_1_0; + break; + default: + return(ERR_INVALID_DATA_SHAPING); } // update modulation parameters @@ -854,7 +894,7 @@ int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { if(_syncWordLen == 0) { _syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_OFF; } else { - // TODO add support for multiple sync words + /// \todo add support for multiple sync words _syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_1; } return(setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening)); @@ -864,7 +904,7 @@ int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) { // check active modem uint8_t modem = getPacketType(); - int16_t state = ERR_NONE; + int16_t state; if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_FLRC)) { // update packet parameters if(modem == SX128X_PACKET_TYPE_GFSK) { @@ -950,9 +990,9 @@ int16_t SX128x::setAccessAddress(uint32_t addr) { return(ERR_WRONG_MODEM); } - // use setSyncWord to set the address - uint8_t syncWord[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; - return(setSyncWord(syncWord, 4)); + // set the address + uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + return(SX128x::writeRegister(SX128X_REG_ACCESS_ADDRESS_BYTE_3, addrBuff, 4)); } float SX128x::getRSSI() { @@ -1001,7 +1041,7 @@ float SX128x::getSNR() { size_t SX128x::getPacketLength(bool update) { (void)update; - uint8_t rxBufStatus[2]; + uint8_t rxBufStatus[2] = {0, 0}; SPIreadCommand(SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); return((size_t)rxBufStatus[0]); } @@ -1057,7 +1097,7 @@ uint32_t SX128x::getTimeOnAir(size_t len) { } else { // long interleaving - abandon hope all ye who enter here - // TODO implement this mess - SX1280 datasheet v3.0 section 7.4.4.2 + /// \todo implement this mess - SX1280 datasheet v3.0 section 7.4.4.2 } @@ -1082,6 +1122,16 @@ int16_t SX128x::setEncoding(uint8_t encoding) { return(setWhitening(encoding)); } +void SX128x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { + _mod->setRfSwitchPins(rxEn, txEn); +} + +uint8_t SX128x::random() { + // it's unclear whether SX128x can measure RSSI while not receiving a packet + // this method is implemented only for PhysicalLayer compatibility + return(0); +} + uint8_t SX128x::getStatus() { uint8_t data = 0; SPIreadCommand(SX128X_CMD_GET_STATUS, &data, 1); @@ -1255,17 +1305,17 @@ int16_t SX128x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d #endif // ensure BUSY is low (state machine ready) - uint32_t start = millis(); - while(digitalRead(_mod->getGpio())) { - yield(); - if(millis() - start >= timeout) { - digitalWrite(_mod->getCs(), HIGH); + uint32_t start = Module::millis(); + while(Module::digitalRead(_mod->getGpio())) { + Module::yield(); + if(Module::millis() - start >= timeout) { + Module::digitalWrite(_mod->getCs(), HIGH); return(ERR_SPI_CMD_TIMEOUT); } } // pull NSS low - digitalWrite(_mod->getCs(), LOW); + Module::digitalWrite(_mod->getCs(), LOW); // start transfer spi->beginTransaction(spiSettings); @@ -1322,15 +1372,15 @@ int16_t SX128x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d // stop transfer spi->endTransaction(); - digitalWrite(_mod->getCs(), HIGH); + Module::digitalWrite(_mod->getCs(), HIGH); // wait for BUSY to go high and then low if(waitForBusy) { - delayMicroseconds(1); - start = millis(); - while(digitalRead(_mod->getGpio())) { - yield(); - if(millis() - start >= timeout) { + Module::delayMicroseconds(1); + start = Module::millis(); + while(Module::digitalRead(_mod->getGpio())) { + Module::yield(); + if(Module::millis() - start >= timeout) { status = SX128X_STATUS_CMD_TIMEOUT; break; } @@ -1379,8 +1429,8 @@ int16_t SX128x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d // some faster platforms require a short delay here // not sure why, but it seems that long enough SPI transaction // (e.g. setPacketParams for GFSK) will fail without it - #if defined(ARDUINO_ARCH_STM32) - delay(1); + #if defined(RADIOLIB_SPI_SLOWDOWN) + Module::delay(1); #endif #endif @@ -1398,3 +1448,5 @@ int16_t SX128x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d return(ERR_NONE); } } + +#endif diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index f093a3c9..5763e527 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SX128X_H +#if !defined(_RADIOLIB_SX128X_H) #define _RADIOLIB_SX128X_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SX128X) + #include "../../Module.h" #include "../../protocols/PhysicalLayer/PhysicalLayer.h" @@ -382,11 +385,9 @@ class SX128x: public PhysicalLayer { \parma preambleLength FSK preamble length in bits. Defaults to 16 bits. - \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. - \returns \ref status_codes */ - int16_t beginGFSK(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t power = 10, uint16_t preambleLength = 16, float dataShaping = 0.5); + int16_t beginGFSK(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t power = 10, uint16_t preambleLength = 16); /*! \brief Initialization method for BLE modem. @@ -403,7 +404,7 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ - int16_t beginBLE(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t power = 10, float dataShaping = 0.5); + int16_t beginBLE(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t power = 10, uint8_t dataShaping = RADIOLIB_SHAPING_0_5); /*! \brief Initialization method for FLRC modem. @@ -422,7 +423,7 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ - int16_t beginFLRC(float freq = 2400.0, uint16_t br = 650, uint8_t cr = 3, int8_t power = 10, uint16_t preambleLength = 16, float dataShaping = 0.5); + int16_t beginFLRC(float freq = 2400.0, uint16_t br = 650, uint8_t cr = 3, int8_t power = 10, uint16_t preambleLength = 16, uint8_t dataShaping = RADIOLIB_SHAPING_0_5); /*! \brief Reset method. Will reset the chip to the default state using RST pin. @@ -442,11 +443,11 @@ class SX128x: public PhysicalLayer { \param len Number of bytes to send. - \param addr Address to send the data to. Will only be added if address filtering was enabled. + \param addr Address to send the data to. Unsupported, compatibility only. \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Blocking binary receive method. @@ -458,7 +459,7 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len); + int16_t receive(uint8_t* data, size_t len) override; /*! \brief Starts direct mode transmission. @@ -467,7 +468,7 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ - int16_t transmitDirect(uint32_t frf = 0); + int16_t transmitDirect(uint32_t frf = 0) override; /*! \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, as %SX128x series does not support direct mode reception. @@ -475,7 +476,7 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ - int16_t receiveDirect(); + int16_t receiveDirect() override; /*! \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. @@ -498,7 +499,7 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ - int16_t standby(); + int16_t standby() override; /*! \brief Sets the module to standby mode. @@ -531,11 +532,11 @@ class SX128x: public PhysicalLayer { \param len Number of bytes to send. - \param addr Address to send the data to. Will only be added if address filtering was enabled. + \param addr Address to send the data to. Unsupported, compatibility only. \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. @@ -555,7 +556,7 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ - int16_t readData(uint8_t* data, size_t len); + int16_t readData(uint8_t* data, size_t len) override; // configuration methods @@ -631,16 +632,17 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ - int16_t setFrequencyDeviation(float freqDev); + int16_t setFrequencyDeviation(float freqDev) override; /*! - \brief Sets time-bandwidth product of Gaussian filter applied for shaping. Allowed values are 0.5 and 1.0. Set to 0 to disable shaping. + \brief Sets time-bandwidth product of Gaussian filter applied for shaping. + Allowed values are RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. \param sh Time-bandwidth product of Gaussian filter to be set. \returns \ref status_codes */ - int16_t setDataShaping(float dataShaping); + int16_t setDataShaping(uint8_t sh) override; /*! \brief Sets FSK/FLRC sync word in the form of array of up to 5 bytes (FSK). For FLRC modem, the sync word must be exactly 4 bytes long @@ -705,7 +707,7 @@ class SX128x: public PhysicalLayer { \returns Length of last received packet in bytes. */ - size_t getPacketLength(bool update = true); + size_t getPacketLength(bool update = true) override; /*! \brief Get expected time-on-air for a given size of payload. @@ -739,17 +741,34 @@ class SX128x: public PhysicalLayer { \returns \ref status_codes */ - int16_t setEncoding(uint8_t encoding); + int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. + When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! + + \param rxEn RX enable pin. + + \param txEn TX enable pin. + */ + void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + + /*! + \brief Dummy random method, to ensure PhysicalLayer compatibility. + + \returns Always returns 0. + */ + uint8_t random(); #ifndef RADIOLIB_GODMODE protected: #endif Module* _mod; - + // cached LoRa parameters - float _bwKhz; - uint8_t _bw, _sf, _cr; - uint8_t _preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa; + float _bwKhz = 0; + uint8_t _bw = 0, _sf = 0, _cr = 0; + uint8_t _preambleLengthLoRa = 0, _headerType = 0, _payloadLen = 0, _crcLoRa = 0; // SX128x SPI command implementations uint8_t getStatus(); @@ -780,19 +799,19 @@ class SX128x: public PhysicalLayer { private: #endif // common parameters - uint8_t _pwr; + uint8_t _pwr = 0; // cached GFSK parameters - float _modIndexReal; - uint16_t _brKbps; - uint8_t _br, _modIndex, _shaping; - uint8_t _preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening; + float _modIndexReal = 0; + uint16_t _brKbps = 0; + uint8_t _br = 0, _modIndex = 0, _shaping = 0; + uint8_t _preambleLengthGFSK = 0, _syncWordLen = 0, _syncWordMatch = 0, _crcGFSK = 0, _whitening = 0; // cached FLRC parameters - uint8_t _crFLRC; + uint8_t _crFLRC = 0; // cached BLE parameters - uint8_t _connectionState, _crcBLE, _bleTestPayload; + uint8_t _connectionState = 0, _crcBLE = 0, _bleTestPayload = 0; int16_t config(uint8_t modem); @@ -805,3 +824,5 @@ class SX128x: public PhysicalLayer { }; #endif + +#endif diff --git a/src/modules/Si443x/Si4430.cpp b/src/modules/Si443x/Si4430.cpp index c59f1ea7..9114ac4b 100644 --- a/src/modules/Si443x/Si4430.cpp +++ b/src/modules/Si443x/Si4430.cpp @@ -1,13 +1,15 @@ #include "Si4430.h" +#if !defined(RADIOLIB_EXCLUDE_SI443X) Si4430::Si4430(Module* mod) : Si4432(mod) { } -int16_t Si4430::begin(float freq, float br, float freqDev, float rxBw, int8_t power) { +int16_t Si4430::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // execute common part - int16_t state = Si443x::begin(br, freqDev, rxBw); + int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_PRINTLN(F("M\tSi4430")); // configure publicly accessible settings state = setFrequency(freq); @@ -32,3 +34,5 @@ int16_t Si4430::setOutputPower(int8_t power) { // set output power return(_mod->SPIsetRegValue(SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); } + +#endif diff --git a/src/modules/Si443x/Si4430.h b/src/modules/Si443x/Si4430.h index 7e7f8b36..ca8a1b8f 100644 --- a/src/modules/Si443x/Si4430.h +++ b/src/modules/Si443x/Si4430.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SI4430_H +#if !defined(_RADIOLIB_SI4430_H) #define _RADIOLIB_SI4430_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SI443X) + #include "../../Module.h" #include "Si4432.h" @@ -37,9 +40,11 @@ class Si4430: public Si4432 { \param power Transmission output power in dBm. Allowed values range from -8 to 13 dBm in 3 dBm steps. + \param preambleLen Preamble Length in bits. Defaults to 16 bits. + \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 10); + int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); // configuration methods @@ -72,3 +77,5 @@ class Si4430: public Si4432 { }; #endif + +#endif diff --git a/src/modules/Si443x/Si4431.cpp b/src/modules/Si443x/Si4431.cpp index 25c7baf9..6f406165 100644 --- a/src/modules/Si443x/Si4431.cpp +++ b/src/modules/Si443x/Si4431.cpp @@ -1,13 +1,15 @@ #include "Si4431.h" +#if !defined(RADIOLIB_EXCLUDE_SI443X) Si4431::Si4431(Module* mod) : Si4432(mod) { } -int16_t Si4431::begin(float freq, float br, float freqDev, float rxBw, int8_t power) { +int16_t Si4431::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // execute common part - int16_t state = Si443x::begin(br, freqDev, rxBw); + int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_PRINTLN(F("M\tSi4431")); // configure publicly accessible settings state = setFrequency(freq); @@ -25,3 +27,5 @@ int16_t Si4431::setOutputPower(int8_t power) { // set output power return(_mod->SPIsetRegValue(SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); } + +#endif diff --git a/src/modules/Si443x/Si4431.h b/src/modules/Si443x/Si4431.h index c033bcbd..0143d41b 100644 --- a/src/modules/Si443x/Si4431.h +++ b/src/modules/Si443x/Si4431.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SI4431_H +#if !defined(_RADIOLIB_SI4431_H) #define _RADIOLIB_SI4431_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SI443X) + #include "../../Module.h" #include "Si4432.h" @@ -37,9 +40,11 @@ class Si4431: public Si4432 { \param power Transmission output power in dBm. Allowed values range from -8 to 13 dBm in 3 dBm steps. + \param preambleLen Preamble Length in bits. Defaults to 16 bits. + \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 10); + int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); // configuration methods @@ -63,3 +68,5 @@ class Si4431: public Si4432 { }; #endif + +#endif diff --git a/src/modules/Si443x/Si4432.cpp b/src/modules/Si443x/Si4432.cpp index 38d42863..aef6dc53 100644 --- a/src/modules/Si443x/Si4432.cpp +++ b/src/modules/Si443x/Si4432.cpp @@ -1,13 +1,15 @@ #include "Si4432.h" +#if !defined(RADIOLIB_EXCLUDE_SI443X) Si4432::Si4432(Module* mod) : Si443x(mod) { } -int16_t Si4432::begin(float freq, float br, float freqDev, float rxBw, int8_t power) { +int16_t Si4432::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) { // execute common part - int16_t state = Si443x::begin(br, freqDev, rxBw); + int16_t state = Si443x::begin(br, freqDev, rxBw, preambleLen); RADIOLIB_ASSERT(state); + RADIOLIB_DEBUG_PRINTLN(F("M\tSi4432")); // configure publicly accessible settings state = setFrequency(freq); @@ -32,3 +34,5 @@ int16_t Si4432::setOutputPower(int8_t power) { // set output power return(_mod->SPIsetRegValue(SI443X_REG_TX_POWER, (uint8_t)((power + 1) / 3), 2, 0)); } + +#endif diff --git a/src/modules/Si443x/Si4432.h b/src/modules/Si443x/Si4432.h index 01dd92c5..2f785634 100644 --- a/src/modules/Si443x/Si4432.h +++ b/src/modules/Si443x/Si4432.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SI4432_H +#if !defined(_RADIOLIB_SI4432_H) #define _RADIOLIB_SI4432_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SI443X) + #include "../../Module.h" #include "Si443x.h" @@ -37,9 +40,11 @@ class Si4432: public Si443x { \param power Transmission output power in dBm. Allowed values range from -1 to 20 dBm in 3 dBm steps. + \param preambleLen Preamble Length in bits. Defaults to 16 bits. + \returns \ref status_codes */ - int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 11); + int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 10, uint8_t preambleLen = 16); // configuration methods @@ -72,3 +77,5 @@ class Si4432: public Si443x { }; #endif + +#endif diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 13af7747..fe1d15a6 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -1,12 +1,11 @@ #include "Si443x.h" +#if !defined(RADIOLIB_EXCLUDE_SI443X) Si443x::Si443x(Module* mod) : PhysicalLayer(SI443X_FREQUENCY_STEP_SIZE, SI443X_MAX_PACKET_LENGTH) { _mod = mod; - - _packetLengthQueried = false; } -int16_t Si443x::begin(float br, float freqDev, float rxBw) { +int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) { // set module properties _mod->init(RADIOLIB_USE_SPI); Module::pinMode(_mod->getIrq(), INPUT); @@ -16,10 +15,10 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw) { // try to find the Si443x chip if(!Si443x::findChip()) { RADIOLIB_DEBUG_PRINTLN(F("No Si443x found!")); - _mod->term(); + _mod->term(RADIOLIB_USE_SPI); return(ERR_CHIP_NOT_FOUND); } else { - RADIOLIB_DEBUG_PRINTLN(F("Found Si443x!")); + RADIOLIB_DEBUG_PRINTLN(F("M\tSi443x")); } // clear POR interrupt @@ -39,7 +38,10 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw) { state = setRxBandwidth(rxBw); RADIOLIB_ASSERT(state); - uint8_t syncWord[] = {0x2D, 0x01}; + state = setPreambleLength(preambleLen); + RADIOLIB_ASSERT(state); + + uint8_t syncWord[] = {0x12, 0xAD}; state = setSyncWord(syncWord, sizeof(syncWord)); RADIOLIB_ASSERT(state); @@ -58,9 +60,9 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw) { void Si443x::reset() { Module::pinMode(_mod->getRst(), OUTPUT); Module::digitalWrite(_mod->getRst(), HIGH); - delay(1); + Module::delay(1); Module::digitalWrite(_mod->getRst(), LOW); - delay(100); + Module::delay(100); } int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { @@ -72,22 +74,27 @@ int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait for transmission end or timeout - uint32_t start = micros(); - while(digitalRead(_mod->getIrq())) { - yield(); - if(micros() - start > timeout) { + uint32_t start = Module::micros(); + while(Module::digitalRead(_mod->getIrq())) { + Module::yield(); + if(Module::micros() - start > timeout) { standby(); clearIRQFlags(); return(ERR_TX_TIMEOUT); } } - // set mode to standby - state = standby(); - // clear interrupt flags clearIRQFlags(); + // set mode to standby + standby(); + + // the next transmission will timeout without the following + _mod->SPIwriteRegister(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_TX_DATA_SOURCE_FIFO, 5, 4); + state = setFrequencyRaw(_freq); + return(state); } @@ -100,9 +107,9 @@ int16_t Si443x::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for packet reception or timeout - uint32_t start = micros(); - while(digitalRead(_mod->getIrq())) { - if(micros() - start > timeout) { + uint32_t start = Module::micros(); + while(Module::digitalRead(_mod->getIrq())) { + if(Module::micros() - start > timeout) { standby(); clearIRQFlags(); return(ERR_RX_TIMEOUT); @@ -114,6 +121,9 @@ int16_t Si443x::receive(uint8_t* data, size_t len) { } int16_t Si443x::sleep() { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, LOW); + // disable wakeup timer interrupt int16_t state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_1, 0x00); RADIOLIB_ASSERT(state); @@ -127,14 +137,21 @@ int16_t Si443x::sleep() { } int16_t Si443x::standby() { - return(_mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_XTAL_ON, 7, 0, 10)); + // set RF switch (if present) + _mod->setRfSwitchState(LOW, LOW); + + //return(_mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_XTAL_ON, 7, 0, 10)); + return(ERR_NONE); } int16_t Si443x::transmitDirect(uint32_t frf) { + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + // user requested to start transmitting immediately (required for RTTY) if(frf != 0) { // convert the 24-bit frequency to the format accepted by the module - // TODO integers only + /// \todo integers only float newFreq = frf / 6400.0; // check high/low band @@ -155,7 +172,7 @@ int16_t Si443x::transmitDirect(uint32_t frf) { // start direct transmission directMode(); - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON); + _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON | SI443X_XTAL_ON); return(ERR_NONE); } @@ -165,17 +182,20 @@ int16_t Si443x::transmitDirect(uint32_t frf) { RADIOLIB_ASSERT(state); // start transmitting - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON); + _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON | SI443X_XTAL_ON); return(state); } int16_t Si443x::receiveDirect() { + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + // activate direct mode int16_t state = directMode(); RADIOLIB_ASSERT(state); // start receiving - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_RX_ON); + _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_RX_ON | SI443X_XTAL_ON); return(state); } @@ -184,11 +204,11 @@ int16_t Si443x::packetMode() { } void Si443x::setIrqAction(void (*func)(void)) { - attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, FALLING); + Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, FALLING); } void Si443x::clearIrqAction() { - detachInterrupt(digitalPinToInterrupt(_mod->getIrq())); + Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq())); } int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -205,25 +225,28 @@ int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { _mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_TX_FIFO_RESET, 0, 0); _mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_TX_FIFO_CLEAR, 0, 0); - // set interrupt mapping - state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_1, SI443X_PACKET_SENT_ENABLED); - RADIOLIB_ASSERT(state); - // clear interrupt flags clearIRQFlags(); // set packet length - // TODO variable packet length + /// \todo variable packet length _mod->SPIwriteRegister(SI443X_REG_TRANSMIT_PACKET_LENGTH, len); - // TODO use header as address field? + /// \todo use header as address field? (void)addr; // write packet to FIFO _mod->SPIwriteRegisterBurst(SI443X_REG_FIFO_ACCESS, data, len); + // set RF switch (if present) + _mod->setRfSwitchState(LOW, HIGH); + + // set interrupt mapping + _mod->SPIwriteRegister(SI443X_REG_INTERRUPT_ENABLE_1, SI443X_PACKET_SENT_ENABLED); + _mod->SPIwriteRegister(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + // set mode to transmit - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON); + _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON | SI443X_XTAL_ON); return(state); } @@ -237,17 +260,18 @@ int16_t Si443x::startReceive() { _mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_RX_FIFO_RESET, 1, 1); _mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_RX_FIFO_CLEAR, 1, 1); - // set interrupt mapping - state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_1, SI443X_VALID_PACKET_RECEIVED_ENABLED, SI443X_CRC_ERROR_ENABLED); - RADIOLIB_ASSERT(state); - state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); - RADIOLIB_ASSERT(state); - // clear interrupt flags clearIRQFlags(); + // set RF switch (if present) + _mod->setRfSwitchState(HIGH, LOW); + + // set interrupt mapping + _mod->SPIwriteRegister(SI443X_REG_INTERRUPT_ENABLE_1, SI443X_PACKET_SENT_ENABLED); + _mod->SPIwriteRegister(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + // set mode to receive - _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_RX_ON); + _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_RX_ON | SI443X_XTAL_ON); return(state); } @@ -318,7 +342,7 @@ int16_t Si443x::setFrequencyDeviation(float freqDev) { if(state == ERR_NONE) { _freqDev = freqDev; } - + return(state); } RADIOLIB_CHECK_RANGE(freqDev, 0.625, 320.0, ERR_INVALID_FREQUENCY_DEVIATION); @@ -366,63 +390,64 @@ int16_t Si443x::setRxBandwidth(float rxBw) { filterSet = ((rxBw - 60.286)/10.7000 + 0.5); // this is the "Lord help thee who tread 'ere" section - no way to approximate this mess - } else if(rxBw == 142.8) { + /// \todo float tolerance equality as macro? + } else if(abs(rxBw - 142.8) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 1; filterSet = 4; - } else if(rxBw == 167.8) { + } else if(abs(rxBw - 167.8) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 1; filterSet = 5; - } else if(rxBw == 181.1) { + } else if(abs(rxBw - 181.1) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 1; filterSet = 6; - } else if(rxBw == 191.5) { + } else if(abs(rxBw - 191.5) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 15; - } else if(rxBw == 225.1) { + } else if(abs(rxBw - 225.1) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 1; - } else if(rxBw == 248.8) { + } else if(abs(rxBw - 248.8) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 2; - } else if(rxBw == 269.3) { + } else if(abs(rxBw - 269.3) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 3; - } else if(rxBw == 284.8) { + } else if(abs(rxBw - 284.8) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 4; - } else if(rxBw == 335.5) { + } else if(abs(rxBw -335.5) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 8; - } else if(rxBw == 391.8) { + } else if(abs(rxBw - 391.8) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 9; - } else if(rxBw == 420.2) { + } else if(abs(rxBw - 420.2) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 10; - } else if(rxBw == 468.4) { + } else if(abs(rxBw - 468.4) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 11; - } else if(rxBw == 518.8) { + } else if(abs(rxBw - 518.8) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 12; - } else if(rxBw == 577.0) { + } else if(abs(rxBw - 577.0) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 13; - } else if(rxBw == 620.7) { + } else if(abs(rxBw - 620.7) <= 0.001) { bypass = SI443X_BYPASS_DEC_BY_3_ON; decRate = 0; filterSet = 14; @@ -460,8 +485,24 @@ int16_t Si443x::setSyncWord(uint8_t* syncWord, size_t len) { return(state); } +int16_t Si443x::setPreambleLength(uint8_t preambleLen) { + // Si443x configures preamble length in bytes + if(preambleLen % 8 != 0) { + return(ERR_INVALID_PREAMBLE_LENGTH); + } + + // set default preamble length + uint8_t preLenBytes = preambleLen / 8; + int16_t state = _mod->SPIsetRegValue(SI443X_REG_PREAMBLE_LENGTH, preLenBytes); + RADIOLIB_ASSERT(state); + + // set default preamble detection threshold to 50% of preamble length (in units of 4 bits) + uint8_t preThreshold = preambleLen / 4; + return(_mod->SPIsetRegValue(SI443X_REG_PREAMBLE_DET_CONTROL, preThreshold << 4, 7, 3)); +} + size_t Si443x::getPacketLength(bool update) { - // TODO variable length mode + /// \todo variable length mode if(!_packetLengthQueried && update) { _packetLength = _mod->SPIreadRegister(SI443X_REG_RECEIVED_PACKET_LENGTH); _packetLengthQueried = true; @@ -476,34 +517,65 @@ int16_t Si443x::setEncoding(uint8_t encoding) { RADIOLIB_ASSERT(state); // set encoding - // TODO - add inverted Manchester? + /// \todo - add inverted Manchester? switch(encoding) { - case 0: + case RADIOLIB_ENCODING_NRZ: return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_OFF | SI443X_WHITENING_OFF, 2, 0)); - case 1: + case RADIOLIB_ENCODING_MANCHESTER: return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_ON | SI443X_WHITENING_OFF, 2, 0)); - case 2: + case RADIOLIB_ENCODING_WHITENING: return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_OFF | SI443X_WHITENING_ON, 2, 0)); default: return(ERR_INVALID_ENCODING); } } -int16_t Si443x::setDataShaping(float sh) { +int16_t Si443x::setDataShaping(uint8_t sh) { // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); - if(sh == 0.0) { - // set modulation to FSK - return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_MODULATION_FSK, 1, 0)); - } else { - // set modulation to GFSK - // TODO implement fiter configuration - docs claim this should be possible, but seems undocumented - return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_MODULATION_GFSK, 1, 0)); + // set data shaping + switch(sh) { + case RADIOLIB_SHAPING_NONE: + return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_OFF | SI443X_WHITENING_OFF, 2, 0)); + case RADIOLIB_SHAPING_0_3: + case RADIOLIB_SHAPING_0_5: + case RADIOLIB_SHAPING_1_0: + /// \todo implement fiter configuration - docs claim this should be possible, but seems undocumented + return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_OFF | SI443X_WHITENING_ON, 2, 0)); + default: + return(ERR_INVALID_ENCODING); } } +void Si443x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) { + _mod->setRfSwitchPins(rxEn, txEn); +} + +uint8_t Si443x::random() { + // set mode to Rx + _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_RX_ON | SI443X_XTAL_ON); + + // wait a bit for the RSSI reading to stabilise + Module::delay(10); + + // read RSSI value 8 times, always keep just the least significant bit + uint8_t randByte = 0x00; + for(uint8_t i = 0; i < 8; i++) { + randByte |= ((_mod->SPIreadRegister(SI443X_REG_RSSI) & 0x01) << i); + } + + // set mode to standby + standby(); + + return(randByte); +} + +int16_t Si443x::getChipVersion() { + return(_mod->SPIgetRegValue(SI443X_REG_DEVICE_VERSION)); +} + int16_t Si443x::setFrequencyRaw(float newFreq) { // set mode to standby int16_t state = standby(); @@ -512,6 +584,7 @@ int16_t Si443x::setFrequencyRaw(float newFreq) { // check high/low band uint8_t bandSelect = SI443X_BAND_SELECT_LOW; uint8_t freqBand = (newFreq / 10) - 24; + _freq = newFreq; if(newFreq >= 480.0) { bandSelect = SI443X_BAND_SELECT_HIGH; freqBand = (newFreq / 20) - 24; @@ -551,7 +624,7 @@ bool Si443x::findChip() { RADIOLIB_DEBUG_PRINT(F(", expected 0x00")); RADIOLIB_DEBUG_PRINTLN(SI443X_DEVICE_VERSION, HEX); #endif - delay(1000); + Module::delay(10); i++; } } @@ -560,8 +633,8 @@ bool Si443x::findChip() { } void Si443x::clearIRQFlags() { - _mod->SPIreadRegister(SI443X_REG_INTERRUPT_STATUS_1); - _mod->SPIreadRegister(SI443X_REG_INTERRUPT_STATUS_2); + uint8_t buff[2]; + _mod->SPIreadRegisterBurst(SI443X_REG_INTERRUPT_STATUS_1, 2, buff); } int16_t Si443x::config() { @@ -570,8 +643,7 @@ int16_t Si443x::config() { RADIOLIB_ASSERT(state); // disable POR and chip ready interrupts - state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); - RADIOLIB_ASSERT(state); + _mod->SPIwriteRegister(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); // disable packet header state = _mod->SPIsetRegValue(SI443X_REG_HEADER_CONTROL_2, SI443X_SYNC_WORD_TIMEOUT_ON | SI443X_HEADER_LENGTH_HEADER_NONE, 7, 4); @@ -599,17 +671,16 @@ int16_t Si443x::updateClockRecovery() { uint8_t rxOsr_int = (uint8_t)rxOsr; uint8_t rxOsr_dec = 0; float rxOsr_temp = rxOsr; - if(rxOsr_temp - rxOsr_int >= 0.5) { + if((rxOsr_temp - rxOsr_int) >= 0.5) { rxOsr_dec |= 0x04; rxOsr_temp -= 0.5; } - if(rxOsr_temp - rxOsr_int >= 0.25) { + if((rxOsr_temp - rxOsr_int) >= 0.25) { rxOsr_dec |= 0x02; rxOsr_temp -= 0.25; } - if(rxOsr_temp - rxOsr_int >= 0.125) { + if((rxOsr_temp - rxOsr_int) >= 0.125) { rxOsr_dec |= 0x01; - rxOsr_temp -= 0.125; } uint16_t rxOsr_fixed = ((uint16_t)rxOsr_int << 3) | ((uint16_t)rxOsr_dec); @@ -667,3 +738,5 @@ int16_t Si443x::directMode() { state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_MODULATION_NONE, 1, 0); return(state); } + +#endif diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index df5ae4d0..f187d291 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_SI443X_H +#if !defined(_RADIOLIB_SI443X_H) #define _RADIOLIB_SI443X_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SI443X) + #include "../../Module.h" #include "../../protocols/PhysicalLayer/PhysicalLayer.h" @@ -576,9 +579,11 @@ class Si443x: public PhysicalLayer { \param rxBw Receiver bandwidth in kHz. + \param preambleLen Preamble Length in bits. + \returns \ref status_codes */ - int16_t begin(float br, float freqDev, float rxBw); + int16_t begin(float br, float freqDev, float rxBw, uint8_t preambleLen); /*! \brief Reset method. Will reset the chip to the default state using SDN pin. @@ -597,7 +602,7 @@ class Si443x: public PhysicalLayer { \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Binary receive method. Will attempt to receive arbitrary binary data up to 64 bytes long. @@ -609,7 +614,7 @@ class Si443x: public PhysicalLayer { \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len); + int16_t receive(uint8_t* data, size_t len) override; /*! \brief Sets the module to sleep to save power. %Module will not be able to transmit or receive any data while in sleep mode. @@ -624,7 +629,7 @@ class Si443x: public PhysicalLayer { \returns \ref status_codes */ - int16_t standby(); + int16_t standby() override; /*! \brief Enables direct transmission mode. While in direct mode, the module will not be able to transmit or receive packets. @@ -633,14 +638,14 @@ class Si443x: public PhysicalLayer { \returns \ref status_codes */ - int16_t transmitDirect(uint32_t frf = 0); + int16_t transmitDirect(uint32_t frf = 0) override; /*! \brief Enables direct reception mode. While in direct mode, the module will not be able to transmit or receive packets. \returns \ref status_codes */ - int16_t receiveDirect(); + int16_t receiveDirect() override; /*! \brief Disables direct mode and enables packet mode, allowing the module to receive packets. @@ -674,7 +679,7 @@ class Si443x: public PhysicalLayer { \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; /*! \brief Interrupt-driven receive method. IRQ will be activated when full valid packet is received. @@ -692,7 +697,7 @@ class Si443x: public PhysicalLayer { \returns \ref status_codes */ - int16_t readData(uint8_t* data, size_t len); + int16_t readData(uint8_t* data, size_t len) override; // configuration methods @@ -712,7 +717,7 @@ class Si443x: public PhysicalLayer { \returns \ref status_codes */ - int16_t setFrequencyDeviation(float freqDev); + int16_t setFrequencyDeviation(float freqDev) override; /*! \brief Sets receiver bandwidth. Allowed values range from 2.6 to 620.7 kHz. @@ -732,6 +737,15 @@ class Si443x: public PhysicalLayer { */ int16_t setSyncWord(uint8_t* syncWord, size_t len); + /*! + \brief Sets preamble length. + + \param preambleLen Preamble length to be set (in bits). + + \returns \ref status_codes + */ + int16_t setPreambleLength(uint8_t preambleLen); + /*! \brief Query modem for the packet length of received payload. @@ -739,37 +753,63 @@ class Si443x: public PhysicalLayer { \returns Length of last received packet in bytes. */ - size_t getPacketLength(bool update = true); + size_t getPacketLength(bool update = true) override; /*! \brief Sets transmission encoding. Only available in FSK mode. + Allowed values are RADIOLIB_ENCODING_NRZ, RADIOLIB_ENCODING_MANCHESTER and RADIOLIB_ENCODING_WHITENING. - \param encoding Encoding to be used. Set to 0 for NRZ, 1 for Manchester and 2 for whitening. + \param encoding Encoding to be used. \returns \ref status_codes */ - int16_t setEncoding(uint8_t encoding); + int16_t setEncoding(uint8_t encoding) override; /*! - \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. - Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. Only available in FSK mode with FSK modulation. + \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. Only available in FSK mode with FSK modulation. + Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5 or RADIOLIB_SHAPING_1_0. Set to RADIOLIB_SHAPING_NONE to disable data shaping. \param sh Gaussian shaping bandwidth-time product that will be used for data shaping \returns \ref status_codes */ - int16_t setDataShaping(float sh); + int16_t setDataShaping(uint8_t sh) override; + + /*! + \brief Some modules contain external RF switch controlled by two pins. This function gives RadioLib control over those two pins to automatically switch Rx and Tx state. + When using automatic RF switch control, DO NOT change the pin mode of rxEn or txEn from Arduino sketch! + + \param rxEn RX enable pin. + + \param txEn TX enable pin. + */ + void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn); + + /*! + \brief Get one truly random byte from RSSI noise. + + \returns TRNG byte. + */ + uint8_t random(); + + /*! + \brief Read version SPI register. Should return SI443X_DEVICE_VERSION (0x06) if Si443x is connected and working. + + \returns Version register contents or \ref status_codes + */ + int16_t getChipVersion(); #ifndef RADIOLIB_GODMODE protected: #endif Module* _mod; - float _br; - float _freqDev; + float _br = 0; + float _freqDev = 0; + float _freq = 0; - size_t _packetLength; - bool _packetLengthQueried; + size_t _packetLength = 0; + bool _packetLengthQueried = false; int16_t setFrequencyRaw(float newFreq); @@ -784,3 +824,5 @@ class Si443x: public PhysicalLayer { }; #endif + +#endif diff --git a/src/modules/XBee/XBee.cpp b/src/modules/XBee/XBee.cpp index aa365ea3..73bb934e 100644 --- a/src/modules/XBee/XBee.cpp +++ b/src/modules/XBee/XBee.cpp @@ -1,10 +1,9 @@ #include "XBee.h" +#if !defined(RADIOLIB_EXCLUDE_XBEE) XBee::XBee(Module* mod) { _mod = mod; - _frameID = 0x01; - _frameLength = 0; - _frameHeaderProcessed = false; + _packetData[0] = '\0'; } int16_t XBee::begin(long speed) { @@ -35,7 +34,7 @@ int16_t XBee::begin(long speed) { RADIOLIB_DEBUG_PRINTLN(state); RADIOLIB_DEBUG_PRINTLN(F("Resetting ...")); reset(); - delay(1000); + Module::delay(10); _mod->ATemptyBuffer(); i++; } @@ -52,10 +51,10 @@ int16_t XBee::begin(long speed) { } void XBee::reset() { - pinMode(_mod->getRst(), OUTPUT); - digitalWrite(_mod->getRst(), LOW); - delay(1); - digitalWrite(_mod->getRst(), HIGH); + Module::pinMode(_mod->getRst(), OUTPUT); + Module::digitalWrite(_mod->getRst(), LOW); + Module::delay(1); + Module::digitalWrite(_mod->getRst(), HIGH); } int16_t XBee::transmit(uint8_t* dest, const char* payload, uint8_t radius) { @@ -96,9 +95,9 @@ size_t XBee::available() { return(0); } - uint8_t header[3]; if(!_frameHeaderProcessed) { // read frame header + uint8_t header[3]; for(uint8_t i = 0; i < 3; i++) { header[i] = _mod->ModuleSerial->read(); } @@ -184,7 +183,8 @@ XBeeSerial::XBeeSerial(Module* mod) : ISerial(mod) { int16_t XBeeSerial::begin(long speed) { // set module properties - _mod->AtLineFeed = "\r"; + char lf[3] = "\r"; + memcpy(_mod->AtLineFeed, lf, strlen(lf)); _mod->baudrate = speed; _mod->init(RADIOLIB_USE_UART); @@ -216,11 +216,11 @@ int16_t XBeeSerial::begin(long speed) { } void XBeeSerial::reset() { - pinMode(_mod->getRst(), OUTPUT); - digitalWrite(_mod->getRst(), LOW); - delay(1); - digitalWrite(_mod->getRst(), HIGH); - pinMode(_mod->getRst(), INPUT); + Module::pinMode(_mod->getRst(), OUTPUT); + Module::digitalWrite(_mod->getRst(), LOW); + Module::delay(1); + Module::digitalWrite(_mod->getRst(), HIGH); + Module::pinMode(_mod->getRst(), INPUT); } int16_t XBeeSerial::setDestinationAddress(const char* destinationAddressHigh, const char* destinationAddressLow) { @@ -308,13 +308,13 @@ int16_t XBeeSerial::setPanId(const char* panId) { bool XBeeSerial::enterCmdMode() { for(uint8_t i = 0; i < 10; i++) { - delay(1000); + Module::delay(1000); _mod->ModuleSerial->write('+'); _mod->ModuleSerial->write('+'); _mod->ModuleSerial->write('+'); - delay(1000); + Module::delay(1000); if(_mod->ATgetResponse()) { return(true); @@ -374,13 +374,13 @@ void XBee::sendApiFrame(uint8_t type, uint8_t id, uint8_t* data, uint16_t length // calculate the checksum uint8_t checksum = 0; - for(uint16_t i = 3; i < frameLength - 1; i++) { + for(size_t i = 3; i < frameLength - 1; i++) { checksum += frame[i]; } frame[5 + length] = 0xFF - checksum; // send the frame - for(uint16_t i = 0; i < frameLength; i++) { + for(size_t i = 0; i < frameLength; i++) { _mod->ModuleSerial->write(frame[i]); } @@ -391,7 +391,7 @@ void XBee::sendApiFrame(uint8_t type, uint8_t id, uint8_t* data, uint16_t length } int16_t XBee::readApiFrame(uint8_t frameID, uint8_t codePos, uint16_t timeout) { - // TODO: modemStatus frames may be sent at any time, interfering with frame parsing. Add check to make sure this does not happen. + /// \todo modemStatus frames may be sent at any time, interfering with frame parsing. Add check to make sure this does not happen. // get number of bytes in response (must be enough to read the length field uint16_t numBytes = getNumBytes(timeout/2, 3); @@ -403,10 +403,10 @@ int16_t XBee::readApiFrame(uint8_t frameID, uint8_t codePos, uint16_t timeout) { numBytes++; // wait until all response bytes are available (5s timeout) - uint32_t start = millis(); + uint32_t start = Module::millis(); while(_mod->ModuleSerial->available() < (int16_t)numBytes) { - yield(); - if(millis() - start >= timeout/2) { + Module::yield(); + if(Module::millis() - start >= timeout/2) { return(ERR_FRAME_MALFORMED); } } @@ -455,10 +455,10 @@ int16_t XBee::readApiFrame(uint8_t frameID, uint8_t codePos, uint16_t timeout) { uint16_t XBee::getNumBytes(uint32_t timeout, size_t minBytes) { // wait for available data - uint32_t start = millis(); + uint32_t start = Module::millis(); while((size_t)_mod->ModuleSerial->available() < minBytes) { - yield(); - if(millis() - start >= timeout) { + Module::yield(); + if(Module::millis() - start >= timeout) { return(0); } } @@ -468,7 +468,7 @@ uint16_t XBee::getNumBytes(uint32_t timeout, size_t minBytes) { uint8_t i = 0; RADIOLIB_DEBUG_PRINT(F("reading frame length: ")); while(_mod->ModuleSerial->available() > 0) { - yield(); + Module::yield(); uint8_t b = _mod->ModuleSerial->read(); RADIOLIB_DEBUG_PRINT(b, HEX); RADIOLIB_DEBUG_PRINT('\t'); @@ -481,3 +481,5 @@ uint16_t XBee::getNumBytes(uint32_t timeout, size_t minBytes) { return((resp[1] << 8) | resp[2]); } + +#endif diff --git a/src/modules/XBee/XBee.h b/src/modules/XBee/XBee.h index 1cb9607a..15d7cb92 100644 --- a/src/modules/XBee/XBee.h +++ b/src/modules/XBee/XBee.h @@ -1,4 +1,4 @@ -#ifndef _RADIOLIB_XBEE_H +#if !defined(_RADIOLIB_XBEE_H) && !defined(RADIOLIB_EXCLUDE_XBEE) #define _RADIOLIB_XBEE_H #include "../../ISerial.h" @@ -79,7 +79,7 @@ class XBeeSerial: public ISerial { \param panId 8-byte PAN ID to be used, in the form of uppercase hexadecimal string (i.e. 16 characters). */ - int16_t setPanId(const char* panID); + int16_t setPanId(const char* panId); #ifndef RADIOLIB_GODMODE private: @@ -170,22 +170,22 @@ class XBee { \param panId 8-byte PAN ID to be used, in the form of uppercase hexadecimal string (i.e. 16 characters). */ - int16_t setPanId(uint8_t* panID); + int16_t setPanId(uint8_t* panId); #ifndef RADIOLIB_GODMODE private: #endif Module* _mod; - uint8_t _frameID; - size_t _frameLength; - bool _frameHeaderProcessed; + uint8_t _frameID = 0x01; + size_t _frameLength = 0; + bool _frameHeaderProcessed = false; #ifdef RADIOLIB_STATIC_ONLY char _packetData[RADIOLIB_STATIC_ARRAY_SIZE]; #else char* _packetData = new char[0]; #endif - uint8_t _packetSource[8]; + uint8_t _packetSource[8] = {0, 0, 0, 0, 0, 0, 0, 0}; int16_t confirmChanges(); diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index ab6cc6b6..a251ca17 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -1,4 +1,5 @@ #include "nRF24.h" +#if !defined(RADIOLIB_EXCLUDE_NRF24) nRF24::nRF24(Module* mod) : PhysicalLayer(NRF24_FREQUENCY_STEP_SIZE, NRF24_MAX_PACKET_LENGTH) { _mod = mod; @@ -15,15 +16,16 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW Module::digitalWrite(_mod->getRst(), LOW); // wait for minimum power-on reset duration - delay(100); + Module::delay(100); // check SPI connection int16_t val = _mod->SPIgetRegValue(NRF24_REG_SETUP_AW); if(!((val >= 0) && (val <= 3))) { RADIOLIB_DEBUG_PRINTLN(F("No nRF24 found!")); - _mod->term(); + _mod->term(RADIOLIB_USE_SPI); return(ERR_CHIP_NOT_FOUND); } + RADIOLIB_DEBUG_PRINTLN(F("M\tnRF24")); // configure settings inaccessible by public API int16_t state = config(); @@ -32,6 +34,7 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW // set mode to standby state = standby(); RADIOLIB_ASSERT(state); + // set frequency state = setFrequency(freq); RADIOLIB_ASSERT(state); @@ -46,6 +49,15 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW // set address width state = setAddressWidth(addrWidth); + RADIOLIB_ASSERT(state); + + // set CRC + state = setCrcFiltering(true); + RADIOLIB_ASSERT(state); + + // set auto-ACK on all pipes + state = setAutoAck(true); + RADIOLIB_ASSERT(state); return(state); } @@ -58,7 +70,7 @@ int16_t nRF24::standby() { // make sure carrier output is disabled _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_CONT_WAVE_OFF, 7, 7); _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_PLL_LOCK_OFF, 4, 4); - digitalWrite(_mod->getRst(), LOW); + Module::digitalWrite(_mod->getRst(), LOW); // use standby-1 mode return(_mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_POWER_UP, 1, 1)); @@ -70,9 +82,9 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ASSERT(state); // wait until transmission is finished - uint32_t start = micros(); - while(digitalRead(_mod->getIrq())) { - yield(); + uint32_t start = Module::micros(); + while(Module::digitalRead(_mod->getIrq())) { + Module::yield(); // check maximum number of retransmits if(getStatus(NRF24_MAX_RT)) { @@ -82,7 +94,7 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { } // check timeout: 15 retries * 4ms (max Tx time as per datasheet) - if(micros() - start >= 60000) { + if(Module::micros() - start >= 60000) { standby(); clearIRQ(); return(ERR_TX_TIMEOUT); @@ -101,12 +113,12 @@ int16_t nRF24::receive(uint8_t* data, size_t len) { RADIOLIB_ASSERT(state); // wait for Rx_DataReady or timeout - uint32_t start = micros(); - while(digitalRead(_mod->getIrq())) { - yield(); - + uint32_t start = Module::micros(); + while(Module::digitalRead(_mod->getIrq())) { + Module::yield(); + // check timeout: 15 retries * 4ms (max Tx time as per datasheet) - if(micros() - start >= 60000) { + if(Module::micros() - start >= 60000) { standby(); clearIRQ(); return(ERR_RX_TIMEOUT); @@ -128,7 +140,7 @@ int16_t nRF24::transmitDirect(uint32_t frf) { int16_t state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PTX, 0, 0); state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_CONT_WAVE_ON, 7, 7); state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_PLL_LOCK_ON, 4, 4); - digitalWrite(_mod->getRst(), HIGH); + Module::digitalWrite(_mod->getRst(), HIGH); return(state); } @@ -139,7 +151,7 @@ int16_t nRF24::receiveDirect() { } void nRF24::setIrqAction(void (*func)(void)) { - attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, FALLING); + Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, FALLING); } int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { @@ -175,9 +187,9 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { SPIwriteTxPayload(data, len); // CE high to start transmitting - digitalWrite(_mod->getRst(), HIGH); - delay(1); - digitalWrite(_mod->getRst(), LOW); + Module::digitalWrite(_mod->getRst(), HIGH); + Module::delay(1); + Module::digitalWrite(_mod->getRst(), LOW); return(state); } @@ -200,10 +212,10 @@ int16_t nRF24::startReceive() { SPItransfer(NRF24_CMD_FLUSH_RX); // CE high to start receiving - digitalWrite(_mod->getRst(), HIGH); + Module::digitalWrite(_mod->getRst(), HIGH); // wait to enter Rx state - delay(1); + Module::delay(1); return(state); } @@ -446,39 +458,39 @@ int16_t nRF24::setCrcFiltering(bool crcOn) { } // Disable CRC - return _mod->SPIsetRegValue(NRF24_REG_CONFIG, crcOn ? NRF24_CRC_ON : NRF24_CRC_OFF, 3, 3); + return _mod->SPIsetRegValue(NRF24_REG_CONFIG, (crcOn ? NRF24_CRC_ON : NRF24_CRC_OFF), 3, 3); } int16_t nRF24::setAutoAck(bool autoAckOn){ - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_ALL_ON : NRF24_AA_ALL_OFF, 5, 0); + return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_ALL_ON : NRF24_AA_ALL_OFF), 5, 0); } int16_t nRF24::setAutoAck(uint8_t pipeNum, bool autoAckOn){ switch(pipeNum) { case 0: - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_P0_ON : NRF24_AA_P0_OFF, 0, 0); + return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_P0_ON : NRF24_AA_P0_OFF), 0, 0); break; case 1: - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_P1_ON : NRF24_AA_P1_OFF, 1, 1); + return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_P1_ON : NRF24_AA_P1_OFF), 1, 1); break; case 2: - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_P2_ON : NRF24_AA_P2_OFF, 2, 2); + return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_P2_ON : NRF24_AA_P2_OFF), 2, 2); break; case 3: - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_P3_ON : NRF24_AA_P3_OFF, 3, 3); + return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_P3_ON : NRF24_AA_P3_OFF), 3, 3); break; case 4: - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_P4_ON : NRF24_AA_P4_OFF, 4, 4); + return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_P4_ON : NRF24_AA_P4_OFF), 4, 4); break; case 5: - return _mod->SPIsetRegValue(NRF24_REG_EN_AA, autoAckOn ? NRF24_AA_P5_ON : NRF24_AA_P5_OFF, 5, 5); + return _mod->SPIsetRegValue(NRF24_REG_EN_AA, (autoAckOn ? NRF24_AA_P5_ON : NRF24_AA_P5_OFF), 5, 5); break; default: return (ERR_INVALID_PIPE_NUMBER); } } -int16_t nRF24::setDataShaping(float sh) { +int16_t nRF24::setDataShaping(uint8_t sh) { // nRF24 is unable to set data shaping // this method is implemented only for PhysicalLayer compatibility (void)sh; @@ -492,6 +504,12 @@ int16_t nRF24::setEncoding(uint8_t encoding) { return(ERR_NONE); } +uint8_t nRF24::random() { + // nRF24 is unable to measure RSSI, hence no TRNG + // this method is implemented only for PhysicalLayer compatibility + return(0); +} + void nRF24::clearIRQ() { // clear status bits _mod->SPIsetRegValue(NRF24_REG_STATUS, NRF24_RX_DR | NRF24_TX_DS | NRF24_MAX_RT, 6, 4); @@ -528,7 +546,7 @@ int16_t nRF24::config() { // power up _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_POWER_UP, 1, 1); - delay(5); + Module::delay(5); return(state); } @@ -547,7 +565,7 @@ void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* data SPISettings spiSettings = _mod->getSpiSettings(); // start transfer - digitalWrite(_mod->getCs(), LOW); + Module::digitalWrite(_mod->getCs(), LOW); spi->beginTransaction(spiSettings); // send command @@ -566,5 +584,7 @@ void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* data // stop transfer spi->endTransaction(); - digitalWrite(_mod->getCs(), HIGH); + Module::digitalWrite(_mod->getCs(), HIGH); } + +#endif diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index a3205f78..d4943a04 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -1,4 +1,4 @@ -#ifndef _RADIOLIB_NRF24_H +#if !defined(_RADIOLIB_NRF24_H) && !defined(RADIOLIB_EXCLUDE_NRF24) #define _RADIOLIB_NRF24_H #include "../../Module.h" @@ -189,7 +189,7 @@ class nRF24: public PhysicalLayer { \param mod Instance of Module that will be used to communicate with the radio. */ - nRF24(Module* module); + nRF24(Module* mod); // basic methods @@ -220,7 +220,7 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ - int16_t standby(); + int16_t standby() override; /*! \brief Blocking binary transmit method. @@ -234,7 +234,7 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ - int16_t transmit(uint8_t* data, size_t len, uint8_t addr); + int16_t transmit(uint8_t* data, size_t len, uint8_t addr) override; /*! \brief Blocking binary receive method. @@ -246,7 +246,7 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ - int16_t receive(uint8_t* data, size_t len); + int16_t receive(uint8_t* data, size_t len) override; /*! \brief Starts direct mode transmission. @@ -255,14 +255,14 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ - int16_t transmitDirect(uint32_t frf = 0); + int16_t transmitDirect(uint32_t frf = 0) override; /*! \brief Dummy direct mode reception method, to ensure PhysicalLayer compatibility. \returns \ref status_codes */ - int16_t receiveDirect(); + int16_t receiveDirect() override; // interrupt methods @@ -285,7 +285,7 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ - int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr); + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr) override; /*! \brief Interrupt-driven receive method. IRQ will be activated when full packet is received. @@ -303,7 +303,7 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ - int16_t readData(uint8_t* data, size_t len); + int16_t readData(uint8_t* data, size_t len) override; // configuration methods @@ -406,7 +406,7 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ - int16_t setFrequencyDeviation(float freqDev); + int16_t setFrequencyDeviation(float freqDev) override; /*! \brief Query modem for the packet length of received payload. @@ -415,8 +415,7 @@ class nRF24: public PhysicalLayer { \returns Length of last received packet in bytes. */ - size_t getPacketLength(bool update = true); - + size_t getPacketLength(bool update = true) override; /*! \brief Enable CRC filtering and generation. @@ -454,7 +453,7 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ - int16_t setDataShaping(float sh); + int16_t setDataShaping(uint8_t sh) override; /*! \brief Dummy encoding configuration method, to ensure PhysicalLayer compatibility. @@ -463,14 +462,21 @@ class nRF24: public PhysicalLayer { \returns \ref status_codes */ - int16_t setEncoding(uint8_t encoding); + int16_t setEncoding(uint8_t encoding) override; + + /*! + \brief Dummy random method, to ensure PhysicalLayer compatibility. + + \returns Always returns 0. + */ + uint8_t random(); #ifndef RADIOLIB_GODMODE private: #endif Module* _mod; - uint8_t _addrWidth; + uint8_t _addrWidth = 0; int16_t config(); void clearIRQ(); diff --git a/src/protocols/AFSK/AFSK.cpp b/src/protocols/AFSK/AFSK.cpp new file mode 100644 index 00000000..831a278d --- /dev/null +++ b/src/protocols/AFSK/AFSK.cpp @@ -0,0 +1,27 @@ +#include "AFSK.h" +#if !defined(RADIOLIB_EXCLUDE_AFSK) + +AFSKClient::AFSKClient(PhysicalLayer* phy, RADIOLIB_PIN_TYPE pin): _pin(pin) { + _phy = phy; +} + +int16_t AFSKClient::tone(uint16_t freq, bool autoStart) { + if(freq == 0) { + return(ERR_INVALID_FREQUENCY); + } + + if(autoStart) { + int16_t state = _phy->transmitDirect(); + RADIOLIB_ASSERT(state); + } + + Module::tone(_pin, freq); + return(ERR_NONE); +} + +int16_t AFSKClient::noTone() { + Module::noTone(_pin); + return(_phy->standby()); +} + +#endif diff --git a/src/protocols/AFSK/AFSK.h b/src/protocols/AFSK/AFSK.h new file mode 100644 index 00000000..d92ffe65 --- /dev/null +++ b/src/protocols/AFSK/AFSK.h @@ -0,0 +1,62 @@ +#if !defined(_RADIOLIB_AFSK_H) +#define _RADIOLIB_AFSK_H + +#include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_AFSK) + +#include "../../Module.h" + +#include "../PhysicalLayer/PhysicalLayer.h" + +/*! + \class AFSKClient + + \brief Client for audio-based transmissions. Requires Arduino tone() function, and a module capable of direct mode transmission using DIO pins. +*/ +class AFSKClient { + public: + /*! + \brief Default contructor. + + \param phy Pointer to the wireless module providing PhysicalLayer communication. + + \param pin The pin that will be used for audio output. + */ + AFSKClient(PhysicalLayer* phy, RADIOLIB_PIN_TYPE pin); + + /*! + \brief Start transmitting audio tone. + + \param freq Frequency of the tone in Hz. + + \param autoStart Whether to automatically enter transmission mode. Defaults to true. + + \returns \ref status_codes + */ + int16_t tone(uint16_t freq, bool autoStart = true); + + /*! + \brief Stops transmitting audio tone. + + \returns \ref status_codes + */ + int16_t noTone(); + +#ifndef RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* _phy; + RADIOLIB_PIN_TYPE _pin; + + // allow specific classes access the private PhysicalLayer pointer + friend class RTTYClient; + friend class MorseClient; + friend class HellClient; + friend class SSTVClient; + friend class AX25Client; +}; + +#endif + +#endif diff --git a/src/protocols/AX25/AX25.cpp b/src/protocols/AX25/AX25.cpp index 7c6a7933..5397a2d1 100644 --- a/src/protocols/AX25/AX25.cpp +++ b/src/protocols/AX25/AX25.cpp @@ -1,4 +1,5 @@ #include "AX25.h" +#if !defined(RADIOLIB_EXCLUDE_AX25) AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control) : AX25Frame(destCallsign, destSSID, srcCallsign, srcSSID, control, 0, NULL, 0) { @@ -48,6 +49,10 @@ AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* src } } +AX25Frame::AX25Frame(const AX25Frame& frame) { + *this = frame; +} + AX25Frame::~AX25Frame() { #ifndef RADIOLIB_STATIC_ONLY // deallocate info field @@ -66,6 +71,41 @@ AX25Frame::~AX25Frame() { #endif } +AX25Frame& AX25Frame::operator=(const AX25Frame& frame) { + // destination callsign/SSID + memcpy(this->destCallsign, frame.destCallsign, strlen(frame.destCallsign)); + this->destCallsign[strlen(frame.destCallsign)] = '\0'; + this->destSSID = frame.destSSID; + + // source callsign/SSID + memcpy(this->srcCallsign, frame.srcCallsign, strlen(frame.srcCallsign)); + this->srcCallsign[strlen(frame.srcCallsign)] = '\0'; + this->srcSSID = frame.srcSSID; + + // repeaters + this->numRepeaters = frame.numRepeaters; + for(uint8_t i = 0; i < this->numRepeaters; i++) { + memcpy(this->repeaterCallsigns[i], frame.repeaterCallsigns[i], strlen(frame.repeaterCallsigns[i])); + } + memcpy(this->repeaterSSIDs, frame.repeaterSSIDs, this->numRepeaters); + + // control field + this->control = frame.control; + + // sequence numbers + this->rcvSeqNumber = frame.rcvSeqNumber; + this->sendSeqNumber = frame.sendSeqNumber; + + // PID field + this->protocolID = frame.protocolID; + + // info field + this->infoLen = frame.infoLen; + memcpy(this->info, frame.info, this->infoLen); + + return(*this); +} + int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters) { // check number of repeaters if((numRepeaters < 1) || (numRepeaters > 8)) { @@ -73,8 +113,7 @@ int16_t AX25Frame::setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs } // check repeater configuration - if(!(((repeaterCallsigns == NULL) && (repeaterSSIDs == NULL) && (numRepeaters == 0)) || - ((repeaterCallsigns != NULL) && (repeaterSSIDs != NULL) && (numRepeaters != 0)))) { + if((repeaterCallsigns == NULL) || (repeaterSSIDs == NULL)) { return(ERR_INVALID_NUM_REPEATERS); } for(uint16_t i = 0; i < numRepeaters; i++) { @@ -112,8 +151,18 @@ void AX25Frame::setSendSequence(uint8_t seqNumber) { AX25Client::AX25Client(PhysicalLayer* phy) { _phy = phy; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + _audio = nullptr; + #endif } +#if !defined(RADIOLIB_EXCLUDE_AFSK) +AX25Client::AX25Client(AFSKClient* audio) { + _phy = audio->_phy; + _audio = audio; +} +#endif + int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t preambleLen) { // set source SSID _srcSSID = srcSSID; @@ -130,11 +179,16 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t prea // save preamble length _preambleLen = preambleLen; - // disable physical layer data shaping and set encoding to NRZ - int16_t state = _phy->setDataShaping(0.0); - RADIOLIB_ASSERT(state); + // set module frequency deviation to 0 if using FSK + int16_t state = ERR_NONE; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio == nullptr) { + state = _phy->setFrequencyDeviation(0); + RADIOLIB_ASSERT(state); - state = _phy->setEncoding(0); + state = _phy->setEncoding(0); + } + #endif return(state); } @@ -154,7 +208,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { if(strlen(frame->destCallsign) > AX25_MAX_CALLSIGN_LEN) { return(ERR_INVALID_CALLSIGN); } - + // check repeater configuration #ifndef RADIOLIB_STATIC_ONLY if(!(((frame->repeaterCallsigns == NULL) && (frame->repeaterSSIDs == NULL) && (frame->numRepeaters == 0)) || @@ -180,7 +234,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // set destination callsign - all address field bytes are shifted by one bit to make room for HDLC address extension bit memset(frameBuffPtr, ' ' << 1, AX25_MAX_CALLSIGN_LEN); - for(uint8_t i = 0; i < strlen(frame->destCallsign); i++) { + for(size_t i = 0; i < strlen(frame->destCallsign); i++) { *(frameBuffPtr + i) = frame->destCallsign[i] << 1; } frameBuffPtr += AX25_MAX_CALLSIGN_LEN; @@ -190,7 +244,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // set source callsign - all address field bytes are shifted by one bit to make room for HDLC address extension bit memset(frameBuffPtr, ' ' << 1, AX25_MAX_CALLSIGN_LEN); - for(uint8_t i = 0; i < strlen(frame->srcCallsign); i++) { + for(size_t i = 0; i < strlen(frame->srcCallsign); i++) { *(frameBuffPtr + i) = frame->srcCallsign[i] << 1; } frameBuffPtr += AX25_MAX_CALLSIGN_LEN; @@ -201,7 +255,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { // set repeater callsigns for(uint16_t i = 0; i < frame->numRepeaters; i++) { memset(frameBuffPtr, ' ' << 1, AX25_MAX_CALLSIGN_LEN); - for(uint8_t j = 0; j < strlen(frame->repeaterCallsigns[i]); j++) { + for(size_t j = 0; j < strlen(frame->repeaterCallsigns[i]); j++) { *(frameBuffPtr + j) = frame->repeaterCallsigns[i][j] << 1; } frameBuffPtr += AX25_MAX_CALLSIGN_LEN; @@ -254,10 +308,13 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { uint8_t stuffedFrameBuff[RADIOLIB_STATIC_ARRAY_SIZE]; #endif + // initialize buffer to all zeros + memset(stuffedFrameBuff, 0x00, _preambleLen + 1 + (6*frameBuffLen)/5 + 2); + // stuff bits (skip preamble and both flags) uint16_t stuffedFrameBuffLenBits = 8*(_preambleLen + 1); uint8_t count = 0; - for(uint16_t i = 0; i < frameBuffLen + 2; i++) { + for(size_t i = 0; i < frameBuffLen + 2; i++) { for(int8_t shift = 7; shift >= 0; shift--) { uint16_t stuffedFrameBuffPos = stuffedFrameBuffLenBits + 7 - 2*(stuffedFrameBuffLenBits%8); if((frameBuff[i] >> shift) & 0x01) { @@ -333,7 +390,37 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { } // transmit - int16_t state = _phy->transmit(stuffedFrameBuff, stuffedFrameBuffLen); + int16_t state = ERR_NONE; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio != nullptr) { + _phy->transmitDirect(); + + // iterate over all bytes in the buffer + for(uint32_t i = 0; i < stuffedFrameBuffLen; i++) { + + // check each bit + for(uint16_t mask = 0x80; mask >= 0x01; mask >>= 1) { + uint32_t start = Module::micros(); + if(stuffedFrameBuff[i] & mask) { + _audio->tone(AX25_AFSK_MARK, false); + } else { + _audio->tone(AX25_AFSK_SPACE, false); + } + while(Module::micros() - start < AX25_AFSK_TONE_DURATION) { + Module::yield(); + } + } + + } + + _audio->noTone(); + + } else { + #endif + state = _phy->transmit(stuffedFrameBuff, stuffedFrameBuffLen); + #if !defined(RADIOLIB_EXCLUDE_AFSK) + } + #endif // deallocate memory #ifndef RADIOLIB_STATIC_ONLY @@ -350,8 +437,8 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) { https://creativecommons.org/licenses/by-sa/4.0/ */ uint16_t AX25Client::getFrameCheckSequence(uint8_t* buff, size_t len) { - uint8_t outBit = 0; - uint16_t mask = 0x0000; + uint8_t outBit; + uint16_t mask; uint16_t shiftReg = CRC_CCITT_INIT; for(size_t i = 0; i < len; i++) { @@ -380,3 +467,5 @@ uint16_t AX25Client::flipBits16(uint16_t i) { i = (i & 0xAAAA) >> 1 | (i & 0x5555) << 1; return i; } + +#endif diff --git a/src/protocols/AX25/AX25.h b/src/protocols/AX25/AX25.h index bfe322af..8f005b3f 100644 --- a/src/protocols/AX25/AX25.h +++ b/src/protocols/AX25/AX25.h @@ -1,8 +1,12 @@ -#ifndef _RADIOLIB_AX25_H +#if !defined(_RADIOLIB_AX25_H) #define _RADIOLIB_AX25_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_AX25) + #include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" // macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html #define SET_BIT_IN_ARRAY(A, k) ( A[(k/8)] |= (1 << (k%8)) ) @@ -69,6 +73,13 @@ #define AX25_PID_NO_LAYER_3 0xF0 #define AX25_PID_ESCAPE_CHARACTER 0xFF +// AFSK tones in Hz +#define AX25_AFSK_MARK 1200 +#define AX25_AFSK_SPACE 2200 + +// tone duration in us (for 1200 baud AFSK) +#define AX25_AFSK_TONE_DURATION 833 + /*! \class AX25Frame @@ -213,11 +224,25 @@ class AX25Frame { */ AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, uint8_t* info, uint16_t infoLen); + /*! + \brief Copy constructor. + + \param frame AX25Frame instance to copy. + */ + AX25Frame(const AX25Frame& frame); + /*! \brief Default destructor. */ ~AX25Frame(); + /*! + \brief Overload for assignment operator. + + \param frame rvalue AX25Frame. + */ + AX25Frame& operator=(const AX25Frame& frame); + /*! \brief Method to set the repeater callsigns and SSIDs. @@ -254,11 +279,20 @@ class AX25Frame { class AX25Client { public: /*! - \brief Default constructor. + \brief Constructor for 2-FSK mode. \param phy Pointer to the wireless module providing PhysicalLayer communication. */ - AX25Client(PhysicalLayer* phy); + explicit AX25Client(PhysicalLayer* phy); + + #if !defined(RADIOLIB_EXCLUDE_AFSK) + /*! + \brief Constructor for AFSK mode. + + \param audio Pointer to the AFSK instance providing audio. + */ + explicit AX25Client(AFSKClient* audio); + #endif // basic methods @@ -301,14 +335,19 @@ class AX25Client { private: #endif PhysicalLayer* _phy; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + AFSKClient* _audio; + #endif - char _srcCallsign[AX25_MAX_CALLSIGN_LEN + 1]; - uint8_t _srcSSID; - uint16_t _preambleLen; + char _srcCallsign[AX25_MAX_CALLSIGN_LEN + 1] = {0, 0, 0, 0, 0, 0, 0}; + uint8_t _srcSSID = 0; + uint16_t _preambleLen = 0; - uint16_t getFrameCheckSequence(uint8_t* buff, size_t len); - uint8_t flipBits(uint8_t b); - uint16_t flipBits16(uint16_t i); + static uint16_t getFrameCheckSequence(uint8_t* buff, size_t len); + static uint8_t flipBits(uint8_t b); + static uint16_t flipBits16(uint16_t i); }; #endif + +#endif diff --git a/src/protocols/HTTP/HTTP.cpp b/src/protocols/HTTP/HTTP.cpp index 9200acb0..fae9d8ae 100644 --- a/src/protocols/HTTP/HTTP.cpp +++ b/src/protocols/HTTP/HTTP.cpp @@ -1,4 +1,5 @@ #include "HTTP.h" +#if !defined(RADIOLIB_EXCLUDE_HTTP) HTTPClient::HTTPClient(TransportLayer* tl, uint16_t port) { _tl = tl; @@ -63,8 +64,6 @@ int16_t HTTPClient::get(const char* url, String& response) { return(state); } - //delay(1000); - // get the response length size_t numBytes = _tl->getNumBytes(); if(numBytes == 0) { @@ -140,8 +139,8 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response, } // build the POST request - char contentLengthStr[8]; - itoa(strlen(content), contentLengthStr, 10); + char contentLengthStr[12]; + sprintf(contentLengthStr, "%u", (uint16_t)strlen(content)); char* request = new char[strlen(endpoint) + strlen(host) + strlen(contentType) + strlen(contentLengthStr) + strlen(content) + 64 + 1]; strcpy(request, "POST "); strcat(request, endpoint); @@ -216,3 +215,5 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response, statusStr[3] = 0x00; return(atoi(statusStr)); } + +#endif diff --git a/src/protocols/HTTP/HTTP.h b/src/protocols/HTTP/HTTP.h index 118df7ec..0f30a43e 100644 --- a/src/protocols/HTTP/HTTP.h +++ b/src/protocols/HTTP/HTTP.h @@ -1,9 +1,11 @@ -#ifndef _RADIOLIB_HTTP_H +#if !defined(_RADIOLIB_HTTP_H) #define _RADIOLIB_HTTP_H #include "../../TypeDef.h" -#include "../TransportLayer/TransportLayer.h" +#if !defined(RADIOLIB_EXCLUDE_HTTP) + +#include "../TransportLayer/TransportLayer.h" /*! \class HTTPClient @@ -19,7 +21,7 @@ class HTTPClient { \param port Port to be used for HTTP. Defaults to 80. */ - HTTPClient(TransportLayer* tl, uint16_t port = 80); + explicit HTTPClient(TransportLayer* tl, uint16_t port = 80); /*! \brief Sends HTTP GET request. @@ -67,3 +69,5 @@ class HTTPClient { }; #endif + +#endif diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp index ffc30ee3..d9caa41e 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.cpp +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -1,18 +1,36 @@ #include "Hellschreiber.h" +#if !defined(RADIOLIB_EXCLUDE_HELLSCHREIBER) HellClient::HellClient(PhysicalLayer* phy) { _phy = phy; + + #if !defined(RADIOLIB_EXCLUDE_AFSK) + _audio = nullptr; + #endif } +#if !defined(RADIOLIB_EXCLUDE_AFSK) +HellClient::HellClient(AFSKClient* audio) { + _phy = audio->_phy; + _audio = audio; +} +#endif + int16_t HellClient::begin(float base, float rate) { // calculate 24-bit frequency + _baseHz = base; _base = (base * 1000000.0) / _phy->getFreqStep(); // calculate "pixel" duration _pixelDuration = 1000000.0/rate; - // set module frequency deviation to 0 - int16_t state = _phy->setFrequencyDeviation(0); + // set module frequency deviation to 0 if using FSK + int16_t state = ERR_NONE; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio == nullptr) { + state = _phy->setFrequencyDeviation(0); + } + #endif return(state); } @@ -21,18 +39,18 @@ size_t HellClient::printGlyph(uint8_t* buff) { // print the character for(uint8_t mask = 0x40; mask >= 0x01; mask >>= 1) { for(int8_t i = HELL_FONT_HEIGHT - 1; i >= 0; i--) { - uint32_t start = micros(); + uint32_t start = Module::micros(); if(buff[i] & mask) { - _phy->transmitDirect(_base); + transmitDirect(_base, _baseHz); } else { - _phy->standby(); + standby(); } - while(micros() - start < _pixelDuration); + while(Module::micros() - start < _pixelDuration); } } // make sure transmitter is off - _phy->standby(); + standby(); return(1); } @@ -67,7 +85,7 @@ size_t HellClient::write(uint8_t b) { uint8_t buff[HELL_FONT_WIDTH]; buff[0] = 0x00; for(uint8_t i = 0; i < HELL_FONT_WIDTH - 2; i++) { - buff[i + 1] = pgm_read_byte(&HellFont[pos][i]); + buff[i + 1] = RADIOLIB_PROGMEM_READ_BYTE(&HellFont[pos][i]); } buff[HELL_FONT_WIDTH - 1] = 0x00; @@ -79,7 +97,7 @@ size_t HellClient::print(__FlashStringHelper* fstr) { PGM_P p = reinterpret_cast(fstr); size_t n = 0; while(true) { - char c = pgm_read_byte(p++); + char c = RADIOLIB_PROGMEM_READ_BYTE(p++); if(c == '\0') { break; } @@ -140,7 +158,8 @@ size_t HellClient::print(double n, int digits) { } size_t HellClient::println(void) { - return(0); + // Hellschreiber has no concept of "line ending", print one space instead + return(HellClient::print(' ')); } size_t HellClient::println(__FlashStringHelper* fstr) { @@ -269,3 +288,23 @@ size_t HellClient::printFloat(double number, uint8_t digits) { return n; } + +int16_t HellClient::transmitDirect(uint32_t freq, uint32_t freqHz) { + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio != nullptr) { + return(_audio->tone(freqHz)); + } + #endif + return(_phy->transmitDirect(freq)); +} + +int16_t HellClient::standby() { + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio != nullptr) { + return(_audio->noTone()); + } + #endif + return(_phy->standby()); +} + +#endif diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h index 9b14c27e..f7c634cb 100644 --- a/src/protocols/Hellschreiber/Hellschreiber.h +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -1,8 +1,12 @@ -#ifndef _RADIOLIB_HELLSCHREIBER_H +#if !defined(_RADIOLIB_HELLSCHREIBER_H) #define _RADIOLIB_HELLSCHREIBER_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_HELLSCHREIBER) + #include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" #define HELL_FONT_WIDTH 7 #define HELL_FONT_HEIGHT 7 @@ -10,7 +14,7 @@ // font definition: characters are stored in rows, // least significant byte of each character is the first row // Hellschreiber use 7x7 characters, but this simplified font uses only 5x5 - the extra bytes aren't stored -static const uint8_t HellFont[64][HELL_FONT_WIDTH - 2] PROGMEM = { +static const uint8_t HellFont[64][HELL_FONT_WIDTH - 2] RADIOLIB_PROGMEM = { { 0b0000000, 0b0000000, 0b0000000, 0b0000000, 0b0000000 }, // space { 0b0001000, 0b0001000, 0b0001000, 0b0000000, 0b0001000 }, // ! { 0b0010100, 0b0010100, 0b0000000, 0b0000000, 0b0000000 }, // " @@ -85,18 +89,27 @@ static const uint8_t HellFont[64][HELL_FONT_WIDTH - 2] PROGMEM = { class HellClient { public: /*! - \brief Default constructor. + \brief Constructor for 2-FSK mode. \param phy Pointer to the wireless module providing PhysicalLayer communication. */ - HellClient(PhysicalLayer* phy); + explicit HellClient(PhysicalLayer* phy); + + #if !defined(RADIOLIB_EXCLUDE_AFSK) + /*! + \brief Constructor for AFSK mode. + + \param audio Pointer to the AFSK instance providing audio. + */ + explicit HellClient(AFSKClient* audio); + #endif // basic methods /*! \brief Initialization method. - \param base Base RF frequency to be used in MHz. + \param base Base RF frequency to be used in MHz (in 2-FSK mode), or the tone frequency in Hz (in AFSK mode). \param rate Baud rate to be used during transmission. Defaults to 122.5 ("Feld Hell") */ @@ -126,7 +139,7 @@ class HellClient { size_t println(void); size_t println(__FlashStringHelper*); - size_t println(const String &s); + size_t println(const String &); size_t println(const char[]); size_t println(char); size_t println(unsigned char, int = DEC); @@ -140,12 +153,20 @@ class HellClient { private: #endif PhysicalLayer* _phy; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + AFSKClient* _audio; + #endif - uint32_t _base; - uint32_t _pixelDuration; + uint32_t _base = 0, _baseHz = 0; + uint32_t _pixelDuration = 0; size_t printNumber(unsigned long, uint8_t); size_t printFloat(double, uint8_t); + + int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); + int16_t standby(); }; #endif + +#endif diff --git a/src/protocols/MQTT/MQTT.cpp b/src/protocols/MQTT/MQTT.cpp index 92583cbb..b86b548f 100644 --- a/src/protocols/MQTT/MQTT.cpp +++ b/src/protocols/MQTT/MQTT.cpp @@ -1,4 +1,5 @@ #include "MQTT.h" +#if !defined(RADIOLIB_EXCLUDE_MQTT) MQTTClient::MQTTClient(TransportLayer* tl, uint16_t port) { _tl = tl; @@ -95,7 +96,6 @@ int16_t MQTTClient::connect(const char* host, const char* clientId, const char* packet[pos++] = (passwordLen & 0xFF00) >> 8;; packet[pos++] = passwordLen & 0x00FF; memcpy(packet + pos, password, passwordLen); - pos += passwordLen; } // create TCP connection @@ -197,7 +197,6 @@ int16_t MQTTClient::publish(const char* topic, const char* message) { // payload // message memcpy(packet + pos, message, messageLen); - pos += messageLen; // send MQTT packet int16_t state = _tl->send(packet, 1 + encodedBytes + remainingLength); @@ -206,7 +205,7 @@ int16_t MQTTClient::publish(const char* topic, const char* message) { #endif return(state); - //TODO: implement QoS > 0 and PUBACK response checking + /// \todo implement QoS > 0 and PUBACK response checking } int16_t MQTTClient::subscribe(const char* topicFilter) { @@ -313,7 +312,6 @@ int16_t MQTTClient::unsubscribe(const char* topicFilter) { packet[pos++] = (topicFilterLen & 0xFF00) >> 8;; packet[pos++] = topicFilterLen & 0x00FF; memcpy(packet + pos, topicFilter, topicFilterLen); - pos += topicFilterLen; // send MQTT packet int16_t state = _tl->send(packet, 1 + encodedBytes + remainingLength); @@ -412,11 +410,11 @@ int16_t MQTTClient::check(void (*func)(const char*, const char*)) { uint8_t* dataIn = new uint8_t[numBytes]; _tl->receive(dataIn, numBytes); if(dataIn[0] == MQTT_PUBLISH << 4) { - // TODO: properly decode remaining length - uint8_t remainingLength = dataIn[1]; + uint8_t remLenFieldLen = 0; + uint32_t remainingLength = decodeLength(dataIn + 1, remLenFieldLen); // get the topic - size_t topicLength = dataIn[3] | dataIn[2] << 8; + size_t topicLength = dataIn[remLenFieldLen + 2] | dataIn[remLenFieldLen + 1] << 8; char* topic = new char[topicLength + 1]; memcpy(topic, dataIn + 4, topicLength); topic[topicLength] = 0x00; @@ -424,7 +422,7 @@ int16_t MQTTClient::check(void (*func)(const char*, const char*)) { // get the message size_t messageLength = remainingLength - topicLength - 2; char* message = new char[messageLength + 1]; - memcpy(message, dataIn + 4 + topicLength, messageLength); + memcpy(message, dataIn + remLenFieldLen + 3 + topicLength, messageLength); message[messageLength] = 0x00; // execute the callback function provided by user @@ -454,7 +452,7 @@ size_t MQTTClient::encodeLength(uint32_t len, uint8_t* encoded) { return(i); } -uint32_t MQTTClient::decodeLength(uint8_t* encoded) { +uint32_t MQTTClient::decodeLength(uint8_t* encoded, uint8_t& numBytes) { // algorithm to decode packet length as per MQTT specification 3.1.1 uint32_t mult = 1; uint32_t len = 0; @@ -466,6 +464,9 @@ uint32_t MQTTClient::decodeLength(uint8_t* encoded) { // malformed remaining length return(0); } - } while((encoded[i] & 128) != 0); + } while((encoded[i++] & 128) != 0); + numBytes = i; return len; } + +#endif diff --git a/src/protocols/MQTT/MQTT.h b/src/protocols/MQTT/MQTT.h index b7a94bdb..6f21f585 100644 --- a/src/protocols/MQTT/MQTT.h +++ b/src/protocols/MQTT/MQTT.h @@ -1,7 +1,10 @@ -#ifndef _RADIOLIB_MQTT_H +#if !defined(_RADIOLIB_MQTT_H) #define _RADIOLIB_MQTT_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_MQTT) + #include "../TransportLayer/TransportLayer.h" // MQTT packet types @@ -39,7 +42,7 @@ class MQTTClient { \param tl Pointer to the wireless module providing TransportLayer communication. */ - MQTTClient(TransportLayer* tl, uint16_t port = 1883); + explicit MQTTClient(TransportLayer* tl, uint16_t port = 1883); // basic methods @@ -135,8 +138,10 @@ class MQTTClient { uint16_t _port; uint16_t _packetId; - size_t encodeLength(uint32_t len, uint8_t* encoded); - uint32_t decodeLength(uint8_t* encoded); + static size_t encodeLength(uint32_t len, uint8_t* encoded); + static uint32_t decodeLength(uint8_t* encoded, uint8_t& numBytes); }; #endif + +#endif diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index 6b3e0c16..593d6278 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -1,18 +1,35 @@ #include "Morse.h" +#if !defined(RADIOLIB_EXCLUDE_MORSE) MorseClient::MorseClient(PhysicalLayer* phy) { _phy = phy; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + _audio = nullptr; + #endif } +#if !defined(RADIOLIB_EXCLUDE_AFSK) +MorseClient::MorseClient(AFSKClient* audio) { + _phy = audio->_phy; + _audio = audio; +} +#endif + int16_t MorseClient::begin(float base, uint8_t speed) { // calculate 24-bit frequency + _baseHz = base; _base = (base * 1000000.0) / _phy->getFreqStep(); // calculate dot length (assumes PARIS as typical word) _dotLength = 1200 / speed; - // set module frequency deviation to 0 - int16_t state = _phy->setFrequencyDeviation(0); + // set module frequency deviation to 0 if using FSK + int16_t state = ERR_NONE; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio == nullptr) { + state = _phy->setFrequencyDeviation(0); + } + #endif return(state); } @@ -46,13 +63,13 @@ size_t MorseClient::write(uint8_t b) { // inter-word pause (space) if(b == ' ') { RADIOLIB_DEBUG_PRINTLN(F("space")); - _phy->standby(); - delay(4 * _dotLength); + standby(); + Module::delay(4 * _dotLength); return(1); } // get morse code from lookup table - uint8_t code = pgm_read_byte(&MorseTable[(uint8_t)(toupper(b) - 32)]); + uint8_t code = RADIOLIB_PROGMEM_READ_BYTE(&MorseTable[(uint8_t)(toupper(b) - 32)]); // check unsupported characters if(code == MORSE_UNSUPORTED) { @@ -65,25 +82,25 @@ size_t MorseClient::write(uint8_t b) { // send dot or dash if (code & MORSE_DASH) { RADIOLIB_DEBUG_PRINT('-'); - _phy->transmitDirect(_base); - delay(3 * _dotLength); + transmitDirect(_base, _baseHz); + Module::delay(3 * _dotLength); } else { RADIOLIB_DEBUG_PRINT('.'); - _phy->transmitDirect(_base); - delay(_dotLength); + transmitDirect(_base, _baseHz); + Module::delay(_dotLength); } // symbol space - _phy->standby(); - delay(_dotLength); + standby(); + Module::delay(_dotLength); // move onto the next bit code >>= 1; } // letter space - _phy->standby(); - delay(2 * _dotLength); + standby(); + Module::delay(2 * _dotLength); RADIOLIB_DEBUG_PRINTLN(); return(1); @@ -93,7 +110,7 @@ size_t MorseClient::print(__FlashStringHelper* fstr) { PGM_P p = reinterpret_cast(fstr); size_t n = 0; while(true) { - char c = pgm_read_byte(p++); + char c = RADIOLIB_PROGMEM_READ_BYTE(p++); if(c == '\0') { break; } @@ -283,3 +300,23 @@ size_t MorseClient::printFloat(double number, uint8_t digits) { return n; } + +int16_t MorseClient::transmitDirect(uint32_t freq, uint32_t freqHz) { + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio != nullptr) { + return(_audio->tone(freqHz)); + } + #endif + return(_phy->transmitDirect(freq)); +} + +int16_t MorseClient::standby() { + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio != nullptr) { + return(_audio->noTone()); + } + #endif + return(_phy->standby()); +} + +#endif diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index 66df3280..caeec47e 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -1,8 +1,9 @@ -#ifndef _RADIOLIB_MORSE_H +#if !defined(_RADIOLIB_MORSE_H) && !defined(RADIOLIB_EXCLUDE_MORSE) #define _RADIOLIB_MORSE_H #include "../../TypeDef.h" #include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" #define MORSE_DOT 0b0 #define MORSE_DASH 0b1 @@ -13,7 +14,7 @@ // - Morse code representation is saved LSb first, using additional bit as guard // - position in array corresponds ASCII code minus MORSE_ASCII_OFFSET // - ASCII characters marked MORSE_UNSUPORTED do not have ITU-R M.1677-1 equivalent -static const uint8_t MorseTable[] PROGMEM = { +static const uint8_t MorseTable[] RADIOLIB_PROGMEM = { 0b00, // space 0b110101, // ! (unsupported) 0b1010010, // " @@ -88,18 +89,27 @@ static const uint8_t MorseTable[] PROGMEM = { class MorseClient { public: /*! - \brief Default constructor. + \brief Constructor for 2-FSK mode. \param phy Pointer to the wireless module providing PhysicalLayer communication. */ - MorseClient(PhysicalLayer* phy); + explicit MorseClient(PhysicalLayer* phy); + + #if !defined(RADIOLIB_EXCLUDE_AFSK) + /*! + \brief Constructor for AFSK mode. + + \param audio Pointer to the AFSK instance providing audio. + */ + explicit MorseClient(AFSKClient* audio); + #endif // basic methods /*! \brief Initialization method. - \param base Base RF frequency to be used in MHz. + \param base Base RF frequency to be used in MHz (in 2-FSK mode), or the tone frequency in Hz (in AFSK mode) \param speed Coding speed in words per minute. @@ -131,7 +141,7 @@ class MorseClient { size_t println(void); size_t println(__FlashStringHelper*); - size_t println(const String &s); + size_t println(const String &); size_t println(const char[]); size_t println(char); size_t println(unsigned char, int = DEC); @@ -145,11 +155,18 @@ class MorseClient { private: #endif PhysicalLayer* _phy; - uint32_t _base; - uint16_t _dotLength; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + AFSKClient* _audio; + #endif + + uint32_t _base = 0, _baseHz = 0; + uint16_t _dotLength = 0; size_t printNumber(unsigned long, uint8_t); size_t printFloat(double, uint8_t); + + int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); + int16_t standby(); }; #endif diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 0fc34b5b..b30a0cf9 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -10,7 +10,7 @@ int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) { size_t len = 0; PGM_P p = reinterpret_cast(fstr); while(true) { - char c = pgm_read_byte(p++); + char c = RADIOLIB_PROGMEM_READ_BYTE(p++); len++; if(c == '\0') { break; @@ -27,7 +27,7 @@ int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) { // copy string from flash p = reinterpret_cast(fstr); for(size_t i = 0; i < len; i++) { - str[i] = pgm_read_byte(p + i); + str[i] = RADIOLIB_PROGMEM_READ_BYTE(p + i); } // transmit string @@ -140,6 +140,30 @@ int16_t PhysicalLayer::receive(String& str, size_t len) { return(state); } -float PhysicalLayer::getFreqStep() { +float PhysicalLayer::getFreqStep() const { return(_freqStep); } + +int32_t PhysicalLayer::random(int32_t max) { + if(max == 0) { + return(0); + } + + // get random bytes from the radio + uint8_t randBuff[4]; + for(uint8_t i = 0; i < 4; i++) { + randBuff[i] = random(); + } + + // create 32-bit TRNG number + int32_t randNum = ((int32_t)randBuff[0] << 24) | ((int32_t)randBuff[1] << 16) | ((int32_t)randBuff[2] << 8) | ((int32_t)randBuff[3]); + return(randNum % max); +} + +int32_t PhysicalLayer::random(int32_t min, int32_t max) { + if(min >= max) { + return(min); + } + + return(PhysicalLayer::random(max - min) + min); +} diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index eca4f6e8..d817fbcc 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -164,7 +164,7 @@ class PhysicalLayer { \brief Enables direct transmission mode on pins DIO1 (clock) and DIO2 (data). Must be implemented in module class. While in direct mode, the module will not be able to transmit or receive packets. Can only be activated in FSK mode. - \param FRF 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY. + \param frf 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY. \returns \ref status_codes */ @@ -193,16 +193,16 @@ class PhysicalLayer { /*! \brief Sets GFSK data shaping. Only available in FSK mode. Must be implemented in module class. - \param sh Shaping to be set. Set to zero to disable data shaping. + \param sh Shaping to be set. See \ref config_shaping for possible values. \returns \ref status_codes */ - virtual int16_t setDataShaping(float sh) = 0; + virtual int16_t setDataShaping(uint8_t sh) = 0; /*! \brief Sets FSK data encoding. Only available in FSK mode. Must be implemented in module class. - \param enc Encoding to be used. Set to zero to for no encoding (NRZ). + \param enc Encoding to be used. See \ref config_encoding for possible values. \returns \ref status_codes */ @@ -213,10 +213,10 @@ class PhysicalLayer { \returns Synthesizer frequency step size in Hz. */ - float getFreqStep(); + float getFreqStep() const; /*! - \brief Query modem for the packet length of received payload. + \brief Query modem for the packet length of received payload. Must be implemented in module class. \param update Update received packet length. Will return cached value when set to false. @@ -224,6 +224,33 @@ class PhysicalLayer { */ virtual size_t getPacketLength(bool update = true) = 0; + /*! + \brief Get truly random number in range 0 - max. + + \param max The maximum value of the random number (non-inclusive). + + \returns Random number. + */ + int32_t random(int32_t max); + + /*! + \brief Get truly random number in range min - max. + + \param min The minimum value of the random number (inclusive). + + \param max The maximum value of the random number (non-inclusive). + + \returns Random number. + */ + int32_t random(int32_t min, int32_t max); + + /*! + \brief Get one truly random byte from RSSI noise. Must be implemented in module class. + + \returns TRNG byte. + */ + virtual uint8_t random() = 0; + #ifndef RADIOLIB_GODMODE private: #endif diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index 085d3794..74973f4f 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -1,4 +1,5 @@ #include "RTTY.h" +#if !defined(RADIOLIB_EXCLUDE_RTTY) ITA2String::ITA2String(char c) { _len = 1; @@ -90,11 +91,11 @@ uint16_t ITA2String::getBits(char c) { // search ITA2 table uint16_t code = 0x0000; for(uint8_t i = 0; i < ITA2_LENGTH; i++) { - if(pgm_read_byte(&ITA2Table[i][0]) == c) { + if(RADIOLIB_PROGMEM_READ_BYTE(&ITA2Table[i][0]) == c) { // character is in letter shift code = (ITA2_LTRS << 5) | i; break; - } else if(pgm_read_byte(&ITA2Table[i][1]) == c) { + } else if(RADIOLIB_PROGMEM_READ_BYTE(&ITA2Table[i][1]) == c) { // character is in figures shift code = (ITA2_FIGS << 5) | i; break; @@ -106,12 +107,24 @@ uint16_t ITA2String::getBits(char c) { RTTYClient::RTTYClient(PhysicalLayer* phy) { _phy = phy; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + _audio = nullptr; + #endif } +#if !defined(RADIOLIB_EXCLUDE_AFSK) +RTTYClient::RTTYClient(AFSKClient* audio) { + _phy = audio->_phy; + _audio = audio; +} +#endif + int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t encoding, uint8_t stopBits) { // save configuration _encoding = encoding; _stopBits = stopBits; + _baseHz = base; + _shiftHz = shift; switch(encoding) { case ASCII: @@ -148,15 +161,18 @@ int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc // calculate 24-bit frequency _base = (base * 1000000.0) / _phy->getFreqStep(); - // set module frequency deviation to 0 - int16_t state = _phy->setFrequencyDeviation(0); + // set module frequency deviation to 0 if using FSK + int16_t state = ERR_NONE; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio == nullptr) { + state = _phy->setFrequencyDeviation(0); + } + #endif return(state); } void RTTYClient::idle() { - _phy->transmitDirect(); - mark(); } @@ -178,7 +194,8 @@ size_t RTTYClient::write(uint8_t* buff, size_t len) { size_t RTTYClient::write(uint8_t b) { space(); - for(uint16_t mask = 0x01; mask <= (uint16_t)(0x01 << (_dataBits - 1)); mask <<= 1) { + uint16_t maxDataMask = 0x01 << (_dataBits - 1); + for(uint16_t mask = 0x01; mask <= maxDataMask; mask <<= 1) { if(b & mask) { mark(); } else { @@ -190,7 +207,7 @@ size_t RTTYClient::write(uint8_t b) { mark(); } - _phy->standby(); + standby(); return(1); } @@ -200,7 +217,7 @@ size_t RTTYClient::print(__FlashStringHelper* fstr) { size_t len = 0; PGM_P p = reinterpret_cast(fstr); while(true) { - char c = pgm_read_byte(p++); + char c = RADIOLIB_PROGMEM_READ_BYTE(p++); len++; if(c == '\0') { break; @@ -217,12 +234,12 @@ size_t RTTYClient::print(__FlashStringHelper* fstr) { // copy string from flash p = reinterpret_cast(fstr); for(size_t i = 0; i < len; i++) { - str[i] = pgm_read_byte(p + i); + str[i] = RADIOLIB_PROGMEM_READ_BYTE(p + i); } size_t n = 0; if(_encoding == ITA2) { - ITA2String ita2 = str; + ITA2String ita2 = ITA2String(str); n = RTTYClient::print(ita2); } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { n = RTTYClient::write((uint8_t*)str, len); @@ -243,7 +260,7 @@ size_t RTTYClient::print(ITA2String& ita2) { size_t RTTYClient::print(const String& str) { size_t n = 0; if(_encoding == ITA2) { - ITA2String ita2 = str.c_str(); + ITA2String ita2 = ITA2String(str.c_str()); n = RTTYClient::print(ita2); } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { n = RTTYClient::write((uint8_t*)str.c_str(), str.length()); @@ -254,7 +271,7 @@ size_t RTTYClient::print(const String& str) { size_t RTTYClient::print(const char str[]) { size_t n = 0; if(_encoding == ITA2) { - ITA2String ita2 = str; + ITA2String ita2 = ITA2String(str); n = RTTYClient::print(ita2); } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { n = RTTYClient::write((uint8_t*)str, strlen(str)); @@ -265,7 +282,7 @@ size_t RTTYClient::print(const char str[]) { size_t RTTYClient::print(char c) { size_t n = 0; if(_encoding == ITA2) { - ITA2String ita2 = c; + ITA2String ita2 = ITA2String(c); n = RTTYClient::print(ita2); } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { n = RTTYClient::write(c); @@ -315,7 +332,7 @@ size_t RTTYClient::print(double n, int digits) { size_t RTTYClient::println(void) { size_t n = 0; if(_encoding == ITA2) { - ITA2String lf = "\r\n"; + ITA2String lf = ITA2String("\r\n"); n = RTTYClient::print(lf); } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { n = RTTYClient::write("\r\n"); @@ -390,18 +407,18 @@ size_t RTTYClient::println(double d, int digits) { } void RTTYClient::mark() { - uint32_t start = micros(); - _phy->transmitDirect(_base + _shift); - while(micros() - start < _bitDuration) { - yield(); + uint32_t start = Module::micros(); + transmitDirect(_base + _shift, _baseHz + _shiftHz); + while(Module::micros() - start < _bitDuration) { + Module::yield(); } } void RTTYClient::space() { - uint32_t start = micros(); - _phy->transmitDirect(_base); - while(micros() - start < _bitDuration) { - yield(); + uint32_t start = Module::micros(); + transmitDirect(_base, _baseHz); + while(Module::micros() - start < _bitDuration) { + Module::yield(); } } @@ -424,7 +441,7 @@ size_t RTTYClient::printNumber(unsigned long n, uint8_t base) { size_t l = 0; if(_encoding == ITA2) { - ITA2String ita2 = str; + ITA2String ita2 = ITA2String(str); uint8_t* arr = ita2.byteArr(); l = RTTYClient::write(arr, ita2.length()); delete[] arr; @@ -435,8 +452,7 @@ size_t RTTYClient::printNumber(unsigned long n, uint8_t base) { return(l); } -// TODO: improve ITA2 float print speed -// (characters are sent one at a time) +/// \todo improve ITA2 float print speed (characters are sent one at a time) size_t RTTYClient::printFloat(double number, uint8_t digits) { size_t n = 0; @@ -448,7 +464,7 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) { if(code[0] != 0x00) { if(_encoding == ITA2) { - ITA2String ita2 = code; + ITA2String ita2 = ITA2String(code); uint8_t* arr = ita2.byteArr(); n = RTTYClient::write(arr, ita2.length()); delete[] arr; @@ -461,7 +477,7 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) { // Handle negative numbers if (number < 0.0) { if(_encoding == ITA2) { - ITA2String ita2 = "-"; + ITA2String ita2 = ITA2String("-"); uint8_t* arr = ita2.byteArr(); n += RTTYClient::write(arr, ita2.length()); delete[] arr; @@ -486,7 +502,7 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) { // Print the decimal point, but only if there are digits beyond if(digits > 0) { if(_encoding == ITA2) { - ITA2String ita2 = "."; + ITA2String ita2 = ITA2String("."); uint8_t* arr = ita2.byteArr(); n += RTTYClient::write(arr, ita2.length()); delete[] arr; @@ -505,3 +521,23 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) { return n; } + +int16_t RTTYClient::transmitDirect(uint32_t freq, uint32_t freqHz) { + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio != nullptr) { + return(_audio->tone(freqHz)); + } + #endif + return(_phy->transmitDirect(freq)); +} + +int16_t RTTYClient::standby() { + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio != nullptr) { + return(_audio->noTone()); + } + #endif + return(_phy->standby()); +} + +#endif diff --git a/src/protocols/RTTY/RTTY.h b/src/protocols/RTTY/RTTY.h index 5c22568c..6eab5fec 100644 --- a/src/protocols/RTTY/RTTY.h +++ b/src/protocols/RTTY/RTTY.h @@ -1,8 +1,12 @@ -#ifndef _RADIOLIB_RTTY_H +#if !defined(_RADIOLIB_RTTY_H) #define _RADIOLIB_RTTY_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_RTTY) + #include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" #define ITA2_FIGS 0x1B #define ITA2_LTRS 0x1F @@ -11,10 +15,10 @@ // ITA2 character table: - position in array corresponds to 5-bit ITA2 code // - characters to the left are in letters shift, characters to the right in figures shift // - characters marked 0x7F do not have ASCII equivalent -static const char ITA2Table[ITA2_LENGTH][2] PROGMEM = {{'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'}, - {'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('}, - {'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'}, - {'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F}}; +static const char ITA2Table[ITA2_LENGTH][2] RADIOLIB_PROGMEM = {{'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'}, + {'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('}, + {'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'}, + {'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F}}; /*! \class ITA2String @@ -28,14 +32,14 @@ class ITA2String { \param c ASCII-encoded character to encode as ITA2. */ - ITA2String(char c); + explicit ITA2String(char c); /*! \brief Default string constructor. \param str ASCII-encoded string to encode as ITA2. */ - ITA2String(const char* str); + explicit ITA2String(const char* str); /*! \brief Default destructor. @@ -68,7 +72,7 @@ class ITA2String { size_t _len; size_t _ita2Len; - uint16_t getBits(char c); + static uint16_t getBits(char c); }; // supported encoding schemes @@ -84,18 +88,27 @@ class ITA2String { class RTTYClient { public: /*! - \brief Default constructor. + \brief Constructor for 2-FSK mode. \param phy Pointer to the wireless module providing PhysicalLayer communication. */ - RTTYClient(PhysicalLayer* phy); + explicit RTTYClient(PhysicalLayer* phy); + + #if !defined(RADIOLIB_EXCLUDE_AFSK) + /*! + \brief Constructor for AFSK mode. + + \param audio Pointer to the AFSK instance providing audio. + */ + explicit RTTYClient(AFSKClient* audio); + #endif // basic methods /*! \brief Initialization method. - \param base Base (space) RF frequency to be used in MHz. + \param base Base (space) frequency to be used in MHz (in 2-FSK mode), or the space tone frequency in Hz (in AFSK mode) \param shift Frequency shift between mark and space in Hz. @@ -133,7 +146,7 @@ class RTTYClient { size_t println(void); size_t println(__FlashStringHelper*); size_t println(ITA2String &); - size_t println(const String &s); + size_t println(const String &); size_t println(const char[]); size_t println(char); size_t println(unsigned char, int = DEC); @@ -147,19 +160,27 @@ class RTTYClient { private: #endif PhysicalLayer* _phy; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + AFSKClient* _audio; + #endif - uint8_t _encoding; - uint32_t _base; - uint32_t _shift; - uint32_t _bitDuration; - uint8_t _dataBits; - uint8_t _stopBits; + uint8_t _encoding = ASCII; + uint32_t _base = 0, _baseHz = 0; + uint32_t _shift = 0, _shiftHz = 0; + uint32_t _bitDuration = 0; + uint8_t _dataBits = 0; + uint8_t _stopBits = 0; void mark(); void space(); size_t printNumber(unsigned long, uint8_t); size_t printFloat(double, uint8_t); + + int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); + int16_t standby(); }; #endif + +#endif diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index c3843ad8..8687cc6f 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -1,4 +1,5 @@ #include "SSTV.h" +#if !defined(RADIOLIB_EXCLUDE_SSTV) const SSTVMode_t Scottie1 { .visCode = SSTV_SCOTTIE_1, @@ -155,9 +156,30 @@ const SSTVMode_t PasokonP7 { SSTVClient::SSTVClient(PhysicalLayer* phy) { _phy = phy; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + _audio = nullptr; + #endif } -int16_t SSTVClient::begin(float base, SSTVMode_t mode, float correction) { +#if !defined(RADIOLIB_EXCLUDE_AFSK) +SSTVClient::SSTVClient(AFSKClient* audio) { + _phy = audio->_phy; + _audio = audio; +} +#endif + +#if !defined(RADIOLIB_EXCLUDE_AFSK) +int16_t SSTVClient::begin(const SSTVMode_t& mode, float correction) { + if(_audio == nullptr) { + // this initialization method can only be used in AFSK mode + return(ERR_WRONG_MODEM); + } + + return(begin(0, mode, correction)); +} +#endif + +int16_t SSTVClient::begin(float base, const SSTVMode_t& mode, float correction) { // save mode _mode = mode; @@ -170,50 +192,57 @@ int16_t SSTVClient::begin(float base, SSTVMode_t mode, float correction) { // calculate 24-bit frequency _base = (base * 1000000.0) / _phy->getFreqStep(); - // set module frequency deviation to 0 - int16_t state = _phy->setFrequencyDeviation(0); + // set module frequency deviation to 0 if using FSK + int16_t state = ERR_NONE; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio == nullptr) { + state = _phy->setFrequencyDeviation(0); + } + #endif return(state); } void SSTVClient::idle() { - tone(SSTV_TONE_LEADER); + _phy->transmitDirect(); + this->tone(SSTV_TONE_LEADER); } void SSTVClient::sendHeader() { // save first header flag for Scottie modes _firstLine = true; + _phy->transmitDirect(); // send the first part of header (leader-break-leader) - tone(SSTV_TONE_LEADER, SSTV_HEADER_LEADER_LENGTH); - tone(SSTV_TONE_BREAK, SSTV_HEADER_BREAK_LENGTH); - tone(SSTV_TONE_LEADER, SSTV_HEADER_LEADER_LENGTH); + this->tone(SSTV_TONE_LEADER, SSTV_HEADER_LEADER_LENGTH); + this->tone(SSTV_TONE_BREAK, SSTV_HEADER_BREAK_LENGTH); + this->tone(SSTV_TONE_LEADER, SSTV_HEADER_LEADER_LENGTH); // VIS start bit - tone(SSTV_TONE_BREAK, SSTV_HEADER_BIT_LENGTH); + this->tone(SSTV_TONE_BREAK, SSTV_HEADER_BIT_LENGTH); // VIS code uint8_t parityCount = 0; for(uint8_t mask = 0x01; mask < 0x80; mask <<= 1) { if(_mode.visCode & mask) { - tone(SSTV_TONE_VIS_1, SSTV_HEADER_BIT_LENGTH); + this->tone(SSTV_TONE_VIS_1, SSTV_HEADER_BIT_LENGTH); parityCount++; } else { - tone(SSTV_TONE_VIS_0, SSTV_HEADER_BIT_LENGTH); + this->tone(SSTV_TONE_VIS_0, SSTV_HEADER_BIT_LENGTH); } } // VIS parity if(parityCount % 2 == 0) { // even parity - tone(SSTV_TONE_VIS_0, SSTV_HEADER_BIT_LENGTH); + this->tone(SSTV_TONE_VIS_0, SSTV_HEADER_BIT_LENGTH); } else { // odd parity - tone(SSTV_TONE_VIS_1, SSTV_HEADER_BIT_LENGTH); + this->tone(SSTV_TONE_VIS_1, SSTV_HEADER_BIT_LENGTH); } // VIS stop bit - tone(SSTV_TONE_BREAK, SSTV_HEADER_BIT_LENGTH); + this->tone(SSTV_TONE_BREAK, SSTV_HEADER_BIT_LENGTH); } void SSTVClient::sendLine(uint32_t* imgLine) { @@ -222,14 +251,14 @@ void SSTVClient::sendLine(uint32_t* imgLine) { _firstLine = false; // send start sync tone - tone(SSTV_TONE_BREAK, 9000); + this->tone(SSTV_TONE_BREAK, 9000); } // send all tones in sequence for(uint8_t i = 0; i < _mode.numTones; i++) { if((_mode.tones[i].type == tone_t::GENERIC) && (_mode.tones[i].len > 0)) { // sync/porch tones - tone(_mode.tones[i].freq, _mode.tones[i].len); + this->tone(_mode.tones[i].freq, _mode.tones[i].len); } else { // scan lines for(uint16_t j = 0; j < _mode.width; j++) { @@ -249,20 +278,30 @@ void SSTVClient::sendLine(uint32_t* imgLine) { case(tone_t::GENERIC): break; } - tone(SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549), _mode.scanPixelLen); + this->tone(SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549), _mode.scanPixelLen); } } } } -uint16_t SSTVClient::getPictureHeight() { +uint16_t SSTVClient::getPictureHeight() const { return(_mode.height); } void SSTVClient::tone(float freq, uint32_t len) { - uint32_t start = micros(); + uint32_t start = Module::micros(); + #if !defined(RADIOLIB_EXCLUDE_AFSK) + if(_audio != nullptr) { + _audio->tone(freq, false); + } else { + _phy->transmitDirect(_base + (freq / _phy->getFreqStep())); + } + #else _phy->transmitDirect(_base + (freq / _phy->getFreqStep())); - while(micros() - start < len) { - yield(); + #endif + while(Module::micros() - start < len) { + Module::yield(); } } + +#endif diff --git a/src/protocols/SSTV/SSTV.h b/src/protocols/SSTV/SSTV.h index d8dc0c8b..fb8fc27a 100644 --- a/src/protocols/SSTV/SSTV.h +++ b/src/protocols/SSTV/SSTV.h @@ -1,8 +1,12 @@ -#ifndef _RADIOLIB_SSTV_H +#if !defined(_RADIOLIB_SSTV_H) #define _RADIOLIB_SSTV_H #include "../../TypeDef.h" + +#if !defined(RADIOLIB_EXCLUDE_SSTV) + #include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" // the following implementation is based on information from // http://www.barberdsp.com/downloads/Dayton%20Paper.pdf @@ -116,22 +120,48 @@ extern const SSTVMode_t PasokonP7; class SSTVClient { public: /*! - \brief Default constructor. + \brief Constructor for 2-FSK mode. \param phy Pointer to the wireless module providing PhysicalLayer communication. */ - SSTVClient(PhysicalLayer* phy); + explicit SSTVClient(PhysicalLayer* phy); + + #if !defined(RADIOLIB_EXCLUDE_AFSK) + /*! + \brief Constructor for AFSK mode. + + \param audio Pointer to the AFSK instance providing audio. + */ + explicit SSTVClient(AFSKClient* audio); + #endif // basic methods /*! - \brief Initialization method. + \brief Initialization method for 2-FSK. - \param base Base RF frequency to be used in MHz. In USB modulation, this corresponds to "0 Hz tone". + \param base Base "0 Hz tone" RF frequency to be used in MHz. \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. + + \param correction Timing correction factor, used to adjust the length of timing pulses. Less than 1.0 leads to shorter timing pulses, defaults to 1.0 (no correction). + + \returns \ref status_codes */ - int16_t begin(float base, SSTVMode_t mode, float correction = 1.0); + int16_t begin(float base, const SSTVMode_t& mode, float correction = 1.0); + + #if !defined(RADIOLIB_EXCLUDE_AFSK) + /*! + \brief Initialization method for AFSK. + + \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. + + \param correction Timing correction factor, used to adjust the length of timing pulses. Less than 1.0 leads to shorter timing pulses, defaults to 1.0 (no correction). + + \returns \ref status_codes + */ + int16_t begin(const SSTVMode_t& mode, float correction = 1.0); + #endif /*! \brief Sends out tone at 1900 Hz. @@ -155,18 +185,23 @@ class SSTVClient { \returns Picture height of the currently configured SSTV mode in pixels. */ - uint16_t getPictureHeight(); + uint16_t getPictureHeight() const; #ifndef RADIOLIB_GODMODE private: #endif PhysicalLayer* _phy; + #if !defined(RADIOLIB_EXCLUDE_AFSK) + AFSKClient* _audio; + #endif - uint32_t _base; - SSTVMode_t _mode; - bool _firstLine; + uint32_t _base = 0; + SSTVMode_t _mode = Scottie1; + bool _firstLine = true; void tone(float freq, uint32_t len = 0); }; #endif + +#endif diff --git a/src/protocols/TransportLayer/TransportLayer.h b/src/protocols/TransportLayer/TransportLayer.h index ecf3ad5b..eb23bd8e 100644 --- a/src/protocols/TransportLayer/TransportLayer.h +++ b/src/protocols/TransportLayer/TransportLayer.h @@ -56,7 +56,7 @@ class TransportLayer { \returns \ref status_codes */ - virtual int16_t send(uint8_t* data, uint32_t len) = 0; + virtual int16_t send(uint8_t* data, size_t len) = 0; /*! \brief Receive data.