Update RadioLib to V6.0.0

This commit is contained in:
lewishe 2023-05-12 11:27:13 +08:00
commit 04f65f1392
166 changed files with 15126 additions and 10136 deletions

View file

@ -0,0 +1,30 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**IMPORTANT: Check the wiki**
Before submitting new issue, please check the [Wiki](https://github.com/jgromes/RadioLib/wiki) and the [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there.
**Describe the bug**
A clear and concise description of what the bug is. When applicable, please include [debug mode output](https://github.com/jgromes/RadioLib/wiki/Debug-mode).
**To Reproduce**
Minimal Arduino sketch to reproduce the behavior. Please use Markdown to style the code to make it readable (see [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code)).
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional info (please complete):**
- MCU: [e.g. Arduino Uno, ESP8266 etc.]
- Link to Arduino core: [e.g. https://github.com/stm32duino/Arduino_Core_STM32 when using official STM32 core. See readme for links to all supported cores]
- Wireless module type [e.g. CC1101, SX1268, etc.]
- Arduino IDE version [e.g. 1.8.5]
- Library version [e.g. 3.0.0]

View file

@ -0,0 +1,23 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**IMPORTANT: Check the wiki**
Before submitting new issue, please check the [Wiki](https://github.com/jgromes/RadioLib/wiki) and the [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there.
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View file

@ -0,0 +1,34 @@
---
name: Module not working
about: Template to use when your module isn't working
title: ''
labels: ''
assignees: ''
---
**IMPORTANT: Before submitting an issue, please check the following:**
1. **Read [CONTRIBUTING.md](https://github.com/jgromes/RadioLib/blob/master/CONTRIBUTING.md)!** Issues that do not follow this document will be closed/locked/deleted/ignored.
2. RadioLib has a [Wiki](https://github.com/jgromes/RadioLib/wiki) and an extensive [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there.
3. Make sure you're using the latest release of the library! Releases can be found [here](https://github.com/jgromes/RadioLib/releases).
4. Use [Arduino forums](https://forum.arduino.cc/) to ask generic questions about wireless modules, wiring, usage, etc. Only create issues for problems specific to RadioLib!
5. Error codes, their meaning and how to fix them can be found on [this page](https://jgromes.github.io/RadioLib/group__status__codes.html).
**Sketch that is causing the module fail**
```c++
paste the sketch here, even if it is an unmodified example code
```
**Hardware setup**
Wiring diagram, schematic, pictures etc.
**Debug mode output**
Enable all [debug levels](https://github.com/jgromes/RadioLib/wiki/Debug-mode) and paste the Serial monitor output here.
**Additional info (please complete):**
- MCU: [e.g. Arduino Uno, ESP8266 etc.]
- Link to Arduino core: [e.g. https://github.com/stm32duino/Arduino_Core_STM32 when using official STM32 core. See readme for links to all supported cores]
- Wireless module type [e.g. CC1101, SX1268, etc.]
- Arduino IDE version [e.g. 1.8.5]
- Library version [e.g. 3.0.0]

View file

@ -0,0 +1,15 @@
---
name: Regular issue
about: Use this template for any other issue
title: ''
labels: ''
assignees: ''
---
**IMPORTANT: Before submitting an issue, please check the following:**
1. **Read [CONTRIBUTING.md](https://github.com/jgromes/RadioLib/blob/master/CONTRIBUTING.md)!** Issues that do not follow this document will be closed/locked/deleted/ignored.
2. RadioLib has a [Wiki](https://github.com/jgromes/RadioLib/wiki) and an extensive [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there.
3. Make sure you're using the latest release of the library! Releases can be found [here](https://github.com/jgromes/RadioLib/releases).
4. Use [Arduino forums](https://forum.arduino.cc/) to ask generic questions about wireless modules, wiring, usage, etc. Only create issues for problems specific to RadioLib!
5. Error codes, their meaning and how to fix them can be found on [this page](https://jgromes.github.io/RadioLib/group__status__codes.html).

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

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

208
lib/RadioLib/.github/workflows/main.yml vendored Normal file
View file

@ -0,0 +1,208 @@
name: CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
inputs:
id:
description: The ID of the platform on which the build is run
required: true
default: arduino:avr:uno
type: choice
options:
- all
- 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
- STMicroelectronics:stm32:GenF3:pnum=BLACKPILL_F303CC
- STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_WL55JC1
- stm32duino:STM32F1:mapleMini
- MegaCoreX:megaavr:4809
- arduino:mbed_rp2040:pico
- rp2040:rp2040:rpipico
- CubeCell:CubeCell:CubeCell-Board
- MegaCore:avr:1281
- teensy:avr:teensy41
jobs:
build:
strategy:
matrix:
# platform-dependent settings - extra board options, board index URLs, skip patterns etc.
include:
- id: arduino:avr:uno
run: echo "skip-pattern=(STM32WL|SSTV)" >> $GITHUB_OUTPUT
- id: arduino:avr:mega
run: echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT
- id: arduino:avr:leonardo
- id: arduino:mbed:nano33ble
- id: arduino:mbed:envie_m4
- id: arduino:megaavr:uno2018
run: echo "options=':mode=on'" >> $GITHUB_OUTPUT
- id: arduino:sam:arduino_due_x
- id: arduino:samd:arduino_zero_native
- id: adafruit:samd:adafruit_feather_m0
run: |
echo "options=':usbstack=arduino,debug=off'" >> $GITHUB_OUTPUT
echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT
- id: adafruit:nrf52:feather52832
run: |
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 "options=':softdevice=s132v6,debug=l0'" >> $GITHUB_OUTPUT
echo "index-url=--additional-urls https://adafruit.github.io/arduino-board-index/package_adafruit_index.json" >> $GITHUB_OUTPUT
- id: esp32:esp32:esp32
run:
python -m pip install pyserial
echo "index-url=--additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" >> $GITHUB_OUTPUT
- id: esp8266:esp8266:generic
run: |
echo "options=':xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K'" >> $GITHUB_OUTPUT
echo "index-url=--additional-urls http://arduino.esp8266.com/stable/package_esp8266com_index.json" >> $GITHUB_OUTPUT
- id: Intel:arc32:arduino_101
- id: SparkFun:apollo3:sfe_artemis
run: |
echo "warnings='none'" >> $GITHUB_OUTPUT
echo "index-url=--additional-urls https://raw.githubusercontent.com/sparkfun/Arduino_Apollo3/master/package_sparkfun_apollo3_index.json" >> $GITHUB_OUTPUT
- id: STMicroelectronics:stm32:GenF3:pnum=BLACKPILL_F303CC
run: echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT
- id: STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_WL55JC1
run: |
# Do *not* skip STM32WL examples
echo "skip-pattern=''" >> $GITHUB_OUTPUT
echo "index-url=--additional-urls https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json" >> $GITHUB_OUTPUT
- id: stm32duino:STM32F1:mapleMini
run: |
echo "options=':bootloader_version=original,cpu_speed=speed_72mhz'" >> $GITHUB_OUTPUT
echo "index-url=--additional-urls http://dan.drown.org/stm32duino/package_STM32duino_index.json" >> $GITHUB_OUTPUT
- id: MegaCoreX:megaavr:4809
run: echo "index-url=--additional-urls https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json" >> $GITHUB_OUTPUT
- id: arduino:mbed_rp2040:pico
- id: rp2040:rp2040:rpipico
run: echo "index-url=--additional-urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json" >> $GITHUB_OUTPUT
- id: CubeCell:CubeCell:CubeCell-Board
run: echo "index-url=--additional-urls https://resource.heltec.cn/download/package_CubeCell_index.json" >> $GITHUB_OUTPUT
- id: MegaCore:avr:1281
run: echo "index-url=--additional-urls https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json" >> $GITHUB_OUTPUT
- id: teensy:avr:teensy41
run: echo "index-url=--additional-urls https://www.pjrc.com/teensy/td_156/package_teensy_index.json" >> $GITHUB_OUTPUT
runs-on: ubuntu-latest
name: ${{ matrix.id }}
env:
run-build: ${{ (matrix.id == '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.id)) || inputs.id == 'all' || inputs.id == matrix.id }}
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.id }}
seperator: ':'
- name: Prepare platform-specific settings
if: ${{ env.run-build == 'true' }}
id: prep
run:
|
# common settings - no extra options, skip STM32WL examples, all warnings
echo "options=''" >> $GITHUB_OUTPUT
echo "skip-pattern=STM32WL" >> $GITHUB_OUTPUT
echo "warnings=all" >> $GITHUB_OUTPUT
# run platform-dependent scripts defined in matrix
${{ matrix.run }}
- 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.id }}${{ 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
rpi-build:
runs-on: [self-hosted, ARM64]
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y pigpio cmake
- name: Install the library
run: |
cd $PWD
mkdir build
cd build
cmake ..
sudo make install
- name: Build the example
run: |
cd $PWD/examples/NonArduino/Raspberry
./build.sh
rpi-test:
needs: rpi-build
runs-on: [self-hosted, ARM64]
steps:
- name: SX126x test
run: |
cd $PWD/extras/test/SX126x
./clean.sh
./build.sh
sudo ./build/rpi-sx1261

View file

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.13)
project(radiolib)
file(GLOB_RECURSE RADIOLIB_SOURCES
"src/*.cpp"
)
add_library(RadioLib ${RADIOLIB_SOURCES})
target_include_directories(RadioLib
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
include(GNUInstallDirs)
install(TARGETS RadioLib
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/RadioLib
FILES_MATCHING PATTERN "*.h"
)

View file

@ -2172,7 +2172,8 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = protected=private
PREDEFINED = protected=private \
DOXYGEN
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The

View file

@ -1,4 +1,4 @@
# RadioLib ![Build Status](https://github.com/jgromes/RadioLib/workflows/CI/badge.svg)
# RadioLib ![Build Status](https://github.com/jgromes/RadioLib/workflows/CI/badge.svg) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/jgromes/library/RadioLib.svg)](https://registry.platformio.org/libraries/jgromes/RadioLib)
### _One radio library to rule them all!_
@ -9,6 +9,8 @@
RadioLib allows its users to integrate all sorts of different wireless communication modules, protocols and even digital modes into a single consistent system.
Want to add a Bluetooth interface to your LoRa network? Sure thing! Do you just want to go really old-school and play around with radio teletype, slow-scan TV, or even Hellschreiber using nothing but a cheap radio module? Why not!
RadioLib natively supports Arduino, but can run in non-Arduino environments as well! See [this Wiki page](https://github.com/jgromes/RadioLib/wiki/Porting-to-non-Arduino-Platforms) and [examples/NonArduino](https://github.com/jgromes/RadioLib/tree/master/examples/NonArduino).
RadioLib was originally created as a driver for [__RadioShield__](https://github.com/jgromes/RadioShield), but it can be used to control as many different wireless modules as you like - or at least as many as your microcontroller can handle!
### Supported modules:
@ -19,6 +21,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
* __RFM2x__ series FSK modules (RFM22, RM23)
* __RFM9x__ series LoRa modules (RFM95, RM96, RFM97, RFM98)
* __Si443x__ series FSK modules (Si4430, Si4431, Si4432)
* __STM32WL__ integrated microcontroller/LoRa module
* __SX126x__ series LoRa modules (SX1261, SX1262, SX1268)
* __SX127x__ series LoRa modules (SX1272, SX1273, SX1276, SX1277, SX1278, SX1279)
* __SX128x__ series LoRa/GFSK/BLE/FLRC modules (SX1280, SX1281, SX1282)
@ -71,7 +74,8 @@ SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x
* [__MegaCore__](https://github.com/MCUdude/MegaCore) - AVR (ATmega1281, ATmega640 etc.)
* __Raspberry Pi__
* [__RP2040__](https://github.com/arduino/ArduinoCore-mbed) - Raspberry Pi Pico and Arduino Nano RP2040 Connect
* [__RP2040__ (official core)](https://github.com/arduino/ArduinoCore-mbed) - Raspberry Pi Pico and Arduino Nano RP2040 Connect
* [__RP2040__ (unofficial core)](https://github.com/earlephilhower/arduino-pico) - Raspberry Pi Pico/RP2040-based boards
* [__Raspberry Pi__](https://github.com/me-no-dev/RasPiArduino) - Arduino framework for RaspberryPI
* __Heltec__
@ -80,7 +84,7 @@ SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x
* __PJRC__
* [__Teensy__](https://github.com/PaulStoffregen/cores) - Teensy 2.x, 3.x and 4.x boards
The list above is by no means exhaustive - RadioLib code is independent of the used platform! Compilation of all examples is tested for all platforms officially supported prior to releasing new version.
The list above is by no means exhaustive - RadioLib code is independent of the used platform! Compilation of all examples is tested for all platforms officially supported prior to releasing new version. In addition, RadioLib includes an internal hardware abstracton layer, which allows it to be easily ported even to non-Arduino encironments.
### In development:
* __AX5243__ FSK module
@ -92,6 +96,9 @@ The list above is by no means exhaustive - RadioLib code is independent of the u
### Where should I start?
First of all, take a look at the [examples](https://github.com/jgromes/RadioLib/tree/master/examples) and the [Wiki](https://github.com/jgromes/RadioLib/wiki) - especially the [Basics](https://github.com/jgromes/RadioLib/wiki/Basics) page. There's a lot of useful information over there. If something isn't working as expected, try searching the [issues](https://github.com/jgromes/RadioLib/issues/).
### Does RadioLib require Arduino?
While RadioLib was originally written with Arduino in mind, it has since evolved and contains its own lightweight hardware abstraction layer. Thanks to this layer, RadioLib can be used on non-Arduino frameworks as well. See [this Wiki page](https://github.com/jgromes/RadioLib/wiki/Porting-to-non-Arduino-Platforms) for details.
### Help, my module isn't working!
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.

View file

@ -0,0 +1,89 @@
/*
RadioLib AFSK External Radio example
This example shows how to use your Arduino
as modulator for an external analogue FM radio.
The example sends APRS position reports with
audio modulated as AFSK at 1200 baud using
Bell 202 tones. However, any other AFSK
protocol (RTTY, SSTV, etc.) may be used as well.
DO NOT transmit in APRS bands unless
you have a ham radio license!
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// create a dummy radio module
ExternalRadio radio;
// create AFSK client instance using the external radio
// pin 5 is connected to the radio sound input
AFSKClient audio(&radio, 5);
// create AX.25 client instance using the AFSK instance
AX25Client ax25(&audio);
// create APRS client instance using the AX.25 client
APRSClient aprs(&ax25);
void setup() {
Serial.begin(9600);
// initialize AX.25 client
Serial.print(F("[AX.25] Initializing ... "));
// source station callsign: "N7LEM"
// source station SSID: 0
// preamble length: 8 bytes
int16_t state = ax25.begin("N7LEM");
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// initialize APRS client
Serial.print(F("[APRS] Initializing ... "));
// symbol: '>' (car)
state = aprs.begin('>');
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
}
void loop() {
Serial.print(F("[APRS] Sending position ... "));
// send a location without message or timestamp
int state = aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E");
delay(500);
// send a location with message and without timestamp
state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!");
delay(500);
// send a location with message and timestamp
state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!", "093045z");
delay(500);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
}
// wait one minute before transmitting again
delay(60000);
}

View file

@ -9,6 +9,7 @@
- SX1231
- CC1101
- Si443x/RFM2x
- SX126x/LLCC68 (only devices without TCXO!)
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration
@ -38,6 +39,7 @@ SX1278 radio = new Module(10, 2, 9, 3);
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
// SX126x/LLCC68: DIO2
AFSKClient audio(&radio, 5);
void setup() {

View file

@ -10,6 +10,7 @@
- SX1231
- CC1101
- Si443x/RFM2x
- SX126x/LLCC68 (only devices without TCXO!)
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration
@ -36,6 +37,7 @@ SX1278 radio = new Module(10, 2, 9, 3);
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
// SX126x/LLCC68: DIO2
AFSKClient audio(&radio, 5);
void setup() {

View file

@ -16,6 +16,7 @@
- CC1101
- nRF24
- Si443x/RFM2x
- SX126x/LLCC68 (only devices without TCXO!)
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration
@ -39,7 +40,14 @@ SX1278 radio = new Module(10, 2, 9, 3);
//SX1278 radio = RadioShield.ModuleA;
// create AFSK client instance using the FSK module
// pin 5 is connected to SX1278 DIO2
// this requires connection to the module direct
// input pin, here connected to Arduino pin 5
// SX127x/RFM9x: DIO2
// RF69: DIO2
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
// SX126x/LLCC68: DIO2
AFSKClient audio(&radio, 5);
// create AX.25 client instance using the AFSK instance

View file

@ -16,6 +16,7 @@
- CC1101
- nRF24
- Si443x/RFM2x
- SX126x/LLCC68 (only devices without TCXO!)
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration
@ -39,7 +40,14 @@ SX1278 radio = new Module(10, 2, 9, 3);
//SX1278 radio = RadioShield.ModuleA;
// create AFSK client instance using the FSK module
// pin 5 is connected to SX1278 DIO2
// this requires connection to the module direct
// input pin, here connected to Arduino pin 5
// SX127x/RFM9x: DIO2
// RF69: DIO2
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
// SX126x/LLCC68: DIO2
AFSKClient audio(&radio, 5);
// create AX.25 client instance using the AFSK instance

View file

@ -13,6 +13,7 @@
- CC1101
- nRF24
- Si443x/RFM2x
- SX126x/LLCC68 (only devices without TCXO!)
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration
@ -36,7 +37,14 @@ SX1278 radio = new Module(10, 2, 9, 3);
//SX1278 radio = RadioShield.ModuleA;
// create AFSK client instance using the FSK module
// pin 5 is connected to SX1278 DIO2
// this requires connection to the module direct
// input pin, here connected to Arduino pin 5
// SX127x/RFM9x: DIO2
// RF69: DIO2
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
// SX126x/LLCC68: DIO2
AFSKClient audio(&radio, 5);
// create AX.25 client instance using the AFSK instance

View file

@ -0,0 +1,116 @@
/*
RadioLib Bell Modem Transmit Example
This example shows how to transmit binary data
using audio Bell 202 tones.
Other implemented Bell modems
- Bell 101
- Bell 103
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// SX1278 has the following connections:
// NSS pin: 10
// DIO0 pin: 2
// RESET pin: 9
// DIO1 pin: 3
SX1278 radio = new Module(10, 2, 9, 3);
// create Bell modem instance using the FSK module
// this requires connection to the module direct
// input pin, here connected to Arduino pin 5
// SX127x/RFM9x: DIO2
// RF69: DIO2
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
// SX126x/LLCC68: DIO2 (only devices without TCXO!)
BellClient bell(&radio, 5);
void setup() {
Serial.begin(9600);
// initialize SX1278 with default settings
Serial.print(F("[SX1278] Initializing ... "));
int state = radio.beginFSK();
// when using one of the non-LoRa modules for AFSK
// (RF69, CC1101, Si4432 etc.), use the basic begin() method
// int state = radio.begin();
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// initialize Bell 202 modem
Serial.print(F("[Bell 202] Initializing ... "));
state = bell.begin(Bell202);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
}
void loop() {
Serial.print(F("[Bell 202] Sending data ... "));
// send out idle condition for 500 ms
bell.idle();
delay(500);
// BellClient supports all methods of the Serial class
// Arduino String class
String aStr = "Arduino String";
bell.println(aStr);
// character array (C-String)
bell.println("C-String");
// string saved in flash
bell.println(F("Flash String"));
// character
bell.println('c');
// byte
// formatting DEC/HEX/OCT/BIN is supported for
// any integer type (byte/int/long)
bell.println(255, HEX);
// integer number
int i = 1000;
bell.println(i);
// floating point number
float f = -3.1415;
bell.println(f, 3);
// ITA2-encoded string
ITA2String str("HELLO WORLD!");
bell.print(str);
// turn the transmitter off
bell.standby();
Serial.println(F("done!"));
// wait for a second before transmitting again
delay(1000);
}

View file

@ -49,7 +49,7 @@ void setup() {
// set the function that will be called
// when new packet is received
radio.setGdo0Action(setFlag);
radio.setGdo0Action(setFlag, RISING);
// start listening for packets
Serial.print(F("[CC1101] Starting to listen ... "));
@ -75,9 +75,6 @@ void setup() {
// flag to indicate that a packet was received
volatile bool receivedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
@ -86,11 +83,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we got a packet, set the flag
receivedFlag = true;
}
@ -98,10 +90,6 @@ void setFlag(void) {
void loop() {
// check if the flag is set
if(receivedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
receivedFlag = false;
@ -147,10 +135,6 @@ void loop() {
// put module back to listen mode
radio.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -51,7 +51,7 @@ void setup() {
// NOTE: Unlike other modules (such as SX127x),
// different GDOx pins are used for
// transmit and receive interrupts!
radio.setGdo2Action(setFlag);
radio.setGdo2Action(setFlag, FALLING);
// start transmitting the first packet
Serial.print(F("[CC1101] Sending first packet ... "));
@ -71,9 +71,6 @@ void setup() {
// flag to indicate that a packet was sent
volatile bool transmittedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is transmitted by the module
// IMPORTANT: this function MUST be 'void' type
@ -82,11 +79,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we sent a packet, set the flag
transmittedFlag = true;
}
@ -94,10 +86,6 @@ void setFlag(void) {
void loop() {
// check if the previous transmission finished
if(transmittedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
transmittedFlag = false;
@ -136,9 +124,5 @@ void loop() {
0x89, 0xAB, 0xCD, 0xEF};
int state = radio.startTransmit(byteArr, 8);
*/
// we're ready to send more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -13,6 +13,7 @@
- SX1231
- CC1101
- Si443x/RFM2x
- SX126x/LLCC68 (only devices without TCXO!)
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration
@ -36,7 +37,14 @@ SX1278 radio = new Module(10, 2, 9, 3);
//SX1278 radio = RadioShield.ModuleA;
// create AFSK client instance using the FSK module
// pin 5 is connected to SX1278 DIO2
// this requires connection to the module direct
// input pin, here connected to Arduino pin 5
// SX127x/RFM9x: DIO2
// RF69: DIO2
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
// SX126x/LLCC68: DIO2
AFSKClient audio(&radio, 5);
// create FSK4 client instance using the AFSK instance
@ -81,7 +89,7 @@ void setup() {
// NOTE: Unlike FSK FSK4, AFSK requires no rounding of
// the frequency shift.
Serial.print(F("[FSK4] Initializing ... "));
// low ("space") frequency: 434.0 MHz
// lowest ("space") frequency: 400 Hz
// frequency shift: 270 Hz
// baud rate: 100 baud
state = fsk4.begin(400, 270, 100);

View file

@ -12,6 +12,7 @@
- SX1231
- CC1101
- Si443x/RFM2x
- SX126x/LLCC68 (only devices without TCXO!)
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration
@ -35,7 +36,14 @@ SX1278 radio = new Module(10, 2, 9, 3);
//SX1278 radio = RadioShield.ModuleA;
// create AFSK client instance using the FSK module
// pin 5 is connected to SX1278 DIO2
// this requires connection to the module direct
// input pin, here connected to Arduino pin 5
// SX127x/RFM9x: DIO2
// RF69: DIO2
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
// SX126x/LLCC68: DIO2
AFSKClient audio(&radio, 5);
// create Hellschreiber client instance using the AFSK instance

View file

@ -12,6 +12,7 @@
- SX1231
- CC1101
- Si443x/RFM2x
- SX126x/LLCC68 (only devices without TCXO!)
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration
@ -35,8 +36,15 @@ SX1278 radio = new Module(10, 2, 9, 3);
//SX1278 radio = RadioShield.ModuleA;
// create AFSK client instance using the FSK module
// pin 5 is connected to SX1278 DIO2
AFSKClient audio(&radio, 10);
// this requires connection to the module direct
// input pin, here connected to Arduino pin 5
// SX127x/RFM9x: DIO2
// RF69: DIO2
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
// SX126x/LLCC68: DIO2
AFSKClient audio(&radio, 5);
// create Morse client instance using the AFSK instance
MorseClient morse(&audio);
@ -72,17 +80,6 @@ void setup() {
Serial.println(state);
while(true);
}
// after that, set mode to OOK
Serial.print(F("[SX1278] Switching to OOK ... "));
state = radio.setOOK(true);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
}
void loop() {

View file

@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.18)
# create the project
project(rpi-sx1261)
# when using debuggers such as gdb, the following line can be used
#set(CMAKE_BUILD_TYPE Debug)
# if you did not build RadioLib as shared library (see README),
# you will have to add it as source directory
# the following is just an example, yours will likely be different
#add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CURRENT_BINARY_DIR}/RadioLib")
# add the executable
add_executable(${PROJECT_NAME} main.cpp)
# link both libraries
target_link_libraries(${PROJECT_NAME} RadioLib pigpio)
# you can also specify RadioLib compile-time flags here
#target_compile_definitions(${PROJECT_NAME} PUBLIC RADIOLIB_DEBUG RADIOLIB_VERBOSE)

View file

@ -0,0 +1,153 @@
#ifndef PI_HAL_H
#define PI_HAL_H
// include RadioLib
#include <RadioLib/RadioLib.h>
// include the library for Raspberry GPIO pins
#include "pigpio.h"
// create a new Raspberry Pi hardware abstraction layer
// using the pigpio library
// the HAL must inherit from the base RadioLibHal class
// and implement all of its virtual methods
class PiHal : public RadioLibHal {
public:
// default constructor - initializes the base HAL and any needed private members
PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000)
: RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, RISING_EDGE, FALLING_EDGE),
_spiChannel(spiChannel),
_spiSpeed(spiSpeed) {
}
void init() override {
// first initialise pigpio library
gpioInitialise();
// now the SPI
spiBegin();
// Waveshare LoRaWAN Hat also needs pin 18 to be pulled high to enable the radio
gpioSetMode(18, PI_OUTPUT);
gpioWrite(18, PI_HIGH);
}
void term() override {
// stop the SPI
spiEnd();
// pull the enable pin low
gpioSetMode(18, PI_OUTPUT);
gpioWrite(18, PI_LOW);
// finally, stop the pigpio library
gpioTerminate();
}
// GPIO-related methods (pinMode, digitalWrite etc.) should check
// RADIOLIB_NC as an alias for non-connected pins
void pinMode(uint32_t pin, uint32_t mode) override {
if(pin == RADIOLIB_NC) {
return;
}
gpioSetMode(pin, mode);
}
void digitalWrite(uint32_t pin, uint32_t value) override {
if(pin == RADIOLIB_NC) {
return;
}
gpioWrite(pin, value);
}
uint32_t digitalRead(uint32_t pin) override {
if(pin == RADIOLIB_NC) {
return(0);
}
return(gpioRead(pin));
}
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
if(interruptNum == RADIOLIB_NC) {
return;
}
gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb);
}
void detachInterrupt(uint32_t interruptNum) override {
if(interruptNum == RADIOLIB_NC) {
return;
}
gpioSetISRFunc(interruptNum, 0, 0, NULL);
}
void delay(unsigned long ms) override {
gpioDelay(ms * 1000);
}
void delayMicroseconds(unsigned long us) override {
gpioDelay(us);
}
unsigned long millis() override {
return(gpioTick() / 1000);
}
unsigned long micros() override {
return(gpioTick());
}
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
if(pin == RADIOLIB_NC) {
return(0);
}
gpioSetMode(pin, PI_INPUT);
uint32_t start = gpioTick();
uint32_t curtick = gpioTick();
while(gpioRead(pin) == state) {
if((gpioTick() - curtick) > timeout) {
return(0);
}
}
return(gpioTick() - start);
}
void spiBegin() {
if(_spiHandle < 0) {
_spiHandle = spiOpen(_spiChannel, _spiSpeed, 0);
}
}
void spiBeginTransaction() {}
uint8_t spiTransfer(uint8_t b) {
char ret;
spiXfer(_spiHandle, (char*)&b, &ret, 1);
return(ret);
}
void spiEndTransaction() {}
void spiEnd() {
if(_spiHandle >= 0) {
spiClose(_spiHandle);
_spiHandle = -1;
}
}
private:
// the HAL can contain any additional private members
const unsigned int _spiSpeed;
const uint8_t _spiChannel;
int _spiHandle = -1;
};
#endif

View file

@ -0,0 +1,8 @@
#!/bin/bash
set -e
mkdir -p build
cd build
cmake -G "CodeBlocks - Unix Makefiles" ..
make -j4
cd ..

View file

@ -0,0 +1,3 @@
#!/bin/bash
rm -rf ./build

View file

@ -0,0 +1,66 @@
/*
RadioLib Non-Arduino Raspberry Pi Example
This example shows how to use RadioLib without Arduino.
In this case, a Raspberry Pi with WaveShare SX1302 LoRaWAN Hat
using the pigpio library.
Can be used as a starting point to port RadioLib to any platform!
See this API reference page for details on the RadioLib hardware abstraction
https://jgromes.github.io/RadioLib/class_hal.html
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib/RadioLib.h>
// include the hardware abstraction layer
#include "PiHal.h"
// create a new instance of the HAL class
// use SPI channel 1, because on Waveshare LoRaWAN Hat,
// the SX1261 CS is connected to CE1
PiHal* hal = new PiHal(1);
// now we can create the radio module
// pinout corresponds to the Waveshare LoRaWAN Hat
// NSS pin: 7
// DIO1 pin: 17
// NRST pin: 22
// BUSY pin: 4
SX1261 radio = new Module(hal, 7, 17, 22, 4);
// the entry point for the program
int main(int argc, char** argv) {
// initialize just like with Arduino
printf("[SX1261] Initializing ... ");
int state = radio.begin();
if (state != RADIOLIB_ERR_NONE) {
printf("failed, code %d\n", state);
return(1);
}
printf("success!\n");
// loop forever
for(;;) {
// send a packet
printf("[SX1261] Transmitting packet ... ");
state = radio.transmit("Hello World!");
if(state == RADIOLIB_ERR_NONE) {
// the packet was successfully transmitted
printf("success!");
// wait for a second before transmitting again
hal->delay(1000);
} else {
printf("failed, code %d\n", state);
}
}
return(0);
}

View file

@ -31,7 +31,15 @@
// DIO1 pin: 3
SX1278 radio = new Module(10, 2, 9, 3);
// DIO2 pin: 5
// receiving packets requires connection
// to the module direct output pin,
// here connected to Arduino pin 5
// SX127x/RFM9x: DIO2
// RF69: DIO2
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
// SX126x/LLCC68: DIO2
const int pin = 5;
// create Pager client instance using the FSK module

View file

@ -67,9 +67,6 @@ void setup() {
// flag to indicate that a packet was received
volatile bool receivedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
@ -78,11 +75,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we got a packet, set the flag
receivedFlag = true;
}
@ -90,10 +82,6 @@ void setFlag(void) {
void loop() {
// check if the flag is set
if(receivedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
receivedFlag = false;
@ -134,10 +122,5 @@ void loop() {
// put module back to listen mode
radio.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -84,9 +84,6 @@ void setup() {
// flag to indicate that a packet was sent
volatile bool transmittedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is transmitted by the module
// IMPORTANT: this function MUST be 'void' type
@ -95,11 +92,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we sent a packet, set the flag
transmittedFlag = true;
}
@ -107,10 +99,6 @@ void setFlag(void) {
void loop() {
// check if the previous transmission finished
if(transmittedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
transmittedFlag = false;
@ -149,9 +137,5 @@ void loop() {
0x89, 0xAB, 0xCD, 0xEF};
int state = radio.startTransmit(byteArr, 8);
*/
// we're ready to send more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -10,6 +10,7 @@
- SX1231
- CC1101
- Si443x/RFM2x
- SX126x/LLCC68 (only devices without TCXO!)
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration
@ -33,7 +34,14 @@ SX1278 radio = new Module(10, 2, 9, 3);
//SX1278 radio = RadioShield.ModuleA;
// create AFSK client instance using the FSK module
// pin 5 is connected to SX1278 DIO2
// this requires connection to the module direct
// input pin, here connected to Arduino pin 5
// SX127x/RFM9x: DIO2
// RF69: DIO2
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
// SX126x/LLCC68: DIO2
AFSKClient audio(&radio, 5);
// create RTTY client instance using the AFSK instance

View file

@ -12,6 +12,7 @@
- SX1231
- CC1101
- Si443x/RFM2x
- SX126x/LLCC68 (only devices without TCXO!)
NOTE: Some platforms (such as Arduino Uno)
might not be fast enough to correctly
@ -42,7 +43,14 @@ SX1278 radio = new Module(10, 2, 9, 3);
//SX1278 radio = RadioShield.ModuleA;
// create AFSK client instance using the FSK module
// pin 5 is connected to SX1278 DIO2
// this requires connection to the module direct
// input pin, here connected to Arduino pin 5
// SX127x/RFM9x: DIO2
// RF69: DIO2
// SX1231: DIO2
// CC1101: GDO2
// Si443x/RFM2x: GPIO
// SX126x/LLCC68: DIO2
AFSKClient audio(&radio, 5);
// create SSTV client instance using the AFSK instance

View file

@ -0,0 +1,61 @@
/*
RadioLib STM32WLx Channel Activity Detection Example
This example uses STM32WLx to scan the current LoRa
channel and detect ongoing LoRa transmissions.
Unlike SX127x CAD, SX126x/STM32WLx can detect any part
of LoRa transmission, not just the preamble.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// no need to configure pins, signals are routed to the radio internally
STM32WLx radio = new STM32WLx_Module();
void setup() {
Serial.begin(9600);
// initialize STM32WLx with default settings
Serial.print(F("[STM32WLx] Initializing ... "));
int state = radio.begin(868.0);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
}
void loop() {
Serial.print(F("[STM32WLx] Scanning channel for LoRa transmission ... "));
// start scanning current channel
int state = radio.scanChannel();
if (state == RADIOLIB_LORA_DETECTED) {
// LoRa preamble was detected
Serial.println(F("detected!"));
} else if (state == RADIOLIB_CHANNEL_FREE) {
// no preamble was detected, channel is free
Serial.println(F("channel is free!"));
} else {
// some other error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
// wait 100 ms before new scan
delay(100);
}

View file

@ -0,0 +1,98 @@
/*
RadioLib STM32WLx Channel Activity Detection Example
This example uses STM32WLx to scan the current LoRa
channel and detect ongoing LoRa transmissions.
Unlike SX127x CAD, SX126x/STM32WLx can detect any part
of LoRa transmission, not just the preamble.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// no need to configure pins, signals are routed to the radio internally
STM32WLx radio = new STM32WLx_Module();
void setup() {
Serial.begin(9600);
// initialize STM32WLx with default settings
Serial.print(F("[STM32WLx] Initializing ... "));
int state = radio.begin(868.0);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set the function that will be called
// when LoRa packet or timeout is detected
radio.setDio1Action(setFlag);
// start scanning the channel
Serial.print(F("[STM32WLx] Starting scan for LoRa preamble ... "));
state = radio.startChannelScan();
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
}
}
// flag to indicate that a packet was detected or CAD timed out
volatile bool scanFlag = false;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
// and MUST NOT have any arguments!
void setFlag(void) {
// something happened, set the flag
scanFlag = true;
}
void loop() {
// check if the flag is set
if(scanFlag) {
// reset flag
scanFlag = false;
// check CAD result
int state = radio.getChannelScanResult();
if (state == RADIOLIB_LORA_DETECTED) {
// LoRa packet was detected
Serial.println(F("[STM32WLx] Packet detected!"));
} else if (state == RADIOLIB_CHANNEL_FREE) {
// channel is free
Serial.println(F("[STM32WLx] Channel is free!"));
} else {
// some other error occurred
Serial.print(F("[STM32WLx] Failed, code "));
Serial.println(state);
}
// start scanning the channel again
Serial.print(F("[STM32WLx] Starting scan for LoRa preamble ... "));
state = radio.startChannelScan();
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
}
}
}

View file

@ -0,0 +1,124 @@
/*
RadioLib STM32WLx Receive Example
This example listens for LoRa transmissions using STM32WL MCU with
integrated (SX126x) LoRa radio.
To successfully receive data, the following settings have to be the same
on both transmitter and receiver:
- carrier frequency
- bandwidth
- spreading factor
- coding rate
- sync word
- preamble length
This example assumes Nucleo WL55JC1 is used. For other Nucleo boards
or standalone STM32WL, some configuration such as TCXO voltage and
RF switch control may have to be adjusted.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// no need to configure pins, signals are routed to the radio internally
STM32WLx radio = new STM32WLx_Module();
// set RF switch configuration for Nucleo WL55JC1
// NOTE: other boards may be different!
static const uint32_t rfswitch_pins[] =
{PC3, PC4, PC5};
static const Module::RfSwitchMode_t rfswitch_table[] = {
{STM32WLx::MODE_IDLE, {LOW, LOW, LOW}},
{STM32WLx::MODE_RX, {HIGH, HIGH, LOW}},
{STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}},
{STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}},
END_OF_MODE_TABLE,
};
void setup() {
Serial.begin(9600);
// set RF switch control configuration
// this has to be done prior to calling begin()
radio.setRfSwitchTable(rfswitch_pins, rfswitch_table);
// initialize STM32WL with default settings, except frequency
Serial.print(F("[STM32WL] Initializing ... "));
int state = radio.begin(868.0);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set appropriate TCXO voltage for Nucleo WL55JC1
state = radio.setTCXO(1.7);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
}
void loop() {
Serial.print(F("[STM32WL] Waiting for incoming transmission ... "));
// you can receive data as an Arduino String
// NOTE: receive() is a blocking method!
// See example ReceiveInterrupt for details
// on non-blocking reception method.
String str;
int state = radio.receive(str);
// you can also receive data as byte array
/*
byte byteArr[8];
int state = radio.receive(byteArr, 8);
*/
if (state == RADIOLIB_ERR_NONE) {
// packet was successfully received
Serial.println(F("success!"));
// print the data of the packet
Serial.print(F("[STM32WL] Data:\t\t"));
Serial.println(str);
// print the RSSI (Received Signal Strength Indicator)
// of the last received packet
Serial.print(F("[STM32WL] RSSI:\t\t"));
Serial.print(radio.getRSSI());
Serial.println(F(" dBm"));
// print the SNR (Signal-to-Noise Ratio)
// of the last received packet
Serial.print(F("[STM32WL] SNR:\t\t"));
Serial.print(radio.getSNR());
Serial.println(F(" dB"));
} else if (state == RADIOLIB_ERR_RX_TIMEOUT) {
// timeout occurred while waiting for a packet
Serial.println(F("timeout!"));
} else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
// packet was received, but is malformed
Serial.println(F("CRC error!"));
} else {
// some other error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
}

View file

@ -0,0 +1,158 @@
/*
RadioLib STM32WLx Receive with Interrupts Example
This example listens for LoRa transmissions and tries to
receive them. Once a packet is received, an interrupt is
triggered. To successfully receive data, the following
settings have to be the same on both transmitter
and receiver:
- carrier frequency
- bandwidth
- spreading factor
- coding rate
- sync word
This example assumes Nucleo WL55JC1 is used. For other Nucleo boards
or standalone STM32WL, some configuration such as TCXO voltage and
RF switch control may have to be adjusted.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// no need to configure pins, signals are routed to the radio internally
STM32WLx radio = new STM32WLx_Module();
// set RF switch configuration for Nucleo WL55JC1
// NOTE: other boards may be different!
static const uint32_t rfswitch_pins[] =
{PC3, PC4, PC5};
static const Module::RfSwitchMode_t rfswitch_table[] = {
{STM32WLx::MODE_IDLE, {LOW, LOW, LOW}},
{STM32WLx::MODE_RX, {HIGH, HIGH, LOW}},
{STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}},
{STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}},
END_OF_MODE_TABLE,
};
void setup() {
Serial.begin(9600);
// set RF switch control configuration
// this has to be done prior to calling begin()
radio.setRfSwitchTable(rfswitch_pins, rfswitch_table);
// initialize STM32WL with default settings, except frequency
Serial.print(F("[STM32WL] Initializing ... "));
int state = radio.begin(868.0);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set appropriate TCXO voltage for Nucleo WL55JC1
state = radio.setTCXO(1.7);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set the function that will be called
// when new packet is received
radio.setDio1Action(setFlag);
// start listening for LoRa packets
Serial.print(F("[STM32WL] Starting to listen ... "));
state = radio.startReceive();
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// if needed, 'listen' mode can be disabled by calling
// any of the following methods:
//
// radio.standby()
// radio.sleep()
// radio.transmit();
// radio.receive();
// radio.readData();
// radio.scanChannel();
}
// flag to indicate that a packet was received
volatile bool receivedFlag = false;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
// and MUST NOT have any arguments!
void setFlag(void) {
// we got a packet, set the flag
receivedFlag = true;
}
void loop() {
// check if the flag is set
if(receivedFlag) {
// reset flag
receivedFlag = false;
// you can read received data as an Arduino String
String str;
int state = radio.readData(str);
// you can also read received data as byte array
/*
byte byteArr[8];
int state = radio.readData(byteArr, 8);
*/
if (state == RADIOLIB_ERR_NONE) {
// packet was successfully received
Serial.println(F("[STM32WL] Received packet!"));
// print data of the packet
Serial.print(F("[STM32WL] Data:\t\t"));
Serial.println(str);
// print RSSI (Received Signal Strength Indicator)
Serial.print(F("[STM32WL] RSSI:\t\t"));
Serial.print(radio.getRSSI());
Serial.println(F(" dBm"));
// print SNR (Signal-to-Noise Ratio)
Serial.print(F("[STM32WL] SNR:\t\t"));
Serial.print(radio.getSNR());
Serial.println(F(" dB"));
} else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
// packet was received, but is malformed
Serial.println(F("CRC error!"));
} else {
// some other error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
// put module back to listen mode
radio.startReceive();
}
}

View file

@ -0,0 +1,112 @@
/*
RadioLib STM32WLx Transmit Example
This example transmits packets using STM32WL MCU with integrated
(SX126x) LoRa radio.
Each packet contains up to 256 bytes of data, in the form of:
- Arduino String
- null-terminated char array (C-string)
- arbitrary binary data (byte array)
This example assumes Nucleo WL55JC1 is used. For other Nucleo boards
or standalone STM32WL, some configuration such as TCXO voltage and
RF switch control may have to be adjusted.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// no need to configure pins, signals are routed to the radio internally
STM32WLx radio = new STM32WLx_Module();
// set RF switch configuration for Nucleo WL55JC1
// NOTE: other boards may be different!
static const uint32_t rfswitch_pins[] =
{PC3, PC4, PC5};
static const Module::RfSwitchMode_t rfswitch_table[] = {
{STM32WLx::MODE_IDLE, {LOW, LOW, LOW}},
{STM32WLx::MODE_RX, {HIGH, HIGH, LOW}},
{STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}},
{STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}},
END_OF_MODE_TABLE,
};
void setup() {
Serial.begin(9600);
// set RF switch control configuration
// this has to be done prior to calling begin()
radio.setRfSwitchTable(rfswitch_pins, rfswitch_table);
// initialize STM32WL with default settings, except frequency
Serial.print(F("[STM32WL] Initializing ... "));
int state = radio.begin(868.0);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set appropriate TCXO voltage for Nucleo WL55JC1
state = radio.setTCXO(1.7);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
}
void loop() {
Serial.print(F("[STM32WL] Transmitting packet ... "));
// you can transmit C-string or Arduino string up to
// 256 characters long
// NOTE: transmit() is a blocking method!
// See example STM32WLx_Transmit_Interrupt for details
// on non-blocking transmission method.
int state = radio.transmit("Hello World!");
// you can also transmit byte array up to 256 bytes long
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF};
int state = radio.transmit(byteArr, 8);
*/
if (state == RADIOLIB_ERR_NONE) {
// the packet was successfully transmitted
Serial.println(F("success!"));
// print measured data rate
Serial.print(F("[STM32WL] Datarate:\t"));
Serial.print(radio.getDataRate());
Serial.println(F(" bps"));
} else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
// the supplied packet was longer than 256 bytes
Serial.println(F("too long!"));
} else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
// timeout occured while transmitting packet
Serial.println(F("timeout!"));
} else {
// some other error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
// wait for a second before transmitting again
delay(1000);
}

View file

@ -0,0 +1,140 @@
/*
RadioLib STM32WLx Transmit with Interrupts Example
This example transmits LoRa packets with one second delays
between them. Each packet contains up to 256 bytes
of data, in the form of:
- Arduino String
- null-terminated char array (C-string)
- arbitrary binary data (byte array)
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// no need to configure pins, signals are routed to the radio internally
STM32WLx radio = new STM32WLx_Module();
// set RF switch configuration for Nucleo WL55JC1
// NOTE: other boards may be different!
static const uint32_t rfswitch_pins[] =
{PC3, PC4, PC5};
static const Module::RfSwitchMode_t rfswitch_table[] = {
{STM32WLx::MODE_IDLE, {LOW, LOW, LOW}},
{STM32WLx::MODE_RX, {HIGH, HIGH, LOW}},
{STM32WLx::MODE_TX_LP, {HIGH, HIGH, HIGH}},
{STM32WLx::MODE_TX_HP, {HIGH, LOW, HIGH}},
END_OF_MODE_TABLE,
};
// save transmission state between loops
int transmissionState = RADIOLIB_ERR_NONE;
void setup() {
Serial.begin(9600);
// set RF switch control configuration
// this has to be done prior to calling begin()
radio.setRfSwitchTable(rfswitch_pins, rfswitch_table);
// initialize STM32WL with default settings, except frequency
Serial.print(F("[STM32WL] Initializing ... "));
int state = radio.begin(868.0);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set appropriate TCXO voltage for Nucleo WL55JC1
state = radio.setTCXO(1.7);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set the function that will be called
// when packet transmission is finished
radio.setDio1Action(setFlag);
// start transmitting the first packet
Serial.print(F("[STM32WL] Sending first packet ... "));
// you can transmit C-string or Arduino string up to
// 256 characters long
transmissionState = radio.startTransmit("Hello World!");
// you can also transmit byte array up to 256 bytes long
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
state = radio.startTransmit(byteArr, 8);
*/
}
// flag to indicate that a packet was sent
volatile bool transmittedFlag = false;
// this function is called when a complete packet
// is transmitted by the module
// IMPORTANT: this function MUST be 'void' type
// and MUST NOT have any arguments!
void setFlag(void) {
// we sent a packet, set the flag
transmittedFlag = true;
}
void loop() {
// check if the previous transmission finished
if(transmittedFlag) {
// reset flag
transmittedFlag = false;
if (transmissionState == RADIOLIB_ERR_NONE) {
// packet was successfully sent
Serial.println(F("transmission finished!"));
// NOTE: when using interrupt-driven transmit method,
// it is not possible to automatically measure
// transmission data rate using getDataRate()
} else {
Serial.print(F("failed, code "));
Serial.println(transmissionState);
}
// clean up after transmission is finished
// this will ensure transmitter is disabled,
// RF switch is powered down etc.
radio.finishTransmit();
// wait a second before transmitting again
delay(1000);
// send another one
Serial.print(F("[STM32WL] Sending another packet ... "));
// you can transmit C-string or Arduino string up to
// 256 characters long
transmissionState = radio.startTransmit("Hello World!");
// you can also transmit byte array up to 256 bytes long
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
int state = radio.startTransmit(byteArr, 8);
*/
}
}

View file

@ -64,9 +64,6 @@ void setup() {
// flag to indicate that a packet was detected or CAD timed out
volatile bool scanFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
@ -75,11 +72,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// something happened, set the flag
scanFlag = true;
}
@ -87,10 +79,6 @@ void setFlag(void) {
void loop() {
// check if the flag is set
if(scanFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
scanFlag = false;
@ -121,9 +109,5 @@ void loop() {
Serial.print(F("failed, code "));
Serial.println(state);
}
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -35,9 +35,6 @@ int transmissionState = RADIOLIB_ERR_NONE;
// flag to indicate transmission or reception state
bool transmitFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// flag to indicate that a packet was sent or received
volatile bool operationDone = false;
@ -46,11 +43,6 @@ volatile bool operationDone = false;
// IMPORTANT: this function MUST be 'void' type
// and MUST NOT have any arguments!
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we sent or received a packet, set the flag
operationDone = true;
}
@ -95,10 +87,6 @@ void setup() {
void loop() {
// check if the previous operation finished
if(operationDone) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
operationDone = false;
@ -153,10 +141,6 @@ void loop() {
transmissionState = radio.startTransmit("Hello World!");
transmitFlag = true;
}
// we're ready to process more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -88,6 +88,11 @@ void loop() {
Serial.print(radio.getSNR());
Serial.println(F(" dB"));
// print frequency error
Serial.print(F("[SX1262] Frequency error:\t"));
Serial.print(radio.getFrequencyError());
Serial.println(F(" Hz"));
} else if (state == RADIOLIB_ERR_RX_TIMEOUT) {
// timeout occurred while waiting for a packet
Serial.println(F("timeout!"));

View file

@ -74,16 +74,12 @@ void setup() {
// radio.sleep()
// radio.transmit();
// radio.receive();
// radio.readData();
// radio.scanChannel();
}
// flag to indicate that a packet was received
volatile bool receivedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
@ -92,11 +88,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we got a packet, set the flag
receivedFlag = true;
}
@ -104,10 +95,6 @@ void setFlag(void) {
void loop() {
// check if the flag is set
if(receivedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
receivedFlag = false;
@ -139,6 +126,11 @@ void loop() {
Serial.print(radio.getSNR());
Serial.println(F(" dB"));
// print frequency error
Serial.print(F("[SX1262] Frequency error:\t"));
Serial.print(radio.getFrequencyError());
Serial.println(F(" Hz"));
} else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
// packet was received, but is malformed
Serial.println(F("CRC error!"));
@ -149,13 +141,5 @@ void loop() {
Serial.println(state);
}
// put module back to listen mode
radio.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -74,7 +74,7 @@ void setup() {
// sync word: 0x34 (public network/LoRaWAN)
// output power: 2 dBm
// preamble length: 20 symbols
state = radio2.begin(915.0, 500.0, 6, 5, 0x34, 20);
state = radio2.begin(915.0, 500.0, 6, 5, 0x34, 2, 20);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {

View file

@ -0,0 +1,113 @@
/*
RadioLib SX126x Spectrum Scan Example
This example shows how to perform a spectrum power scan using SX126x.
The output is in the form of scan lines, each line has 33 power bins.
First power bin corresponds to -11 dBm, the second to -15 dBm and so on.
Higher number of samples in a bin corresponds to more power received
at that level.
To show the results in a plot, run the Python script
RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py
WARNING: This functionality is experimental and requires a binary patch
to be uploaded to the SX126x device. There may be some undocumented
side effects!
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// this file contains binary patch for the SX1262
#include <modules/SX126x/patches/SX126x_patch_scan.h>
// SX1262 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// NRST pin: 3
// BUSY pin: 9
SX1262 radio = new Module(10, 2, 3, 9);
void setup() {
Serial.begin(115200);
// initialize SX1262 FSK modem with default settings
Serial.print(F("[SX1262] Initializing ... "));
int state = radio.beginFSK();
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// upload a patch to the SX1262 to enable spectral scan
// NOTE: this patch is uploaded into volatile memory,
// and must be re-uploaded on every power up
Serial.print(F("[SX1262] Uploading patch ... "));
state = radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan));
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// configure scan bandwidth to 234.4 kHz
// and disable the data shaping
Serial.print(F("[SX1262] Setting scan parameters ... "));
state = radio.setRxBandwidth(234.3);
state |= radio.setDataShaping(RADIOLIB_SHAPING_NONE);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
}
void loop() {
Serial.print(F("[SX1262] Starting spectral scan ... "));
// start spectral scan
// number of scans in each line is 2048
// number of samples: 2048 (fewer samples = better temporal resolution)
int state = radio.spectralScanStart(2048);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// wait for spectral scan to finish
while(radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) {
delay(10);
}
// read the results
uint16_t results[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE];
state = radio.spectralScanGetResult(results);
if(state == RADIOLIB_ERR_NONE) {
// we have some results, print it
Serial.print("SCAN ");
for(uint8_t i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) {
Serial.print(results[i]);
Serial.print(',');
}
Serial.println(" END");
}
// wait a little bit before the next scan
delay(5);
}

View file

@ -0,0 +1,129 @@
/*
RadioLib SX126x Spectrum Scan Example
This example shows how to perform a spectrum power scan using SX126x.
The output is in the form of scan lines, each line has 33 power bins.
First power bin corresponds to -11 dBm, the second to -15 dBm and so on.
Higher number of samples in a bin corresponds to more power received
at that level. The example performs frequency sweep over a given range.
To show the results in a plot, run the Python script
RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py
WARNING: This functionality is experimental and requires a binary patch
to be uploaded to the SX126x device. There may be some undocumented
side effects!
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// this file contains binary patch for the SX1262
#include <modules/SX126x/patches/SX126x_patch_scan.h>
// SX1262 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// NRST pin: 3
// BUSY pin: 9
SX1262 radio = new Module(10, 2, 3, 9);
// frequency range in MHz to scan
const float freqStart = 431;
const float freqEnd = 435;
void setup() {
Serial.begin(115200);
// initialize SX1262 FSK modem at the initial frequency
Serial.print(F("[SX1262] Initializing ... "));
int state = radio.beginFSK(freqStart);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// upload a patch to the SX1262 to enable spectral scan
// NOTE: this patch is uploaded into volatile memory,
// and must be re-uploaded on every power up
Serial.print(F("[SX1262] Uploading patch ... "));
state = radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan));
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// configure scan bandwidth to 234.4 kHz
// and disable the data shaping
Serial.print(F("[SX1262] Setting scan parameters ... "));
state = radio.setRxBandwidth(234.3);
state |= radio.setDataShaping(RADIOLIB_SHAPING_NONE);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
}
void loop() {
// perform scan over the entire frequency range
float freq = freqStart;
while(freq <= freqEnd) {
Serial.print("FREQ ");
Serial.println(freq, 2);
// start spectral scan
// number of samples: 2048 (fewer samples = better temporal resolution)
Serial.print(F("[SX1262] Starting spectral scan ... "));
int state = radio.spectralScanStart(2048);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// wait for spectral scan to finish
while(radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) {
delay(10);
}
// read the results
uint16_t results[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE];
state = radio.spectralScanGetResult(results);
if(state == RADIOLIB_ERR_NONE) {
// we have some results, print it
Serial.print("SCAN ");
for(uint8_t i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) {
Serial.print(results[i]);
Serial.print(',');
}
Serial.println(" END");
}
// wait a little bit before the next scan
delay(5);
// set the next frequency
// the frequency step should be slightly smaller
// or the same as the Rx bandwidth set in setup
freq += 0.2;
radio.setFrequency(freq);
}
}

View file

@ -73,9 +73,6 @@ void setup() {
// flag to indicate that a packet was sent
volatile bool transmittedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is transmitted by the module
// IMPORTANT: this function MUST be 'void' type
@ -84,11 +81,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we sent a packet, set the flag
transmittedFlag = true;
}
@ -96,10 +88,6 @@ void setFlag(void) {
void loop() {
// check if the previous transmission finished
if(transmittedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
transmittedFlag = false;
@ -138,9 +126,5 @@ void loop() {
0x89, 0xAB, 0xCD, 0xEF};
int state = radio.startTransmit(byteArr, 8);
*/
// we're ready to send more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -47,11 +47,11 @@ void setup() {
// set the function that will be called
// when LoRa preamble is not detected within CAD timeout period
radio.setDio0Action(setFlagTimeout);
radio.setDio0Action(setFlagTimeout, RISING);
// set the function that will be called
// when LoRa preamble is detected
radio.setDio1Action(setFlagDetected);
radio.setDio1Action(setFlagDetected, RISING);
// start scanning the channel
Serial.print(F("[SX1278] Starting scan for LoRa preamble ... "));
@ -70,9 +70,6 @@ volatile bool timeoutFlag = false;
// flag to indicate that a preamble was detected
volatile bool detectedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when no preamble
// is detected within timeout period
// IMPORTANT: this function MUST be 'void' type
@ -81,11 +78,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlagTimeout(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we timed out, set the flag
timeoutFlag = true;
}
@ -98,11 +90,6 @@ void setFlagTimeout(void) {
ICACHE_RAM_ATTR
#endif
void setFlagDetected(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we got a preamble, set the flag
detectedFlag = true;
}
@ -110,10 +97,6 @@ void setFlagDetected(void) {
void loop() {
// check if we need to restart channel activity detection
if(detectedFlag || timeoutFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// check if we got a preamble
if(detectedFlag) {
// LoRa preamble was detected
@ -138,10 +121,5 @@ void loop() {
// reset flags
timeoutFlag = false;
detectedFlag = false;
// enable interrupts again
enableInterrupt = true;
}
}

View file

@ -53,11 +53,11 @@ void setup() {
// set the function that will be called
// when LoRa preamble is not detected within CAD timeout period
// or when a packet is received
radio.setDio0Action(setFlagTimeout);
radio.setDio0Action(setFlagTimeout, RISING);
// set the function that will be called
// when LoRa preamble is detected
radio.setDio1Action(setFlagDetected);
radio.setDio1Action(setFlagDetected, RISING);
// start scanning the channel
Serial.print(F("[SX1278] Starting scan for LoRa preamble ... "));
@ -76,9 +76,6 @@ volatile bool timeoutFlag = false;
// flag to indicate that a preamble was detected
volatile bool detectedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// flag to indicate if we are currently receiving
bool receiving = false;
@ -90,11 +87,6 @@ bool receiving = false;
ICACHE_RAM_ATTR
#endif
void setFlagTimeout(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we timed out, set the flag
timeoutFlag = true;
}
@ -107,11 +99,6 @@ void setFlagTimeout(void) {
ICACHE_RAM_ATTR
#endif
void setFlagDetected(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we got a preamble, set the flag
detectedFlag = true;
}
@ -120,10 +107,6 @@ void loop() {
// check if we need to restart channel activity detection
if(detectedFlag || timeoutFlag) {
int state = RADIOLIB_ERR_NONE;
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// check ongoing reception
if(receiving) {
@ -217,10 +200,5 @@ void loop() {
// reset flags
timeoutFlag = false;
detectedFlag = false;
// enable interrupts again
enableInterrupt = true;
}
}

View file

@ -32,9 +32,6 @@ int transmissionState = RADIOLIB_ERR_NONE;
// flag to indicate transmission or reception state
bool transmitFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// flag to indicate that a packet was sent or received
volatile bool operationDone = false;
@ -43,11 +40,6 @@ volatile bool operationDone = false;
// IMPORTANT: this function MUST be 'void' type
// and MUST NOT have any arguments!
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we sent or received packet, set the flag
operationDone = true;
}
@ -68,7 +60,7 @@ void setup() {
// set the function that will be called
// when new packet is received
radio.setDio0Action(setFlag);
radio.setDio0Action(setFlag, RISING);
#if defined(INITIATING_NODE)
// send the first packet on this node
@ -92,10 +84,6 @@ void setup() {
void loop() {
// check if the previous operation finished
if(operationDone) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
operationDone = false;
@ -150,10 +138,5 @@ void loop() {
transmissionState = radio.startTransmit("Hello World!");
transmitFlag = true;
}
// we're ready to process more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -96,10 +96,10 @@ void setup() {
}
// set the function to call when reception is finished
radio.setDio0Action(setRxFlag);
radio.setDio0Action(setRxFlag, RISING);
// set the function to call when we need to change frequency
radio.setDio1Action(setFHSSFlag);
radio.setDio1Action(setFHSSFlag, RISING);
// start listening for LoRa packets
Serial.print(F("[SX1278] Starting to listen ... "));

View file

@ -51,7 +51,7 @@ void setup() {
// set the function that will be called
// when new packet is received
radio.setDio0Action(setFlag);
radio.setDio0Action(setFlag, RISING);
// start listening for LoRa packets
Serial.print(F("[SX1278] Starting to listen ... "));
@ -71,16 +71,12 @@ void setup() {
// radio.sleep()
// radio.transmit();
// radio.receive();
// radio.readData();
// radio.scanChannel();
}
// flag to indicate that a packet was received
volatile bool receivedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
@ -89,11 +85,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we got a packet, set the flag
receivedFlag = true;
}
@ -101,10 +92,6 @@ void setFlag(void) {
void loop() {
// check if the flag is set
if(receivedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
receivedFlag = false;
@ -151,13 +138,5 @@ void loop() {
Serial.println(state);
}
// put module back to listen mode
radio.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -68,11 +68,11 @@ void setup() {
// bandwidth: 500.0 kHz
// spreading factor: 6
// coding rate: 5
// sync word: 0x14
// sync word: 0x34
// output power: 2 dBm
// preamble length: 20 symbols
// amplifier gain: 1 (maximum gain)
state = radio2.begin(915.0, 500.0, 6, 5, 0x14, 2, 20, 1);
state = radio2.begin(915.0, 500.0, 6, 5, 0x34, 2, 20, 1);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {

View file

@ -108,10 +108,10 @@ void setup() {
}
// set the function to call when transmission is finished
radio.setDio0Action(setTxFlag);
radio.setDio0Action(setTxFlag, RISING);
// set the function to call when we need to change frequency
radio.setDio1Action(setFHSSFlag);
radio.setDio1Action(setFHSSFlag, RISING);
// start transmitting the first packet
Serial.print(F("[SX1278] Sending first packet ... "));

View file

@ -50,7 +50,7 @@ void setup() {
// set the function that will be called
// when packet transmission is finished
radio.setDio0Action(setFlag);
radio.setDio0Action(setFlag, RISING);
// start transmitting the first packet
Serial.print(F("[SX1278] Sending first packet ... "));
@ -70,9 +70,6 @@ void setup() {
// flag to indicate that a packet was sent
volatile bool transmittedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is transmitted by the module
// IMPORTANT: this function MUST be 'void' type
@ -81,11 +78,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we sent a packet, set the flag
transmittedFlag = true;
}
@ -93,10 +85,6 @@ void setFlag(void) {
void loop() {
// check if the previous transmission finished
if(transmittedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
transmittedFlag = false;
@ -135,9 +123,5 @@ void loop() {
0x89, 0xAB, 0xCD, 0xEF};
int state = radio.startTransmit(byteArr, 8);
*/
// we're ready to send more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -6,7 +6,10 @@
distance between the modules using time-of-flight
measurement.
Only SX1280 and SX1282 support ranging!
Only SX1280 and SX1282 without external RF switch support ranging!
Note that to get accurate ranging results, calibration is needed!
The process is described in Semtech SX1280 Application Note AN1200.29
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem
@ -57,12 +60,24 @@ void loop() {
int state = radio.range(false, 0x12345678);
*/
// if ranging calibration is known, it can be provided
// this should improve the accuracy and precision
/*
uint16_t calibration[3][6] = {
{ 10299, 10271, 10244, 10242, 10230, 10246 },
{ 11486, 11474, 11453, 11426, 11417, 11401 },
{ 13308, 13493, 13528, 13515, 13430, 13376 }
};
int state = radio.range(true, 0x12345678, calibration);
*/
if (state == RADIOLIB_ERR_NONE) {
// ranging finished successfully
Serial.println(F("success!"));
Serial.print(F("[SX1280] Distance:\t\t\t"));
Serial.print(radio.getRangingResult());
Serial.println(F(" meters"));
Serial.println(F(" meters (raw)"));
} else if (state == RADIOLIB_ERR_RANGING_TIMEOUT) {
// timed out waiting for ranging packet

View file

@ -78,9 +78,6 @@ void setup() {
// flag to indicate that a packet was received
volatile bool receivedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
@ -89,11 +86,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we got a packet, set the flag
receivedFlag = true;
}
@ -101,10 +93,6 @@ void setFlag(void) {
void loop() {
// check if the flag is set
if(receivedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
receivedFlag = false;
@ -155,10 +143,5 @@ void loop() {
// put module back to listen mode
radio.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -65,9 +65,10 @@ void setup() {
// bandwidth: 1625.0 kHz
// spreading factor: 7
// coding rate: 5
// sync word: 0x12 (private network)
// output power: 2 dBm
// preamble length: 20 symbols
state = radio2.begin(2450.0, 1625.0, 7, 5, 2, 20);
state = radio2.begin(2450.0, 1625.0, 7, 5, 0x12, 2, 20);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {

View file

@ -70,9 +70,6 @@ void setup() {
// flag to indicate that a packet was sent
volatile bool transmittedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is transmitted by the module
// IMPORTANT: this function MUST be 'void' type
@ -81,11 +78,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we sent a packet, set the flag
transmittedFlag = true;
}
@ -93,10 +85,6 @@ void setFlag(void) {
void loop() {
// check if the previous transmission finished
if(transmittedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
transmittedFlag = false;
@ -131,9 +119,5 @@ void loop() {
0x89, 0xAB, 0xCD, 0xEF};
int state = radio.startTransmit(byteArr, 8);
*/
// we're ready to send more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -69,9 +69,6 @@ void setup() {
// flag to indicate that a packet was received
volatile bool receivedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
@ -80,11 +77,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we got a packet, set the flag
receivedFlag = true;
}
@ -92,10 +84,6 @@ void setFlag(void) {
void loop() {
// check if the flag is set
if(receivedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
receivedFlag = false;
@ -130,10 +118,5 @@ void loop() {
// put module back to listen mode
radio.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -68,9 +68,6 @@ void setup() {
// flag to indicate that a packet was sent
volatile bool transmittedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is transmitted by the module
// IMPORTANT: this function MUST be 'void' type
@ -79,11 +76,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we sent a packet, set the flag
transmittedFlag = true;
}
@ -91,10 +83,6 @@ void setFlag(void) {
void loop() {
// check if the previous transmission finished
if(transmittedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
transmittedFlag = false;
@ -129,9 +117,5 @@ void loop() {
0x89, 0xAB, 0xCD, 0xEF};
int state = radio.startTransmit(byteArr, 8);
*/
// we're ready to send more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -86,9 +86,6 @@ void setup() {
// flag to indicate that a packet was received
volatile bool receivedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// how many bytes are there in total
const int totalLength = 512;
@ -106,11 +103,6 @@ volatile uint8_t rxBuffer[totalLength + 1];
ICACHE_RAM_ATTR
#endif
void fifoGet(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// set the flag when we receive the full packet
receivedFlag = radio.fifoGet(rxBuffer, totalLength, &receivedLength);
}
@ -118,10 +110,6 @@ void fifoGet(void) {
void loop() {
// check if the flag is set
if(receivedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// packet was successfully received
Serial.println(F("[SX1278] Received packet!"));
@ -135,10 +123,5 @@ void loop() {
// put module back to listen mode
radio.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -80,17 +80,17 @@ void setup() {
transmissionState = radio.startTransmit(longPacket);
}
// flag to indicate that a packet was sent
volatile bool transmittedFlag = false;
// flag to indicate we can keep adding more bytes to FIFO
volatile bool fifoEmpty = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// flag to indicate that a packet was sent
bool transmittedFlag = false;
// how many bytes are there in total
volatile int totalLength = longPacket.length();
int totalLength = longPacket.length();
// counter to keep track of how many bytes still need to be sent
volatile int remLength = totalLength;
int remLength = totalLength;
// this function is called when the radio transmit buffer
// is empty and ready to be refilled
@ -100,23 +100,22 @@ volatile int remLength = totalLength;
ICACHE_RAM_ATTR
#endif
void fifoAdd(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// add more bytes to the transmit buffer
uint8_t* txBuffPtr = (uint8_t*)longPacket.c_str();
transmittedFlag = radio.fifoAdd(txBuffPtr, totalLength, &remLength);
// we can send more bytes
fifoEmpty = true;
}
void loop() {
if(fifoEmpty) {
// reset flag
fifoEmpty = false;
// add more bytes to the transmit buffer
uint8_t* txBuffPtr = (uint8_t*)longPacket.c_str();
transmittedFlag = radio.fifoAdd(txBuffPtr, totalLength, &remLength);
}
// check if the previous transmission finished
if(transmittedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
transmittedFlag = false;
@ -148,9 +147,5 @@ void loop() {
// send another one
Serial.print(F("[SX1278] Sending another long packet ... "));
transmissionState = radio.startTransmit(longPacket);
// we're ready to send more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -87,9 +87,6 @@ void setup() {
// flag to indicate that a packet was received
volatile bool receivedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
@ -98,11 +95,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we got a packet, set the flag
receivedFlag = true;
}
@ -110,10 +102,6 @@ void setFlag(void) {
void loop() {
// check if the flag is set
if(receivedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
receivedFlag = false;
@ -144,10 +132,5 @@ void loop() {
// put module back to listen mode
radio.startReceive();
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -83,9 +83,6 @@ void setup() {
// flag to indicate that a packet was sent
volatile bool transmittedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is transmitted by the module
// IMPORTANT: this function MUST be 'void' type
@ -94,11 +91,6 @@ volatile bool enableInterrupt = true;
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we sent a packet, set the flag
transmittedFlag = true;
}
@ -106,10 +98,6 @@ void setFlag(void) {
void loop() {
// check if the previous transmission finished
if(transmittedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
transmittedFlag = false;
@ -148,9 +136,5 @@ void loop() {
0x89, 0xAB, 0xCD, 0xEF};
int state = radio.startTransmit(byteArr, 8);
*/
// we're ready to send more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -0,0 +1,176 @@
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
import argparse
import serial
import sys
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from datetime import datetime
from argparse import RawTextHelpFormatter
# number of samples in each scanline
SCAN_WIDTH = 33
# scanline Serial start/end markers
SCAN_MARK_START = 'SCAN '
SCAN_MARK_FREQ = 'FREQ '
SCAN_MARK_END = ' END'
# output path
OUT_PATH = 'out'
# default settings
DEFAULT_BAUDRATE = 115200
DEFAULT_COLOR_MAP = 'viridis'
DEFAULT_SCAN_LEN = 200
DEFAULT_RSSI_OFFSET = -11
# Print iterations progress
# from https://stackoverflow.com/questions/3173320/text-progress-bar-in-terminal-with-block-characters
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 50, fill = '', printEnd = "\r"):
"""
Call in a loop to create terminal progress bar
@params:
iteration - Required : current iteration (Int)
total - Required : total iterations (Int)
prefix - Optional : prefix string (Str)
suffix - Optional : suffix string (Str)
decimals - Optional : positive number of decimals in percent complete (Int)
length - Optional : character length of bar (Int)
fill - Optional : bar fill character (Str)
printEnd - Optional : end character (e.g. "\r", "\r\n") (Str)
"""
percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
filledLength = int(length * iteration // total)
bar = fill * filledLength + '-' * (length - filledLength)
print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd)
if iteration == total:
print()
def main():
parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description='''
RadioLib SX126x_Spectrum_Scan plotter script. Displays output from SX126x_Spectrum_Scan example
as grayscale and
Depends on pyserial and matplotlib, install by:
'python3 -m pip install pyserial matplotlib'
Step-by-step guide on how to use the script:
1. Upload the SX126x_Spectrum_Scan example to your Arduino board with SX1262 connected.
2. Run the script with appropriate arguments.
3. Once the scan is complete, output files will be saved to out/
''')
parser.add_argument('port',
type=str,
help='COM port to connect to the device')
parser.add_argument('--speed',
default=DEFAULT_BAUDRATE,
type=int,
help=f'COM port baudrate (defaults to {DEFAULT_BAUDRATE})')
parser.add_argument('--map',
default=DEFAULT_COLOR_MAP,
type=str,
help=f'Matplotlib color map to use for the output (defaults to "{DEFAULT_COLOR_MAP}")')
parser.add_argument('--len',
default=DEFAULT_SCAN_LEN,
type=int,
help=f'Number of scanlines to record (defaults to {DEFAULT_SCAN_LEN})')
parser.add_argument('--offset',
default=DEFAULT_RSSI_OFFSET,
type=int,
help=f'Default RSSI offset in dBm (defaults to {DEFAULT_RSSI_OFFSET})')
parser.add_argument('--freq',
default=-1,
type=float,
help=f'Default starting frequency in MHz')
args = parser.parse_args()
freq_mode = False
scan_len = args.len
if (args.freq != -1):
freq_mode = True
scan_len = 1000
# create the color map and the result array
arr = np.zeros((SCAN_WIDTH, scan_len))
# scanline counter
row = 0
# list of frequencies in frequency mode
freq_list = []
# open the COM port
with serial.Serial(args.port, args.speed, timeout=None) as com:
while(True):
# update the progress bar
if not freq_mode:
printProgressBar(row, scan_len)
# read a single line
try:
line = com.readline().decode('utf-8')
except:
continue
if SCAN_MARK_FREQ in line:
new_freq = float(line.split(' ')[1])
if (len(freq_list) > 1) and (new_freq < freq_list[-1]):
break
freq_list.append(new_freq)
print('{:.3f}'.format(new_freq), end = '\r')
continue
# check the markers
if (SCAN_MARK_START in line) and (SCAN_MARK_END in line):
# get the values
scanline = line[len(SCAN_MARK_START):-len(SCAN_MARK_END)].split(',')
for col in range(SCAN_WIDTH):
arr[col][row] = int(scanline[col])
# increment the row counter
row = row + 1
# check if we're done
if (not freq_mode) and (row >= scan_len):
break
# scale to the number of scans (sum of any given scanline)
num_samples = arr.sum(axis=0)[0]
arr *= (num_samples/arr.max())
if freq_mode:
scan_len = len(freq_list)
# create the figure
fig, ax = plt.subplots()
# display the result as heatmap
extent = [0, scan_len, -4*(SCAN_WIDTH + 1), args.offset]
if freq_mode:
extent[0] = freq_list[0]
extent[1] = freq_list[-1]
im = ax.imshow(arr[:,:scan_len], cmap=args.map, extent=extent)
fig.colorbar(im)
# set some properites and show
timestamp = datetime.now().strftime('%y-%m-%d %H-%M-%S')
title = f'RadioLib SX126x Spectral Scan {timestamp}'
if freq_mode:
plt.xlabel("Frequency [Hz]")
else:
plt.xlabel("Time [sample]")
plt.ylabel("RSSI [dBm]")
ax.set_aspect('auto')
fig.suptitle(title)
fig.canvas.manager.set_window_title(title)
plt.savefig(f'{OUT_PATH}/{title.replace(" ", "_")}.png', dpi=300)
plt.show()
if __name__ == "__main__":
main()

View file

@ -9,6 +9,8 @@
RadioLib KEYWORD1
RadioShield KEYWORD1
Module KEYWORD1
RadioLibHal KEYWORD1
ArduinoHal KEYWORD1
# modules
CC1101 KEYWORD1
@ -38,6 +40,8 @@ SX1279 KEYWORD1
SX1280 KEYWORD1
SX1281 KEYWORD1
SX1282 KEYWORD1
STM32WLx KEYWORD1
STM32WLx_Module KEYWORD1
# protocols
RTTYClient KEYWORD1
@ -50,6 +54,8 @@ AFSKClient KEYWORD1
FSK4Client KEYWORD1
APRSClient KEYWORD1
PagerClient KEYWORD1
ExternalRadio KEYWORD1
BellClient KEYWORD1
# SSTV modes
Scottie1 KEYWORD1
@ -62,6 +68,11 @@ PasokonP3 KEYWORD1
PasokonP5 KEYWORD1
PasokonP7 KEYWORD1
# Bell Modems
Bell101 KEYWORD1
Bell103 KEYWORD1
Bell202 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
@ -69,7 +80,7 @@ PasokonP7 KEYWORD1
# RadioLib
ModuleA KEYWORD2
ModuleB KEYWORD2
Module KEYWORD2
setRfSwitchTable KEYWORD2
# SX127x/RFM9x + RF69 + CC1101
begin KEYWORD2
@ -191,6 +202,12 @@ setRegulatorDCDC KEYWORD2
getCurrentLimit KEYWORD2
getIrqStatus KEYWORD2
getLastError KEYWORD2
setRxBoostedGainMode KEYWORD2
uploadPatch KEYWORD2
spectralScanStart KEYWORD2
spectralScanAbort KEYWORD2
spectralScanGetStatus KEYWORD2
spectralScanGetResult KEYWORD2
# nRF24
setIrqAction KEYWORD2
@ -249,12 +266,16 @@ dropSync KEYWORD2
setTimerFlag KEYWORD2
setInterruptSetup KEYWORD2
# BellModem
setModem KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
RADIOLIB_NC LITERAL1
RADIOLIB_VERSION LITERAL1
RADIOLIB_PIN_TYPE LITERAL1
RADIOLIB_SHAPING_NONE LITERAL1
RADIOLIB_SHAPING_0_3 LITERAL1

26
lib/RadioLib/library.json Normal file
View file

@ -0,0 +1,26 @@
{
"name": "RadioLib",
"version": "6.0.0",
"description": "Universal wireless communication library. User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.).",
"keywords": "radio, communication, morse, cc1101, aprs, sx1276, sx1278, sx1272, rtty, ax25, afsk, nrf24, rfm96, sx1231, rfm96, rfm98, sstv, sx1278, sx1272, sx1276, sx1280, sx1281, sx1282, sx1261, sx1262, sx1268, si4432, rfm22, llcc68, pager, pocsag",
"homepage": "https://github.com/jgromes/RadioLib",
"repository":
{
"type": "git",
"url": "https://github.com/jgromes/RadioLib.git"
},
"authors":
{
"name": "Jan Gromeš",
"email": "gromes.jan@gmail.com",
"maintainer": true
},
"license": "MIT",
"frameworks": "*",
"platforms": "*",
"headers": "RadioLib.h",
"build":
{
"libLDFMode": "chain+"
}
}

View file

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

View file

@ -0,0 +1,165 @@
#include "ArduinoHal.h"
#if defined(RADIOLIB_BUILD_ARDUINO)
ArduinoHal::ArduinoHal(): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&RADIOLIB_DEFAULT_SPI), initInterface(true) {}
ArduinoHal::ArduinoHal(SPIClass& spi, SPISettings spiSettings): RadioLibHal(INPUT, OUTPUT, LOW, HIGH, RISING, FALLING), spi(&spi), spiSettings(spiSettings) {}
void ArduinoHal::init() {
if(initInterface) {
spiBegin();
}
}
void ArduinoHal::term() {
if(initInterface) {
spiEnd();
}
}
void inline ArduinoHal::pinMode(uint32_t pin, uint32_t mode) {
if(pin == RADIOLIB_NC) {
return;
}
::pinMode(pin, RADIOLIB_ARDUINOHAL_PIN_MODE_CAST mode);
}
void inline ArduinoHal::digitalWrite(uint32_t pin, uint32_t value) {
if(pin == RADIOLIB_NC) {
return;
}
::digitalWrite(pin, RADIOLIB_ARDUINOHAL_PIN_STATUS_CAST value);
}
uint32_t inline ArduinoHal::digitalRead(uint32_t pin) {
if(pin == RADIOLIB_NC) {
return 0;
}
return(::digitalRead(pin));
}
void inline ArduinoHal::attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) {
if(interruptNum == RADIOLIB_NC) {
return;
}
::attachInterrupt(interruptNum, interruptCb, RADIOLIB_ARDUINOHAL_INTERRUPT_MODE_CAST mode);
}
void inline ArduinoHal::detachInterrupt(uint32_t interruptNum) {
if(interruptNum == RADIOLIB_NC) {
return;
}
::detachInterrupt(interruptNum);
}
void inline ArduinoHal::delay(unsigned long ms) {
::delay(ms);
}
void inline ArduinoHal::delayMicroseconds(unsigned long us) {
::delayMicroseconds(us);
}
unsigned long inline ArduinoHal::millis() {
return(::millis());
}
unsigned long inline ArduinoHal::micros() {
return(::micros());
}
long inline ArduinoHal::pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) {
if(pin == RADIOLIB_NC) {
return 0;
}
return(::pulseIn(pin, state, timeout));
}
void inline ArduinoHal::spiBegin() {
spi->begin();
}
void inline ArduinoHal::spiBeginTransaction() {
spi->beginTransaction(spiSettings);
}
uint8_t inline ArduinoHal::spiTransfer(uint8_t b) {
return(spi->transfer(b));
}
void inline ArduinoHal::spiEndTransaction() {
spi->endTransaction();
}
void inline ArduinoHal::spiEnd() {
spi->end();
}
void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) {
#if !defined(RADIOLIB_TONE_UNSUPPORTED)
if(pin == RADIOLIB_NC) {
return;
}
::tone(pin, frequency, duration);
#elif defined(ESP32)
// ESP32 tone() emulation
(void)duration;
if(prev == -1) {
ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL);
}
if(prev != frequency) {
ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, frequency);
}
prev = frequency;
#elif defined(RADIOLIB_MBED_TONE_OVERRIDE)
// better tone for mbed OS boards
(void)duration;
if(!pwmPin) {
pwmPin = new mbed::PwmOut(digitalPinToPinName(pin));
}
pwmPin->period(1.0 / frequency);
pwmPin->write(0.5);
#endif
}
void inline ArduinoHal::noTone(uint32_t pin) {
#if !defined(RADIOLIB_TONE_UNSUPPORTED) and defined(ARDUINO_ARCH_STM32)
if(pin == RADIOLIB_NC) {
return;
}
::noTone(pin, false);
#elif !defined(RADIOLIB_TONE_UNSUPPORTED)
if(pin == RADIOLIB_NC) {
return;
}
::noTone(pin);
#elif defined(ESP32)
if(pin == RADIOLIB_NC) {
return;
}
// ESP32 tone() emulation
ledcDetachPin(pin);
ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0);
prev = -1;
#elif defined(RADIOLIB_MBED_TONE_OVERRIDE)
if(pin == RADIOLIB_NC) {
return;
}
// better tone for mbed OS boards
(void)pin;
pwmPin->suspend();
#endif
}
void inline ArduinoHal::yield() {
#if !defined(RADIOLIB_YIELD_UNSUPPORTED)
::yield();
#endif
}
uint32_t inline ArduinoHal::pinToInterrupt(uint32_t pin) {
return(digitalPinToInterrupt(pin));
}
#endif

View file

@ -0,0 +1,80 @@
// make sure this is always compiled
#include "TypeDef.h"
#if !defined(_RADIOLIB_ARDUINOHAL_H)
#define _RADIOLIB_ARDUINOHAL_H
// this file only makes sense for Arduino builds
#if defined(RADIOLIB_BUILD_ARDUINO)
#if defined(RADIOLIB_MBED_TONE_OVERRIDE)
#include "mbed.h"
#endif
#include "Hal.h"
#include <SPI.h>
/*!
\class ArduinoHal
\brief Arduino default hardware abstraction library implementation.
This class can be extended to support other Arduino platform or change behaviour of the default implementation.
*/
class ArduinoHal : public RadioLibHal {
public:
/*!
\brief Arduino Hal constructor. Will use the default SPI interface and automatically initialize it.
*/
ArduinoHal();
/*!
\brief Arduino Hal constructor. Will not attempt SPI interface initialization.
\param spi SPI interface to be used, can also use software SPI implementations.
\param spiSettings SPI interface settings.
*/
ArduinoHal(SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS);
// implementations of pure virtual RadioLibHal methods
void pinMode(uint32_t pin, uint32_t mode) override;
void digitalWrite(uint32_t pin, uint32_t value) override;
uint32_t digitalRead(uint32_t pin) override;
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override;
void detachInterrupt(uint32_t interruptNum) override;
void delay(unsigned long ms) override;
void delayMicroseconds(unsigned long us) override;
unsigned long millis() override;
unsigned long micros() override;
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override;
void spiBegin() override;
void spiBeginTransaction() override;
uint8_t spiTransfer(uint8_t b) override;
void spiEndTransaction() override;
void spiEnd() override;
// implementations of virtual RadioLibHal methods
void init() override;
void term() override;
void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) override;
void noTone(uint32_t pin) override;
void yield() override;
uint32_t pinToInterrupt(uint32_t pin) override;
#if !defined(RADIOLIB_GODMODE)
private:
#endif
SPIClass* spi = NULL;
SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS;
bool initInterface = false;
#if defined(RADIOLIB_MBED_TONE_OVERRIDE)
mbed::PwmOut *pwmPin = NULL;
#endif
#if defined(ESP32)
int32_t prev = -1;
#endif
};
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
#if !defined(_RADIOLIB_USER_BUILD_OPTIONS_H)
#define _RADIOLIB_USER_BUILD_OPTIONS_H
// this file can be used to define any user build options
// most commonly, RADIOLIB_EXCLUDE_* macros
// or enabling debug output
//#define RADIOLIB_DEBUG
//#define RADIOLIB_VERBOSE
#endif

35
lib/RadioLib/src/Hal.cpp Normal file
View file

@ -0,0 +1,35 @@
#include "Hal.h"
RadioLibHal::RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling)
: GpioModeInput(input),
GpioModeOutput(output),
GpioLevelLow(low),
GpioLevelHigh(high),
GpioInterruptRising(rising),
GpioInterruptFalling(falling) {}
void RadioLibHal::init() {
}
void RadioLibHal::term() {
}
void RadioLibHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) {
(void)pin;
(void)frequency;
(void)duration;
};
void RadioLibHal::noTone(uint32_t pin) {
(void)pin;
};
void RadioLibHal::yield() {
};
uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) {
return(pin);
};

209
lib/RadioLib/src/Hal.h Normal file
View file

@ -0,0 +1,209 @@
#if !defined(_RADIOLIB_HAL_H)
#define _RADIOLIB_HAL_H
#include <stdint.h>
#include <stddef.h>
/*!
\class Hal
\brief Hardware abstraction library base interface.
*/
class RadioLibHal {
public:
// values for pin modes, levels and change directions
// these tell RadioLib how are different logic states represented on a given platform
/*!
\brief Value to be used as the "input" GPIO direction.
*/
const uint32_t GpioModeInput;
/*!
\brief Value to be used as the "output" GPIO direction.
*/
const uint32_t GpioModeOutput;
/*!
\brief Value to be used as the "low" GPIO level.
*/
const uint32_t GpioLevelLow;
/*!
\brief Value to be used as the "high" GPIO level.
*/
const uint32_t GpioLevelHigh;
/*!
\brief Value to be used as the "rising" GPIO level change direction.
*/
const uint32_t GpioInterruptRising;
/*!
\brief Value to be used as the "falling" GPIO level change direction.
*/
const uint32_t GpioInterruptFalling;
/*!
\brief Default constructor.
\param input Value to be used as the "input" GPIO direction.
\param output Value to be used as the "output" GPIO direction.
\param low Value to be used as the "low" GPIO level.
\param high Value to be used as the "high" GPIO level.
\param rising Value to be used as the "rising" GPIO level change direction.
\param falling Value to be used as the "falling" GPIO level change direction.
*/
RadioLibHal(const uint32_t input, const uint32_t output, const uint32_t low, const uint32_t high, const uint32_t rising, const uint32_t falling);
// pure virtual methods - these must be implemented by the hardware abstraction for RadioLib to function
/*!
\brief GPIO pin mode (input/output/...) configuration method.
Must be implemented by the platform-specific hardware abstraction!
\param pin Pin to be changed (platform-specific).
\param mode Mode to be set (platform-specific).
*/
virtual void pinMode(uint32_t pin, uint32_t mode) = 0;
/*!
\brief Digital write method.
Must be implemented by the platform-specific hardware abstraction!
\param pin Pin to be changed (platform-specific).
\param value Value to set (platform-specific).
*/
virtual void digitalWrite(uint32_t pin, uint32_t value) = 0;
/*!
\brief Digital read method.
Must be implemented by the platform-specific hardware abstraction!
\param pin Pin to be changed (platform-specific).
\returns Value read on the pin (platform-specific).
*/
virtual uint32_t digitalRead(uint32_t pin) = 0;
/*!
\brief Method to attach function to an external interrupt.
Must be implemented by the platform-specific hardware abstraction!
\param interruptNum Interrupt number to attach to (platform-specific).
\param interruptCb Interrupt service routine to execute.
\param mode Rising/falling mode (platform-specific).
*/
virtual void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) = 0;
/*!
\brief Method to detach function from an external interrupt.
Must be implemented by the platform-specific hardware abstraction!
\param interruptNum Interrupt number to detach from (platform-specific).
*/
virtual void detachInterrupt(uint32_t interruptNum) = 0;
/*!
\brief Blocking wait function.
Must be implemented by the platform-specific hardware abstraction!
\param ms Number of milliseconds to wait.
*/
virtual void delay(unsigned long ms) = 0;
/*!
\brief Blocking microsecond wait function.
Must be implemented by the platform-specific hardware abstraction!
\param us Number of microseconds to wait.
*/
virtual void delayMicroseconds(unsigned long us) = 0;
/*!
\brief Get number of milliseconds since start.
Must be implemented by the platform-specific hardware abstraction!
\returns Number of milliseconds since start.
*/
virtual unsigned long millis() = 0;
/*!
\brief Get number of microseconds since start.
Must be implemented by the platform-specific hardware abstraction!
\returns Number of microseconds since start.
*/
virtual unsigned long micros() = 0;
/*!
\brief Measure the length of incoming digital pulse in microseconds.
Must be implemented by the platform-specific hardware abstraction!
\param pin Pin to measure on (platform-specific).
\param state Pin level to monitor (platform-specific).
\param timeout Timeout in microseconds.
\returns Pulse length in microseconds, or 0 if the pulse did not start before timeout.
*/
virtual long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) = 0;
/*!
\brief SPI initialization method.
*/
virtual void spiBegin() = 0;
/*!
\brief Method to start SPI transaction.
*/
virtual void spiBeginTransaction() = 0;
/*!
\brief Method to transfer one byte over SPI.
\param b Byte to send.
\returns Received byte.
*/
virtual uint8_t spiTransfer(uint8_t b) = 0;
/*!
\brief Method to end SPI transaction.
*/
virtual void spiEndTransaction() = 0;
/*!
\brief SPI termination method.
*/
virtual void spiEnd() = 0;
// virtual methods - these may or may not exists on a given platform
// they exist in this implementation, but do nothing
/*!
\brief Module initialization method.
This will be called by all radio modules at the beginning of startup.
Can be used to e.g., initalize SPI interface.
*/
virtual void init();
/*!
\brief Module termination method.
This will be called by all radio modules when the desctructor is called.
Can be used to e.g., stop SPI interface.
*/
virtual void term();
/*!
\brief Method to produce a square-wave with 50% duty cycle ("tone") of a given frequency at some pin.
\param pin Pin to be used as the output.
\param frequency Frequency of the square wave.
\param duration Duration of the tone in ms. When set to 0, the tone will be infinite.
*/
virtual void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0);
/*!
\brief Method to stop producing a tone.
\param pin Pin which is currently producing the tone.
*/
virtual void noTone(uint32_t pin);
/*!
\brief Yield method, called from long loops in multi-threaded environment (to prevent blocking other threads).
*/
virtual void yield();
/*!
\brief Function to convert from pin number to interrupt number.
\param pin Pin to convert from.
\returns The interrupt number of a given pin.
*/
virtual uint32_t pinToInterrupt(uint32_t pin);
};
#endif

View file

@ -1,94 +1,31 @@
#include "Module.h"
// the following is probably only needed on non-Arduino builds
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#if defined(RADIOLIB_DEBUG)
// needed for debug print
#include <stdarg.h>
#endif
#if defined(RADIOLIB_BUILD_ARDUINO)
#include "ArduinoHal.h"
// we need this to emulate tone() on mbed Arduino boards
#if defined(RADIOLIB_MBED_TONE_OVERRIDE)
#include "mbed.h"
mbed::PwmOut *pwmPin = NULL;
Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) {
this->hal = new ArduinoHal();
}
Module::Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio, SPIClass& spi, SPISettings spiSettings) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) {
this->hal = new ArduinoHal(spi, spiSettings);
}
#endif
Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio):
_cs(cs),
_irq(irq),
_rst(rst),
_gpio(gpio)
{
_spi = &RADIOLIB_DEFAULT_SPI;
_initInterface = true;
// this is Arduino build, pre-set callbacks
setCb_pinMode(::pinMode);
setCb_digitalRead(::digitalRead);
setCb_digitalWrite(::digitalWrite);
#if !defined(RADIOLIB_TONE_UNSUPPORTED)
setCb_tone(::tone);
setCb_noTone(::noTone);
#endif
setCb_attachInterrupt(::attachInterrupt);
setCb_detachInterrupt(::detachInterrupt);
#if !defined(RADIOLIB_YIELD_UNSUPPORTED)
setCb_yield(::yield);
#endif
setCb_delay(::delay);
setCb_delayMicroseconds(::delayMicroseconds);
setCb_millis(::millis);
setCb_micros(::micros);
setCb_pulseIn(::pulseIn);
setCb_SPIbegin(&Module::SPIbegin);
setCb_SPIbeginTransaction(&Module::beginTransaction);
setCb_SPItransfer(&Module::transfer);
setCb_SPIendTransaction(&Module::endTransaction);
setCb_SPIend(&Module::end);
Module::Module(RadioLibHal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio) : csPin(cs), irqPin(irq), rstPin(rst), gpioPin(gpio) {
this->hal = hal;
}
Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings):
_cs(cs),
_irq(irq),
_rst(rst),
_gpio(gpio),
_spiSettings(spiSettings)
{
_spi = &spi;
_initInterface = false;
// this is Arduino build, pre-set callbacks
setCb_pinMode(::pinMode);
setCb_digitalRead(::digitalRead);
setCb_digitalWrite(::digitalWrite);
#if !defined(RADIOLIB_TONE_UNSUPPORTED)
setCb_tone(::tone);
setCb_noTone(::noTone);
#endif
setCb_attachInterrupt(::attachInterrupt);
setCb_detachInterrupt(::detachInterrupt);
#if !defined(RADIOLIB_YIELD_UNSUPPORTED)
setCb_yield(::yield);
#endif
setCb_delay(::delay);
setCb_delayMicroseconds(::delayMicroseconds);
setCb_millis(::millis);
setCb_micros(::micros);
setCb_pulseIn(::pulseIn);
setCb_SPIbegin(&Module::SPIbegin);
setCb_SPIbeginTransaction(&Module::beginTransaction);
setCb_SPItransfer(&Module::transfer);
setCb_SPIendTransaction(&Module::endTransaction);
setCb_SPIend(&Module::end);
}
#else
Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio):
_cs(cs),
_irq(irq),
_rst(rst),
_gpio(gpio)
{
// not an Arduino build, it's up to the user to set all callbacks
}
#endif
Module::Module(const Module& mod) {
*this = mod;
}
@ -96,38 +33,25 @@ Module::Module(const Module& mod) {
Module& Module::operator=(const Module& mod) {
this->SPIreadCommand = mod.SPIreadCommand;
this->SPIwriteCommand = mod.SPIwriteCommand;
this->_cs = mod.getCs();
this->_irq = mod.getIrq();
this->_rst = mod.getRst();
this->_gpio = mod.getGpio();
this->csPin = mod.csPin;
this->irqPin = mod.irqPin;
this->rstPin = mod.rstPin;
this->gpioPin = mod.gpioPin;
return(*this);
}
void Module::init() {
this->pinMode(_cs, OUTPUT);
this->digitalWrite(_cs, HIGH);
#if defined(RADIOLIB_BUILD_ARDUINO)
if(_initInterface) {
(this->*cb_SPIbegin)();
}
#endif
this->hal->init();
this->hal->pinMode(csPin, this->hal->GpioModeOutput);
this->hal->digitalWrite(csPin, this->hal->GpioLevelHigh);
}
void Module::term() {
// stop hardware interfaces (if they were initialized by the library)
#if defined(RADIOLIB_BUILD_ARDUINO)
if(!_initInterface) {
return;
}
if(_spi != nullptr) {
this->SPIend();
}
#endif
this->hal->term();
}
int16_t Module::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) {
int16_t Module::SPIgetRegValue(uint16_t reg, uint8_t msb, uint8_t lsb) {
if((msb > 7) || (lsb > 7) || (lsb > msb)) {
return(RADIOLIB_ERR_INVALID_BIT_RANGE);
}
@ -137,7 +61,7 @@ int16_t Module::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) {
return(maskedValue);
}
int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) {
int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) {
if((msb > 7) || (lsb > 7) || (lsb > msb)) {
return(RADIOLIB_ERR_INVALID_BIT_RANGE);
}
@ -150,9 +74,9 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t
#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 = this->micros();
uint32_t start = this->hal->micros();
uint8_t readValue = 0x00;
while(this->micros() - start < (checkInterval * 1000)) {
while(this->hal->micros() - start < (checkInterval * 1000)) {
readValue = SPIreadRegister(reg);
if((readValue & checkMask) == (newValue & checkMask)) {
// check passed, we can stop the loop
@ -162,23 +86,13 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t
// 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();
RADIOLIB_DEBUG_PRINTLN("address:\t0x%X", reg);
RADIOLIB_DEBUG_PRINTLN("bits:\t\t%d %d", msb, lsb);
RADIOLIB_DEBUG_PRINT("value:\t\t0x%X", value);
RADIOLIB_DEBUG_PRINT("current:\t0x%X", currentValue);
RADIOLIB_DEBUG_PRINT("mask:\t\t0x%X", mask);
RADIOLIB_DEBUG_PRINT("new:\t\t0x%X", newValue);
RADIOLIB_DEBUG_PRINTLN("read:\t\t0x%X", readValue);
return(RADIOLIB_ERR_SPI_WRITE_FAILED);
#else
@ -186,310 +100,278 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t
#endif
}
void Module::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes) {
SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes);
void Module::SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inBytes) {
if(!SPIstreamType) {
SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes);
} else {
uint8_t cmd[] = { SPIreadCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) };
SPItransferStream(cmd, 3, false, NULL, inBytes, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT);
}
}
uint8_t Module::SPIreadRegister(uint8_t reg) {
uint8_t Module::SPIreadRegister(uint16_t reg) {
uint8_t resp = 0;
SPItransfer(SPIreadCommand, reg, NULL, &resp, 1);
if(!SPIstreamType) {
SPItransfer(SPIreadCommand, reg, NULL, &resp, 1);
} else {
uint8_t cmd[] = { SPIreadCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) };
SPItransferStream(cmd, 3, false, NULL, &resp, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT);
}
return(resp);
}
void Module::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, uint8_t numBytes) {
SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes);
void Module::SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes) {
if(!SPIstreamType) {
SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes);
} else {
uint8_t cmd[] = { SPIwriteCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) };
SPItransferStream(cmd, 3, true, data, NULL, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT);
}
}
void Module::SPIwriteRegister(uint8_t reg, uint8_t data) {
SPItransfer(SPIwriteCommand, reg, &data, NULL, 1);
void Module::SPIwriteRegister(uint16_t reg, uint8_t data) {
if(!SPIstreamType) {
SPItransfer(SPIwriteCommand, reg, &data, NULL, 1);
} else {
uint8_t cmd[] = { SPIwriteCommand, (uint8_t)((reg >> 8) & 0xFF), (uint8_t)(reg & 0xFF) };
SPItransferStream(cmd, 3, true, &data, NULL, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT);
}
}
void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) {
void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) {
// start SPI transaction
this->SPIbeginTransaction();
this->hal->spiBeginTransaction();
// pull CS low
this->digitalWrite(_cs, LOW);
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow);
// send SPI register address with access command
this->SPItransfer(reg | cmd);
if(this->SPIaddrWidth <= 8) {
this->hal->spiTransfer(reg | cmd);
} else {
this->hal->spiTransfer((reg >> 8) | cmd);
this->hal->spiTransfer(reg & 0xFF);
}
#if defined(RADIOLIB_VERBOSE)
if(cmd == SPIwriteCommand) {
RADIOLIB_VERBOSE_PRINT('W');
RADIOLIB_VERBOSE_PRINT("W");
} else if(cmd == SPIreadCommand) {
RADIOLIB_VERBOSE_PRINT('R');
RADIOLIB_VERBOSE_PRINT("R");
}
RADIOLIB_VERBOSE_PRINT('\t')
RADIOLIB_VERBOSE_PRINT(reg, HEX);
RADIOLIB_VERBOSE_PRINT('\t');
RADIOLIB_VERBOSE_PRINT("\t%X\t", reg);
#endif
// send data or get response
if(cmd == SPIwriteCommand) {
if(dataOut != NULL) {
for(size_t n = 0; n < numBytes; n++) {
this->SPItransfer(dataOut[n]);
RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX);
RADIOLIB_VERBOSE_PRINT('\t');
this->hal->spiTransfer(dataOut[n]);
RADIOLIB_VERBOSE_PRINT("%X\t", dataOut[n]);
}
}
} else if (cmd == SPIreadCommand) {
if(dataIn != NULL) {
for(size_t n = 0; n < numBytes; n++) {
dataIn[n] = this->SPItransfer(0x00);
RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX);
RADIOLIB_VERBOSE_PRINT('\t');
dataIn[n] = this->hal->spiTransfer(0x00);
RADIOLIB_VERBOSE_PRINT("%X\t", dataIn[n]);
}
}
}
RADIOLIB_VERBOSE_PRINTLN();
// release CS
this->digitalWrite(_cs, HIGH);
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh);
// end SPI transaction
this->SPIendTransaction();
this->hal->spiEndTransaction();
}
int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
return(this->SPIreadStream(&cmd, 1, data, numBytes, waitForGpio, verify));
}
int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
// send the command
int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT);
RADIOLIB_ASSERT(state);
// check the status
if(verify) {
state = this->SPIcheckStream();
}
return(state);
}
int16_t Module::SPIwriteStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
return(this->SPIwriteStream(&cmd, 1, data, numBytes, waitForGpio, verify));
}
int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
// send the command
int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT);
RADIOLIB_ASSERT(state);
// check the status
if(verify) {
state = this->SPIcheckStream();
}
return(state);
}
int16_t Module::SPIcheckStream() {
int16_t state = RADIOLIB_ERR_NONE;
#if defined(RADIOLIB_SPI_PARANOID)
// get the status
uint8_t spiStatus = 0;
uint8_t cmd = this->SPIstatusCommand;
state = this->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT);
RADIOLIB_ASSERT(state);
// translate to RadioLib status code
if(this->SPIparseStatusCb != nullptr) {
this->SPIstreamError = this->SPIparseStatusCb(spiStatus);
}
#endif
return(state);
}
int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, uint32_t timeout) {
#if defined(RADIOLIB_VERBOSE)
uint8_t debugBuff[RADIOLIB_STATIC_ARRAY_SIZE];
#endif
// ensure GPIO is low
uint32_t start = this->hal->millis();
while(this->hal->digitalRead(this->gpioPin)) {
this->hal->yield();
if(this->hal->millis() - start >= timeout) {
RADIOLIB_DEBUG_PRINTLN("Timed out waiting for GPIO pin, is it connected?");
return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
}
}
// pull NSS low
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow);
// start transfer
this->hal->spiBeginTransaction();
// send command byte(s)
for(uint8_t n = 0; n < cmdLen; n++) {
this->hal->spiTransfer(cmd[n]);
}
// variable to save error during SPI transfer
int16_t state = RADIOLIB_ERR_NONE;
// send/receive all bytes
if(write) {
for(size_t n = 0; n < numBytes; n++) {
// send byte
uint8_t in = this->hal->spiTransfer(dataOut[n]);
#if defined(RADIOLIB_VERBOSE)
debugBuff[n] = in;
#endif
// check status
if(this->SPIparseStatusCb != nullptr) {
state = this->SPIparseStatusCb(in);
}
}
} else {
// skip the first byte for read-type commands (status-only)
uint8_t in = this->hal->spiTransfer(this->SPInopCommand);
#if defined(RADIOLIB_VERBOSE)
debugBuff[0] = in;
#endif
// check status
if(this->SPIparseStatusCb != nullptr) {
state = this->SPIparseStatusCb(in);
} else {
state = RADIOLIB_ERR_NONE;
}
// read the data
if(state == RADIOLIB_ERR_NONE) {
for(size_t n = 0; n < numBytes; n++) {
dataIn[n] = this->hal->spiTransfer(this->SPInopCommand);
}
}
}
// stop transfer
this->hal->spiEndTransaction();
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh);
// wait for GPIO to go high and then low
if(waitForGpio) {
this->hal->delayMicroseconds(1);
uint32_t start = this->hal->millis();
while(this->hal->digitalRead(this->gpioPin)) {
this->hal->yield();
if(this->hal->millis() - start >= timeout) {
state = RADIOLIB_ERR_SPI_CMD_TIMEOUT;
break;
}
}
}
// print debug output
#if defined(RADIOLIB_VERBOSE)
// print command byte(s)
RADIOLIB_VERBOSE_PRINT("CMD\t");
for(uint8_t n = 0; n < cmdLen; n++) {
RADIOLIB_VERBOSE_PRINT("%X\t", cmd[n]);
}
RADIOLIB_VERBOSE_PRINTLN();
// print data bytes
RADIOLIB_VERBOSE_PRINT("DAT");
if(write) {
RADIOLIB_VERBOSE_PRINT("W\t");
for(size_t n = 0; n < numBytes; n++) {
RADIOLIB_VERBOSE_PRINT("%X\t%X\t", dataOut[n], debugBuff[n]);
}
RADIOLIB_VERBOSE_PRINTLN();
} else {
RADIOLIB_VERBOSE_PRINT("R\t%X\t%X\t", this->SPInopCommand, debugBuff[0]);
for(size_t n = 0; n < numBytes; n++) {
RADIOLIB_VERBOSE_PRINT("%X\t%X\t", this->SPInopCommand, dataIn[n]);
}
RADIOLIB_VERBOSE_PRINTLN();
}
RADIOLIB_VERBOSE_PRINTLN();
#endif
return(state);
}
void Module::waitForMicroseconds(uint32_t start, uint32_t len) {
#if defined(RADIOLIB_INTERRUPT_TIMING)
(void)start;
if((this->TimerSetupCb != nullptr) && (len != this->_prevTimingLen)) {
if((this->TimerSetupCb != nullptr) && (len != this->prevTimingLen)) {
_prevTimingLen = len;
this->TimerSetupCb(len);
}
this->TimerFlag = false;
while(!this->TimerFlag) {
this->yield();
this->hal->yield();
}
#else
while(this->micros() - start < len) {
this->yield();
while(this->hal->micros() - start < len) {
this->hal->yield();
}
#endif
}
void Module::pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode) {
if((pin == RADIOLIB_NC) || (cb_pinMode == nullptr)) {
return;
}
cb_pinMode(pin, mode);
}
void Module::digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value) {
if((pin == RADIOLIB_NC) || (cb_digitalWrite == nullptr)) {
return;
}
cb_digitalWrite(pin, value);
}
RADIOLIB_PIN_STATUS Module::digitalRead(RADIOLIB_PIN_TYPE pin) {
if((pin == RADIOLIB_NC) || (cb_digitalRead == nullptr)) {
return((RADIOLIB_PIN_STATUS)0);
}
return(cb_digitalRead(pin));
}
#if defined(ESP32)
// we need to cache the previous tone value for emulation on ESP32
int32_t prev = -1;
#endif
void Module::tone(RADIOLIB_PIN_TYPE pin, uint16_t value, uint32_t duration) {
#if !defined(RADIOLIB_TONE_UNSUPPORTED)
if((pin == RADIOLIB_NC) || (cb_tone == nullptr)) {
return;
}
cb_tone(pin, value, duration);
#else
if(pin == RADIOLIB_NC) {
return;
}
#if defined(ESP32)
// ESP32 tone() emulation
(void)duration;
if(prev == -1) {
ledcAttachPin(pin, RADIOLIB_TONE_ESP32_CHANNEL);
}
if(prev != value) {
ledcWriteTone(RADIOLIB_TONE_ESP32_CHANNEL, value);
}
prev = value;
#elif defined(RADIOLIB_MBED_TONE_OVERRIDE)
// better tone for mbed OS boards
(void)duration;
if(!pwmPin) {
pwmPin = new mbed::PwmOut(digitalPinToPinName(pin));
}
pwmPin->period(1.0 / value);
pwmPin->write(0.5);
#else
(void)value;
(void)duration;
#endif
#endif
}
void Module::noTone(RADIOLIB_PIN_TYPE pin) {
#if !defined(RADIOLIB_TONE_UNSUPPORTED)
if((pin == RADIOLIB_NC) || (cb_noTone == nullptr)) {
return;
}
#if defined(ARDUINO_ARCH_STM32)
cb_noTone(pin, false);
#else
cb_noTone(pin);
#endif
#else
if(pin == RADIOLIB_NC) {
return;
}
#if defined(ESP32)
// ESP32 tone() emulation
ledcDetachPin(pin);
ledcWrite(RADIOLIB_TONE_ESP32_CHANNEL, 0);
prev = -1;
#elif defined(RADIOLIB_MBED_TONE_OVERRIDE)
// better tone for mbed OS boards
(void)pin;
pwmPin->suspend();
#endif
#endif
}
void Module::attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode) {
if((interruptNum == RADIOLIB_NC) || (cb_attachInterrupt == nullptr)) {
return;
}
cb_attachInterrupt(interruptNum, userFunc, mode);
}
void Module::detachInterrupt(RADIOLIB_PIN_TYPE interruptNum) {
if((interruptNum == RADIOLIB_NC) || (cb_detachInterrupt == nullptr)) {
return;
}
cb_detachInterrupt(interruptNum);
}
void Module::yield() {
if(cb_yield == nullptr) {
return;
}
#if !defined(RADIOLIB_YIELD_UNSUPPORTED)
cb_yield();
#endif
}
void Module::delay(uint32_t ms) {
if(cb_delay == nullptr) {
return;
}
cb_delay(ms);
}
void Module::delayMicroseconds(uint32_t us) {
if(cb_delayMicroseconds == nullptr) {
return;
}
cb_delayMicroseconds(us);
}
uint32_t Module::millis() {
if(cb_millis == nullptr) {
return(0);
}
return(cb_millis());
}
uint32_t Module::micros() {
if(cb_micros == nullptr) {
return(0);
}
return(cb_micros());
}
uint32_t Module::pulseIn(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS state, uint32_t timeout) {
if(cb_pulseIn == nullptr) {
return(0);
}
return(cb_pulseIn(pin, state, timeout));
}
void Module::begin() {
#if defined(RADIOLIB_BUILD_ARDUINO)
if(cb_SPIbegin == nullptr) {
return;
}
(this->*cb_SPIbegin)();
#endif
}
void Module::beginTransaction() {
#if defined(RADIOLIB_BUILD_ARDUINO)
if(cb_SPIbeginTransaction == nullptr) {
return;
}
(this->*cb_SPIbeginTransaction)();
#endif
}
uint8_t Module::transfer(uint8_t b) {
#if defined(RADIOLIB_BUILD_ARDUINO)
if(cb_SPItransfer == nullptr) {
return(0xFF);
}
return((this->*cb_SPItransfer)(b));
#endif
}
void Module::endTransaction() {
#if defined(RADIOLIB_BUILD_ARDUINO)
if(cb_SPIendTransaction == nullptr) {
return;
}
(this->*cb_SPIendTransaction)();
#endif
}
void Module::end() {
#if defined(RADIOLIB_BUILD_ARDUINO)
if(cb_SPIend == nullptr) {
return;
}
(this->*cb_SPIend)();
#endif
}
#if defined(RADIOLIB_BUILD_ARDUINO)
void Module::SPIbegin() {
_spi->begin();
}
#endif
void Module::SPIbeginTransaction() {
#if defined(RADIOLIB_BUILD_ARDUINO)
_spi->beginTransaction(_spiSettings);
#endif
}
uint8_t Module::SPItransfer(uint8_t b) {
#if defined(RADIOLIB_BUILD_ARDUINO)
return(_spi->transfer(b));
#endif
}
void Module::SPIendTransaction() {
#if defined(RADIOLIB_BUILD_ARDUINO)
_spi->endTransaction();
#endif
}
#if defined(RADIOLIB_BUILD_ARDUINO)
void Module::SPIend() {
_spi->end();
}
#endif
uint8_t Module::flipBits(uint8_t b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
@ -505,17 +387,29 @@ uint16_t Module::flipBits16(uint16_t i) {
return i;
}
void Module::hexdump(uint8_t* data, size_t len) {
void Module::hexdump(uint8_t* data, size_t len, uint32_t offset, uint8_t width, bool be) {
size_t rem_len = len;
for(size_t i = 0; i < len; i+=16) {
char str[80];
sprintf(str, "%07x ", i);
sprintf(str, "%07" PRIx32 " ", i+offset);
size_t line_len = 16;
if(rem_len < line_len) {
line_len = rem_len;
}
for(size_t j = 0; j < line_len; j++) {
sprintf(&str[8 + j*3], "%02x ", data[i+j]);
for(size_t j = 0; j < line_len; j+=width) {
if(width > 1) {
int m = 0;
int step = width/2;
if(be) {
step *= -1;
}
for(int32_t k = width - 1; k >= -width + 1; k+=step) {
sprintf(&str[8 + (j+m)*3], "%02x ", data[i+j+k+m]);
m++;
}
} else {
sprintf(&str[8 + (j)*3], "%02x ", data[i+j]);
}
}
for(size_t j = line_len; j < 16; j++) {
sprintf(&str[8 + j*3], " ");
@ -532,39 +426,97 @@ void Module::hexdump(uint8_t* data, size_t len) {
for(size_t j = line_len; j < 16; j++) {
sprintf(&str[58 + j], " ");
}
RADIOLIB_DEBUG_PRINTLN(str);
RADIOLIB_DEBUG_PRINT(str);
RADIOLIB_DEBUG_PRINTLN();
rem_len -= 16;
}
}
void Module::regdump(uint8_t start, uint8_t len) {
void Module::regdump(uint16_t start, size_t len) {
#if defined(RADIOLIB_STATIC_ONLY)
uint8_t buff[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* buff = new uint8_t[len];
#endif
SPIreadRegisterBurst(start, len, buff);
hexdump(buff, len);
hexdump(buff, len, start);
#if !defined(RADIOLIB_STATIC_ONLY)
delete[] buff;
#endif
}
void Module::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) {
_useRfSwitch = true;
_rxEn = rxEn;
_txEn = txEn;
this->pinMode(rxEn, OUTPUT);
this->pinMode(txEn, OUTPUT);
#if defined(RADIOLIB_DEBUG) and defined(RADIOLIB_BUILD_ARDUINO)
// https://github.com/esp8266/Arduino/blob/65579d29081cb8501e4d7f786747bf12e7b37da2/cores/esp8266/Print.cpp#L50
size_t Module::serialPrintf(const char* format, ...) {
va_list arg;
va_start(arg, format);
char temp[64];
char* buffer = temp;
size_t len = vsnprintf(temp, sizeof(temp), format, arg);
va_end(arg);
if (len > sizeof(temp) - 1) {
buffer = new char[len + 1];
if (!buffer) {
return 0;
}
va_start(arg, format);
vsnprintf(buffer, len + 1, format, arg);
va_end(arg);
}
len = RADIOLIB_DEBUG_PORT.write((const uint8_t*)buffer, len);
if (buffer != temp) {
delete[] buffer;
}
return len;
}
#endif
void Module::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
// This can be on the stack, setRfSwitchTable copies the contents
const uint32_t pins[] = {
rxEn, txEn, RADIOLIB_NC,
};
// This must be static, since setRfSwitchTable stores a reference.
static const RfSwitchMode_t table[] = {
{ MODE_IDLE, {this->hal->GpioLevelLow, this->hal->GpioLevelLow} },
{ MODE_RX, {this->hal->GpioLevelHigh, this->hal->GpioLevelLow} },
{ MODE_TX, {this->hal->GpioLevelLow, this->hal->GpioLevelHigh} },
END_OF_MODE_TABLE,
};
setRfSwitchTable(pins, table);
}
void Module::setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState) {
// check RF switch control is enabled
if(!_useRfSwitch) {
void Module::setRfSwitchTable(const uint32_t (&pins)[3], const RfSwitchMode_t table[]) {
memcpy(this->rfSwitchPins, pins, sizeof(this->rfSwitchPins));
this->rfSwitchTable = table;
for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++)
this->hal->pinMode(pins[i], this->hal->GpioModeOutput);
}
const Module::RfSwitchMode_t *Module::findRfSwitchMode(uint8_t mode) const {
const RfSwitchMode_t *row = this->rfSwitchTable;
while (row && row->mode != MODE_END_OF_TABLE) {
if (row->mode == mode)
return row;
++row;
}
return nullptr;
}
void Module::setRfSwitchState(uint8_t mode) {
const RfSwitchMode_t *row = findRfSwitchMode(mode);
if(!row) {
// RF switch control is disabled or does not have this mode
return;
}
// set pins
this->digitalWrite(_rxEn, rxPinState);
this->digitalWrite(_txEn, txPinState);
const uint32_t *value = &row->values[0];
for(size_t i = 0; i < RFSWITCH_MAX_PINS; i++) {
uint32_t pin = this->rfSwitchPins[i];
if (pin != RADIOLIB_NC)
this->hal->digitalWrite(pin, *value);
++value;
}
}

View file

@ -2,84 +2,124 @@
#define _RADIOLIB_MODULE_H
#include "TypeDef.h"
#include "Hal.h"
#if defined(RADIOLIB_BUILD_ARDUINO)
#include <SPI.h>
#endif
#if defined(STM32WLxx)
#include <SubGhz.h>
#endif
/*!
* Value to use as the last element in a mode table to indicate the
* end of the table.
*
* See setRfSwitchTable() for details.
*/
#define END_OF_MODE_TABLE { Module::MODE_END_OF_TABLE, {} }
// default timeout for SPI transfers
#define RADIOLIB_MODULE_SPI_TIMEOUT (1000)
/*!
\class Module
\brief Implements all common low-level methods to control the wireless module.
Every module class contains one private instance of this class.
*/
class Module {
public:
#if defined(RADIOLIB_BUILD_ARDUINO)
/*!
* \brief The maximum number of pins supported by the RF switch
* code.
*
* Note: It is not recommended to use this constant in your sketch
* when defining a rfswitch pins array, to prevent issues when this
* value is ever increased and such an array gets extra zero
* elements (that will be interpreted as pin 0).
*/
static const size_t RFSWITCH_MAX_PINS = 3;
/*!
\brief Arduino Module constructor. Will use the default SPI interface and automatically initialize it
* Description of RF switch pin states for a single mode.
*
* See setRfSwitchTable() for details.
*/
struct RfSwitchMode_t {
uint8_t mode;
uint32_t values[RFSWITCH_MAX_PINS];
};
/*!
* Constants to use in a mode table set be setRfSwitchTable. These
* constants work for most radios, but some radios define their own
* constants to be used instead.
*
* See setRfSwitchTable() for details.
*/
enum OpMode_t {
/*! End of table marker, use \ref END_OF_MODE_TABLE constant
* instead. Value is zero to ensure zero-initialized mode ends the
* table */
MODE_END_OF_TABLE = 0,
/*! Idle mode */
MODE_IDLE,
/*! Receive mode */
MODE_RX,
/*! Transmission mode */
MODE_TX,
};
#if defined(RADIOLIB_BUILD_ARDUINO)
/*!
\brief Arduino Module constructor. Will use the default SPI interface and automatically initialize it.
\param cs Arduino pin to be used as chip select.
\param irq Arduino pin to be used as interrupt/GPIO.
\param rst Arduino pin to be used as hardware reset for the module.
\param gpio Arduino pin to be used as additional interrupt/GPIO.
*/
Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio = RADIOLIB_NC);
Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio = RADIOLIB_NC);
/*!
\brief Arduino Module constructor. Will not attempt SPI interface initialization.
\param cs Arduino pin to be used as chip select.
\param irq Arduino pin to be used as interrupt/GPIO.
\param rst Arduino pin to be used as hardware reset for the module.
\param gpio Arduino pin to be used as additional interrupt/GPIO.
\param spi SPI interface to be used, can also use software SPI implementations.
\param spiSettings SPI interface settings.
*/
Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS);
#else
/*!
\brief Default constructor.
\param cs Pin to be used as chip select.
\param irq Pin to be used as interrupt/GPIO.
\param rst Pin to be used as hardware reset for the module.
\param gpio Pin to be used as additional interrupt/GPIO.
*/
Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio = RADIOLIB_NC);
Module(uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio, SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS);
#endif
/*!
\brief Copy constructor.
\brief Module constructor.
\param hal A Hardware abstraction layer instance. An ArduinoHal instance for example.
\param cs Pin to be used as chip select.
\param irq Pin to be used as interrupt/GPIO.
\param rst Pin to be used as hardware reset for the module.
\param gpio Pin to be used as additional interrupt/GPIO.
*/
Module(RadioLibHal *hal, uint32_t cs, uint32_t irq, uint32_t rst, uint32_t gpio = RADIOLIB_NC);
/*!
\brief Copy constructor.
\param mod Module instance to copy.
*/
Module(const Module& mod);
/*!
\brief Overload for assignment operator.
\param frame rvalue Module.
*/
Module& operator=(const Module& mod);
// public member variables
/*!
\brief Hardware abstraction layer to be used.
*/
RadioLibHal* hal = NULL;
/*!
\brief Basic SPI read command. Defaults to 0x00.
@ -91,6 +131,43 @@ class Module {
*/
uint8_t SPIwriteCommand = 0b10000000;
/*!
\brief Basic SPI no-operation command. Defaults to 0x00.
*/
uint8_t SPInopCommand = 0x00;
/*!
\brief Basic SPI status read command. Defaults to 0x00.
*/
uint8_t SPIstatusCommand = 0x00;
/*!
\brief SPI address width. Defaults to 8, currently only supports 8 and 16-bit addresses.
*/
uint8_t SPIaddrWidth = 8;
/*!
\brief Whether the SPI interface is stream-type (e.g. SX126x) or register-type (e.g. SX127x).
Defaults to register-type SPI interfaces.
*/
bool SPIstreamType = false;
/*!
\brief The last recorded SPI stream error.
*/
int16_t SPIstreamError = RADIOLIB_ERR_UNKNOWN;
/*!
\brief SPI status parsing callback typedef.
*/
typedef int16_t (*SPIparseStatusCb_t)(uint8_t in);
/*!
\brief Callback to function that will parse the module-specific status codes to RadioLib status codes.
Typically used for modules with SPI stream-type interface (e.g. SX126x/SX128x).
*/
SPIparseStatusCb_t SPIparseStatusCb = nullptr;
#if defined(RADIOLIB_INTERRUPT_TIMING)
/*!
@ -126,281 +203,263 @@ class Module {
/*!
\brief SPI read method that automatically masks unused bits. This method is the preferred SPI read mechanism.
\param reg Address of SPI register to read.
\param msb Most significant bit of the register variable. Bits above this one will be masked out.
\param lsb Least significant bit of the register variable. Bits below this one will be masked out.
\returns Masked register value or status code.
*/
int16_t SPIgetRegValue(uint8_t reg, uint8_t msb = 7, uint8_t lsb = 0);
int16_t SPIgetRegValue(uint16_t reg, uint8_t msb = 7, uint8_t lsb = 0);
/*!
\brief Overwrite-safe SPI write method with verification. This method is the preferred SPI write mechanism.
\param reg Address of SPI register to write.
\param value Single byte value that will be written to the SPI register.
\param msb Most significant bit of the register variable. Bits above this one will not be affected by the write operation.
\param lsb Least significant bit of the register variable. Bits below this one will not be affected by the write operation.
\param checkInterval Number of milliseconds between register writing and verification reading. Some registers need up to 10ms to process the change.
\param checkMask Mask of bits to check, only bits set to 1 will be verified.
\returns \ref status_codes
*/
int16_t SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2, uint8_t checkMask = 0xFF);
int16_t SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb = 7, uint8_t lsb = 0, uint8_t checkInterval = 2, uint8_t checkMask = 0xFF);
/*!
\brief SPI burst read method.
\param reg Address of SPI register to read.
\param numBytes Number of bytes that will be read.
\param inBytes Pointer to array that will hold the read data.
*/
void SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes);
void SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inBytes);
/*!
\brief SPI basic read method. Use of this method is reserved for special cases, SPIgetRegValue should be used instead.
\param reg Address of SPI register to read.
\returns Value that was read from register.
*/
uint8_t SPIreadRegister(uint8_t reg);
uint8_t SPIreadRegister(uint16_t reg);
/*!
\brief SPI burst write method.
\param reg Address of SPI register to write.
\param data Pointer to array that holds the data that will be written.
\param numBytes Number of bytes that will be written.
*/
void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, uint8_t numBytes);
void SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes);
/*!
\brief SPI basic write method. Use of this method is reserved for special cases, SPIsetRegValue should be used instead.
\param reg Address of SPI register to write.
\param data Value that will be written to the register.
*/
void SPIwriteRegister(uint8_t reg, uint8_t data);
void SPIwriteRegister(uint16_t reg, uint8_t data);
/*!
\brief SPI single transfer method.
\param cmd SPI access command (read/write/burst/...).
\param reg Address of SPI register to transfer to/from.
\param dataOut Data that will be transfered from master to slave.
\param dataIn Data that was transfered from slave to master.
\param numBytes Number of bytes to transfer.
*/
void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes);
void SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes);
/*!
\brief Method to check the result of last SPI stream transfer.
\returns \ref status_codes
*/
int16_t SPIcheckStream();
/*!
\brief Method to perform a read transaction with SPI stream.
\param cmd SPI operation command.
\param data Data that will be transferred from slave to master.
\param numBytes Number of bytes to transfer.
\param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x).
\param verify Whether to verify the result of the transaction after it is finished.
\returns \ref status_codes
*/
int16_t SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true);
/*!
\brief Method to perform a read transaction with SPI stream.
\param cmd SPI operation command.
\param cmdLen SPI command length in bytes.
\param data Data that will be transferred from slave to master.
\param numBytes Number of bytes to transfer.
\param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x).
\param verify Whether to verify the result of the transaction after it is finished.
\returns \ref status_codes
*/
int16_t SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true);
/*!
\brief Method to perform a write transaction with SPI stream.
\param cmd SPI operation command.
\param data Data that will be transferred from master to slave.
\param numBytes Number of bytes to transfer.
\param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x).
\param verify Whether to verify the result of the transaction after it is finished.
\returns \ref status_codes
*/
int16_t SPIwriteStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true);
/*!
\brief Method to perform a write transaction with SPI stream.
\param cmd SPI operation command.
\param cmdLen SPI command length in bytes.
\param data Data that will be transferred from master to slave.
\param numBytes Number of bytes to transfer.
\param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x).
\param verify Whether to verify the result of the transaction after it is finished.
\returns \ref status_codes
*/
int16_t SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true);
/*!
\brief SPI single transfer method for modules with stream-type SPI interface (SX126x, SX128x etc.).
\param cmd SPI operation command.
\param cmdLen SPI command length in bytes.
\param write Set to true for write commands, false for read commands.
\param dataOut Data that will be transfered from master to slave.
\param dataIn Data that was transfered from slave to master.
\param numBytes Number of bytes to transfer.
\param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x).
\param timeout GPIO wait period timeout in milliseconds.
\returns \ref status_codes
*/
int16_t SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, uint32_t timeout);
// pin number access methods
/*!
\brief Access method to get the pin number of SPI chip select.
\returns Pin number of SPI chip select configured in the constructor.
*/
RADIOLIB_PIN_TYPE getCs() const { return(_cs); }
uint32_t getCs() const { return(csPin); }
/*!
\brief Access method to get the pin number of interrupt/GPIO.
\returns Pin number of interrupt/GPIO configured in the constructor.
*/
RADIOLIB_PIN_TYPE getIrq() const { return(_irq); }
uint32_t getIrq() const { return(irqPin); }
/*!
\brief Access method to get the pin number of hardware reset pin.
\returns Pin number of hardware reset pin configured in the constructor.
*/
RADIOLIB_PIN_TYPE getRst() const { return(_rst); }
uint32_t getRst() const { return(rstPin); }
/*!
\brief Access method to get the pin number of second interrupt/GPIO.
\returns Pin number of second interrupt/GPIO configured in the constructor.
*/
RADIOLIB_PIN_TYPE getGpio() const { return(_gpio); }
uint32_t getGpio() const { return(gpioPin); }
/*!
\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 Some modules contain external RF switch controlled by pins.
This function gives RadioLib control over those pins to
automatically switch between various modes: When idle both pins
will be LOW, during TX the `txEn` pin will be HIGH, during RX the
`rxPin` will be HIGH.
Radiolib will automatically set the pin mode and value of these
pins, so do not control them from the sketch.
When more than two pins or more control over the output values are
needed, use the setRfSwitchTable() function.
\param rxEn RX enable pin.
\param txEn TX enable pin.
*/
void setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn);
void setRfSwitchPins(uint32_t rxEn, uint32_t txEn);
/*!
\brief Some modules contain external RF switch controlled by pins.
This function gives RadioLib control over those pins to
automatically switch between various modes.
Radiolib will automatically set the pin mode and value of these
pins, so do not control them from the sketch.
\param pins A reference to an array of pins to control. This
should always be an array of 3 elements. If you need less pins,
use RADIOLIB_NC for the unused elements.
\param table A reference to an array of pin values to use for each
supported mode. Each element is an RfSwitchMode_T struct that
lists the mode for which it applies and the values for each of the
pins passed in the pins argument respectively.
The `pins` array will be copied into the Module object, so the
original array can be deallocated after this call. However,
a reference to the `table` array will be stored, so that array
must remain valid as long RadioLib is being used.
The `mode` field in each table row should normally use any of the
`MODE_*` constants from the Module::OpMode_t enum. However, some
radios support additional modes and will define their own OpMode_t
enum.
The length of the table is variable (to support radios that add
additional modes), so the table must always be terminated with the
special END_OF_MODE_TABLE value.
Normally all modes should be listed in the table, but for some
radios, modes can be omitted to indicate they are not supported
(e.g. when a radio has a high power and low power TX mode but
external circuitry only supports low power). If applicable, this
is documented in the radio class itself.
#### Example
For example, on a board that has an RF switch with an enable pin
connected to PA0 and a TX/RX select pin connected to PA1:
\code
// In global scope, define the pin array and mode table
static const uint32_t rfswitch_pins[] =
{PA0, PA1, RADIOLIB_NC};
static const Module::RfSwitchMode_t rfswitch_table[] = {
{Module::MODE_IDLE, {LOW, LOW}},
{Module::MODE_RX, {HIGH, LOW}},
{Module::MODE_TX, {HIGH, HIGH}},
Module::END_OF_MODE_TABLE,
};
void setup() {
...
// Then somewhere in setup, pass them to radiolib
radio.setRfSwitchTable(rfswitch_pins, rfswitch_table);
...
}
\endcode
*/
void setRfSwitchTable(const uint32_t (&pins)[RFSWITCH_MAX_PINS], const RfSwitchMode_t table[]);
/*!
\brief Find a mode in the RfSwitchTable.
\param The mode to find.
\returns A pointer to the RfSwitchMode_t struct in the table that
matches the passed mode. Returns nullptr if no rfswitch pins are
configured, or the passed mode is not listed in the table.
*/
const RfSwitchMode_t *findRfSwitchMode(uint8_t mode) const;
/*!
\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).
\param mode The mode to set. This must be one of the MODE_ constants, or a radio-specific constant.
*/
void setRfSwitchState(RADIOLIB_PIN_STATUS rxPinState, RADIOLIB_PIN_STATUS txPinState);
void setRfSwitchState(uint8_t mode);
/*!
\brief Wait for time to elapse, either using the microsecond timer, or the TimerFlag.
Note that in interrupt timing mode, it is up to the user to set up the timing interrupt!
\param start Waiting start timestamp, in microseconds.
\param len Waiting duration, in microseconds;
*/
void waitForMicroseconds(uint32_t start, uint32_t len);
// Arduino core overrides
/*!
\brief Arduino core pinMode override that checks RADIOLIB_NC as alias for unused pin.
\param pin Pin to change the mode of.
\param mode Which mode to set.
*/
void pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode);
/*!
\brief Arduino core digitalWrite override that checks RADIOLIB_NC as alias for unused pin.
\param pin Pin to write to.
\param value Whether to set the pin high or low.
*/
void digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value);
/*!
\brief Arduino core digitalWrite override that checks RADIOLIB_NC as alias for unused pin.
\param pin Pin to read from.
\returns Pin value.
*/
RADIOLIB_PIN_STATUS digitalRead(RADIOLIB_PIN_TYPE pin);
/*!
\brief Arduino core tone override that checks RADIOLIB_NC as alias for unused pin and RADIOLIB_TONE_UNSUPPORTED to make sure the platform does support tone.
\param pin Pin to write to.
\param value Frequency to output.
*/
void tone(RADIOLIB_PIN_TYPE pin, uint16_t value, uint32_t duration = 0);
/*!
\brief Arduino core noTone override that checks RADIOLIB_NC as alias for unused pin and RADIOLIB_TONE_UNSUPPORTED to make sure the platform does support tone.
\param pin Pin to write to.
*/
void noTone(RADIOLIB_PIN_TYPE pin);
/*!
\brief Arduino core attachInterrupt override.
\param interruptNum Interrupt number.
\param userFunc Interrupt service routine.
\param mode Pin hcange direction.
*/
void attachInterrupt(RADIOLIB_PIN_TYPE interruptNum, void (*userFunc)(void), RADIOLIB_INTERRUPT_STATUS mode);
/*!
\brief Arduino core detachInterrupt override.
\param interruptNum Interrupt number.
*/
void detachInterrupt(RADIOLIB_PIN_TYPE interruptNum);
/*!
\brief Arduino core yield override.
*/
void yield();
/*!
\brief Arduino core delay override.
\param ms Delay length in milliseconds.
*/
void delay(uint32_t ms);
/*!
\brief Arduino core delayMicroseconds override.
\param us Delay length in microseconds.
*/
void delayMicroseconds(uint32_t us);
/*!
\brief Arduino core millis override.
*/
uint32_t millis();
/*!
\brief Arduino core micros override.
*/
uint32_t micros();
/*!
\brief Arduino core pulseIn override.
*/
uint32_t pulseIn(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS state, uint32_t timeout);
/*!
\brief Arduino core SPI begin override.
*/
void begin();
/*!
\brief Arduino core SPI beginTransaction override.
*/
void beginTransaction();
/*!
\brief Arduino core SPI transfer override.
*/
uint8_t transfer(uint8_t b);
/*!
\brief Arduino core SPI endTransaction override.
*/
void endTransaction();
/*!
\brief Arduino core SPI end override.
*/
void end();
// helper functions to set up SPI overrides on Arduino
#if defined(RADIOLIB_BUILD_ARDUINO)
void SPIbegin();
void SPIend();
#endif
virtual void SPIbeginTransaction();
virtual uint8_t SPItransfer(uint8_t b);
virtual void SPIendTransaction();
/*!
\brief Function to reflect bits within a byte.
*/
@ -413,77 +472,38 @@ class Module {
/*!
\brief Function to dump data as hex into the debug port.
\param data Data to dump.
\param len Number of bytes to dump.
\param width Word width (1 for uint8_t, 2 for uint16_t, 4 for uint32_t).
\param be Print multi-byte data as big endian. Defaults to false.
*/
static void hexdump(uint8_t* data, size_t len);
static void hexdump(uint8_t* data, size_t len, uint32_t offset = 0, uint8_t width = 1, bool be = false);
/*!
\brief Function to dump device registers as hex into the debug port.
\param start First address to dump.
\param len Number of bytes to dump.
*/
void regdump(uint8_t start, uint8_t len);
void regdump(uint16_t start, size_t len);
#if defined(RADIOLIB_DEBUG) and defined(RADIOLIB_BUILD_ARDUINO)
static size_t serialPrintf(const char* format, ...);
#endif
#if !defined(RADIOLIB_GODMODE)
private:
#endif
uint32_t csPin = RADIOLIB_NC;
uint32_t irqPin = RADIOLIB_NC;
uint32_t rstPin = RADIOLIB_NC;
uint32_t gpioPin = RADIOLIB_NC;
// pins
RADIOLIB_PIN_TYPE _cs = RADIOLIB_NC;
RADIOLIB_PIN_TYPE _irq = RADIOLIB_NC;
RADIOLIB_PIN_TYPE _rst = RADIOLIB_NC;
RADIOLIB_PIN_TYPE _gpio = RADIOLIB_NC;
// SPI interface (Arduino only)
#if defined(RADIOLIB_BUILD_ARDUINO)
SPIClass* _spi = NULL;
SPISettings _spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS;
bool _initInterface = false;
#endif
// RF switch presence and pins
bool _useRfSwitch = false;
RADIOLIB_PIN_TYPE _rxEn = RADIOLIB_NC;
RADIOLIB_PIN_TYPE _txEn = RADIOLIB_NC;
// RF switch pins and table
uint32_t rfSwitchPins[RFSWITCH_MAX_PINS] = { RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC };
const RfSwitchMode_t *rfSwitchTable = nullptr;
#if defined(RADIOLIB_INTERRUPT_TIMING)
uint32_t _prevTimingLen = 0;
#endif
// hardware abstraction layer callbacks
// this is placed at the end of Module class because the callback generator macros
// screw with the private/public access specifiers
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_PIN_MODE);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DIGITAL_WRITE);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DIGITAL_READ);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_TONE);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_NO_TONE);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_ATTACH_INTERRUPT);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DETACH_INTERRUPT);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_YIELD);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DELAY);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DELAY_MICROSECONDS);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_MILLIS);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_MICROS);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_PULSE_IN);
#if defined(RADIOLIB_BUILD_ARDUINO)
RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_BEGIN);
RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION);
RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_TRANSFER);
RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_END_TRANSACTION);
RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_END);
#else
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_BEGIN);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_TRANSFER);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_END_TRANSACTION);
RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_SPI_END);
uint32_t prevTimingLen = 0;
#endif
};

