Merge remote-tracking branch 'upstream/master'

* upstream/master: (249 commits)
  [SX127x] OOK functions style cleanup
  [RF69] OOK functions style cleanup
  styles and syntax changes
  added RF69::setOokThresholdType
  added RF69::setLnaTestBoost
  doc fix
  SX1278::getRSSI() modified for OOK so it wont require an activation
  SX127x::setOokPeakThresholdDecrement
  ignore jetbrain .idea
  SX1278::setGain() added support for FSK_OOK modes
  SX127x::setOokFixedOrFloorThreshold
  SX1278::setOokThresholdType()
  RF69::setOOK
  [SX127x] Fixed shaping in OOK (#268)
  [SX127x] Added FSK CRC mode configuration (#266)
  Bump version to 4.3.0
  [nRF24] Added low-level access macro
  [XBee] Added low-level access macro
  [Si443x] Added low-level access macro
  [SX128x] Added low-level access macro
  ...
This commit is contained in:
Federico Maggi 2021-04-13 09:42:02 +02:00
commit 4d2764edb2
89 changed files with 2210 additions and 1023 deletions

66
.github/workflows/codeql-analysis.yml vendored Normal file
View file

@ -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

26
.github/workflows/doxygen.yml vendored Normal file
View file

@ -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

162
.github/workflows/main.yml vendored Normal file
View file

@ -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

46
.gitignore vendored
View file

@ -1,42 +1,16 @@
# 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
# Jetbrain IDEs
.idea
# Debug decoder
extras/decoder/log.txt
extras/decoder/out.txt
# PlatformIO
.pio*

View file

@ -1,195 +0,0 @@
env:
global:
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="arduino:avr:uno"
- BOARD="arduino:avr:mega:cpu=atmega2560"
- BOARD="arduino:avr:leonardo"
- BOARD="esp8266:esp8266:generic:xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K"
- BOARD="esp32:esp32:esp32"
- BOARD="STM32:stm32:GenF3:pnum=BLACKPILL_F303CC"
- BOARD="arduino:samd:arduino_zero_native"
- BOARD="arduino:sam:arduino_due_x"
- BOARD="adafruit:nrf52:feather52832:softdevice=s132v6,debug=l0"
- BOARD="Intel:arc32:arduino_101"
- BOARD="arduino:megaavr:uno2018:mode=on"
- BOARD="SparkFun:apollo3:amap3redboard"
- BOARD="arduino:mbed:nano33ble"
- BOARD="stm32duino:STM32F1:mapleMini:bootloader_version=original,cpu_speed=speed_72mhz"
- BOARD="adafruit:samd:adafruit_feather_m0:usbstack=arduino,debug=off"
- BOARD="arduino-beta:mbed:envie_m4"
addons:
apt:
packages:
# required for Adafruit nRF52 (adafruit-nrfutil package)
- python3
- python3-pip
- python3-setuptools
before_install:
# install Arduino CLI
- curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
- export PATH=$PATH:$PWD/bin
# check every board in matrix and install 3rd party definitions
- |
if [[ "$BOARD" =~ "arduino:avr:uno" ]]; then
export BUILD_EXAMPLES=true;
export WARNINGS=all;
arduino-cli core update-index;
arduino-cli core install arduino:avr;
elif [[ "$BOARD" =~ "arduino:avr:mega" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index;
arduino-cli core install arduino:avr;
elif [[ "$BOARD" =~ "arduino:avr:leonardo" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index;
arduino-cli core install arduino:avr;
elif [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index --additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json;
arduino-cli core install esp8266:esp8266 --additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json;
export SKIP_PAT='(HTTP|MQTT).*ino';
elif [[ "$BOARD" =~ "esp32:esp32:" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index --additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json;
arduino-cli core install esp32:esp32 --additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json;
elif [[ "$BOARD" =~ "STM32:stm32:" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index --additional-urls https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json;
arduino-cli core install STM32:stm32 --additional-urls https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json;
elif [[ "$BOARD" =~ "arduino:samd:" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index;
arduino-cli core install arduino:samd;
elif [[ "$BOARD" =~ "arduino:sam:" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index;
arduino-cli core install arduino:sam;
elif [[ "$BOARD" =~ "adafruit:nrf52:" ]]; then
pip3 install --user adafruit-nrfutil;
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index --additional-urls https://www.adafruit.com/package_adafruit_index.json;
arduino-cli core install adafruit:nrf52 --additional-urls https://www.adafruit.com/package_adafruit_index.json;
elif [[ "$BOARD" =~ "Intel:arc32:" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index;
arduino-cli core install Intel:arc32;
elif [[ "$BOARD" =~ "arduino:megaavr:" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index;
arduino-cli core install arduino:megaavr;
elif [[ "$BOARD" =~ "SparkFun:apollo3:" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=none;
arduino-cli core update-index --additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Boards/master/IDE_Board_Manager/package_sparkfun_index.json;
arduino-cli core install SparkFun:apollo3 --additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Boards/master/IDE_Board_Manager/package_sparkfun_index.json;
elif [[ "$BOARD" =~ "arduino:mbed:" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index;
arduino-cli core install arduino:mbed;
export SKIP_PAT='(HTTP|MQTT).*ino';
elif [[ "$BOARD" =~ "stm32duino:STM32F1:" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index --additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json;
arduino-cli core install stm32duino:STM32F1 --additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json;
elif [[ "$BOARD" =~ "adafruit:samd:" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index --additional-urls https://www.adafruit.com/package_adafruit_index.json
arduino-cli core install adafruit:samd --additional-urls https://www.adafruit.com/package_adafruit_index.json
elif [[ "$BOARD" =~ "arduino-beta:mbed:" ]]; then
export BUILD_EXAMPLES=false;
export WARNINGS=all;
arduino-cli core update-index;
arduino-cli core install arduino-beta:mbed;
export SKIP_PAT='(HTTP|MQTT).*ino';
fi
# check if this release commit (or forced build) and if so, build for every board
- if [[ "$TRAVIS_COMMIT_MESSAGE" =~ "Bump version to" || "$TRAVIS_COMMIT_MESSAGE" =~ "TRAVIS_FORCE_BUILD" ]]; then
export BUILD_EXAMPLES=true;
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
- |
if [ ! -z "$BUILD_EXAMPLES" ] && [ "$BUILD_EXAMPLES" = true ] ; then
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-cli compile --fqbn $BOARD $example --warnings=$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
else
echo -e "\n\033[1;33mExample builds skipped for $BOARD\033[0m";
fi
# 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"

3
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,3 @@
# Code of Conduct
Don't be an a*shole.

View file

@ -1,4 +1,4 @@
# RadioLib [![Build Status](https://travis-ci.org/jgromes/RadioLib.svg?branch=master)](https://travis-ci.org/jgromes/RadioLib)
# RadioLib ![Build Status](https://github.com/jgromes/RadioLib/workflows/CI/badge.svg)
### _One radio library to rule them all!_
@ -69,6 +69,9 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x
* [__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:
@ -83,7 +86,7 @@ The list above is by no means exhaustive. Most of RadioLib code is independent o
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.

5
SECURITY.md Normal file
View file

@ -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.

View file

@ -58,6 +58,17 @@ void setup() {
Serial.println(state);
while(true);
}
// initialize AFSK client
Serial.print(F("[AFSK] Initializing ... "));
state = audio.begin();
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
}
void loop() {

View file

@ -46,7 +46,7 @@ void setup() {
int state = radio.beginFSK();
// when using one of the non-LoRa modules for AFSK
// (RF69, CC1101,, Si4432 etc.), use the basic begin() method
// (RF69, CC1101, Si4432 etc.), use the basic begin() method
// int state = radio.begin();
if(state == ERR_NONE) {
@ -56,17 +56,30 @@ void setup() {
Serial.println(state);
while(true);
}
// initialize AFSK client
Serial.print(F("[AFSK] Initializing ... "));
state = audio.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
Serial.print(F("[AFSK] 400 Hz tone ... "));
audio.tone(400);
delay(1000);
// silence
Serial.println(F("done!"));
audio.noTone();
delay(1000);

View file

@ -44,8 +44,7 @@ void setup() {
Serial.print(F("[SX1278] Initializing ... "));
// carrier frequency: 434.0 MHz
// 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);
int state = radio.beginFSK(434.0, 1.2);
// when using one of the non-LoRa modules for AX.25
// (RF69, CC1101,, Si4432 etc.), use the basic begin() method

View file

@ -111,6 +111,11 @@ void loop() {
}
// NOTE: in FSK mode, SX127x will not automatically
// turn transmitter off after sending a packet
// set mode to standby to ensure we don't jam others
//radio.standby()
// wait a second before transmitting again
delay(1000);

View file

@ -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()

View file

@ -130,6 +130,11 @@ getTempRaw KEYWORD2
setRfSwitchPins KEYWORD2
forceLDRO KEYWORD2
autoLDRO KEYWORD2
getChipVersion KEYWORD2
invertIQ KEYWORD2
setOokThresholdType KEYWORD2
setOokPeakThresholdDecrement KEYWORD2
setOokFixedOrFloorThreshold KEYWORD2
# RF69-specific
setAESKey KEYWORD2
@ -137,6 +142,7 @@ enableAES KEYWORD2
disableAES KEYWORD2
getTemperature KEYWORD2
setAmbientTemperature KEYWORD2
setLnaTestBoost KEYWORD2
# CC1101-specific
getLQI KEYWORD2
@ -144,6 +150,7 @@ setGdo0Action KEYWORD2
setGdo2Action KEYWORD2
clearGdo0Action KEYWORD2
clearGdo2Action KEYWORD2
setCrcFiltering KEYWORD2
# SX126x-specific
setTCXO KEYWORD2

View file

@ -1,5 +1,5 @@
name=RadioLib
version=4.0.1
version=4.3.0
author=Jan Gromes <gromes.jan@gmail.com>
maintainer=Jan Gromes <gromes.jan@gmail.com>
sentence=Universal wireless communication library for Arduino

View file

@ -1,4 +1,4 @@
#ifndef _RADIOLIB_BUILD_OPTIONS_H
#if !defined(_RADIOLIB_BUILD_OPTIONS_H)
#define _RADIOLIB_BUILD_OPTIONS_H
#if ARDUINO >= 100
@ -10,13 +10,16 @@
/*
* Platform-specific configuration.
*
* RADIOLIB_PLATFORM - platform name, used in debugging to quickly check the correct platform is detected,
* 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_DIGITAL_PIN_TO_INTERRUPT - function to be used to convert digital pin number to interrupt pin number.
* 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.
@ -43,6 +46,8 @@
#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)
// the following must be defined if the Arduino core does not support SoftwareSerial library
//#define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
@ -51,6 +56,11 @@
// the following must be defined if the Arduino core does not support tone function
//#define RADIOLIB_TONE_UNSUPPORTED
// some platforms seem to have issues with SPI modules that use a command interface
// this can be mitigated by adding delays into SPI communication
// (see https://github.com/jgromes/RadioLib/issues/158 for details)
//#define RADIOLIB_SPI_SLOWDOWN
// 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
@ -80,7 +90,7 @@
//#define RADIOLIB_EXCLUDE_SSTV
#else
#if defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY))
#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
@ -90,6 +100,8 @@
#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
@ -101,6 +113,8 @@
#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
@ -115,9 +129,14 @@
#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)
@ -126,15 +145,20 @@
#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(digitalPinToPinName(p))
#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)
// Arduino SAMD (Zero, MKR, etc.) and Adafruit SAMD boards (M0 and M4)
#define RADIOLIB_PLATFORM "Arduino/Adafruit SAMD"
// 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
@ -142,6 +166,26 @@
#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
@ -155,6 +199,8 @@
#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
@ -169,6 +215,8 @@
#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
@ -180,6 +228,8 @@
#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
@ -191,20 +241,29 @@
#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(AM_PART_APOLLO3)
// Sparkfun Artemis boards
#define RADIOLIB_PLATFORM "Sparkfun Artemis"
#define RADIOLIB_PIN_TYPE uint8_t
#define RADIOLIB_PIN_MODE uint8_t
#define RADIOLIB_PIN_STATUS uint8_t
#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
#define RADIOLIB_TONE_UNSUPPORTED
// 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
@ -216,6 +275,8 @@
#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
@ -232,6 +293,8 @@
#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
@ -248,9 +311,23 @@
#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
#define RADIOLIB_TONE_UNSUPPORTED
#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
@ -263,6 +340,8 @@
#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
@ -297,6 +376,23 @@
#define RADIOLIB_VERBOSE_PRINTLN(...) {}
#endif
/*
* Uncomment to enable "paranoid" SPI mode
* Every write to an SPI register using SPI set function will be verified by a subsequent read operation.
* This improves reliablility, but slightly slows down communication.
* Note: Enabled by default.
*/
#define RADIOLIB_SPI_PARANOID
/*
* Uncomment to enable parameter range checking
* RadioLib will check provided parameters (such as frequency) against limits determined by the device manufacturer.
* It is highly advised to keep this macro defined, removing it will allow invalid values to be set,
* possibly leading to bricked module and/or program crashing.
* Note: Enabled by default.
*/
#define RADIOLIB_CHECK_PARAMS
/*
* Uncomment to enable god mode - all methods and member variables in all classes will be made public, thus making them accessible from Arduino code.
* Warning: Come on, it's called GOD mode - obviously only use this if you know what you're doing.
@ -304,6 +400,13 @@
*/
//#define RADIOLIB_GODMODE
/*
* Uncomment to enable low-level hardware access
* This will make some hardware methods like SPI get/set accessible from the user sketch - think of it as "god mode lite"
* Warning: RadioLib won't stop you from writing invalid stuff into your device, so it's quite easy to brick your module with this.
*/
//#define RADIOLIB_LOW_LEVEL
/*
* Uncomment to enable pre-defined modules when using RadioShield.
*/
@ -313,7 +416,6 @@
* Uncomment to enable static-only memory management: no dynamic allocation will be performed.
* Warning: Large static arrays will be created in some methods. It is not advised to send large packets in this mode.
*/
//#define RADIOLIB_STATIC_ONLY
// set the size of static arrays to use
@ -327,15 +429,18 @@
#define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != ERR_NONE) { return(STATEVAR); } }
/*!
\brief Macro to check variable is within constraints - this is commonly used to check parameter ranges.
\brief Macro to check variable is within constraints - this is commonly used to check parameter ranges. Requires RADIOLIB_CHECK_RANGE to be enabled
*/
#if defined(RADIOLIB_CHECK_PARAMS)
#define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) { if(!(((VAR) >= (MIN)) && ((VAR) <= (MAX)))) { return(ERR); } }
#else
#define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) {}
#endif
// version definitions
#define RADIOLIB_VERSION_MAJOR (0x04)
#define RADIOLIB_VERSION_MINOR (0x00)
#define RADIOLIB_VERSION_PATCH (0x01)
#define RADIOLIB_VERSION_MINOR (0x03)
#define RADIOLIB_VERSION_PATCH (0x00)
#define RADIOLIB_VERSION_EXTRA (0x00)
#define RADIOLIB_VERSION ((RADIOLIB_VERSION_MAJOR << 24) | (RADIOLIB_VERSION_MINOR << 16) | (RADIOLIB_VERSION_PATCH << 8) | (RADIOLIB_VERSION_EXTRA))

View file

@ -33,28 +33,11 @@ void ISerial::flush() {
_mod->ModuleSerial->flush();
}
// SoftwareSerial-only methods
#if !defined(RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED)
bool ISerial::listen() {
return(_mod->ModuleSerial->listen());
}
bool ISerial::isListening() {
return(_mod->ModuleSerial->isListening());
}
bool ISerial::stopListening() {
return(_mod->ModuleSerial->stopListening());
}
bool ISerial::overflow() {
return(_mod->ModuleSerial->overflow());
}
#endif
#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));
@ -96,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));

View file

@ -1,13 +1,8 @@
#ifndef _RADIOLIB_ISERIAL_H
#if !defined(_RADIOLIB_ISERIAL_H)
#define _RADIOLIB_ISERIAL_H
#include "Module.h"
#include <stdio.h>
#include "WString.h"
#include "Printable.h"
/*!
\class ISerial
@ -25,15 +20,9 @@ class ISerial {
int available();
void flush();
// SoftwareSerial-only methods
#if !defined(RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED)
bool listen();
bool isListening();
bool stopListening();
bool overflow();
#endif
#if !defined(ARDUINO_ARCH_MEGAAVR)
size_t print(const __FlashStringHelper *);
#endif
size_t print(const String &);
size_t print(const char[]);
size_t print(char);
@ -45,7 +34,9 @@ class ISerial {
size_t print(double, int = 2);
size_t print(const Printable&);
#if !defined(ARDUINO_ARCH_MEGAAVR)
size_t println(const __FlashStringHelper *);
#endif
size_t println(const String &s);
size_t println(const char[]);
size_t println(char);
@ -58,7 +49,7 @@ class ISerial {
size_t println(const Printable&);
size_t println(void);
#ifndef RADIOLIB_GODMODE
#if !(defined(RADIOLIB_LOW_LEVEL) || defined(RADIOLIB_GODMODE))
protected:
#endif
Module* _mod;

View file

@ -175,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);
@ -216,39 +216,43 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t
uint8_t newValue = (currentValue & ~mask) | (value & mask);
SPIwriteRegister(reg, newValue);
// 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;
while(micros() - start < (checkInterval * 1000)) {
readValue = SPIreadRegister(reg);
if(readValue == newValue) {
// check passed, we can stop the loop
return(ERR_NONE);
#if defined(RADIOLIB_SPI_PARANOID)
// 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 = 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
return(ERR_NONE);
}
}
}
// check failed, print debug info
RADIOLIB_DEBUG_PRINTLN();
RADIOLIB_DEBUG_PRINT(F("address:\t0x"));
RADIOLIB_DEBUG_PRINTLN(reg, HEX);
RADIOLIB_DEBUG_PRINT(F("bits:\t\t"));
RADIOLIB_DEBUG_PRINT(msb);
RADIOLIB_DEBUG_PRINT(' ');
RADIOLIB_DEBUG_PRINTLN(lsb);
RADIOLIB_DEBUG_PRINT(F("value:\t\t0b"));
RADIOLIB_DEBUG_PRINTLN(value, BIN);
RADIOLIB_DEBUG_PRINT(F("current:\t0b"));
RADIOLIB_DEBUG_PRINTLN(currentValue, BIN);
RADIOLIB_DEBUG_PRINT(F("mask:\t\t0b"));
RADIOLIB_DEBUG_PRINTLN(mask, BIN);
RADIOLIB_DEBUG_PRINT(F("new:\t\t0b"));
RADIOLIB_DEBUG_PRINTLN(newValue, BIN);
RADIOLIB_DEBUG_PRINT(F("read:\t\t0b"));
RADIOLIB_DEBUG_PRINTLN(readValue, BIN);
RADIOLIB_DEBUG_PRINTLN();
// check failed, print debug info
RADIOLIB_DEBUG_PRINTLN();
RADIOLIB_DEBUG_PRINT(F("address:\t0x"));
RADIOLIB_DEBUG_PRINTLN(reg, HEX);
RADIOLIB_DEBUG_PRINT(F("bits:\t\t"));
RADIOLIB_DEBUG_PRINT(msb);
RADIOLIB_DEBUG_PRINT(' ');
RADIOLIB_DEBUG_PRINTLN(lsb);
RADIOLIB_DEBUG_PRINT(F("value:\t\t0b"));
RADIOLIB_DEBUG_PRINTLN(value, BIN);
RADIOLIB_DEBUG_PRINT(F("current:\t0b"));
RADIOLIB_DEBUG_PRINTLN(currentValue, BIN);
RADIOLIB_DEBUG_PRINT(F("mask:\t\t0b"));
RADIOLIB_DEBUG_PRINTLN(mask, BIN);
RADIOLIB_DEBUG_PRINT(F("new:\t\t0b"));
RADIOLIB_DEBUG_PRINTLN(newValue, BIN);
RADIOLIB_DEBUG_PRINT(F("read:\t\t0b"));
RADIOLIB_DEBUG_PRINTLN(readValue, BIN);
RADIOLIB_DEBUG_PRINTLN();
return(ERR_SPI_WRITE_FAILED);
return(ERR_SPI_WRITE_FAILED);
#else
return(ERR_NONE);
#endif
}
void Module::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes) {
@ -336,21 +340,62 @@ RADIOLIB_PIN_STATUS Module::digitalRead(RADIOLIB_PIN_TYPE pin) {
}
void Module::tone(RADIOLIB_PIN_TYPE pin, uint16_t value) {
/// \todo Add tone support for platforms without tone()
#ifndef RADIOLIB_TONE_UNSUPPORTED
if(pin != RADIOLIB_NC) {
::tone(pin, 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) {
/// \todo Add tone support for platforms without tone()
#ifndef RADIOLIB_TONE_UNSUPPORTED
if(pin != RADIOLIB_NC) {
::noTone(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) {

View file

@ -4,7 +4,6 @@
#include "TypeDef.h"
#include <SPI.h>
//#include <Wire.h>
#ifndef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED
#include <SoftwareSerial.h>
#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.
@ -356,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.
@ -400,23 +420,51 @@ class Module {
static void noTone(RADIOLIB_PIN_TYPE pin);
/*!
\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!
\brief Arduino core attachInterrupt override.
\param rxEn RX enable pin.
\param interruptNum Interrupt number.
\param txEn TX enable pin.
\param userFunc Interrupt service routine.
\param mode Pin hcange direction.
*/
void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn);
static void attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode);
/*!
\brief Set RF switch state.
\brief Arduino core detachInterrupt override.
\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).
\param interruptNum Interrupt number.
*/
void setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState);
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:

View file

@ -1,4 +1,4 @@
#ifndef _RADIOLIB_H
#if !defined(_RADIOLIB_H)
#define _RADIOLIB_H
/*!

View file

@ -1,4 +1,4 @@
#ifndef _RADIOLIB_TYPES_H
#if !defined(_RADIOLIB_TYPES_H)
#define _RADIOLIB_TYPES_H
#include "BuildOpt.h"
@ -283,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
/*!
@ -320,6 +325,11 @@
*/
#define ERR_INVALID_MODULATION -107
/*!
\brief Supplied Peak type is invalid.
*/
#define ERR_INVALID_OOK_RSSI_PEAK_TYPE -108
// ESP8266 status codes
/*!

View file

@ -16,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
@ -28,10 +28,10 @@ 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(10);
Module::delay(10);
i++;
}
}
@ -41,7 +41,7 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po
_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
@ -96,18 +96,35 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po
}
int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) {
// calculate timeout (5ms + 500 % of expected time-on-air)
uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0);
// start transmission
int16_t state = startTransmit(data, len, addr);
RADIOLIB_ASSERT(state);
// wait for transmission start
while(!digitalRead(_mod->getIrq())) {
yield();
// wait for transmission start or timeout
uint32_t start = Module::micros();
while(!Module::digitalRead(_mod->getIrq())) {
Module::yield();
if(Module::micros() - start > timeout) {
standby();
SPIsendCommand(CC1101_CMD_FLUSH_TX);
return(ERR_TX_TIMEOUT);
}
}
// wait for transmission end
while(digitalRead(_mod->getIrq())) {
yield();
// wait for transmission end or timeout
start = Module::micros();
while(Module::digitalRead(_mod->getIrq())) {
Module::yield();
if(Module::micros() - start > timeout) {
standby();
SPIsendCommand(CC1101_CMD_FLUSH_TX);
return(ERR_TX_TIMEOUT);
}
}
// set mode to standby
@ -120,13 +137,35 @@ int16_t CC1101::transmit(uint8_t* data, size_t len, uint8_t addr) {
}
int16_t CC1101::receive(uint8_t* data, size_t len) {
// calculate timeout (500 ms + 400 full max-length packets at current bit rate)
uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(CC1101_MAX_PACKET_LENGTH*400.0);
// start reception
int16_t state = startReceive();
RADIOLIB_ASSERT(state);
// wait for rx queue to exceed threshold.
while (!digitalRead(_mod->getIrq())) {
yield();
// wait for sync word or timeout
uint32_t start = Module::micros();
while(!Module::digitalRead(_mod->getIrq())) {
Module::yield();
if(Module::micros() - start > timeout) {
standby();
SPIsendCommand(CC1101_CMD_FLUSH_TX);
return(ERR_RX_TIMEOUT);
}
}
// wait for packet end or timeout
start = Module::micros();
while(Module::digitalRead(_mod->getIrq())) {
Module::yield();
if(Module::micros() - start > timeout) {
standby();
SPIsendCommand(CC1101_CMD_FLUSH_TX);
return(ERR_RX_TIMEOUT);
}
}
// read packet data
@ -185,11 +224,11 @@ int16_t CC1101::packetMode() {
}
void CC1101::setGdo0Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) {
attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, dir);
Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, dir);
}
void CC1101::clearGdo0Action() {
detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()));
Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()));
}
void CC1101::setGdo2Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) {
@ -197,14 +236,14 @@ void CC1101::setGdo2Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) {
return;
}
Module::pinMode(_mod->getGpio(), INPUT);
attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_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(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()));
Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()));
}
int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
@ -414,12 +453,10 @@ int16_t CC1101::setBitRate(float br) {
// set bit rate value
int16_t state = SPIsetRegValue(CC1101_REG_MDMCFG4, e, 3, 0);
state |= SPIsetRegValue(CC1101_REG_MDMCFG3, m);
if (state == ERR_NONE) {
_br = br;
if(state == ERR_NONE) {
CC1101::_br = br;
}
return (state);
return(state);
}
int16_t CC1101::setRxBandwidth(float rxBw) {
@ -443,14 +480,13 @@ int16_t CC1101::setRxBandwidth(float rxBw) {
}
int16_t CC1101::setFrequencyDeviation(float freqDev) {
// set frequency deviation to lowest available setting (required for RTTY)
if(freqDev == 0.0) {
int16_t state = SPIsetRegValue(CC1101_REG_DEVIATN, 0, 6, 4);
state |= SPIsetRegValue(CC1101_REG_DEVIATN, 0, 2, 0);
return(state);
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
if(freqDev < 0.0) {
newFreqDev = 1.587;
}
RADIOLIB_CHECK_RANGE(freqDev, 1.587, 380.8, ERR_INVALID_FREQUENCY_DEVIATION);
RADIOLIB_CHECK_RANGE(newFreqDev, 1.587, 380.8, ERR_INVALID_FREQUENCY_DEVIATION);
// set mode to standby
SPIsendCommand(CC1101_CMD_IDLE);
@ -458,7 +494,7 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) {
// calculate exponent and mantissa values
uint8_t e = 0;
uint8_t m = 0;
getExpMant(freqDev * 1000.0, 8, 17, 7, e, m);
getExpMant(newFreqDev * 1000.0, 8, 17, 7, e, m);
// set frequency deviation value
int16_t state = SPIsetRegValue(CC1101_REG_DEVIATN, (e << 4), 6, 4);
@ -622,7 +658,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)
@ -678,9 +714,9 @@ uint8_t CC1101::getLQI() const {
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;
@ -698,23 +734,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) {
@ -761,10 +794,10 @@ int16_t CC1101::setDataShaping(uint8_t sh) {
// set data shaping
switch(sh) {
case RADIOLIB_SHAPING_NONE:
state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_2_FSK, 6, 4);
state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_2_FSK, 6, 4);
break;
case RADIOLIB_SHAPING_0_5:
state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_GFSK, 6, 4);
state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_GFSK, 6, 4);
break;
default:
return(ERR_INVALID_DATA_SHAPING);
@ -780,17 +813,17 @@ int16_t CC1101::setEncoding(uint8_t encoding) {
// set encoding
switch(encoding) {
case RADIOLIB_ENCODING_NRZ:
state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_OFF, 3, 3);
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));
return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF, 6, 6));
case RADIOLIB_ENCODING_MANCHESTER:
state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_ON, 3, 3);
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));
return(SPIsetRegValue(CC1101_REG_PKTCTRL0, CC1101_WHITE_DATA_OFF, 6, 6));
case RADIOLIB_ENCODING_WHITENING:
state = _mod->SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MANCHESTER_EN_OFF, 3, 3);
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);
}
@ -800,12 +833,36 @@ 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);
@ -863,11 +920,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
@ -921,10 +978,21 @@ 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);
}

View file

@ -456,7 +456,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
@ -528,7 +529,7 @@ class CC1101: public PhysicalLayer {
\param freqDev Frequency deviation from carrier frequency in kHz Defaults to 48.0 kHz.
\param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz.
\param rxBw Receiver bandwidth in kHz. Defaults to 135.0 kHz.
\param power Output power in dBm. Defaults to 10 dBm.
@ -875,12 +876,41 @@ class CC1101: public PhysicalLayer {
*/
void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn);
#ifndef RADIOLIB_GODMODE
private:
#endif
Module* _mod;
/*!
\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();
#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL)
protected:
#endif
Module* _mod;
// SPI read overrides to set bit for burst write and status registers access
int16_t SPIgetRegValue(uint8_t reg, uint8_t msb = 7, uint8_t lsb = 0);
int16_t SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2);
void SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes);
uint8_t SPIreadRegister(uint8_t reg);
void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len);
void SPIwriteRegister(uint8_t reg, uint8_t data);
void SPIsendCommand(uint8_t cmd);
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
float _freq = 0;
float _br = 0;
uint8_t _rawRSSI = 0;
uint8_t _rawLQI = 0;
uint8_t _modulation = CC1101_MOD_FORMAT_2_FSK;
@ -899,16 +929,6 @@ class CC1101: public PhysicalLayer {
int16_t directMode();
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
int16_t SPIgetRegValue(uint8_t reg, uint8_t msb = 7, uint8_t lsb = 0);
int16_t SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2);
void SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes);
uint8_t SPIreadRegister(uint8_t reg);
void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len);
void SPIwriteRegister(uint8_t reg, uint8_t data);
void SPIsendCommand(uint8_t cmd);
};
#endif

View file

@ -30,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);
}
@ -192,11 +192,11 @@ int16_t ESP8266::send(uint8_t* data, size_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);
@ -209,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);
}
}
@ -220,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;
}

View file

@ -55,10 +55,14 @@ class ESP8266: public TransportLayer {
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:
#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL)
protected:
#endif
Module* _mod;
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
};
#endif

View file

@ -18,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
@ -33,7 +33,7 @@ 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(10);
Module::delay(10);
i++;
}
}
@ -43,7 +43,7 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe
_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
@ -102,9 +102,9 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe
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) {
@ -116,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);
@ -145,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();
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_RX_TIMEOUT);
@ -267,26 +267,26 @@ int16_t RF69::startReceive() {
}
void RF69::setDio0Action(void (*func)(void)) {
attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING);
Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING);
}
void RF69::clearDio0Action() {
detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_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(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_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(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()));
Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()));
}
int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
@ -369,23 +369,26 @@ int16_t RF69::readData(uint8_t* data, size_t len) {
return(ERR_NONE);
}
int16_t CC1101::setOOK(bool enableOOK) {
// Change modulation
int16_t RF69::setOOK(bool enableOOK) {
// set OOK and if successful, save the new setting
int16_t state = ERR_NONE;
if(enableOOK) {
int16_t state = SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_OOK, 4, 3);
RADIOLIB_ASSERT(state);
// update current modulation
_modulation = CC1101_MOD_FORMAT_ASK_OOK;
state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_OOK, 4, 3, 5);
} else {
int16_t state = SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK, 4, 3);
RADIOLIB_ASSERT(state);
// update current modulation
_modulation = CC1101_MOD_FORMAT_2_FSK;
state = _mod->SPIsetRegValue(RF69_REG_DATA_MODUL, RF69_FSK, 4, 3, 5);
}
if(state == ERR_NONE) {
_ook = enableOOK;
}
return(setOutputPower(_power));
return(state);
}
int16_t RF69::setOokThresholdType(uint8_t type) {
if((type != RF69_OOK_THRESH_FIXED) && (type != RF69_OOK_THRESH_PEAK) && (type != RF69_OOK_THRESH_AVERAGE)) {
return(ERR_INVALID_OOK_RSSI_PEAK_TYPE);
}
return(_mod->SPIsetRegValue(RF69_REG_OOK_PEAK, type, 7, 3, 5));
}
int16_t RF69::setFrequency(float freq) {
@ -401,11 +404,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) {
@ -525,8 +527,14 @@ int16_t RF69::setRxBandwidth(float rxBw) {
}
int16_t RF69::setFrequencyDeviation(float freqDev) {
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
if(freqDev < 0.0) {
newFreqDev = 0.6;
}
// check frequency deviation range
if(!((freqDev + _br/2 <= 500))) {
if(!((newFreqDev + _br/2 <= 500))) {
return(ERR_INVALID_FREQUENCY_DEVIATION);
}
@ -535,7 +543,7 @@ int16_t RF69::setFrequencyDeviation(float freqDev) {
// set frequency deviation from carrier frequency
uint32_t base = 1;
uint32_t fdev = (freqDev * (base << 19)) / 32000;
uint32_t fdev = (newFreqDev * (base << 19)) / 32000;
int16_t state = _mod->SPIsetRegValue(RF69_REG_FDEV_MSB, (fdev & 0xFF00) >> 8, 5, 0);
state |= _mod->SPIsetRegValue(RF69_REG_FDEV_LSB, fdev & 0x00FF, 7, 0);
@ -659,7 +667,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);
@ -776,6 +784,14 @@ int16_t RF69::setEncoding(uint8_t encoding) {
}
}
int16_t RF69::setLnaTestBoost(bool value) {
if(value) {
return (_mod->SPIsetRegValue(RF69_REG_TEST_LNA, RF69_TEST_LNA_BOOST_HIGH, 7, 0));
}
return(_mod->SPIsetRegValue(RF69_TEST_LNA_BOOST_NORMAL, RF69_TEST_LNA_BOOST_HIGH, 7, 0));
}
float RF69::getRSSI() {
return(-1.0 * (_mod->SPIgetRegValue(RF69_REG_RSSI_VALUE)/2.0));
}
@ -784,6 +800,29 @@ 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;

View file

@ -91,6 +91,7 @@
#define RF69_REG_AES_KEY_16 0x4D
#define RF69_REG_TEMP_1 0x4E
#define RF69_REG_TEMP_2 0x4F
#define RF69_REG_TEST_LNA 0x58
#define RF69_REG_TEST_PA1 0x5A
#define RF69_REG_TEST_PA2 0x5C
#define RF69_REG_TEST_DAGC 0x6F
@ -162,6 +163,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)
@ -406,6 +410,10 @@
#define RF69_AES_OFF 0b00000000 // 0 0 AES encryption disabled (default)
#define RF69_AES_ON 0b00000001 // 0 0 AES encryption enabled, payload size limited to 66 bytes
// RF69_REG_TEST_LNA
#define RF69_TEST_LNA_BOOST_NORMAL 0x1B // 7 0
#define RF69_TEST_LNA_BOOST_HIGH 0x2D // 7 0
// RF69_REG_TEMP_1
#define RF69_TEMP_MEAS_START 0b00001000 // 3 3 trigger temperature measurement
#define RF69_TEMP_MEAS_RUNNING 0b00000100 // 2 2 temperature measurement status: on-going
@ -740,6 +748,24 @@ class RF69: public PhysicalLayer {
*/
size_t getPacketLength(bool update = true) override;
/*!
\brief Enables/disables OOK modulation instead of FSK.
\param enableOOK Enable (true) or disable (false) OOK.
\returns \ref status_codes
*/
int16_t setOOK(bool enableOOK);
/*!
\brief Selects the type of threshold in the OOK data slicer
\param type Threshold type: RF69_OOK_THRESH_PEAK(default), RF69_OOK_THRESH_FIXED or RF69_OOK_THRESH_AVERAGE
\returns \ref status_codes
*/
int16_t setOokThresholdType(uint8_t type);
/*!
\brief Set modem in fixed packet length mode.
@ -777,7 +803,7 @@ class RF69: public PhysicalLayer {
/*!
\brief Enable CRC filtering and generation.
\param crcOn Set or unset promiscuous mode.
\param crcOn Set or unset CRC filtering.
\returns \ref status_codes
*/
@ -812,6 +838,15 @@ class RF69: public PhysicalLayer {
*/
int16_t setEncoding(uint8_t encoding) override;
/*!
\brief Enable/disable LNA Boost mode (disabled by default).
\param value True to enable, false to disable.
\returns \ref status_codes
*/
int16_t setLnaTestBoost(bool value);
/*!
\brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet.
@ -829,13 +864,32 @@ class RF69: public PhysicalLayer {
*/
void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn);
#ifndef RADIOLIB_GODMODE
/*!
\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();
#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL)
protected:
#endif
Module* _mod;
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
float _br = 0;
float _rxBw = 0;
bool _ook = false;
int16_t _tempOffset = 0;
int8_t _power = 0;
@ -851,7 +905,7 @@ class RF69: public PhysicalLayer {
int16_t directMode();
int16_t setPacketMode(uint8_t mode, uint8_t len);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif
int16_t setMode(uint8_t mode);

View file

@ -16,16 +16,14 @@ int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW
// some other error
return(state);
}
// configure settings not accessible by API
state = config();
RADIOLIB_ASSERT(state);
RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278"));
RADIOLIB_DEBUG_PRINTLN(F("M\tRFM95"));
// configure publicly accessible settings
state = setFrequency(freq);
state = setBandwidth(bw);
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
@ -45,8 +43,12 @@ 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, 862.0, 1020.0, ERR_INVALID_FREQUENCY);
// set frequency
return(SX127x::setFrequencyRaw(freq));
// set frequency and if successful, save the new setting
int16_t state = SX127x::setFrequencyRaw(freq);
if(state == ERR_NONE) {
SX127x::_freq = freq;
}
return(state);
}
#endif

View file

@ -68,7 +68,7 @@ class RFM95: public SX1278 {
*/
int16_t setFrequency(float freq);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -16,16 +16,14 @@ int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW
// some other error
return(state);
}
// configure settings not accessible by API
state = config();
RADIOLIB_ASSERT(state);
RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278"));
RADIOLIB_DEBUG_PRINTLN(F("M\tRFM96"));
// configure publicly accessible settings
state = setFrequency(freq);
state = setBandwidth(bw);
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
@ -46,8 +44,12 @@ int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW
int16_t RFM96::setFrequency(float freq) {
RADIOLIB_CHECK_RANGE(freq, 410.0, 525.0, ERR_INVALID_FREQUENCY);
// set frequency
return(SX127x::setFrequencyRaw(freq));
// set frequency and if successful, save the new setting
int16_t state = SX127x::setFrequencyRaw(freq);
if(state == ERR_NONE) {
SX127x::_freq = freq;
}
return(state);
}
#endif

View file

@ -68,7 +68,7 @@ class RFM96: public SX1278 {
*/
int16_t setFrequency(float freq);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -38,7 +38,7 @@ class RFM97: public RFM95 {
*/
int16_t setSpreadingFactor(uint8_t sf);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -15,7 +15,7 @@ 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;
@ -25,13 +25,13 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po
RADIOLIB_DEBUG_PRINT(i + 1);
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(10);
Module::delay(10);
i++;
}
}
@ -40,13 +40,13 @@ int16_t SX1231::begin(float freq, float br, float rxBw, float freqDev, int8_t po
RADIOLIB_DEBUG_PRINTLN(F("No SX1231 found!"));
_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);

View file

@ -51,7 +51,7 @@ class SX1231: public RF69 {
*/
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
#if !defined(RADIOLIB_GODMODE)
private:
#endif
uint8_t _chipRevision = 0;

View file

@ -35,7 +35,7 @@ class SX1261 : public SX1262 {
*/
int16_t setOutputPower(int8_t power);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -95,7 +95,7 @@ class SX1262: public SX126x {
*/
int16_t setOutputPower(int8_t power);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -95,7 +95,7 @@ class SX1268: public SX126x {
*/
int16_t setOutputPower(int8_t power);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -10,6 +10,7 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16
_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;
@ -80,6 +81,7 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL
_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
@ -159,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
@ -168,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();
@ -178,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);
}
}
@ -223,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);
@ -283,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();
@ -354,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
@ -384,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);
}
@ -402,11 +404,11 @@ int16_t SX126x::standby(uint8_t mode) {
}
void SX126x::setDio1Action(void (*func)(void)) {
attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING);
Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING);
}
void SX126x::clearDio1Action() {
detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()));
Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()));
}
int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
@ -463,8 +465,8 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
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);
@ -730,11 +732,17 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) {
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
return(ERR_WRONG_MODEM);
}
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
if(freqDev < 0.0) {
newFreqDev = 0.6;
}
RADIOLIB_CHECK_RANGE(freqDev, 0.0, 200.0, ERR_INVALID_FREQUENCY_DEVIATION);
RADIOLIB_CHECK_RANGE(newFreqDev, 0.6, 200.0, ERR_INVALID_FREQUENCY_DEVIATION);
// calculate raw frequency deviation value
uint32_t freqDevRaw = (uint32_t)(((freqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (SX126X_CRYSTAL_FREQ * 1000000.0));
uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (SX126X_CRYSTAL_FREQ * 1000000.0));
// check modulation parameters
/*if(2 * freqDevRaw + _br > _rxBwKhz * 1000.0) {
@ -1128,6 +1136,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));
}
@ -1173,6 +1188,27 @@ int16_t SX126x::autoLDRO() {
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();
@ -1182,6 +1218,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) {
@ -1531,9 +1572,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);
@ -1565,14 +1606,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);
}
}
@ -1632,15 +1673,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;
}
@ -1689,8 +1730,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) || defined(SAMD_SERIES)
delay(1);
#if defined(RADIOLIB_SPI_SLOWDOWN)
Module::delay(1);
#endif
#endif

View file

@ -733,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);
@ -803,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.
@ -854,7 +864,7 @@ class SX126x: public PhysicalLayer {
/*!
\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()
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).
@ -870,6 +880,13 @@ class SX126x: public PhysicalLayer {
*/
int16_t autoLDRO();
/*!
\brief Get one truly random byte from RSSI noise.
\returns TRNG byte.
*/
uint8_t random();
#ifndef RADIOLIB_GODMODE
protected:
#endif
@ -911,11 +928,22 @@ class SX126x: public PhysicalLayer {
int16_t fixImplicitTimeout();
int16_t fixInvertedIQ(uint8_t iqConfig);
#ifndef RADIOLIB_GODMODE
private:
#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL)
protected:
#endif
Module* _mod;
// common low-level SPI interface
int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout = 5000);
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
uint8_t _bw = 0, _sf = 0, _cr = 0, _ldro = 0, _crcType = 0, _headerType = 0;
uint16_t _preambleLength = 0;
float _bwKhz = 0;
@ -933,13 +961,6 @@ class SX126x: public PhysicalLayer {
size_t _implicitLen = 0;
int16_t config(uint8_t modem);
// common low-level SPI interface
int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout = 5000);
};
#endif

View file

@ -10,20 +10,16 @@ int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
int16_t state = SX127x::begin(SX1272_CHIP_VERSION, syncWord, preambleLength);
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
RADIOLIB_ASSERT(state);
// mitigation of receiver spurious response
// see SX1272/73 Errata, section 2.2 for details
state = _mod->SPIsetRegValue(0x31, 0b10000000, 7, 7);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
state = setBandwidth(bw);
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
@ -54,21 +50,26 @@ int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setDataShaping(RADIOLIB_SHAPING_NONE);
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
RADIOLIB_ASSERT(state);
if(enableOOK) {
state = setDataShapingOOK(RADIOLIB_SHAPING_NONE);
RADIOLIB_ASSERT(state);
} else {
state = setDataShaping(RADIOLIB_SHAPING_NONE);
RADIOLIB_ASSERT(state);
}
return(state);
}
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) {
@ -242,11 +243,6 @@ int16_t SX1272::setOutputPower(int8_t power) {
}
int16_t SX1272::setGain(uint8_t gain) {
// check active modem
if(getActiveModem() != SX127X_LORA) {
return(ERR_WRONG_MODEM);
}
// check allowed range
if(gain > 6) {
return(ERR_INVALID_GAIN);
@ -255,14 +251,30 @@ int16_t SX1272::setGain(uint8_t gain) {
// set mode to standby
int16_t state = SX127x::standby();
// set gain
if(gain == 0) {
// gain set to 0, enable AGC loop
state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_AGC_AUTO_ON, 2, 2);
} else {
state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_AGC_AUTO_OFF, 2, 2);
state |= _mod->SPIsetRegValue(SX127X_REG_LNA, (gain << 5) | SX127X_LNA_BOOST_ON);
// get modem
int16_t modem = getActiveModem();
if(modem == SX127X_LORA){
// set gain
if(gain == 0) {
// gain set to 0, enable AGC loop
state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_AGC_AUTO_ON, 2, 2);
} else {
state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_AGC_AUTO_OFF, 2, 2);
state |= _mod->SPIsetRegValue(SX127X_REG_LNA, (gain << 5) | SX127X_LNA_BOOST_ON);
}
} else if(modem == SX127X_FSK_OOK) {
// set gain
if(gain == 0) {
// gain set to 0, enable AGC loop
state |= _mod->SPIsetRegValue(SX127X_REG_RX_CONFIG, SX127X_AGC_AUTO_ON, 3, 3);
} else {
state |= _mod->SPIsetRegValue(SX127X_REG_RX_CONFIG, SX127X_AGC_AUTO_ON, 3, 3);
state |= _mod->SPIsetRegValue(SX127X_REG_LNA, (gain << 5) | SX127X_LNA_BOOST_ON);
}
}
return(state);
}
@ -273,7 +285,7 @@ int16_t SX1272::setDataShaping(uint8_t sh) {
}
// check modulation
if(!SX127x::_ook) {
if(SX127x::_ook) {
return(ERR_INVALID_MODULATION);
}
@ -329,7 +341,7 @@ int16_t SX1272::setDataShapingOOK(uint8_t sh) {
return(state);
}
float SX1272::getRSSI() {
float SX1272::getRSSI(bool skipReceive) {
if(getActiveModem() == SX127X_LORA) {
// RSSI calculation uses different constant for low-frequency and high-frequency ports
float lastPacketRSSI = -139 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE);
@ -345,33 +357,47 @@ float SX1272::getRSSI() {
} else {
// enable listen mode
startReceive();
if(!skipReceive) {
startReceive();
}
// read the value for FSK
float rssi = (float)_mod->SPIgetRegValue(SX127X_REG_RSSI_VALUE_FSK) / -2.0;
// set mode back to standby
standby();
if(!skipReceive) {
standby();
}
// return the value
return(rssi);
}
}
int16_t SX1272::setCRC(bool enableCRC) {
int16_t SX1272::setCRC(bool enable, bool mode) {
if(getActiveModem() == SX127X_LORA) {
// set LoRa CRC
if(enableCRC) {
SX127x::_crcEnabled = enable;
if(enable) {
return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_RX_CRC_MODE_ON, 2, 2));
} else {
return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_RX_CRC_MODE_OFF, 2, 2));
}
} else {
// set FSK CRC
if(enableCRC) {
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_ON, 4, 4));
int16_t state = ERR_NONE;
if(enable) {
state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_ON, 4, 4);
} else {
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_OFF, 4, 4));
state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_OFF, 4, 4);
}
RADIOLIB_ASSERT(state);
// set FSK CRC mode
if(mode) {
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_WHITENING_TYPE_IBM, 0, 0));
} else {
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0));
}
}
}
@ -398,6 +424,13 @@ int16_t SX1272::autoLDRO() {
return(ERR_NONE);
}
int16_t SX1272::implicitHeader(size_t len) {
return(setHeaderType(SX1272_HEADER_IMPL_MODE, len));
}
int16_t SX1272::explicitHeader() {
return(setHeaderType(SX1272_HEADER_EXPL_MODE));
}
int16_t SX1272::setBandwidthRaw(uint8_t newBandwidth) {
// set mode to standby
@ -414,12 +447,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);
@ -436,6 +469,26 @@ int16_t SX1272::setCodingRateRaw(uint8_t newCodingRate) {
return(state);
}
int16_t SX1272::setHeaderType(uint8_t headerType, size_t len) {
// check active modem
if(getActiveModem() != SX127X_LORA) {
return(ERR_WRONG_MODEM);
}
// set requested packet mode
int16_t state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, headerType, 2, 2);
RADIOLIB_ASSERT(state);
// set length to register
state = _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len);
RADIOLIB_ASSERT(state);
// update cached value
_packetLength = len;
return(state);
}
int16_t SX1272::configFSK() {
// configure common registers
int16_t state = SX127x::configFSK();
@ -443,11 +496,6 @@ int16_t SX1272::configFSK() {
// set fast PLL hop
state = _mod->SPIsetRegValue(SX1272_REG_PLL_HOP, SX127X_FAST_HOP_ON, 7, 7);
RADIOLIB_ASSERT(state);
// set Gauss filter BT product to 0.5
state = _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_5, 4, 3);
return(state);
}

View file

@ -27,7 +27,7 @@
#define SX1272_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz
#define SX1272_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers
// SX1272_REG_MODEM_CONFIG_1
// SX127X_REG_MODEM_CONFIG_1
#define SX1272_BW_125_00_KHZ 0b00000000 // 7 6 bandwidth: 125 kHz
#define SX1272_BW_250_00_KHZ 0b01000000 // 7 6 250 kHz
#define SX1272_BW_500_00_KHZ 0b10000000 // 7 6 500 kHz
@ -42,7 +42,7 @@
#define SX1272_LOW_DATA_RATE_OPT_OFF 0b00000000 // 0 0 low data rate optimization disabled
#define SX1272_LOW_DATA_RATE_OPT_ON 0b00000001 // 0 0 low data rate optimization enabled, mandatory for SF 11 and 12 with BW 125 kHz
// SX1272_REG_MODEM_CONFIG_2
// SX127X_REG_MODEM_CONFIG_2
#define SX1272_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA
#define SX1272_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop
@ -240,18 +240,22 @@ class SX1272: public SX127x {
/*!
\brief Gets recorded signal strength indicator of the latest received packet for LoRa modem, or current RSSI level for FSK modem.
\param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FKS/OOK mode.
\returns Last packet RSSI for LoRa modem, or current RSSI level for FSK modem.
*/
float getRSSI();
float getRSSI(bool skipReceive = false);
/*!
\brief Enables/disables CRC check of received packets.
\param enableCRC Enable (true) or disable (false) CRC.
\param enable Enable (true) or disable (false) CRC.
\param mode Set CRC mode to SX127X_CRC_WHITENING_TYPE_CCITT for CCITT, polynomial X16 + X12 + X5 + 1 (false) or SX127X_CRC_WHITENING_TYPE_IBM for IBM, polynomial X16 + X15 + X2 + 1 (true). Only valid in FSK mode.
\returns \ref status_codes
*/
int16_t setCRC(bool enableCRC);
int16_t setCRC(bool enable, bool mode = false);
/*!
\brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to
@ -271,16 +275,33 @@ class SX1272: public SX127x {
*/
int16_t autoLDRO();
#ifndef RADIOLIB_GODMODE
/*!
\brief Set implicit header mode for future reception/transmission.
\returns \ref status_codes
*/
int16_t implicitHeader(size_t len);
/*!
\brief Set explicit header mode for future reception/transmission.
\param len Payload length in bytes.
\returns \ref status_codes
*/
int16_t explicitHeader();
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
int16_t setBandwidthRaw(uint8_t newBandwidth);
int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor);
int16_t setCodingRateRaw(uint8_t newCodingRate);
int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF);
int16_t configFSK();
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif
bool _ldroAuto = true;

View file

@ -10,20 +10,16 @@ int16_t SX1273::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
int16_t state = SX127x::begin(SX1272_CHIP_VERSION, syncWord, preambleLength);
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
RADIOLIB_ASSERT(state);
// mitigation of receiver spurious response
// see SX1272/73 Errata, section 2.2 for details
state = _mod->SPIsetRegValue(0x31, 0b10000000, 7, 7);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
state = setBandwidth(bw);
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);

View file

@ -62,7 +62,7 @@ class SX1273: public SX1272 {
*/
int16_t setSpreadingFactor(uint8_t sf);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -10,15 +10,11 @@ int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, preambleLength);
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
state = setBandwidth(bw);
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
@ -36,6 +32,24 @@ int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
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);
}
int16_t SX1276::setFrequency(float freq) {
RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, ERR_INVALID_FREQUENCY);
@ -102,8 +116,12 @@ int16_t SX1276::setFrequency(float freq) {
}
}
// set frequency
return(SX127x::setFrequencyRaw(freq));
// set frequency and if successful, save the new setting
int16_t state = SX127x::setFrequencyRaw(freq);
if(state == ERR_NONE) {
SX127x::_freq = freq;
}
return(state);
}
#endif

View file

@ -51,6 +51,28 @@ class SX1276: public SX1278 {
*/
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
/*!
@ -62,7 +84,7 @@ class SX1276: public SX1278 {
*/
int16_t setFrequency(float freq);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -10,15 +10,11 @@ int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, preambleLength);
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
state = setBandwidth(bw);
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
@ -36,6 +32,24 @@ int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
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);
}
int16_t SX1277::setFrequency(float freq) {
RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, ERR_INVALID_FREQUENCY);
@ -103,7 +117,11 @@ int16_t SX1277::setFrequency(float freq) {
}
// set frequency and if successful, save the new setting
return(SX127x::setFrequencyRaw(freq));
int16_t state = SX127x::setFrequencyRaw(freq);
if(state == ERR_NONE) {
SX127x::_freq = freq;
}
return(state);
}
int16_t SX1277::setSpreadingFactor(uint8_t sf) {

View file

@ -51,6 +51,28 @@ class SX1277: public SX1278 {
*/
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
/*!
@ -71,7 +93,7 @@ class SX1277: public SX1278 {
*/
int16_t setSpreadingFactor(uint8_t sf);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -10,15 +10,11 @@ int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, preambleLength);
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
state = setBandwidth(bw);
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
@ -52,8 +48,13 @@ int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
state = setOutputPower(power);
RADIOLIB_ASSERT(state);
state = setDataShaping(RADIOLIB_SHAPING_NONE);
RADIOLIB_ASSERT(state);
if(enableOOK) {
state = setDataShapingOOK(RADIOLIB_SHAPING_NONE);
RADIOLIB_ASSERT(state);
} else {
state = setDataShaping(RADIOLIB_SHAPING_NONE);
RADIOLIB_ASSERT(state);
}
return(state);
}
@ -61,9 +62,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) {
@ -314,11 +315,6 @@ int16_t SX1278::setOutputPower(int8_t power) {
}
int16_t SX1278::setGain(uint8_t gain) {
// check active modem
if(getActiveModem() != SX127X_LORA) {
return(ERR_WRONG_MODEM);
}
// check allowed range
if(gain > 6) {
return(ERR_INVALID_GAIN);
@ -327,14 +323,30 @@ int16_t SX1278::setGain(uint8_t gain) {
// set mode to standby
int16_t state = SX127x::standby();
// set gain
if(gain == 0) {
// gain set to 0, enable AGC loop
state |= _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_AGC_AUTO_ON, 2, 2);
} else {
state |= _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_AGC_AUTO_OFF, 2, 2);
state |= _mod->SPIsetRegValue(SX127X_REG_LNA, (gain << 5) | SX127X_LNA_BOOST_ON);
// get modem
int16_t modem = getActiveModem();
if(modem == SX127X_LORA){
// set gain
if(gain == 0) {
// gain set to 0, enable AGC loop
state |= _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_AGC_AUTO_ON, 2, 2);
} else {
state |= _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_AGC_AUTO_OFF, 2, 2);
state |= _mod->SPIsetRegValue(SX127X_REG_LNA, (gain << 5) | SX127X_LNA_BOOST_ON);
}
} else if(modem == SX127X_FSK_OOK) {
// set gain
if(gain == 0) {
// gain set to 0, enable AGC loop
state |= _mod->SPIsetRegValue(SX127X_REG_RX_CONFIG, SX127X_AGC_AUTO_ON, 3, 3);
} else {
state |= _mod->SPIsetRegValue(SX127X_REG_RX_CONFIG, SX127X_AGC_AUTO_ON, 3, 3);
state |= _mod->SPIsetRegValue(SX127X_REG_LNA, (gain << 5) | SX127X_LNA_BOOST_ON);
}
}
return(state);
}
@ -356,13 +368,13 @@ int16_t SX1278::setDataShaping(uint8_t sh) {
// set data shaping
switch(sh) {
case RADIOLIB_SHAPING_NONE:
return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1278_NO_SHAPING, 6, 5));
return(_mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_NO_SHAPING, 6, 5));
case RADIOLIB_SHAPING_0_3:
return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1278_FSK_GAUSSIAN_0_3, 6, 5));
return(_mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_3, 6, 5));
case RADIOLIB_SHAPING_0_5:
return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1278_FSK_GAUSSIAN_0_5, 6, 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_OP_MODE, SX1278_FSK_GAUSSIAN_1_0, 6, 5));
return(_mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_1_0, 6, 5));
default:
return(ERR_INVALID_DATA_SHAPING);
}
@ -400,7 +412,7 @@ int16_t SX1278::setDataShapingOOK(uint8_t sh) {
return(state);
}
float SX1278::getRSSI() {
float SX1278::getRSSI(bool skipReceive) {
if(getActiveModem() == SX127X_LORA) {
// for LoRa, get RSSI of the last packet
float lastPacketRSSI;
@ -423,33 +435,47 @@ float SX1278::getRSSI() {
} else {
// enable listen mode
startReceive();
if(!skipReceive) {
startReceive();
}
// read the value for FSK
float rssi = (float)_mod->SPIgetRegValue(SX127X_REG_RSSI_VALUE_FSK) / -2.0;
// set mode back to standby
standby();
if(!skipReceive) {
standby();
}
// return the value
return(rssi);
}
}
int16_t SX1278::setCRC(bool enableCRC) {
int16_t SX1278::setCRC(bool enable, bool mode) {
if(getActiveModem() == SX127X_LORA) {
// set LoRa CRC
if(enableCRC) {
SX127x::_crcEnabled = enable;
if(enable) {
return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_ON, 2, 2));
} else {
return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_OFF, 2, 2));
}
} else {
// set FSK CRC
if(enableCRC) {
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_ON, 4, 4));
int16_t state = ERR_NONE;
if(enable) {
state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_ON, 4, 4);
} else {
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_OFF, 4, 4));
state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_OFF, 4, 4);
}
RADIOLIB_ASSERT(state);
// set FSK CRC mode
if(mode) {
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_WHITENING_TYPE_IBM, 0, 0));
} else {
return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0));
}
}
}
@ -476,6 +502,14 @@ int16_t SX1278::autoLDRO() {
return(ERR_NONE);
}
int16_t SX1278::implicitHeader(size_t len) {
return(setHeaderType(SX1278_HEADER_IMPL_MODE, len));
}
int16_t SX1278::explicitHeader() {
return(setHeaderType(SX1278_HEADER_EXPL_MODE));
}
int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) {
// set mode to standby
int16_t state = SX127x::standby();
@ -492,12 +526,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);
}
@ -513,6 +547,26 @@ int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) {
return(state);
}
int16_t SX1278::setHeaderType(uint8_t headerType, size_t len) {
// check active modem
if(getActiveModem() != SX127X_LORA) {
return(ERR_WRONG_MODEM);
}
// set requested packet mode
int16_t state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, headerType, 0, 0);
RADIOLIB_ASSERT(state);
// set length to register
state = _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len);
RADIOLIB_ASSERT(state);
// update cached value
_packetLength = len;
return(state);
}
int16_t SX1278::configFSK() {
// configure common registers
int16_t state = SX127x::configFSK();
@ -520,11 +574,6 @@ int16_t SX1278::configFSK() {
// set fast PLL hop
state = _mod->SPIsetRegValue(SX1278_REG_PLL_HOP, SX127X_FAST_HOP_ON, 7, 7);
RADIOLIB_ASSERT(state);
// set Gauss filter BT product to 0.5
state = _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_5, 6, 5);
return(state);
}