View file

@ -38,6 +38,12 @@
#include "TypeDef.h"
#include "Module.h"
#include "Hal.h"
#if defined(RADIOLIB_BUILD_ARDUINO)
#include "ArduinoHal.h"
#endif
// warnings are printed in this file since BuildOpt.h is compiled in multiple places
// check God mode
@ -78,6 +84,7 @@
#include "modules/SX126x/SX1261.h"
#include "modules/SX126x/SX1262.h"
#include "modules/SX126x/SX1268.h"
#include "modules/SX126x/STM32WLx.h"
#include "modules/SX127x/SX1272.h"
#include "modules/SX127x/SX1273.h"
#include "modules/SX127x/SX1276.h"
@ -99,6 +106,9 @@
#include "protocols/SSTV/SSTV.h"
#include "protocols/FSK4/FSK4.h"
#include "protocols/APRS/APRS.h"
#include "protocols/ExternalRadio/ExternalRadio.h"
#include "protocols/Print/Print.h"
#include "protocols/BellModem/BellModem.h"
// only create Radio class when using RadioShield
#if defined(RADIOLIB_RADIOSHIELD)

View file

@ -1,6 +1,8 @@
#if !defined(_RADIOLIB_TYPES_H)
#define _RADIOLIB_TYPES_H
// user build options may override the default
#include "BuildOptUser.h"
#include "BuildOpt.h"
/*!
@ -63,6 +65,31 @@
\}
*/
/*!
\defgroup config_standby Standby mode type aliases.
\{
*/
/*!
\brief Default standby used by the module
*/
#define RADIOLIB_STANDBY_DEFAULT (0x00)
/*!
\brief Warm standby (e.g. crystal left running).
*/
#define RADIOLIB_STANDBY_WARM (0x01)
/*!
\brief Cold standby (e.g. only internal RC oscillator running).
*/
#define RADIOLIB_STANDBY_COLD (0x02)
/*!
\}
*/
/*!
\defgroup status_codes Status Codes
@ -287,6 +314,28 @@
*/
#define RADIOLIB_ERR_MIC_E_TELEMETRY_STATUS (-204)
// SSDV status codes
/*!
\brief SSDV mode is invalid.
*/
#define RADIOLIB_ERR_INVALID_SSDV_MODE (-301)
/*!
\brief Image size is invalid.
*/
#define RADIOLIB_ERR_INVALID_IMAGE_SIZE (-302)
/*!
\brief Image quality is invalid.
*/
#define RADIOLIB_ERR_INVALID_IMAGE_QUALITY (-303)
/*!
\brief Image subsampling is invalid.
*/
#define RADIOLIB_ERR_INVALID_SUBSAMPLING (-304)
// RTTY status codes
/*!
@ -362,6 +411,11 @@
/*!
\brief SX126x failed to execute SPI command.
Often this means that the module is trying to use TCXO while
XTAL is connected (or vice versa). Make sure your crystal setup
(e.g. TCXO reference voltage) matches your hardware by setting
"tcxoVoltage" to 0 when using XTAL module, or to appropriate value
when using TCXO module.
*/
#define RADIOLIB_ERR_SPI_CMD_FAILED (-707)