View file

@ -38,7 +38,7 @@
// SX1278_REG_LNA
#define SX1278_LNA_BOOST_LF_OFF 0b00000000 // 4 3 default LNA current
// SX1278_REG_MODEM_CONFIG_1
// SX127X_REG_MODEM_CONFIG_1
#define SX1278_BW_7_80_KHZ 0b00000000 // 7 4 bandwidth: 7.80 kHz
#define SX1278_BW_10_40_KHZ 0b00010000 // 7 4 10.40 kHz
#define SX1278_BW_15_60_KHZ 0b00100000 // 7 4 15.60 kHz
@ -56,7 +56,7 @@
#define SX1278_HEADER_EXPL_MODE 0b00000000 // 0 0 explicit header mode
#define SX1278_HEADER_IMPL_MODE 0b00000001 // 0 0 implicit header mode
// SX1278_REG_MODEM_CONFIG_2
// SX127X_REG_MODEM_CONFIG_2
#define SX1278_RX_CRC_MODE_OFF 0b00000000 // 2 2 CRC disabled
#define SX1278_RX_CRC_MODE_ON 0b00000100 // 2 2 CRC enabled
@ -248,18 +248,22 @@ class SX1278: public SX127x {
/*!
\brief Gets recorded signal strength indicator of the latest received packet for LoRa modem, or current RSSI level for FSK modem.
\param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FKS/OOK mode.
\returns Last packet RSSI for LoRa modem, or current RSSI level for FSK modem.
*/
float getRSSI();
float getRSSI(bool skipReceive = false);
/*!
\brief Enables/disables CRC check of received packets.
\param enableCRC Enable (true) or disable (false) CRC.
\param enable Enable (true) or disable (false) CRC.
\param mode Set CRC mode to SX127X_CRC_WHITENING_TYPE_CCITT for CCITT, polynomial X16 + X12 + X5 + 1 (false) or SX127X_CRC_WHITENING_TYPE_IBM for IBM, polynomial X16 + X15 + X2 + 1 (true). Only valid in FSK mode.
\returns \ref status_codes
*/
int16_t setCRC(bool enableCRC);
int16_t setCRC(bool enable, bool mode = false);
/*!
\brief Forces LoRa low data rate optimization. Only available in LoRa mode. After calling this method, LDRO will always be set to
@ -279,16 +283,33 @@ class SX1278: public SX127x {
*/
int16_t autoLDRO();
#ifndef RADIOLIB_GODMODE
/*!
\brief Set implicit header mode for future reception/transmission.
\returns \ref status_codes
*/
int16_t implicitHeader(size_t len);
/*!
\brief Set explicit header mode for future reception/transmission.
\param len Payload length in bytes.
\returns \ref status_codes
*/
int16_t explicitHeader();
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
int16_t setBandwidthRaw(uint8_t newBandwidth);
int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor);
int16_t setCodingRateRaw(uint8_t newCodingRate);
int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF);
int16_t configFSK();
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif
bool _ldroAuto = true;

View file

@ -10,15 +10,11 @@ int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
int16_t state = SX127x::begin(SX1278_CHIP_VERSION, syncWord, preambleLength);
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config();
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
state = setBandwidth(bw);
RADIOLIB_ASSERT(state);
state = setBandwidth(bw);
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setSpreadingFactor(sf);
@ -36,11 +32,33 @@ int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
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);
}
int16_t SX1279::setFrequency(float freq) {
RADIOLIB_CHECK_RANGE(freq, 137.0, 960.0, ERR_INVALID_FREQUENCY);
// set frequency
return(SX127x::setFrequencyRaw(freq));
// set frequency and if successful, save the new setting
int16_t state = SX127x::setFrequencyRaw(freq);
if(state == ERR_NONE) {
SX127x::_freq = freq;
}
return(state);
}
#endif

View file

@ -51,6 +51,28 @@ class SX1279: public SX1278 {
*/
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
/*!
@ -62,7 +84,7 @@ class SX1279: public SX1278 {
*/
int16_t setFrequency(float freq);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -16,14 +16,17 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint16_t preambleLe
RADIOLIB_DEBUG_PRINTLN(F("No SX127x found!"));
_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
@ -59,12 +62,14 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB
RADIOLIB_DEBUG_PRINTLN(F("No SX127x found!"));
_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);
// check currently active modem
int16_t state;
if(getActiveModem() != SX127X_FSK_OOK) {
// set FSK mode
state = setActiveModem(SX127X_FSK_OOK);
@ -143,10 +148,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);
}
@ -161,10 +166,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);
@ -175,7 +180,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
@ -197,9 +202,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);
}
@ -214,10 +219,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);
}
@ -255,9 +260,9 @@ int16_t SX127x::scanChannel() {
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);
}
@ -395,25 +400,25 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) {
}
void SX127x::setDio0Action(void (*func)(void)) {
attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING);
Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING);
}
void SX127x::clearDio0Action() {
detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_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(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_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(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()));
Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()));
}
int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
@ -453,7 +458,9 @@ 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);
@ -488,11 +495,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);
}
@ -581,9 +595,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);
}
@ -693,8 +708,14 @@ int16_t SX127x::setFrequencyDeviation(float freqDev) {
return(ERR_WRONG_MODEM);
}
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
if(freqDev < 0.0) {
newFreqDev = 0.6;
}
// check frequency deviation range
if(!((freqDev + _br/2.0 <= 250.0) && (freqDev <= 200.0))) {
if(!((newFreqDev + _br/2.0 <= 250.0) && (freqDev <= 200.0))) {
return(ERR_INVALID_FREQUENCY_DEVIATION);
}
@ -704,7 +725,7 @@ int16_t SX127x::setFrequencyDeviation(float freqDev) {
// set allowed frequency deviation
uint32_t base = 1;
uint32_t FDEV = (freqDev * (base << 19)) / 32000;
uint32_t FDEV = (newFreqDev * (base << 19)) / 32000;
state = _mod->SPIsetRegValue(SX127X_REG_FDEV_MSB, (FDEV & 0xFF00) >> 8, 5, 0);
state |= _mod->SPIsetRegValue(SX127X_REG_FDEV_LSB, FDEV & 0x00FF, 7, 0);
return(state);
@ -753,7 +774,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);
}
@ -815,6 +836,30 @@ int16_t SX127x::disableAddressFiltering() {
return(_mod->SPIsetRegValue(SX127X_REG_BROADCAST_ADRS, 0x00));
}
int16_t SX127x::setOokThresholdType(uint8_t type) {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
return(_mod->SPIsetRegValue(SX127X_REG_OOK_PEAK, type, 4, 3, 5));
}
int16_t SX127x::setOokFixedOrFloorThreshold(uint8_t value) {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
return(_mod->SPIsetRegValue(SX127X_REG_OOK_FIX, value, 7, 0, 5));
}
int16_t SX127x::setOokPeakThresholdDecrement(uint8_t value) {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
return(ERR_WRONG_MODEM);
}
return(_mod->SPIsetRegValue(SX127X_REG_OOK_AVG, value, 7, 5, 5));
}
int16_t SX127x::setOOK(bool enableOOK) {
// check active modem
if(getActiveModem() != SX127X_FSK_OOK) {
@ -858,14 +903,18 @@ size_t SX127x::getPacketLength(bool update) {
return(_mod->SPIreadRegister(SX127X_REG_RX_NB_BYTES));
} else {
// return the maximum value for SF6
return(SX127X_MAX_PACKET_LENGTH);
// return the cached value for SF6
return(_packetLength);
}
} 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;
}
}
@ -952,6 +1001,35 @@ 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;
@ -975,7 +1053,7 @@ int8_t SX127x::getTempRaw() {
_mod->SPIsetRegValue(SX127X_REG_IMAGE_CAL, SX127X_TEMP_MONITOR_ON, 0, 0);
// wait
delayMicroseconds(200);
Module::delayMicroseconds(200);
// disable temperature reading
_mod->SPIsetRegValue(SX127X_REG_IMAGE_CAL, SX127X_TEMP_MONITOR_OFF, 0, 0);
@ -1019,7 +1097,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);
@ -1038,10 +1116,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);
}
@ -1078,7 +1154,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 {
@ -1088,12 +1164,12 @@ bool SX127x::findChip(uint8_t ver) {
RADIOLIB_DEBUG_PRINT(F(" of 10 tries) SX127X_REG_VERSION == "));
char buffHex[12];
sprintf(buffHex, "0x%02X", version);
sprintf(buffHex, "0x%04X", version);
RADIOLIB_DEBUG_PRINT(buffHex);
RADIOLIB_DEBUG_PRINT(F(", expected 0x00"));
RADIOLIB_DEBUG_PRINTLN(ver, HEX);
#endif
delay(10);
Module::delay(10);
i++;
}
}
@ -1138,4 +1214,24 @@ void SX127x::clearFIFO(size_t count) {
}
}
int16_t SX127x::invertIQ(bool invertIQ) {
// check active modem
if(getActiveModem() != SX127X_LORA) {
return(ERR_WRONG_MODEM);
}
int16_t state;
if(invertIQ) {
state = _mod->SPIsetRegValue(SX127X_REG_INVERT_IQ, SX127X_INVERT_IQ_RXPATH_ON, 6, 6);
state |= _mod->SPIsetRegValue(SX127X_REG_INVERT_IQ, SX127X_INVERT_IQ_TXPATH_ON, 0, 0);
state |= _mod->SPIsetRegValue(SX127X_REG_INVERT_IQ2, SX127X_IQ2_ENABLE);
} else {
state = _mod->SPIsetRegValue(SX127X_REG_INVERT_IQ, SX127X_INVERT_IQ_RXPATH_OFF, 6, 6);
state |= _mod->SPIsetRegValue(SX127X_REG_INVERT_IQ, SX127X_INVERT_IQ_TXPATH_OFF, 0, 0);
state |= _mod->SPIsetRegValue(SX127X_REG_INVERT_IQ2, SX127X_IQ2_DISABLE);
}
return(state);
}
#endif