View file

@ -1,20 +1,21 @@
#include "CC1101.h"
#include <math.h>
#if !defined(RADIOLIB_EXCLUDE_CC1101)
CC1101::CC1101(Module* module) : PhysicalLayer(RADIOLIB_CC1101_FREQUENCY_STEP_SIZE, RADIOLIB_CC1101_MAX_PACKET_LENGTH) {
_mod = module;
this->mod = module;
}
Module* CC1101::getMod() {
return(_mod);
return(this->mod);
}
int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLength) {
int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLength) {
// set module properties
_mod->SPIreadCommand = RADIOLIB_CC1101_CMD_READ;
_mod->SPIwriteCommand = RADIOLIB_CC1101_CMD_WRITE;
_mod->init();
_mod->pinMode(_mod->getIrq(), INPUT);
this->mod->SPIreadCommand = RADIOLIB_CC1101_CMD_READ;
this->mod->SPIwriteCommand = RADIOLIB_CC1101_CMD_WRITE;
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
// try to find the CC1101 chip
uint8_t i = 0;
@ -24,28 +25,18 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po
if((version == RADIOLIB_CC1101_VERSION_CURRENT) || (version == RADIOLIB_CC1101_VERSION_LEGACY) || (version == RADIOLIB_CC1101_VERSION_CLONE)) {
flagFound = true;
} else {
#if defined(RADIOLIB_DEBUG)
RADIOLIB_DEBUG_PRINT(F("CC1101 not found! ("));
RADIOLIB_DEBUG_PRINT(i + 1);
RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RADIOLIB_CC1101_REG_VERSION == "));
char buffHex[7];
sprintf(buffHex, "0x%04X", version);
RADIOLIB_DEBUG_PRINT(buffHex);
RADIOLIB_DEBUG_PRINT(F(", expected 0x0004/0x0014"));
RADIOLIB_DEBUG_PRINTLN();
#endif
_mod->delay(10);
RADIOLIB_DEBUG_PRINTLN("CC1101 not found! (%d of 10 tries) RADIOLIB_CC1101_REG_VERSION == 0x%04X, expected 0x0004/0x0014", i + 1, version);
this->mod->hal->delay(10);
i++;
}
}
if(!flagFound) {
RADIOLIB_DEBUG_PRINTLN(F("No CC1101 found!"));
_mod->term();
RADIOLIB_DEBUG_PRINTLN("No CC1101 found!");
this->mod->term();
return(RADIOLIB_ERR_CHIP_NOT_FOUND);
} else {
RADIOLIB_DEBUG_PRINTLN(F("M\tCC1101"));
RADIOLIB_DEBUG_PRINTLN("M\tCC1101");
}
// configure settings not accessible by API
@ -69,7 +60,7 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po
RADIOLIB_ASSERT(state);
// configure default TX output power
state = setOutputPower(power);
state = setOutputPower(pwr);
RADIOLIB_ASSERT(state);
// set default packet length mode
@ -77,7 +68,7 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po
RADIOLIB_ASSERT(state);
// configure default preamble length
state = setPreambleLength(preambleLength);
state = setPreambleLength(preambleLength, preambleLength - 4);
RADIOLIB_ASSERT(state);
// set default data shaping
@ -94,37 +85,48 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po
RADIOLIB_ASSERT(state);
// flush FIFOs
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX);
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX | RADIOLIB_CC1101_CMD_READ);
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX);
return(state);
}
void CC1101::reset() {
// this is the manual power-on-reset sequence
this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow);
this->mod->hal->delayMicroseconds(5);
this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh);
this->mod->hal->delayMicroseconds(40);
this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow);
this->mod->hal->delay(10);
SPIsendCommand(RADIOLIB_CC1101_CMD_RESET);
}
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);
uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (this->bitRate * 1000.0)) * 5000000.0);
// start transmission
int16_t state = startTransmit(data, len, addr);
RADIOLIB_ASSERT(state);
// wait for transmission start or timeout
uint32_t start = _mod->micros();
while(!_mod->digitalRead(_mod->getGpio())) {
_mod->yield();
uint32_t start = this->mod->hal->micros();
while(!this->mod->hal->digitalRead(this->mod->getGpio())) {
this->mod->hal->yield();
if(_mod->micros() - start > timeout) {
if(this->mod->hal->micros() - start > timeout) {
finishTransmit();
return(RADIOLIB_ERR_TX_TIMEOUT);
}
}
// wait for transmission end or timeout
start = _mod->micros();
while(_mod->digitalRead(_mod->getGpio())) {
_mod->yield();
start = this->mod->hal->micros();
while(this->mod->hal->digitalRead(this->mod->getGpio())) {
this->mod->hal->yield();
if(_mod->micros() - start > timeout) {
if(this->mod->hal->micros() - start > timeout) {
finishTransmit();
return(RADIOLIB_ERR_TX_TIMEOUT);
}
@ -135,18 +137,18 @@ 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))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0);
uint32_t timeout = 500000 + (1.0/(this->bitRate*1000.0))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0);
// start reception
int16_t state = startReceive();
RADIOLIB_ASSERT(state);
// wait for packet or timeout
uint32_t start = _mod->micros();
while(!_mod->digitalRead(_mod->getIrq())) {
_mod->yield();
uint32_t start = this->mod->hal->micros();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
if(_mod->micros() - start > timeout) {
if(this->mod->hal->micros() - start > timeout) {
standby();
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX);
return(RADIOLIB_ERR_RX_TIMEOUT);
@ -162,10 +164,15 @@ int16_t CC1101::standby() {
SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE);
// set RF switch (if present)
_mod->setRfSwitchState(LOW, LOW);
this->mod->setRfSwitchState(Module::MODE_IDLE);
return(RADIOLIB_ERR_NONE);
}
int16_t CC1101::standby(uint8_t mode) {
(void)mode;
return(standby());
}
int16_t CC1101::transmitDirect(uint32_t frf) {
return transmitDirect(true, frf);
}
@ -176,7 +183,7 @@ int16_t CC1101::transmitDirectAsync(uint32_t frf) {
int16_t CC1101::transmitDirect(bool sync, uint32_t frf) {
// set RF switch (if present)
_mod->setRfSwitchState(LOW, HIGH);
this->mod->setRfSwitchState(Module::MODE_TX);
// user requested to start transmitting immediately (required for RTTY)
if(frf != 0) {
@ -206,7 +213,7 @@ int16_t CC1101::receiveDirectAsync() {
int16_t CC1101::receiveDirect(bool sync) {
// set RF switch (if present)
_mod->setRfSwitchState(HIGH, LOW);
this->mod->setRfSwitchState(Module::MODE_RX);
// activate direct mode
int16_t state = directMode(sync);
@ -220,38 +227,38 @@ int16_t CC1101::receiveDirect(bool sync) {
int16_t CC1101::packetMode() {
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, RADIOLIB_CC1101_CRC_AUTOFLUSH_OFF | RADIOLIB_CC1101_APPEND_STATUS_ON | RADIOLIB_CC1101_ADR_CHK_NONE, 3, 0);
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_WHITE_DATA_OFF | RADIOLIB_CC1101_PKT_FORMAT_NORMAL, 6, 4);
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_ON | _packetLengthConfig, 2, 0);
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_ON | this->packetLengthConfig, 2, 0);
return(state);
}
void CC1101::setGdo0Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) {
_mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, dir);
void CC1101::setGdo0Action(void (*func)(void), uint32_t dir) {
this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, dir);
}
void CC1101::clearGdo0Action() {
_mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()));
this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
}
void CC1101::setGdo2Action(void (*func)(void), RADIOLIB_INTERRUPT_STATUS dir) {
if(_mod->getGpio() == RADIOLIB_NC) {
void CC1101::setGdo2Action(void (*func)(void), uint32_t dir) {
if(this->mod->getGpio() == RADIOLIB_NC) {
return;
}
_mod->pinMode(_mod->getGpio(), INPUT);
_mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), func, dir);
this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()), func, dir);
}
void CC1101::clearGdo2Action() {
if(_mod->getGpio() == RADIOLIB_NC) {
if(this->mod->getGpio() == RADIOLIB_NC) {
return;
}
_mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()));
this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()));
}
int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// check packet length
if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) {
/*if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
}*/
// set mode to standby
standby();
@ -260,16 +267,22 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX);
// set GDO0 mapping
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_RECEIVED, 5, 0);
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED, 5, 0);
RADIOLIB_ASSERT(state);
/*int16_t state = RADIOLIB_ERR_NONE;
if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) {
state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_TX_FIFO_ABOVE_THR);
} else {
state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED);
}*/
// data put on FIFO.
// data put on FIFO
uint8_t dataSent = 0;
// optionally write packet length
if (_packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) {
if (this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) {
// enforce variable len limit.
// enforce variable len limit
if (len > RADIOLIB_CC1101_MAX_PACKET_LENGTH - 1) {
return (RADIOLIB_ERR_PACKET_TOO_LONG);
}
@ -285,36 +298,47 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
dataSent += 1;
}
// fill the FIFO.
// fill the FIFO
/*if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) {
SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, RADIOLIB_CC1101_FIFO_THRESH_TX);
} else {
uint8_t initialWrite = min((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent));
SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, initialWrite);
dataSent += initialWrite;
}*/
uint8_t initialWrite = min((uint8_t)len, (uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - dataSent));
SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, data, initialWrite);
dataSent += initialWrite;
// set RF switch (if present)
_mod->setRfSwitchState(LOW, HIGH);
this->mod->setRfSwitchState(Module::MODE_TX);
// set mode to transmit
SPIsendCommand(RADIOLIB_CC1101_CMD_TX);
// keep feeding the FIFO until the packet is over.
if(len > RADIOLIB_CC1101_MAX_PACKET_LENGTH) {
return(state);
}
// keep feeding the FIFO until the packet is over
while (dataSent < len) {
// get number of bytes in FIFO.
// get number of bytes in FIFO
uint8_t bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_TXBYTES, 6, 0);
// if there's room then put other data.
// if there's room then put other data
if (bytesInFIFO < RADIOLIB_CC1101_FIFO_SIZE) {
uint8_t bytesToWrite = min((uint8_t)(RADIOLIB_CC1101_FIFO_SIZE - bytesInFIFO), (uint8_t)(len - dataSent));
SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_FIFO, &data[dataSent], bytesToWrite);
dataSent += bytesToWrite;
} else {
// wait for radio to send some data.
// wait for radio to send some data
/*
* Does this work for all rates? If 1 ms is longer than the 1ms delay
* then the entire FIFO will be transmitted during that delay.
*
* TODO: test this on real hardware
*/
delayMicroseconds(250);
this->mod->hal->delayMicroseconds(250);
}
}
@ -324,6 +348,7 @@ int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
int16_t CC1101::finishTransmit() {
// set mode to standby to disable transmitter/RF switch
int16_t state = standby();
RADIOLIB_ASSERT(state);
// flush Tx FIFO
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_TX);
@ -333,18 +358,20 @@ int16_t CC1101::finishTransmit() {
int16_t CC1101::startReceive() {
// set mode to standby
standby();
int16_t state = standby();
RADIOLIB_ASSERT(state);
// flush Rx FIFO
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX);
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX | RADIOLIB_CC1101_CMD_READ);
// set GDO0 mapping: Asserted when RX FIFO > 4 bytes.
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END);
state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_RX_FIFO_FULL_OR_PKT_END);
//state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SYNC_WORD_SENT_OR_PKT_RECEIVED);
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FIFOTHR, RADIOLIB_CC1101_FIFO_THR_TX_61_RX_4, 3, 0);
RADIOLIB_ASSERT(state);
// set RF switch (if present)
_mod->setRfSwitchState(HIGH, LOW);
this->mod->setRfSwitchState(Module::MODE_RX);
// set mode to receive
SPIsendCommand(RADIOLIB_CC1101_CMD_RX);
@ -352,13 +379,30 @@ int16_t CC1101::startReceive() {
return(state);
}
int16_t CC1101::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) {
(void)timeout;
(void)irqFlags;
(void)irqMask;
(void)len;
return(startReceive());
}
int16_t CC1101::readData(uint8_t* data, size_t len) {
// get packet length
size_t length = getPacketLength();
/*RADIOLIB_DEBUG_PRINTLN("length = %d", length);
if(length == 0) {
this->packetLengthQueried = false;
standby();
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX);
return(RADIOLIB_ERR_RX_TIMEOUT);
}*/
if((len != 0) && (len < length)) {
// user requested less data than we got, only return what was requested
length = len;
}
//SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE | RADIOLIB_CC1101_CMD_READ);
SPIreadRegister(RADIOLIB_CC1101_REG_RXBYTES);
// check address filtering
uint8_t filter = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 1, 0);
@ -368,17 +412,17 @@ int16_t CC1101::readData(uint8_t* data, size_t len) {
uint8_t bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0);
size_t readBytes = 0;
uint32_t lastPop = millis();
uint32_t lastPop = this->mod->hal->millis();
// keep reading from FIFO until we get all the packet.
while (readBytes < length) {
if (bytesInFIFO == 0) {
if (millis() - lastPop > 5) {
if (this->mod->hal->millis() - lastPop > 5) {
// readData was required to read a packet longer than the one received.
RADIOLIB_DEBUG_PRINTLN(F("No data for more than 5mS. Stop here."));
RADIOLIB_DEBUG_PRINTLN("No data for more than 5mS. Stop here.");
break;
} else {
delay(1);
this->mod->hal->delay(1);
bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0);
continue;
}
@ -388,7 +432,7 @@ int16_t CC1101::readData(uint8_t* data, size_t len) {
uint8_t bytesToRead = min((uint8_t)(length - readBytes), bytesInFIFO);
SPIreadRegisterBurst(RADIOLIB_CC1101_REG_FIFO, bytesToRead, &(data[readBytes]));
readBytes += bytesToRead;
lastPop = millis();
lastPop = this->mod->hal->millis();
// Get how many bytes are left in FIFO.
bytesInFIFO = SPIgetRegValue(RADIOLIB_CC1101_REG_RXBYTES, 6, 0);
@ -398,35 +442,35 @@ int16_t CC1101::readData(uint8_t* data, size_t len) {
bool isAppendStatus = SPIgetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, 2, 2) == RADIOLIB_CC1101_APPEND_STATUS_ON;
// for some reason, we need this delay here to get the correct status bytes
delay(3);
this->mod->hal->delay(3);
// If status byte is enabled at least 2 bytes (2 status bytes + any following packet) will remain in FIFO.
if (isAppendStatus) {
// read RSSI byte
_rawRSSI = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO);
this->rawRSSI = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO);
// read LQI and CRC byte
uint8_t val = SPIgetRegValue(RADIOLIB_CC1101_REG_FIFO);
_rawLQI = val & 0x7F;
this->rawLQI = val & 0x7F;
// check CRC
if (_crcOn && (val & RADIOLIB_CC1101_CRC_OK) == RADIOLIB_CC1101_CRC_ERROR) {
_packetLengthQueried = false;
if (this->crcOn && (val & RADIOLIB_CC1101_CRC_OK) == RADIOLIB_CC1101_CRC_ERROR) {
this->packetLengthQueried = false;
return (RADIOLIB_ERR_CRC_MISMATCH);
}
}
// clear internal flag so getPacketLength can return the new packet length
_packetLengthQueried = false;
this->packetLengthQueried = false;
// Flush then standby according to RXOFF_MODE (default: RADIOLIB_CC1101_RXOFF_IDLE)
if (SPIgetRegValue(RADIOLIB_CC1101_REG_MCSM1, 3, 2) == RADIOLIB_CC1101_RXOFF_IDLE) {
// flush Rx FIFO
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX);
// set mode to standby
standby();
// flush Rx FIFO
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX | RADIOLIB_CC1101_CMD_READ);
}
return(RADIOLIB_ERR_NONE);
@ -451,11 +495,11 @@ int16_t CC1101::setFrequency(float freq) {
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_FREQ0, FRF & 0x0000FF, 7, 0);
if(state == RADIOLIB_ERR_NONE) {
_freq = freq;
this->frequency = freq;
}
// Update the TX power accordingly to new freq. (PA values depend on chosen freq)
return(setOutputPower(_power));
return(setOutputPower(this->power));
}
int16_t CC1101::setBitRate(float br) {
@ -473,7 +517,7 @@ int16_t CC1101::setBitRate(float br) {
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG4, e, 3, 0);
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG3, m);
if(state == RADIOLIB_ERR_NONE) {
_br = br;
this->bitRate = br;
}
return(state);
}
@ -532,7 +576,7 @@ int16_t CC1101::getFrequencyDeviation(float *freqDev) {
}
// if ASK/OOK, deviation makes no sense
if (_modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK) {
if (this->modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK) {
*freqDev = 0.0;
return(RADIOLIB_ERR_NONE);
@ -551,16 +595,16 @@ int16_t CC1101::getFrequencyDeviation(float *freqDev) {
return(RADIOLIB_ERR_NONE);
}
int16_t CC1101::setOutputPower(int8_t power) {
int16_t CC1101::setOutputPower(int8_t pwr) {
// round to the known frequency settings
uint8_t f;
if(_freq < 374.0) {
if(this->frequency < 374.0) {
// 315 MHz
f = 0;
} else if(_freq < 650.5) {
} else if(this->frequency < 650.5) {
// 434 MHz
f = 1;
} else if(_freq < 891.5) {
} else if(this->frequency < 891.5) {
// 868 MHz
f = 2;
} else {
@ -579,7 +623,7 @@ int16_t CC1101::setOutputPower(int8_t power) {
{0xC2, 0xC0, 0xC2, 0xC0}};
uint8_t powerRaw;
switch(power) {
switch(pwr) {
case -30:
powerRaw = paTable[0][f];
break;
@ -609,9 +653,9 @@ int16_t CC1101::setOutputPower(int8_t power) {
}
// store the value
_power = power;
this->power = pwr;
if(_modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK){
if(this->modulation == RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK){
// Amplitude modulation:
// PA_TABLE[0] is the power to be used when transmitting a 0 (no power)
// PA_TABLE[1] is the power to be used when transmitting a 1 (full power)
@ -655,10 +699,10 @@ int16_t CC1101::setSyncWord(uint8_t syncH, uint8_t syncL, uint8_t maxErrBits, bo
return(setSyncWord(syncWord, sizeof(syncWord), maxErrBits, requireCarrierSense));
}
int16_t CC1101::setPreambleLength(uint8_t preambleLength) {
int16_t CC1101::setPreambleLength(uint8_t preambleLength, uint8_t qualityThreshold) {
// check allowed values
uint8_t value;
switch(preambleLength){
switch(preambleLength) {
case 16:
value = RADIOLIB_CC1101_NUM_PREAMBLE_2;
break;
@ -687,7 +731,14 @@ int16_t CC1101::setPreambleLength(uint8_t preambleLength) {
return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
}
return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG1, value, 6, 4));
// set preabmble quality threshold and the actual length
uint8_t pqt = qualityThreshold/4;
if(pqt > 7) {
pqt = 7;
}
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL1, pqt << 5, 7, 5);
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG1, value, 6, 4);
return(state);
}
int16_t CC1101::setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs) {
@ -723,7 +774,7 @@ int16_t CC1101::setOOK(bool enableOOK) {
RADIOLIB_ASSERT(state);
// update current modulation
_modulation = RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK;
this->modulation = RADIOLIB_CC1101_MOD_FORMAT_ASK_OOK;
} else {
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, RADIOLIB_CC1101_MOD_FORMAT_2_FSK, 6, 4);
RADIOLIB_ASSERT(state);
@ -733,21 +784,21 @@ int16_t CC1101::setOOK(bool enableOOK) {
RADIOLIB_ASSERT(state);
// update current modulation
_modulation = RADIOLIB_CC1101_MOD_FORMAT_2_FSK;
this->modulation = RADIOLIB_CC1101_MOD_FORMAT_2_FSK;
}
// Update PA_TABLE values according to the new _modulation.
return(setOutputPower(_power));
// Update PA_TABLE values according to the new this->modulation.
return(setOutputPower(this->power));
}
float CC1101::getRSSI() {
float rssi;
if (_directMode) {
if(_rawRSSI >= 128) {
rssi = (((float)_rawRSSI - 256.0)/2.0) - 74.0;
if (this->directModeEnabled) {
if(this->rawRSSI >= 128) {
rssi = (((float)this->rawRSSI - 256.0)/2.0) - 74.0;
} else {
rssi = (((float)_rawRSSI)/2.0) - 74.0;
rssi = (((float)this->rawRSSI)/2.0) - 74.0;
}
} else {
uint8_t rawRssi = SPIreadRegister(RADIOLIB_CC1101_REG_RSSI);
@ -764,24 +815,38 @@ float CC1101::getRSSI() {
}
uint8_t CC1101::getLQI() const {
return(_rawLQI);
return(this->rawLQI);
}
size_t CC1101::getPacketLength(bool update) {
if(!_packetLengthQueried && update) {
if (_packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) {
_packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_FIFO);
RADIOLIB_DEBUG_PRINTLN("this->packetLengthQueried=%d", this->packetLengthQueried);
RADIOLIB_DEBUG_PRINTLN("update=%d", update);
RADIOLIB_DEBUG_PRINTLN("this->packetLengthConfig=%d", this->packetLengthConfig);
if(!this->packetLengthQueried && update) {
if (this->packetLengthConfig == RADIOLIB_CC1101_LENGTH_CONFIG_VARIABLE) {
this->packetLength = 0;
while(this->packetLength == 0) {
this->packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_FIFO);
}
} else {
_packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_PKTLEN);
this->packetLength = SPIreadRegister(RADIOLIB_CC1101_REG_PKTLEN);
}
_packetLengthQueried = true;
this->packetLengthQueried = true;
}
RADIOLIB_DEBUG_PRINTLN("this->packetLength=%d", this->packetLength);
return(_packetLength);
return(this->packetLength);
}
int16_t CC1101::fixedPacketLengthMode(uint8_t len) {
if(len == 0) {
// infinite packet mode
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_LENGTH_CONFIG_INFINITE, 1, 0);
RADIOLIB_ASSERT(state);
}
return(setPacketMode(RADIOLIB_CC1101_LENGTH_CONFIG_FIXED, len));
}
@ -790,52 +855,56 @@ int16_t CC1101::variablePacketLengthMode(uint8_t maxLen) {
}
int16_t CC1101::enableSyncWordFiltering(uint8_t maxErrBits, bool requireCarrierSense) {
switch(maxErrBits){
int16_t state = RADIOLIB_ERR_NONE;
switch(maxErrBits) {
case 0:
// in 16 bit sync word, expect all 16 bits
return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_16_16_THR : RADIOLIB_CC1101_SYNC_MODE_16_16), 2, 0));
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_16_16_THR : RADIOLIB_CC1101_SYNC_MODE_16_16), 2, 0);
break;
case 1:
// in 16 bit sync word, expect at least 15 bits
return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_15_16_THR : RADIOLIB_CC1101_SYNC_MODE_15_16), 2, 0));
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_15_16_THR : RADIOLIB_CC1101_SYNC_MODE_15_16), 2, 0);
break;
default:
return(RADIOLIB_ERR_INVALID_SYNC_WORD);
state = RADIOLIB_ERR_INVALID_SYNC_WORD;
break;
}
return(state);
}
int16_t CC1101::disableSyncWordFiltering(bool requireCarrierSense) {
return(SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_NONE_THR : RADIOLIB_CC1101_SYNC_MODE_NONE), 2, 0));
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MDMCFG2, (requireCarrierSense ? RADIOLIB_CC1101_SYNC_MODE_NONE_THR : RADIOLIB_CC1101_SYNC_MODE_NONE), 2, 0);
return(state);
}
int16_t CC1101::setCrcFiltering(bool crcOn) {
_crcOn = crcOn;
int16_t CC1101::setCrcFiltering(bool enable) {
this->crcOn = enable;
if (crcOn == true) {
if (this->crcOn == true) {
return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_ON, 2, 2));
} else {
return(SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_CRC_OFF, 2, 2));
}
}
int16_t CC1101::setPromiscuousMode(bool promiscuous) {
int16_t CC1101::setPromiscuousMode(bool enable) {
int16_t state = RADIOLIB_ERR_NONE;
if (_promiscuous == promiscuous) {
if(this->promiscuous == enable) {
return(state);
}
if (promiscuous == true) {
// disable preamble detection and generation
state = setPreambleLength(0);
RADIOLIB_ASSERT(state);
if(enable) {
// disable sync word filtering and insertion
// this also disables preamble
state = disableSyncWordFiltering();
RADIOLIB_ASSERT(state);
// disable CRC filtering
state = setCrcFiltering(false);
} else {
state = setPreambleLength(RADIOLIB_CC1101_DEFAULT_PREAMBLELEN);
state = setPreambleLength(RADIOLIB_CC1101_DEFAULT_PREAMBLELEN, RADIOLIB_CC1101_DEFAULT_PREAMBLELEN/4);
RADIOLIB_ASSERT(state);
// enable sync word filtering and insertion
@ -846,13 +915,13 @@ int16_t CC1101::setPromiscuousMode(bool promiscuous) {
state = setCrcFiltering(true);
}
_promiscuous = promiscuous;
this->promiscuous = enable;
return(state);
}
bool CC1101::getPromiscuousMode() {
return (_promiscuous);
return (this->promiscuous);
}
int16_t CC1101::setDataShaping(uint8_t sh) {
@ -898,17 +967,21 @@ int16_t CC1101::setEncoding(uint8_t encoding) {
}
}
void CC1101::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) {
_mod->setRfSwitchPins(rxEn, txEn);
void CC1101::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
this->mod->setRfSwitchPins(rxEn, txEn);
}
void CC1101::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
this->mod->setRfSwitchTable(pins, table);
}
uint8_t CC1101::randomByte() {
// set mode to Rx
SPIsendCommand(RADIOLIB_CC1101_CMD_RX);
RADIOLIB_DEBUG_PRINTLN("random");
RADIOLIB_DEBUG_PRINTLN("CC1101::randomByte");
// wait a bit for the RSSI reading to stabilise
_mod->delay(10);
this->mod->hal->delay(10);
// read RSSI value 8 times, always keep just the least significant bit
uint8_t randByte = 0x00;
@ -928,30 +1001,39 @@ int16_t CC1101::getChipVersion() {
#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE)
void CC1101::setDirectAction(void (*func)(void)) {
setGdo0Action(func);
setGdo0Action(func, this->mod->hal->GpioInterruptRising);
}
void CC1101::readBit(RADIOLIB_PIN_TYPE pin) {
updateDirectBuffer((uint8_t)digitalRead(pin));
void CC1101::readBit(uint32_t pin) {
updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin));
}
#endif
int16_t CC1101::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) {
if (pin > 2)
return RADIOLIB_ERR_INVALID_DIO_PIN;
int16_t CC1101::setDIOMapping(uint32_t pin, uint32_t value) {
if(pin > 2) {
return(RADIOLIB_ERR_INVALID_DIO_PIN);
}
return(SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0 - pin, value));
}
int16_t CC1101::config() {
// Reset the radio. Registers may be dirty from previous usage.
SPIsendCommand(RADIOLIB_CC1101_CMD_RESET);
reset();
// Wait a ridiculous amount of time to be sure radio is ready.
_mod->delay(150);
this->mod->hal->delay(150);
// enable automatic frequency synthesizer calibration
standby();
// enable automatic frequency synthesizer calibration and disable pin control
int16_t state = SPIsetRegValue(RADIOLIB_CC1101_REG_MCSM0, RADIOLIB_CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4);
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_MCSM0, RADIOLIB_CC1101_PIN_CTRL_OFF, 1, 1);
RADIOLIB_ASSERT(state);
// set GDOs to Hi-Z so that it doesn't output clock on startup (might confuse GDO0 action)
state = SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_HIGH_Z, 5, 0);
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_HIGH_Z, 5, 0);
RADIOLIB_ASSERT(state);
// set packet mode
@ -965,16 +1047,15 @@ int16_t CC1101::directMode(bool sync) {
SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE);
int16_t state = 0;
_directMode = sync;
if (sync) {
this->directModeEnabled = sync;
if(sync) {
// set GDO0 and GDO2 mapping
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_CLOCK , 5, 0);
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG2, RADIOLIB_CC1101_GDOX_SERIAL_DATA_SYNC , 5, 0);
// set continuous mode
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_PKTCTRL0, RADIOLIB_CC1101_PKT_FORMAT_SYNCHRONOUS, 5, 4);
}
else {
} else {
// set GDO0 mapping
state |= SPIsetRegValue(RADIOLIB_CC1101_REG_IOCFG0, RADIOLIB_CC1101_GDOX_SERIAL_DATA_ASYNC , 5, 0);
@ -1027,8 +1108,8 @@ int16_t CC1101::setPacketMode(uint8_t mode, uint16_t len) {
RADIOLIB_ASSERT(state);
// update the cached value
_packetLength = len;
_packetLengthConfig = mode;
this->packetLength = len;
this->packetLengthConfig = mode;
return(state);
}
@ -1038,7 +1119,7 @@ int16_t CC1101::SPIgetRegValue(uint8_t reg, uint8_t msb, uint8_t lsb) {
reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG;
}
return(_mod->SPIgetRegValue(reg, msb, lsb));
return(this->mod->SPIgetRegValue(reg, msb, lsb));
}
int16_t CC1101::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval) {
@ -1047,11 +1128,11 @@ int16_t CC1101::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t
reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG;
}
return(_mod->SPIsetRegValue(reg, value, msb, lsb, checkInterval));
return(this->mod->SPIsetRegValue(reg, value, msb, lsb, checkInterval));
}
void CC1101::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes) {
_mod->SPIreadRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, numBytes, inBytes);
this->mod->SPIreadRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, numBytes, inBytes);
}
uint8_t CC1101::SPIreadRegister(uint8_t reg) {
@ -1060,7 +1141,7 @@ uint8_t CC1101::SPIreadRegister(uint8_t reg) {
reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG;
}
return(_mod->SPIreadRegister(reg));
return(this->mod->SPIreadRegister(reg));
}
void CC1101::SPIwriteRegister(uint8_t reg, uint8_t data) {
@ -1069,26 +1150,28 @@ void CC1101::SPIwriteRegister(uint8_t reg, uint8_t data) {
reg |= RADIOLIB_CC1101_CMD_ACCESS_STATUS_REG;
}
return(_mod->SPIwriteRegister(reg, data));
return(this->mod->SPIwriteRegister(reg, data));
}
void CC1101::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, size_t len) {
_mod->SPIwriteRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, data, len);
this->mod->SPIwriteRegisterBurst(reg | RADIOLIB_CC1101_CMD_BURST, data, len);
}
void CC1101::SPIsendCommand(uint8_t cmd) {
// pull NSS low
_mod->digitalWrite(_mod->getCs(), LOW);
this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow);
// start transfer
_mod->SPIbeginTransaction();
this->mod->hal->spiBeginTransaction();
// send the command byte
_mod->SPItransfer(cmd);
uint8_t status = this->mod->hal->spiTransfer(cmd);
// stop transfer
_mod->SPIendTransaction();
_mod->digitalWrite(_mod->getCs(), HIGH);
this->mod->hal->spiEndTransaction();
this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh);
RADIOLIB_VERBOSE_PRINTLN("CMD\tW\t%02X\t%02X", cmd, status);
(void)status;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -2,10 +2,10 @@
#if !defined(RADIOLIB_EXCLUDE_SX126X)
LLCC68::LLCC68(Module* mod) : SX1262(mod) {
chipType = RADIOLIB_LLCC68_CHIP_TYPE;
}
int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
// execute common part
int16_t state = SX126x::begin(cr, syncWord, preambleLength, tcxoVoltage, useRegulatorLDO);
RADIOLIB_ASSERT(state);
@ -20,7 +20,7 @@ int16_t LLCC68::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
state = setSpreadingFactor(sf);
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
state = setOutputPower(pwr);
RADIOLIB_ASSERT(state);
state = SX126x::fixPaClamping();
@ -35,7 +35,7 @@ int16_t LLCC68::setBandwidth(float bw) {
}
int16_t LLCC68::setSpreadingFactor(uint8_t sf) {
switch(SX126x::_bw) {
switch(SX126x::bandwidth) {
case RADIOLIB_SX126X_LORA_BW_125_0:
RADIOLIB_CHECK_RANGE(sf, 5, 9, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
break;

View file

@ -8,59 +8,48 @@
#include "../../Module.h"
#include "../SX126x/SX1262.h"
//RADIOLIB_SX126X_REG_VERSION_STRING
#define RADIOLIB_LLCC68_CHIP_TYPE "LLCC68"
/*!
\class LLCC68
\brief Derived class for %LLCC68 modules.
*/
class LLCC68: public SX1262 {
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
LLCC68(Module* mod);
/*!
\brief Initialization method for LoRa modem.
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz.
\param sf LoRa spreading factor. Defaults to 9.
\param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7).
\param syncWord 2-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12).
\param power Output power in dBm. Defaults to 10 dBm.
\param syncWord 1-byte LoRa sync word. Defaults to RADIOLIB_SX126X_SYNC_WORD_PRIVATE (0x12).
\param pwr Output power in dBm. Defaults to 10 dBm.
\param preambleLength LoRa preamble length in symbols. Defaults to 8 symbols.
\param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip.
\param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
\returns \ref status_codes
*/
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t pwr = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
// configuration methods
/*!
\brief Sets LoRa bandwidth. Allowed values are 125.0, 250.0 and 500.0 kHz.
\param bw LoRa bandwidth to be set in kHz.
\returns \ref status_codes
*/
int16_t setBandwidth(float bw);
/*!
\brief Sets LoRa spreading factor. Allowed values range from 5 to 11, depending on currently set spreading factor.
\param sf LoRa spreading factor to be set.
\returns \ref status_codes
*/
int16_t setSpreadingFactor(uint8_t sf);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,6 @@
/*!
\class RFM22
\brief Only exists as alias for Si4432, since there seems to be no difference between %RFM22 and %Si4432 modules.
*/
RADIOLIB_TYPE_ALIAS(Si4432, RFM22);

View file

@ -11,7 +11,6 @@
/*!
\class RFM23
\brief Only exists as alias for Si4431, since there seems to be no difference between %RFM23 and %Si4431 modules.
*/
RADIOLIB_TYPE_ALIAS(Si4431, RFM23);

View file

@ -16,8 +16,8 @@ int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW
// some other error
return(state);
}
RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278"));
RADIOLIB_DEBUG_PRINTLN(F("M\tRFM95"));
RADIOLIB_DEBUG_PRINTLN("M\tSX1278");
RADIOLIB_DEBUG_PRINTLN("M\tRFM95");
// configure publicly accessible settings
state = setBandwidth(bw);
@ -42,17 +42,17 @@ int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW
int16_t RFM95::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(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, br, freqDev, rxBw, preambleLength, enableOOK);
int16_t state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, freqDev, rxBw, preambleLength, enableOOK);
if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) {
// SX127X_REG_VERSION might be set 0x12
state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, br, freqDev, rxBw, preambleLength, enableOOK);
state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, freqDev, rxBw, preambleLength, enableOOK);
RADIOLIB_ASSERT(state);
} else if(state != RADIOLIB_ERR_NONE) {
// some other error
return(state);
}
RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278"));
RADIOLIB_DEBUG_PRINTLN(F("M\tRFM95"));
RADIOLIB_DEBUG_PRINTLN("M\tSX1278");
RADIOLIB_DEBUG_PRINTLN("M\tRFM95");
// configure settings not accessible by API
state = configFSK();
@ -62,6 +62,9 @@ int16_t RFM95::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setBitRate(br);
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
RADIOLIB_ASSERT(state);
@ -82,7 +85,7 @@ int16_t RFM95::setFrequency(float freq) {
// set frequency and if successful, save the new setting
int16_t state = SX127x::setFrequencyRaw(freq);
if(state == RADIOLIB_ERR_NONE) {
SX127x::_freq = freq;
SX127x::frequency = freq;
}
return(state);
}