View file

@ -59,6 +59,7 @@
#define SX127X_REG_INVERT_IQ 0x33
#define SX127X_REG_DETECTION_THRESHOLD 0x37
#define SX127X_REG_SYNC_WORD 0x39
#define SX127X_REG_INVERT_IQ2 0x3B
#define SX127X_REG_DIO_MAPPING_1 0x40
#define SX127X_REG_DIO_MAPPING_2 0x41
#define SX127X_REG_VERSION 0x42
@ -122,6 +123,12 @@
#define SX127X_DETECT_OPTIMIZE_SF_6 0b00000101 // 2 0 SF6 detection optimization
#define SX127X_DETECT_OPTIMIZE_SF_7_12 0b00000011 // 2 0 SF7 to SF12 detection optimization
// SX127X_REG_INVERT_IQ
#define SX127X_INVERT_IQ_RXPATH_ON 0b01000000 // 6 6 I and Q signals are inverted
#define SX127X_INVERT_IQ_RXPATH_OFF 0b00000000 // 6 6 normal mode
#define SX127X_INVERT_IQ_TXPATH_ON 0b00000001 // 0 0 I and Q signals are inverted
#define SX127X_INVERT_IQ_TXPATH_OFF 0b00000000 // 0 0 normal mode
// SX127X_REG_DETECTION_THRESHOLD
#define SX127X_DETECTION_THRESHOLD_SF_6 0b00001100 // 7 0 SF6 detection threshold
#define SX127X_DETECTION_THRESHOLD_SF_7_12 0b00001010 // 7 0 SF7 to SF12 detection threshold
@ -172,6 +179,10 @@
#define SX127X_SYNC_WORD 0x12 // 7 0 default LoRa sync word
#define SX127X_SYNC_WORD_LORAWAN 0x34 // 7 0 sync word reserved for LoRaWAN networks
// SX127X_REG_INVERT_IQ2
#define SX127X_IQ2_ENABLE 0x19 // 7 0 enable optimize for inverted IQ
#define SX127X_IQ2_DISABLE 0x1D // 7 0 reset optimize for inverted IQ
// SX127x series common FSK registers
// NOTE: FSK register names that are conflicting with LoRa registers are marked with "_FSK" suffix
#define SX127X_REG_BITRATE_MSB 0x02
@ -745,9 +756,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
*/
@ -848,6 +859,33 @@ class SX127x: public PhysicalLayer {
*/
int16_t setOOK(bool enableOOK);
/*!
\brief Selects the type of threshold in the OOK data slicer.
\param type Threshold type: SX127X_OOK_THRESH_PEAK(default), SX127X_OOK_THRESH_FIXED, SX127X_OOK_THRESH_AVERAGE
\returns \ref status_codes
*/
int16_t setOokThresholdType(uint8_t type);
/*!
\brief Period of decrement of the RSSI threshold in the OOK demodulator.
\param value Use defines SX127X_OOK_PEAK_THRESH_DEC_X_X_CHIP
\returns \ref status_codes
*/
int16_t setOokPeakThresholdDecrement(uint8_t value);
/*!
\brief Fixed threshold for the Data Slicer in OOK mode or floor threshold for the Data Slicer in OOK when Peak mode is used.
\param value The actual value used by teh data slicer is (128 - value/2).
\returns \ref status_codes
*/
int16_t setOokFixedOrFloorThreshold(uint8_t value);
/*!
\brief Query modem for the packet length of received payload.
@ -931,11 +969,38 @@ class SX127x: public PhysicalLayer {
*/
void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn);
#ifndef RADIOLIB_GODMODE
/*!
\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();
/*!
\brief Enables/disables Invert the LoRa I and Q signals.
\param invertIQ Enable (true) or disable (false) LoRa I and Q signals.
\returns \ref status_codes
*/
int16_t invertIQ(bool invertIQ);
#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL)
protected:
#endif
Module* _mod;
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
float _freq = 0;
float _bw = 0;
uint8_t _sf = 0;
@ -943,6 +1008,8 @@ class SX127x: public PhysicalLayer {
float _br = 0;
float _rxBw = 0;
bool _ook = false;
bool _crcEnabled = false;
size_t _packetLength = 0;
int16_t setFrequencyRaw(float newFreq);
int16_t config();
@ -951,11 +1018,10 @@ class SX127x: public PhysicalLayer {
int16_t directMode();
int16_t setPacketMode(uint8_t mode, uint8_t len);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif
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;

View file

@ -11,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);

View file

@ -52,7 +52,7 @@ class SX1280: public SX1281 {
*/
float getRangingResult();
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -22,7 +22,7 @@ class SX1281: public SX128x {
*/
SX1281(Module* mod);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -23,7 +23,7 @@ class SX1282: public SX1280 {
*/
SX1282(Module* mod);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif

View file

@ -10,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;
@ -61,6 +62,7 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, 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 GFSK modulation variables
_brKbps = br;
@ -123,6 +125,7 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, u
_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;
@ -171,6 +174,7 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uin
_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;
@ -228,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
@ -237,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();
@ -247,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);
}
}
@ -285,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);
@ -329,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);
@ -392,8 +396,8 @@ int16_t SX128x::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
@ -422,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);
}
@ -440,11 +444,11 @@ int16_t SX128x::standby(uint8_t mode) {
}
void SX128x::setDio1Action(void (*func)(void)) {
attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING);
Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING);
}
void SX128x::clearDio1Action() {
detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()));
Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()));
}
int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
@ -504,8 +508,8 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
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);
@ -798,17 +802,23 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) {
return(ERR_WRONG_MODEM);
}
RADIOLIB_CHECK_RANGE(freqDev, 0.0, 3200.0, ERR_INVALID_FREQUENCY_DEVIATION);
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
if(freqDev < 0.0) {
newFreqDev = 62.5;
}
RADIOLIB_CHECK_RANGE(newFreqDev, 62.5, 1000.0, ERR_INVALID_FREQUENCY_DEVIATION);
// override for the lowest possible frequency deviation - required for some PhysicalLayer protocols
if(freqDev == 0.0) {
if(newFreqDev == 0.0) {
_modIndex = SX128X_BLE_GFSK_MOD_IND_0_35;
_br = SX128X_BLE_GFSK_BR_0_125_BW_0_3;
return(setModulationParams(_br, _modIndex, _shaping));
}
// update modulation parameters
uint8_t modIndex = (uint8_t)((8.0 * (freqDev / (float)_brKbps)) - 1.0);
uint8_t modIndex = (uint8_t)((8.0 * (newFreqDev / (float)_brKbps)) - 1.0);
if(modIndex > SX128X_BLE_GFSK_MOD_IND_4_00) {
return(ERR_INVALID_MODULATION_PARAMETERS);
}
@ -1122,6 +1132,12 @@ 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);
@ -1295,17 +1311,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);
@ -1362,15 +1378,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;
}
@ -1419,8 +1435,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) || defined(SAMD_SERIES)
delay(1);
#if defined(RADIOLIB_SPI_SLOWDOWN)
Module::delay(1);
#endif
#endif

View file

@ -753,11 +753,22 @@ class SX128x: public PhysicalLayer {
*/
void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn);
#ifndef RADIOLIB_GODMODE
/*!
\brief Dummy random method, to ensure PhysicalLayer compatibility.
\returns Always returns 0.
*/
uint8_t random();
#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL)
protected:
#endif
Module* _mod;
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
// cached LoRa parameters
float _bwKhz = 0;
uint8_t _bw = 0, _sf = 0, _cr = 0;
@ -788,7 +799,18 @@ class SX128x: public PhysicalLayer {
int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL)
private:
#endif
// common low-level SPI interface
int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout = 5000);
#if !defined(RADIOLIB_GODMODE)
private:
#endif
// common parameters
@ -807,13 +829,6 @@ class SX128x: public PhysicalLayer {
uint8_t _connectionState = 0, _crcBLE = 0, _bleTestPayload = 0;
int16_t config(uint8_t modem);
// common low-level SPI interface
int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout = 5000);
};
#endif

View file

@ -9,6 +9,7 @@ int16_t Si4430::begin(float freq, float br, float freqDev, float rxBw, int8_t po
// execute common part
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);

View file

@ -67,11 +67,11 @@ class Si4430: public Si4432 {
int16_t setOutputPower(int8_t power);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif
};