View file

@ -10,12 +10,11 @@
#include "../SX127x/SX1278.h"
// SX127X_REG_VERSION
#define RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL 0x11
#define RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12
#define RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL 0x11
#define RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12
/*!
\class RFM95
\brief Derived class for %RFM95 modules. Overrides some methods from SX1278 due to different parameter ranges.
*/
class RFM95: public SX1278 {
@ -25,7 +24,6 @@ class RFM95: public SX1278 {
/*!
\brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
*/
RFM95(Module* mod);
@ -34,47 +32,30 @@ class RFM95: public SX1278 {
/*!
\brief %LoRa 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 868.0 MHz to 915.0 MHz.
\param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
\param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
Allowed values range from 6 to 65535.
\param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_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 = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false);
@ -83,9 +64,7 @@ class RFM95: public SX1278 {
/*!
\brief Sets carrier frequency. Allowed values range from 868.0 MHz to 915.0 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);

View file

@ -16,8 +16,8 @@ int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW
// some other error
return(state);
}
RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278"));
RADIOLIB_DEBUG_PRINTLN(F("M\tRFM96"));
RADIOLIB_DEBUG_PRINTLN("M\tSX1278");
RADIOLIB_DEBUG_PRINTLN("M\tRFM96");
// configure publicly accessible settings
state = setBandwidth(bw);
@ -43,17 +43,17 @@ int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW
int16_t RFM96::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(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, br, freqDev, rxBw, preambleLength, enableOOK);
int16_t state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL, freqDev, rxBw, preambleLength, enableOOK);
if(state == RADIOLIB_ERR_CHIP_NOT_FOUND) {
// SX127X_REG_VERSION might be set 0x12
state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, br, freqDev, rxBw, preambleLength, enableOOK);
state = SX127x::beginFSK(RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL, freqDev, rxBw, preambleLength, enableOOK);
RADIOLIB_ASSERT(state);
} else if(state != RADIOLIB_ERR_NONE) {
// some other error
return(state);
}
RADIOLIB_DEBUG_PRINTLN(F("M\tSX1278"));
RADIOLIB_DEBUG_PRINTLN(F("M\tRFM96"));
RADIOLIB_DEBUG_PRINTLN("M\tSX1278");
RADIOLIB_DEBUG_PRINTLN("M\tRFM96");
// configure settings not accessible by API
state = configFSK();
@ -63,6 +63,9 @@ int16_t RFM96::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setBitRate(br);
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
RADIOLIB_ASSERT(state);
@ -83,7 +86,7 @@ int16_t RFM96::setFrequency(float freq) {
// set frequency and if successful, save the new setting
int16_t state = SX127x::setFrequencyRaw(freq);
if(state == RADIOLIB_ERR_NONE) {
SX127x::_freq = freq;
SX127x::frequency = freq;
}
return(state);
}

View file

@ -10,12 +10,11 @@
#include "../SX127x/SX1278.h"
// SX127X_REG_VERSION
#define RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL 0x11
#define RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12
#define RADIOLIB_RFM9X_CHIP_VERSION_OFFICIAL 0x11
#define RADIOLIB_RFM9X_CHIP_VERSION_UNOFFICIAL 0x12 // according to datasheet, only 0x11 should be possible, but some modules seem to have 0x12
/*!
\class RFM96
\brief Derived class for %RFM96 modules. Overrides some methods from SX1278 due to different parameter ranges.
*/
class RFM96: public SX1278 {
@ -25,7 +24,6 @@ class RFM96: public SX1278 {
/*!
\brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
*/
RFM96(Module* mod);
@ -34,47 +32,32 @@ class RFM96: public SX1278 {
/*!
\brief %LoRa 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 433.0 MHz to 470.0 MHz.
\param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
\param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
\param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
\param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
\param syncWord %LoRa sync word. Can be used to distinguish different networks.
Note that value 0x34 is reserved for LoRaWAN networks.
\param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
Allowed values range from 6 to 65535.
\param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
Set to 0 to enable automatic gain control (recommended).
\param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols
longer than the set number. Allowed values range from 6 to 65535.
\param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6
where 1 is the highest gain. Set to 0 to enable automatic gain control (recommended).
\returns \ref status_codes
*/
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_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 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 = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint16_t preambleLength = 16, bool enableOOK = false);
@ -83,9 +66,7 @@ class RFM96: public SX1278 {
/*!
\brief Sets carrier frequency. Allowed values range from 433.0 MHz to 470.0 MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
@ -98,7 +79,6 @@ class RFM96: public SX1278 {
/*!
\class RFM98
\brief Only exists as alias for RFM96, since there seems to be no difference between %RFM96 and %RFM98 modules.
*/
RADIOLIB_TYPE_ALIAS(RFM96, RFM98);

View file

@ -34,7 +34,7 @@ int16_t RFM97::setSpreadingFactor(uint8_t sf) {
// set spreading factor and if successful, save the new setting
int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor);
if(state == RADIOLIB_ERR_NONE) {
SX127x::_sf = sf;
SX127x::spreadingFactor = sf;
}
return(state);
}

View file

@ -12,7 +12,6 @@
/*!
\class RFM97
\brief Derived class for %RFM97 modules. Overrides some methods from RFM95 due to different parameter ranges.
*/
class RFM97: public RFM95 {
@ -22,7 +21,6 @@ class RFM97: public RFM95 {
/*!
\brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
*/
RFM97(Module* mod);
@ -31,9 +29,7 @@ class RFM97: public RFM95 {
/*!
\brief Sets %LoRa link spreading factor. Allowed values range from 6 to 9. Only available in %LoRa mode.
\param sf %LoRa link spreading factor to be set.
\returns \ref status_codes
*/
int16_t setSpreadingFactor(uint8_t sf);

View file

@ -7,9 +7,9 @@ SX1231::SX1231(Module* mod) : RF69(mod) {
int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t preambleLen) {
// set module properties
_mod->init();
_mod->pinMode(_mod->getIrq(), INPUT);
_mod->pinMode(_mod->getRst(), OUTPUT);
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput);
// try to find the SX1231 chip
uint8_t i = 0;
@ -18,42 +18,32 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po
int16_t version = getChipVersion();
if((version == 0x21) || (version == 0x22) || (version == 0x23)) {
flagFound = true;
_chipRevision = version;
this->chipRevision = version;
} else {
#if defined(RADIOLIB_DEBUG)
RADIOLIB_DEBUG_PRINT(F("SX1231 not found! ("));
RADIOLIB_DEBUG_PRINT(i + 1);
RADIOLIB_DEBUG_PRINT(F(" of 10 tries) RF69_REG_VERSION == "));
char buffHex[12];
sprintf(buffHex, "0x%04X", version);
RADIOLIB_DEBUG_PRINT(buffHex);
RADIOLIB_DEBUG_PRINT(F(", expected 0x0021 / 0x0022 / 0x0023"));
RADIOLIB_DEBUG_PRINTLN();
#endif
_mod->delay(10);
RADIOLIB_DEBUG_PRINTLN("SX1231 not found! (%d of 10 tries) RF69_REG_VERSION == 0x%04X, expected 0x0021 / 0x0022 / 0x0023", i + 1, version);
this->mod->hal->delay(10);
i++;
}
}
if(!flagFound) {
RADIOLIB_DEBUG_PRINTLN(F("No SX1231 found!"));
_mod->term();
RADIOLIB_DEBUG_PRINTLN("No SX1231 found!");
this->mod->term();
return(RADIOLIB_ERR_CHIP_NOT_FOUND);
}
RADIOLIB_DEBUG_PRINTLN(F("M\tSX1231"));
RADIOLIB_DEBUG_PRINTLN("M\tSX1231");
// configure settings not accessible by API
int16_t state = config();
RADIOLIB_ASSERT(state);
RADIOLIB_DEBUG_PRINTLN(F("M\tRF69"));
RADIOLIB_DEBUG_PRINTLN("M\tRF69");
// configure publicly accessible settings
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
// configure bitrate
_rxBw = 125.0;
this->rxBandwidth = 125.0;
state = setBitRate(br);
RADIOLIB_ASSERT(state);
@ -85,13 +75,13 @@ int16_t SX1231::begin(float freq, float br, float freqDev, float rxBw, int8_t po
}
// SX1231 V2a only
if(_chipRevision == RADIOLIB_SX1231_CHIP_REVISION_2_A) {
if(this->chipRevision == RADIOLIB_SX1231_CHIP_REVISION_2_A) {
// modify default OOK threshold value
state = _mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD);
state = this->mod->SPIsetRegValue(RADIOLIB_SX1231_REG_TEST_OOK, RADIOLIB_SX1231_OOK_DELTA_THRESHOLD);
RADIOLIB_ASSERT(state);
// enable OCP with 95 mA limit
state = _mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM, 4, 0);
state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_OCP, RADIOLIB_RF69_OCP_ON | RADIOLIB_RF69_OCP_TRIM, 4, 0);
RADIOLIB_ASSERT(state);
}

View file

@ -8,113 +8,104 @@
#include "../../Module.h"
#include "../RF69/RF69.h"
#define RADIOLIB_SX1231_CHIP_REVISION_2_A 0x21
#define RADIOLIB_SX1231_CHIP_REVISION_2_B 0x22
#define RADIOLIB_SX1231_CHIP_REVISION_2_C 0x23
#define RADIOLIB_SX1231_CHIP_REVISION_2_A 0x21
#define RADIOLIB_SX1231_CHIP_REVISION_2_B 0x22
#define RADIOLIB_SX1231_CHIP_REVISION_2_C 0x23
//SX1231 specific register map
#define RADIOLIB_SX1231_REG_TEST_OOK 0x6E
// RADIOLIB_SX1231 specific register map
#define RADIOLIB_SX1231_REG_TEST_OOK 0x6E
//SX1231_REG_TEST_OOK
#define RADIOLIB_SX1231_OOK_DELTA_THRESHOLD 0x0C
// RADIOLIB_SX1231_REG_TEST_OOK
#define RADIOLIB_SX1231_OOK_DELTA_THRESHOLD 0x0C
// SX1231_REG_DIO_MAPPING_1
#define RADIOLIB_SX1231_DIO0_CONT_LOW_BAT 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_MODE_READY 0b11000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_PLL_LOCK 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_TIMEOUT 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_RSSI 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_MODE_READY 0b11000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_TX_READY 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_LOW_BAT 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_PLL_LOCK 0b11000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_CRC_OK 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_PAYLOAD_READY 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_SYNC_ADDRESS 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_RSSI 0b11000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_TX_READY 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO1_CONT_LOW_BAT 0b00100000 // 5 4
#define RADIOLIB_SX1231_DIO1_CONT_PLL_LOCK 0b00110000 // 5 4
#define RADIOLIB_SX1231_DIO1_CONT_DCLK 0b00000000 // 5 4
#define RADIOLIB_SX1231_DIO1_CONT_RX_READY 0b00010000 // 5 4
#define RADIOLIB_SX1231_DIO1_CONT_SYNC_ADDRESS 0b00110000 // 5 4
#define RADIOLIB_SX1231_DIO1_CONT_TX_READY 0b00010000 // 5 4
#define RADIOLIB_SX1231_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4
#define RADIOLIB_SX1231_DIO1_PACK_FIFO_FULL 0b00010000 // 5 4
#define RADIOLIB_SX1231_DIO1_PACK_FIFO_NOT_EMPTY 0b00100000 // 5 4
#define RADIOLIB_SX1231_DIO1_PACK_PLL_LOCK 0b00110000 // 5 4
#define RADIOLIB_SX1231_DIO1_PACK_TIMEOUT 0b00110000 // 5 4
#define RADIOLIB_SX1231_DIO2_CONT_DATA 0b00000000 // 3 2
#define RADIOLIB_SX1231_DIO2_PACK_FIFO_NOT_EMPTY 0b00000000 // 3 2
#define RADIOLIB_SX1231_DIO2_PACK_LOW_BAT 0b00001000 // 3 2
#define RADIOLIB_SX1231_DIO2_PACK_AUTO_MODE 0b00001100 // 3 2
#define RADIOLIB_SX1231_DIO2_PACK_DATA 0b00000100 // 3 2
#define RADIOLIB_SX1231_DIO3_CONT_AUTO_MODE 0b00000010 // 0 1
#define RADIOLIB_SX1231_DIO3_CONT_RSSI 0b00000000 // 0 1
#define RADIOLIB_SX1231_DIO3_CONT_RX_READY 0b00000001 // 0 1
#define RADIOLIB_SX1231_DIO3_CONT_TIMEOUT 0b00000011 // 0 1
#define RADIOLIB_SX1231_DIO3_CONT_TX_READY 0b00000001 // 0 1
#define RADIOLIB_SX1231_DIO3_PACK_FIFO_FULL 0b00000000 // 0 1
#define RADIOLIB_SX1231_DIO3_PACK_LOW_BAT 0b00000010 // 0 1
#define RADIOLIB_SX1231_DIO3_PACK_PLL_LOCK 0b00000011 // 0 1
#define RADIOLIB_SX1231_DIO3_PACK_RSSI 0b00000001 // 0 1
#define RADIOLIB_SX1231_DIO3_PACK_SYNC_ADDRESSS 0b00000010 // 0 1
#define RADIOLIB_SX1231_DIO3_PACK_TX_READY 0b00000001 // 0 1
// RADIOLIB_SX1231_REG_DIO_MAPPING_1
#define RADIOLIB_SX1231_DIO0_CONT_LOW_BAT 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_MODE_READY 0b11000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_PLL_LOCK 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_TIMEOUT 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_RSSI 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_MODE_READY 0b11000000 // 7 6
#define RADIOLIB_SX1231_DIO0_CONT_TX_READY 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_LOW_BAT 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_PLL_LOCK 0b11000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_CRC_OK 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_PAYLOAD_READY 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_SYNC_ADDRESS 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_RSSI 0b11000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO0_PACK_TX_READY 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO1_CONT_LOW_BAT 0b00100000 // 5 4
#define RADIOLIB_SX1231_DIO1_CONT_PLL_LOCK 0b00110000 // 5 4
#define RADIOLIB_SX1231_DIO1_CONT_DCLK 0b00000000 // 5 4
#define RADIOLIB_SX1231_DIO1_CONT_RX_READY 0b00010000 // 5 4
#define RADIOLIB_SX1231_DIO1_CONT_SYNC_ADDRESS 0b00110000 // 5 4
#define RADIOLIB_SX1231_DIO1_CONT_TX_READY 0b00010000 // 5 4
#define RADIOLIB_SX1231_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4
#define RADIOLIB_SX1231_DIO1_PACK_FIFO_FULL 0b00010000 // 5 4
#define RADIOLIB_SX1231_DIO1_PACK_FIFO_NOT_EMPTY 0b00100000 // 5 4
#define RADIOLIB_SX1231_DIO1_PACK_PLL_LOCK 0b00110000 // 5 4
#define RADIOLIB_SX1231_DIO1_PACK_TIMEOUT 0b00110000 // 5 4
#define RADIOLIB_SX1231_DIO2_CONT_DATA 0b00000000 // 3 2
#define RADIOLIB_SX1231_DIO2_PACK_FIFO_NOT_EMPTY 0b00000000 // 3 2
#define RADIOLIB_SX1231_DIO2_PACK_LOW_BAT 0b00001000 // 3 2
#define RADIOLIB_SX1231_DIO2_PACK_AUTO_MODE 0b00001100 // 3 2
#define RADIOLIB_SX1231_DIO2_PACK_DATA 0b00000100 // 3 2
#define RADIOLIB_SX1231_DIO3_CONT_AUTO_MODE 0b00000010 // 0 1
#define RADIOLIB_SX1231_DIO3_CONT_RSSI 0b00000000 // 0 1
#define RADIOLIB_SX1231_DIO3_CONT_RX_READY 0b00000001 // 0 1
#define RADIOLIB_SX1231_DIO3_CONT_TIMEOUT 0b00000011 // 0 1
#define RADIOLIB_SX1231_DIO3_CONT_TX_READY 0b00000001 // 0 1
#define RADIOLIB_SX1231_DIO3_PACK_FIFO_FULL 0b00000000 // 0 1
#define RADIOLIB_SX1231_DIO3_PACK_LOW_BAT 0b00000010 // 0 1
#define RADIOLIB_SX1231_DIO3_PACK_PLL_LOCK 0b00000011 // 0 1
#define RADIOLIB_SX1231_DIO3_PACK_RSSI 0b00000001 // 0 1
#define RADIOLIB_SX1231_DIO3_PACK_SYNC_ADDRESSS 0b00000010 // 0 1
#define RADIOLIB_SX1231_DIO3_PACK_TX_READY 0b00000001 // 0 1
// SX1231_REG_DIO_MAPPING_2
#define RADIOLIB_SX1231_DIO4_CONT_LOW_BAT 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO4_CONT_PLL_LOCK 0b11000000 // 7 6
#define RADIOLIB_SX1231_DIO4_CONT_TIMEOUT 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO4_CONT_RX_READY 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO4_CONT_SYNC_ADDRESS 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO4_CONT_TX_READY 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_LOW_BAT 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_PLL_LOCK 0b11000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_TIMEOUT 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_RSSI 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_RX_READY 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_MODE_READY 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_TX_READY 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO5_CONT_LOW_BAT 0b00100000 // 5 4
#define RADIOLIB_SX1231_DIO5_CONT_MODE_READY 0b00110000 // 5 4
#define RADIOLIB_SX1231_DIO5_CONT_CLK_OUT 0b00000000 // 5 4
#define RADIOLIB_SX1231_DIO5_CONT_RSSI 0b00010000 // 5 4
#define RADIOLIB_SX1231_DIO5_PACK_LOW_BAT 0b00100000 // 5 4
#define RADIOLIB_SX1231_DIO5_PACK_MODE_READY 0b00110000 // 5 4
#define RADIOLIB_SX1231_DIO5_PACK_CLK_OUT 0b00000000 // 5 4
#define RADIOLIB_SX1231_DIO5_PACK_DATA 0b00010000 // 5 4
// RADIOLIB_SX1231_REG_DIO_MAPPING_2
#define RADIOLIB_SX1231_DIO4_CONT_LOW_BAT 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO4_CONT_PLL_LOCK 0b11000000 // 7 6
#define RADIOLIB_SX1231_DIO4_CONT_TIMEOUT 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO4_CONT_RX_READY 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO4_CONT_SYNC_ADDRESS 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO4_CONT_TX_READY 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_LOW_BAT 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_PLL_LOCK 0b11000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_TIMEOUT 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_RSSI 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_RX_READY 0b10000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_MODE_READY 0b00000000 // 7 6
#define RADIOLIB_SX1231_DIO4_PACK_TX_READY 0b01000000 // 7 6
#define RADIOLIB_SX1231_DIO5_CONT_LOW_BAT 0b00100000 // 5 4
#define RADIOLIB_SX1231_DIO5_CONT_MODE_READY 0b00110000 // 5 4
#define RADIOLIB_SX1231_DIO5_CONT_CLK_OUT 0b00000000 // 5 4
#define RADIOLIB_SX1231_DIO5_CONT_RSSI 0b00010000 // 5 4
#define RADIOLIB_SX1231_DIO5_PACK_LOW_BAT 0b00100000 // 5 4
#define RADIOLIB_SX1231_DIO5_PACK_MODE_READY 0b00110000 // 5 4
#define RADIOLIB_SX1231_DIO5_PACK_CLK_OUT 0b00000000 // 5 4
#define RADIOLIB_SX1231_DIO5_PACK_DATA 0b00010000 // 5 4
/*!
\class SX1231
\brief Control class for %SX1231 module. Overrides some methods from RF69 due to different register values.
*/
class SX1231: public RF69 {
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1231(Module* mod);
/*!
\brief Initialization method.
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param br Bit rate to be used in kbps. Defaults to 4.8 kbps.
\param freqDev Frequency deviation from carrier frequency in kHz Defaults to 5.0 kHz.
\param rxBw Receiver bandwidth in kHz. Defaults to 125.0 kHz.
\param power Output power in dBm. Defaults to 10 dBm.
\param preambleLen Preamble Length in bits. Defaults to 16 bits.
\returns \ref status_codes
*/
int16_t begin(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 125.0, int8_t power = 10, uint8_t preambleLen = 16);
@ -122,7 +113,7 @@ class SX1231: public RF69 {
#if !defined(RADIOLIB_GODMODE)
private:
#endif
uint8_t _chipRevision = 0;
uint8_t chipRevision = 0;
};
#endif

View file

@ -0,0 +1,102 @@
/*
Copyright (c) 2018 Jan Gromeš
Copyright (c) 2022 STMicroelectronics
This file is licensed under the MIT License: https://opensource.org/licenses/MIT
*/
#include "STM32WLx.h"
#if !defined(RADIOLIB_EXCLUDE_STM32WLX)
STM32WLx::STM32WLx(STM32WLx_Module* mod) : SX1262(mod) { }
int16_t STM32WLx::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
// Execute common part
int16_t state = SX1262::begin(freq, bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage, useRegulatorLDO);
RADIOLIB_ASSERT(state);
// This overrides the value in SX126x::begin()
// On STM32WL, DIO2 is hardwired to the radio IRQ on the MCU, so it
// should really not be used as RfSwitch control output.
state = setDio2AsRfSwitch(false);
RADIOLIB_ASSERT(state);
return(state);
}
int16_t STM32WLx::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
// Execute common part
int16_t state = SX1262::beginFSK(freq, br, freqDev, rxBw, power, preambleLength, tcxoVoltage, useRegulatorLDO);
RADIOLIB_ASSERT(state);
// This overrides the value in SX126x::beginFSK()
// On STM32WL, DIO2 is hardwired to the radio IRQ on the MCU, so it
// should really not be used as RfSwitch control output.
state = setDio2AsRfSwitch(false);
RADIOLIB_ASSERT(state);
return(state);
}
int16_t STM32WLx::setOutputPower(int8_t power) {
// get current OCP configuration
uint8_t ocp = 0;
int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
RADIOLIB_ASSERT(state);
// Use HP only if available and needed for the requested power
bool hp_supported = this->mod->findRfSwitchMode(MODE_TX_HP);
bool use_hp = power > 14 && hp_supported;
// set PA config.
if(use_hp) {
RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
state = SX126x::setPaConfig(0x04, 0x00, 0x07); // HP output up to 22dBm
this->txMode = MODE_TX_HP;
} else {
RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
state = SX126x::setPaConfig(0x04, 0x01, 0x00); // LP output up to 14dBm
this->txMode = MODE_TX_LP;
}
RADIOLIB_ASSERT(state);
// Apply workaround for HP only
state = SX126x::fixPaClamping(use_hp);
RADIOLIB_ASSERT(state);
// set output power
/// \todo power ramp time configuration
state = SX126x::setTxParams(power);
RADIOLIB_ASSERT(state);
// restore OCP configuration
return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
}
int16_t STM32WLx::clearIrqStatus(uint16_t clearIrqParams) {
int16_t res = SX126x::clearIrqStatus(clearIrqParams);
// The NVIC interrupt is level-sensitive, so clear away any pending
// flag that is only set because the radio IRQ status was not cleared
// in the interrupt (to prevent each IRQ triggering twice and allow
// reading the irq status through the pending flag).
SubGhz.clearPendingInterrupt();
if(SubGhz.hasInterrupt())
SubGhz.enableInterrupt();
return(res);
}
void STM32WLx::setDio1Action(void (*func)(void)) {
SubGhz.attachInterrupt([func]() {
// Because the interrupt is level-triggered, we disable it in the
// NVIC (otherwise we would need an SPI command to clear the IRQ in
// the radio, or it would trigger over and over again).
SubGhz.disableInterrupt();
func();
});
}
void STM32WLx::clearDio1Action() {
SubGhz.detachInterrupt();
}
#endif // !defined(RADIOLIB_EXCLUDE_STM32WLX)

View file

@ -0,0 +1,134 @@
/*
Copyright (c) 2018 Jan Gromeš
Copyright (c) 2022 STMicroelectronics
This file is licensed under the MIT License: https://opensource.org/licenses/MIT
*/
#if !defined(_RADIOLIB_STM32WLx_H)
#define _RADIOLIB_STM32WLx_H
#include "../../TypeDef.h"
#if !defined(RADIOLIB_EXCLUDE_STM32WLX)
#include "../../Module.h"
#include "SX1262.h"
#include "STM32WLx_Module.h"
/*!
\class STM32WLx
\brief Derived class for STM32WL modules.
The radio integrated into these modules is essentially the same as the
Semtech %SX126x external radio chips, so most of the documentation for
those also applies here.
One notable difference with the %SX126x radios is that this radio
essentially combines the %SX1261 and %SX1262 by integrating both the
low-power (LP) and high-power (HP) amplifier. See setOutputPower() and
setRfSwitchTable() for details on how this is handled.
*/
class STM32WLx : public SX1262 {
// NOTE: This class could not be named STM32WL (or STM32WLxx), since
// those are macros defined by
// system/Drivers/CMSIS/Device/ST/STM32WLxxx/Include/stm32wlxx.h
public:
/*!
\brief Default constructor.
\param mod Instance of STM32WLx_Module that will be used to communicate with the radio.
*/
STM32WLx(STM32WLx_Module* mod);
/*!
\brief Custom operation modes for STMWLx.
This splits the TX mode into two modes: Low-power and high-power.
These constants can be used with the setRfSwitchTable() method,
instead of the Module::OpMode_t constants.
*/
enum OpMode_t {
/*! End of table marker, use \ref END_OF_MODE_TABLE constant instead */
MODE_END_OF_TABLE = Module::MODE_END_OF_TABLE,
/*! Idle mode */
MODE_IDLE = Module::MODE_IDLE,
/*! Receive mode */
MODE_RX = Module::MODE_RX,
/*! Low power transmission mode */
MODE_TX_LP = Module::MODE_TX,
/*! High power transmission mode */
MODE_TX_HP,
};
// basic methods
/*!
\copydoc SX1262::begin
*/
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = RADIOLIB_SX126X_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
/*!
\copydoc SX1262::beginFSK
*/
int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
// configuration methods
/*!
\brief Sets output power. Allowed values are in range from -17 to 22 dBm.
This automatically switches between the low-power (LP) and high-power (HP) amplifier.
LP is preferred and supports -17 to +14dBm. When a higher power is
requested (or the LP amplifier is marked as unvailable using
setRfSwitchTable()), HP is used, which supports -9 to +22dBm.
\param power Output power to be set in dBm.
\returns \ref status_codes
*/
virtual int16_t setOutputPower(int8_t power) override;
/*!
\copybrief Module::setRfSwitchTable
This method works like Module::setRfSwitchTable(), except that you
should use STM32WLx::OpMode_t constants for modes, which
distinguishes between a low-power (LP) and high-power (HP) TX mode.
For boards that do not support both modes, just omit the
unsupported mode from the table and it will not be used (and the
valid power range is adjusted by setOutputPower() accordingly).
Note that the setRfSwitchTable() method should be called *before* the
begin() method, to ensure the radio knows which modes are supported
during initialization.
*/
// Note: This explicitly inherits this method only to override docs
using SX126x::setRfSwitchTable;
/*!
\brief Sets interrupt service routine to call when DIO1/2/3 activates.
\param func ISR to call.
*/
void setDio1Action(void (*func)(void));
/*!
\brief Clears interrupt service routine to call when DIO1/2/3 activates.
*/
void clearDio1Action();
#if !defined(RADIOLIB_GODMODE)
protected:
#endif
virtual int16_t clearIrqStatus(uint16_t clearIrqParams) override;
#if !defined(RADIOLIB_GODMODE)
private:
#endif
};
#endif // !defined(RADIOLIB_EXCLUDE_SX126X)
#endif // _RADIOLIB_STM32WLX_MODULE_H

View file

@ -0,0 +1,106 @@
/*
Copyright (c) 2022 STMicroelectronics
This file is licensed under the MIT License: https://opensource.org/licenses/MIT
*/
#include "STM32WLx_Module.h"
#if !defined(RADIOLIB_EXCLUDE_STM32WLX)
#include "../../ArduinoHal.h"
// This defines some dummy pin numbers (starting at NUM_DIGITAL_PINS to
// guarantee these are not valid regular pin numbers) that can be passed
// to the parent Module class, to be stored here and then passed back to
// the overridden callbacks when these are used.
enum {
RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS = NUM_DIGITAL_PINS,
RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY,
RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ,
RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET,
};
class Stm32wlxHal : public ArduinoHal {
public:
Stm32wlxHal(): ArduinoHal(SubGhz.SPI, SubGhz.spi_settings) {}
void pinMode(uint32_t dwPin, uint32_t dwMode) {
switch(dwPin) {
case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS:
case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY:
case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ:
case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET:
// Nothing to do
break;
default:
::pinMode(dwPin, dwMode);
break;
}
}
void digitalWrite(uint32_t dwPin, uint32_t dwVal) {
switch (dwPin) {
case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS:
SubGhz.setNssActive(dwVal == LOW);
break;
case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET:
SubGhz.setResetActive(dwVal == LOW);
break;
case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY:
case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ:
// Should not (and cannot) be written, just ignore
break;
default:
::digitalWrite(dwPin, dwVal);
break;
}
}
uint32_t digitalRead(uint32_t ulPin) {
switch (ulPin) {
case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY:
return(SubGhz.isBusy() ? HIGH : LOW);
case RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ:
// We cannot use the radio IRQ output directly, but since:
// - the pending flag will be set whenever the IRQ output is set,
// and
// - the pending flag will be cleared (by
// STM32WLx::clearIrqStatus()) whenever the radio IRQ output is
// cleared,
// the pending flag should always reflect the current radio IRQ
// output. There is one exception: when the ISR starts the pending
// flag is cleared by hardware and not set again until after the
// ISR finishes, so the value is incorrect *inside* the ISR, but
// running RadioLib code inside the ISR (especially code that
// polls the IRQ flag) is not supported and probably broken in
// other ways too.
return(SubGhz.isInterruptPending() ? HIGH : LOW);
case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS:
return(SubGhz.isNssActive() ? LOW : HIGH);
case RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET:
return(SubGhz.isResetActive() ? LOW : HIGH);
default:
return(::digitalRead(ulPin));
}
}
};
STM32WLx_Module::STM32WLx_Module():
Module(
new Stm32wlxHal,
RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS,
RADIOLIB_STM32WLx_VIRTUAL_PIN_IRQ,
RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET,
RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY
) {}
#endif // !defined(RADIOLIB_EXCLUDE_STM32WLX)

View file

@ -0,0 +1,38 @@
/*
Copyright (c) 2022 STMicroelectronics
This file is licensed under the MIT License: https://opensource.org/licenses/MIT
*/
#if !defined(_RADIOLIB_STM32WLX_MODULE_H)
#define _RADIOLIB_STM32WLX_MODULE_H
#include "../../TypeDef.h"
#if !defined(RADIOLIB_EXCLUDE_STM32WLX)
#include "../../Module.h"
/*!
* \class STM32WLx_Module
*
* This is a subclass of Module to be used with the STM32WLx driver.
*
* It is used to override some callbacks, allowing access to some of the
* radio control signals that are wired to internal registers instead of
* actual GPIO pins.
*/
class STM32WLx_Module : public Module {
// Note: We cannot easily override any methods here, since most calls
// are non-virtual and made through a Module*, so they would not be
// calling any overridden methods. This means this class works by
// overriding some of the callbacks in its constructor.
public:
STM32WLx_Module();
};
#endif // !defined(RADIOLIB_EXCLUDE_STM32WLX)
#endif // _RADIOLIB_STM32WLX_MODULE_H

View file

@ -2,7 +2,7 @@
#if !defined(RADIOLIB_EXCLUDE_SX126X)
SX1261::SX1261(Module* mod): SX1262(mod) {
chipType = RADIOLIB_SX1261_CHIP_TYPE;
}
int16_t SX1261::setOutputPower(int8_t power) {

View file

@ -10,27 +10,26 @@
#include "SX1262.h"
//RADIOLIB_SX126X_CMD_SET_PA_CONFIG
#define RADIOLIB_SX126X_PA_CONFIG_SX1261 0x01
#define RADIOLIB_SX126X_PA_CONFIG_SX1261 0x01
//RADIOLIB_SX126X_REG_VERSION_STRING
#define RADIOLIB_SX1261_CHIP_TYPE "SX1261"
/*!
\class SX1261
\brief Derived class for %SX1261 modules.
*/
class SX1261 : public SX1262 {
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1261(Module* mod);
/*!
\brief Sets output power. Allowed values are in range from -17 to 14 dBm.
\param power Output power to be set in dBm.
\returns \ref status_codes
*/
int16_t setOutputPower(int8_t power);

Some files were not shown because too many files have changed in this diff Show more