View file

@ -9,6 +9,7 @@ int16_t Si4431::begin(float freq, float br, float freqDev, float rxBw, int8_t po
// execute common part
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);

View file

@ -58,11 +58,11 @@ class Si4431: public Si4432 {
int16_t setOutputPower(int8_t power);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif
};

View file

@ -9,6 +9,7 @@ int16_t Si4432::begin(float freq, float br, float freqDev, float rxBw, int8_t po
// execute common part
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);

View file

@ -67,11 +67,11 @@ class Si4432: public Si443x {
int16_t setOutputPower(int8_t power);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif
};

View file

@ -18,7 +18,7 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen)
_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
@ -60,9 +60,9 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen)
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) {
@ -74,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);
}
@ -102,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);
@ -135,7 +140,8 @@ int16_t Si443x::standby() {
// 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(_mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_XTAL_ON, 7, 0, 10));
return(ERR_NONE);
}
int16_t Si443x::transmitDirect(uint32_t frf) {
@ -166,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);
}
@ -176,7 +182,7 @@ 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);
}
@ -189,7 +195,7 @@ int16_t Si443x::receiveDirect() {
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);
}
@ -198,11 +204,11 @@ int16_t Si443x::packetMode() {
}
void Si443x::setIrqAction(void (*func)(void)) {
attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, FALLING);
Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, FALLING);
}
void Si443x::clearIrqAction() {
detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()));
Module::detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()));
}
int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
@ -219,10 +225,6 @@ 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();
@ -239,8 +241,12 @@ int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// 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);
}
@ -254,20 +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);
}
@ -330,28 +334,23 @@ int16_t Si443x::setBitRate(float br) {
}
int16_t Si443x::setFrequencyDeviation(float freqDev) {
// set frequency deviation to lowest available setting (required for RTTY)
if(freqDev == 0.0) {
int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, 0x00, 2, 2);
_mod->SPIwriteRegister(SI443X_REG_FREQUENCY_DEVIATION, 0x00);
if(state == ERR_NONE) {
_freqDev = freqDev;
}
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
if(freqDev < 0.0) {
newFreqDev = 0.625;
}
RADIOLIB_CHECK_RANGE(freqDev, 0.625, 320.0, ERR_INVALID_FREQUENCY_DEVIATION);
RADIOLIB_CHECK_RANGE(newFreqDev, 0.625, 320.0, ERR_INVALID_FREQUENCY_DEVIATION);
// calculate raw frequency deviation value
uint16_t fdev = (uint16_t)(freqDev / 0.625);
uint16_t fdev = (uint16_t)(newFreqDev / 0.625);
// update registers
int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, (uint8_t)((fdev & 0x0100) >> 6), 2, 2);
_mod->SPIwriteRegister(SI443X_REG_FREQUENCY_DEVIATION, (uint8_t)(fdev & 0xFF));
if(state == ERR_NONE) {
_freqDev = freqDev;
_freqDev = newFreqDev;
}
return(state);
@ -386,63 +385,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;
@ -493,7 +493,7 @@ int16_t Si443x::setPreambleLength(uint8_t preambleLen) {
// 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, 3, 7));
return(_mod->SPIsetRegValue(SI443X_REG_PREAMBLE_DET_CONTROL, preThreshold << 4, 7, 3));
}
size_t Si443x::getPacketLength(bool update) {
@ -548,6 +548,29 @@ 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();
@ -556,6 +579,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;
@ -595,7 +619,7 @@ bool Si443x::findChip() {
RADIOLIB_DEBUG_PRINT(F(", expected 0x00"));
RADIOLIB_DEBUG_PRINTLN(SI443X_DEVICE_VERSION, HEX);
#endif
delay(10);
Module::delay(10);
i++;
}
}
@ -604,8 +628,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() {
@ -614,8 +638,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);

View file

@ -785,20 +785,39 @@ class Si443x: public PhysicalLayer {
*/
void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn);
#ifndef RADIOLIB_GODMODE
/*!
\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();
#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL)
protected:
#endif
Module* _mod;
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
float _br = 0;
float _freqDev = 0;
float _freq = 0;
size_t _packetLength = 0;
bool _packetLengthQueried = false;
int16_t setFrequencyRaw(float newFreq);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif
bool findChip();

View file

@ -34,7 +34,7 @@ int16_t XBee::begin(long speed) {
RADIOLIB_DEBUG_PRINTLN(state);
RADIOLIB_DEBUG_PRINTLN(F("Resetting ..."));
reset();
delay(10);
Module::delay(10);
_mod->ATemptyBuffer();
i++;
}
@ -51,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) {
@ -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]);
}
@ -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');

View file

@ -81,7 +81,7 @@ class XBeeSerial: public ISerial {
*/
int16_t setPanId(const char* panId);
#ifndef RADIOLIB_GODMODE
#if !defined(RADIOLIB_GODMODE)
private:
#endif
bool enterCmdMode();
@ -172,10 +172,15 @@ class XBee {
*/
int16_t setPanId(uint8_t* panId);
#ifndef RADIOLIB_GODMODE
private:
#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL)
protected:
#endif
Module* _mod;
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
uint8_t _frameID = 0x01;
size_t _frameLength = 0;
bool _frameHeaderProcessed = false;

View file

@ -10,13 +10,14 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW
_mod->SPIreadCommand = NRF24_CMD_READ;
_mod->SPIwriteCommand = NRF24_CMD_WRITE;
_mod->init(RADIOLIB_USE_SPI);
Module::pinMode(_mod->getIrq(), INPUT);
// set pin mode on RST (connected to nRF24 CE pin)
Module::pinMode(_mod->getRst(), OUTPUT);
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);
@ -25,6 +26,7 @@ int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrW
_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();
@ -69,7 +71,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));
@ -81,9 +83,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)) {
@ -93,7 +95,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);
@ -112,12 +114,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);
@ -139,7 +141,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);
}
@ -150,7 +152,7 @@ int16_t nRF24::receiveDirect() {
}
void nRF24::setIrqAction(void (*func)(void)) {
attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_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) {
@ -186,9 +188,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);
}
@ -211,10 +213,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);
}
@ -457,32 +459,32 @@ 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);
@ -503,6 +505,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);
@ -539,7 +547,7 @@ int16_t nRF24::config() {
// power up
_mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_POWER_UP, 1, 1);
delay(5);
Module::delay(5);
return(state);
}
@ -558,7 +566,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
@ -577,7 +585,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

View file

@ -464,19 +464,30 @@ class nRF24: public PhysicalLayer {
*/
int16_t setEncoding(uint8_t encoding) override;
#ifndef RADIOLIB_GODMODE
private:
/*!
\brief Dummy random method, to ensure PhysicalLayer compatibility.
\returns Always returns 0.
*/
uint8_t random();
#if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL)
protected:
#endif
Module* _mod;
void SPIreadRxPayload(uint8_t* data, uint8_t numBytes);
void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes);
void SPItransfer(uint8_t cmd, bool write = false, uint8_t* dataOut = NULL, uint8_t* dataIn = NULL, uint8_t numBytes = 0);
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
uint8_t _addrWidth = 0;
int16_t config();
void clearIRQ();
void SPIreadRxPayload(uint8_t* data, uint8_t numBytes);
void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes);
void SPItransfer(uint8_t cmd, bool write = false, uint8_t* dataOut = NULL, uint8_t* dataIn = NULL, uint8_t numBytes = 0);
};
#endif

View file

@ -5,6 +5,10 @@ AFSKClient::AFSKClient(PhysicalLayer* phy, RADIOLIB_PIN_TYPE pin): _pin(pin) {
_phy = phy;
}
int16_t AFSKClient::begin() {
return(_phy->startDirect());
}
int16_t AFSKClient::tone(uint16_t freq, bool autoStart) {
if(freq == 0) {
return(ERR_INVALID_FREQUENCY);

View file

@ -25,6 +25,13 @@ class AFSKClient {
*/
AFSKClient(PhysicalLayer* phy, RADIOLIB_PIN_TYPE pin);
/*!
\brief Initialization method.
\returns \ref status_codes
*/
int16_t begin();
/*!
\brief Start transmitting audio tone.

View file

@ -179,17 +179,8 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t prea
// save preamble length
_preambleLen = preambleLen;
// 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);
}
#endif
return(state);
// configure for direct mode
return(_phy->startDirect());
}
int16_t AX25Client::transmit(const char* str, const char* destCallsign, uint8_t destSSID) {
@ -234,7 +225,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;
@ -244,7 +235,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;
@ -255,7 +246,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;
@ -314,7 +305,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) {
// 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) {
@ -400,14 +391,14 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) {
// check each bit
for(uint16_t mask = 0x80; mask >= 0x01; mask >>= 1) {
uint32_t start = micros();
uint32_t start = Module::micros();
if(stuffedFrameBuff[i] & mask) {
_audio->tone(AX25_AFSK_MARK, false);
} else {
_audio->tone(AX25_AFSK_SPACE, false);
}
while(micros() - start < 833) {
yield();
while(Module::micros() - start < AX25_AFSK_TONE_DURATION) {
Module::yield();
}
}

View file

@ -64,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) {

View file

@ -24,28 +24,21 @@ int16_t HellClient::begin(float base, float rate) {
// calculate "pixel" duration
_pixelDuration = 1000000.0/rate;
// 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);
// configure for direct mode
return(_phy->startDirect());
}
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) {
transmitDirect(_base, _baseHz);
} else {
standby();
}
while(micros() - start < _pixelDuration);
while(Module::micros() - start < _pixelDuration);
}
}
@ -85,7 +78,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;
@ -97,7 +90,7 @@ size_t HellClient::print(__FlashStringHelper* fstr) {
PGM_P p = reinterpret_cast<PGM_P>(fstr);
size_t n = 0;
while(true) {
char c = pgm_read_byte(p++);
char c = RADIOLIB_PROGMEM_READ_BYTE(p++);
if(c == '\0') {
break;
}

View file

@ -14,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 }, // "

View file

@ -23,15 +23,8 @@ int16_t MorseClient::begin(float base, uint8_t speed) {
// calculate dot length (assumes PARIS as typical word)
_dotLength = 1200 / speed;
// 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);
// configure for direct mode
return(_phy->startDirect());
}
size_t MorseClient::startSignal() {
@ -64,12 +57,12 @@ size_t MorseClient::write(uint8_t b) {
if(b == ' ') {
RADIOLIB_DEBUG_PRINTLN(F("space"));
standby();
delay(4 * _dotLength);
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) {
@ -83,16 +76,16 @@ size_t MorseClient::write(uint8_t b) {
if (code & MORSE_DASH) {
RADIOLIB_DEBUG_PRINT('-');
transmitDirect(_base, _baseHz);
delay(3 * _dotLength);
Module::delay(3 * _dotLength);
} else {
RADIOLIB_DEBUG_PRINT('.');
transmitDirect(_base, _baseHz);
delay(_dotLength);
Module::delay(_dotLength);
}
// symbol space
standby();
delay(_dotLength);
Module::delay(_dotLength);
// move onto the next bit
code >>= 1;
@ -100,7 +93,7 @@ size_t MorseClient::write(uint8_t b) {
// letter space
standby();
delay(2 * _dotLength);
Module::delay(2 * _dotLength);
RADIOLIB_DEBUG_PRINTLN();
return(1);
@ -110,7 +103,7 @@ size_t MorseClient::print(__FlashStringHelper* fstr) {
PGM_P p = reinterpret_cast<PGM_P>(fstr);
size_t n = 0;
while(true) {
char c = pgm_read_byte(p++);
char c = RADIOLIB_PROGMEM_READ_BYTE(p++);
if(c == '\0') {
break;
}

View file

@ -14,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, // "

View file

@ -10,7 +10,7 @@ int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) {
size_t len = 0;
PGM_P p = reinterpret_cast<PGM_P>(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<PGM_P>(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
@ -143,3 +143,41 @@ int16_t PhysicalLayer::receive(String& str, size_t len) {
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);
}
int16_t PhysicalLayer::startDirect() {
// disable encodings
int16_t state = setEncoding(RADIOLIB_ENCODING_NRZ);
RADIOLIB_ASSERT(state);
// disable shaping
state = setDataShaping(RADIOLIB_SHAPING_NONE);
RADIOLIB_ASSERT(state);
// set frequency deviation to the lowest possible value
state = setFrequencyDeviation(-1);
return(state);
}

View file

@ -216,7 +216,7 @@ class PhysicalLayer {
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,40 @@ 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;
/*!
\brief Configure module parameters for direct modes. Must be called prior to "ham" modes like RTTY or AX.25. Only available in FSK mode.
\returns \ref status_codes
*/
int16_t startDirect();
#ifndef RADIOLIB_GODMODE
private:
#endif

View file

@ -91,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;
@ -161,19 +161,11 @@ 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 if using FSK
int16_t state = ERR_NONE;
#if !defined(RADIOLIB_EXCLUDE_AFSK)
if(_audio == nullptr) {
state = _phy->setFrequencyDeviation(0);
}
#endif
return(state);
// configure for direct mode
return(_phy->startDirect());
}
void RTTYClient::idle() {
transmitDirect();
mark();
}
@ -195,7 +187,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 {
@ -217,7 +210,7 @@ size_t RTTYClient::print(__FlashStringHelper* fstr) {
size_t len = 0;
PGM_P p = reinterpret_cast<PGM_P>(fstr);
while(true) {
char c = pgm_read_byte(p++);
char c = RADIOLIB_PROGMEM_READ_BYTE(p++);
len++;
if(c == '\0') {
break;
@ -234,7 +227,7 @@ size_t RTTYClient::print(__FlashStringHelper* fstr) {
// copy string from flash
p = reinterpret_cast<PGM_P>(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;
@ -407,18 +400,18 @@ size_t RTTYClient::println(double d, int digits) {
}
void RTTYClient::mark() {
uint32_t start = micros();
uint32_t start = Module::micros();
transmitDirect(_base + _shift, _baseHz + _shiftHz);
while(micros() - start < _bitDuration) {
yield();
while(Module::micros() - start < _bitDuration) {
Module::yield();
}
}
void RTTYClient::space() {
uint32_t start = micros();
uint32_t start = Module::micros();
transmitDirect(_base, _baseHz);
while(micros() - start < _bitDuration) {
yield();
while(Module::micros() - start < _bitDuration) {
Module::yield();
}
}

View file

@ -15,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

View file

@ -192,20 +192,13 @@ int16_t SSTVClient::begin(float base, const SSTVMode_t& mode, float correction)
// calculate 24-bit frequency
_base = (base * 1000000.0) / _phy->getFreqStep();
// 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);
// configure for direct mode
return(_phy->startDirect());
}
void SSTVClient::idle() {
_phy->transmitDirect();
tone(SSTV_TONE_LEADER);
this->tone(SSTV_TONE_LEADER);
}
void SSTVClient::sendHeader() {
@ -214,35 +207,35 @@ void SSTVClient::sendHeader() {
_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) {
@ -251,14 +244,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++) {
@ -278,7 +271,7 @@ 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);
}
}
}
@ -289,7 +282,7 @@ uint16_t SSTVClient::getPictureHeight() const {
}
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);
@ -299,8 +292,8 @@ void SSTVClient::tone(float freq, uint32_t len) {
#else
_phy->transmitDirect(_base + (freq / _phy->getFreqStep()));
#endif
while(micros() - start < len) {
yield();
while(Module::micros() - start < len) {
Module::yield();
}
}