Update RadioLib

This commit is contained in:
lewisxhe 2024-05-14 14:09:37 +08:00
commit 1fba8bc2ec
143 changed files with 10097 additions and 2417 deletions

View file

@ -24,4 +24,4 @@ jobs:
- name: Run cppcheck
run:
cppcheck src --enable=all --force
cppcheck src --enable=all --force --inline-suppr --quiet --suppress=ConfigurationNotChecked --suppress=unusedFunction

View file

@ -104,6 +104,10 @@ jobs:
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 "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT
echo "index-url=--additional-urls https://www.pjrc.com/teensy/package_teensy_index.json" >> $GITHUB_OUTPUT
- id: arduino:renesas_uno:minima
run: |
echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT
@ -166,7 +170,7 @@ jobs:
else
# apply special flags for LoRaWAN
if [[ ${example} =~ "LoRaWAN" ]]; then
flags="-DRADIOLIB_LORAWAN_DEV_ADDR=0 -DRADIOLIB_LORAWAN_NWKS_KEY=0 -DRADIOLIB_LORAWAN_SNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_NWKSENC_KEY=0 -DRADIOLIB_LORAWAN_APPS_KEY=0 -DRADIOLIB_LORAWAN_APP_KEY=0 -DRADIOLIB_LORAWAN_NWK_KEY=0 -DRADIOLIB_LORAWAN_DEV_EUI=0 -DARDUINO_TTGO_LORA32_V1"
flags="-DRADIOLIB_LORAWAN_DEV_ADDR=0 -DRADIOLIB_LORAWAN_FNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_SNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_NWKSENC_KEY=0 -DRADIOLIB_LORAWAN_APPS_KEY=0 -DRADIOLIB_LORAWAN_APP_KEY=0 -DRADIOLIB_LORAWAN_NWK_KEY=0 -DRADIOLIB_LORAWAN_DEV_EUI=0 -DARDUINO_TTGO_LORA32_V1"
fi
# build sketch
@ -222,13 +226,15 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get install -y gcc-arm-none-eabi
sudo apt-get install -y gcc-arm-none-eabi gcc-riscv64-unknown-elf
cargo install elf2tab
- name: Build the example
run: |
cd $PWD/examples/NonArduino/Tock
./build.sh
git clone https://github.com/tock/libtock-c.git
cd libtock-c; git checkout 44bf89c545953d8859faf101d4b4a4b6a151fe6c; cd ../
LIBTOCK_C_DIRECTORY="$(pwd)/libtock-c" ./build.sh
rpi-build:
runs-on: [self-hosted, ARM64]

View file

@ -1,3 +0,0 @@
[submodule "examples/NonArduino/Tock/libtock-c"]
path = examples/NonArduino/Tock/libtock-c
url = https://github.com/tock/libtock-c.git

View file

@ -32,6 +32,12 @@ target_include_directories(RadioLib
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
# use c++20 standard
set_property(TARGET RadioLib PROPERTY CXX_STANDARD 20)
# enable most warnings
target_compile_options(RadioLib PRIVATE -Wall -Wextra)
include(GNUInstallDirs)
install(TARGETS RadioLib

View file

@ -16,6 +16,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
### Supported modules:
* __CC1101__ FSK radio module
* __LLCC68__ LoRa module
* __LR11x0__ series LoRa/GFSK modules (LR1110, LR1120, LR1121)
* __nRF24L01__ 2.4 GHz module
* __RF69__ FSK/OOK radio module
* __RFM2x__ series FSK modules (RFM22, RM23)
@ -29,21 +30,21 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
### Supported protocols and digital modes:
* [__AX.25__](https://www.sigidwiki.com/wiki/PACKET) using 2-FSK or AFSK for modules:
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x, Si443x, LR11x0 and SX128x
* [__RTTY__](https://www.sigidwiki.com/wiki/RTTY) using 2-FSK or AFSK for modules:
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX128x
* [__Morse Code__](https://www.sigidwiki.com/wiki/Morse_Code_(CW)) using 2-FSK or AFSK for modules:
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX128x
* [__SSTV__](https://www.sigidwiki.com/wiki/SSTV) using 2-FSK or AFSK for modules:
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x
* [__Hellschreiber__](https://www.sigidwiki.com/wiki/Hellschreiber) using 2-FSK or AFSK for modules:
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x, LR11x0 and SX128x
* [__APRS__](https://www.sigidwiki.com/wiki/APRS) using AFSK for modules:
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x
* [__POCSAG__](https://www.sigidwiki.com/wiki/POCSAG) using 2-FSK for modules:
SX127x, RFM9x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x
* [__LoRaWAN__](https://lora-alliance.org/) using LoRa for modules:
SX127x, RFM9x, SX126x and SX128x
SX127x, RFM9x, SX126x, LR11x0 and SX128x
* NOTE: LoRaWAN support is currently in beta, feedback via [Issues](https://github.com/jgromes/RadioLib/issues) and [Discussions](https://github.com/jgromes/RadioLib/discussions) is appreciated!
### Supported Arduino platforms:

View file

@ -8,6 +8,7 @@
- SX127x/RFM9x
- SX126x/LLCC68
- SX128x
- LR11x0
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration

View file

@ -12,6 +12,7 @@
- SX126x
- nRF24
- Si443x/RFM2x
- LR11x0
Using raw AX.25 frames requires some
knowledge of the protocol, refer to

View file

@ -12,6 +12,7 @@
- SX126x
- nRF24
- Si443x/RFM2x
- LR11x0
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration

View file

@ -13,6 +13,7 @@
- nRF24
- Si443x/RFM2x
- SX128x
- LR11x0
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration

View file

@ -0,0 +1,75 @@
/*
RadioLib LR11x0 Blocking Channel Activity Detection Example
This example uses LR1110 to scan the current LoRa
channel and detect ongoing LoRa transmissions.
Unlike SX127x CAD, LR11x0 can detect any part
of LoRa transmission, not just the preamble.
Other modules from LR11x0 family can also be used.
Using blocking CAD is not recommended, as it will lead
to significant amount of timeouts, inefficient use of processor
time and can some miss packets!
Instead, interrupt CAD is recommended.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// LR1110 has the following connections:
// NSS pin: 10
// IRQ pin: 2
// NRST pin: 3
// BUSY pin: 9
LR1110 radio = new Module(10, 2, 3, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//LR1110 radio = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize LR1110 with default settings
Serial.print(F("[LR1110] Initializing ... "));
int state = radio.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("[LR1110] 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,110 @@
/*
RadioLib LR11x0 Channel Activity Detection Example
This example uses LR1110 to scan the current LoRa
channel and detect ongoing LoRa transmissions.
Unlike SX127x CAD, LR11x0 can detect any part
of LoRa transmission, not just the preamble.
Other modules from LR11x0 family can also be used.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// LR1110 has the following connections:
// NSS pin: 10
// IRQ pin: 2
// NRST pin: 3
// BUSY pin: 9
LR1110 radio = new Module(10, 2, 3, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//LR1110 radio = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize LR1110 with default settings
Serial.print(F("[LR1110] Initializing ... "));
int state = radio.begin();
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.setIrqAction(setFlag);
// start scanning the channel
Serial.print(F("[LR1110] 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!
#if defined(ESP8266) || defined(ESP32)
ICACHE_RAM_ATTR
#endif
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("[LR1110] Packet detected!"));
} else if (state == RADIOLIB_CHANNEL_FREE) {
// channel is free
Serial.println(F("[LR1110] Channel is free!"));
} else {
// some other error occurred
Serial.print(F("[LR1110] Failed, code "));
Serial.println(state);
}
// start scanning the channel again
Serial.print(F("[LR1110] 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,153 @@
/*
RadioLib LR11x0 GFSK Modem Example
This example shows how to use GFSK modem in LR11x0 chips.
NOTE: The sketch below is just a guide on how to use
GFSK modem, so this code should not be run directly!
Instead, modify the other examples to use GFSK
modem and use the appropriate configuration
methods.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---gfsk-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// LR1110 has the following connections:
// NSS pin: 10
// IRQ pin: 2
// NRST pin: 3
// BUSY pin: 9
LR1110 radio = new Module(10, 2, 3, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//LR1110 radio = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize LR1110 with default settings
Serial.print(F("[LR1110] Initializing ... "));
int state = radio.beginGFSK();
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// if needed, you can switch between any of the modems
//
// radio.begin() start LoRa modem (and disable GFSK)
// radio.beginGFSK() start GFSK modem (and disable LoRa)
// the following settings can also
// be modified at run-time
state = radio.setFrequency(433.5);
state = radio.setBitRate(100.0);
state = radio.setFrequencyDeviation(10.0);
state = radio.setRxBandwidth(250.0);
state = radio.setOutputPower(10.0);
state = radio.setDataShaping(RADIOLIB_SHAPING_1_0);
uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
state = radio.setSyncWord(syncWord, 8);
if (state != RADIOLIB_ERR_NONE) {
Serial.print(F("Unable to set configuration, code "));
Serial.println(state);
while (true);
}
// GFSK modem on LR11x0 can handle the sync word setting in bits, not just
// whole bytes. The value used is left-justified.
// This makes same result as radio.setSyncWord(syncWord, 8):
state = radio.setSyncBits(syncWord, 64);
// This will use 0x012 as sync word (12 bits only):
state = radio.setSyncBits(syncWord, 12);
// GFSK modem allows advanced CRC configuration
// Default is CCIT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted)
// Set CRC to IBM CRC (2 bytes, initial 0xFFFF, polynomial 0x8005, non-inverted)
state = radio.setCRC(2, 0xFFFF, 0x8005, false);
// set CRC length to 0 to disable CRC
#warning "This sketch is just an API guide! Read the note at line 6."
}
void loop() {
// GFSK modem can use the same transmit/receive methods
// as the LoRa modem, even their interrupt-driven versions
// transmit GFSK packet
int state = radio.transmit("Hello World!");
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
int state = radio.transmit(byteArr, 8);
*/
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("[LR1110] Packet transmitted successfully!"));
} else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
Serial.println(F("[LR1110] Packet too long!"));
} else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
Serial.println(F("[LR1110] Timed out while transmitting!"));
} else {
Serial.println(F("[LR1110] Failed to transmit packet, code "));
Serial.println(state);
}
// receive GFSK packet
String str;
state = radio.receive(str);
/*
byte byteArr[8];
int state = radio.receive(byteArr, 8);
*/
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("[LR1110] Received packet!"));
Serial.print(F("[LR1110] Data:\t"));
Serial.println(str);
} else if (state == RADIOLIB_ERR_RX_TIMEOUT) {
Serial.println(F("[LR1110] Timed out while waiting for packet!"));
} else {
Serial.print(F("[LR1110] Failed to receive packet, code "));
Serial.println(state);
}
// GFSK modem has built-in address filtering system
// it can be enabled by setting node address, broadcast
// address, or both
//
// to transmit packet to a particular address,
// use the following methods:
//
// radio.transmit("Hello World!", address);
// radio.startTransmit("Hello World!", address);
// set node address to 0x02
state = radio.setNodeAddress(0x02);
// set broadcast address to 0xFF
state = radio.setBroadcastAddress(0xFF);
if (state != RADIOLIB_ERR_NONE) {
Serial.println(F("[LR1110] Unable to set address filter, code "));
Serial.println(state);
}
// address filtering can also be disabled
// NOTE: calling this method will also erase previously set
// node and broadcast address
/*
state = radio.disableAddressFiltering();
if (state != RADIOLIB_ERR_NONE) {
Serial.println(F("Unable to remove address filter, code "));
}
*/
}

View file

@ -0,0 +1,110 @@
/*
RadioLib LR11x0 LR-FHSS Modem Example
This example shows how to use LR-FHSS modem in LR11x0 chips.
NOTE: The sketch below is just a guide on how to use
LR-FHSS modem, so this code should not be run directly!
Instead, modify the other examples to use LR-FHSS
modem and use the appropriate configuration
methods.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lr-fhss-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// LR1110 has the following connections:
// NSS pin: 10
// IRQ pin: 2
// NRST pin: 3
// BUSY pin: 9
LR1110 radio = new Module(10, 2, 3, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//LR1110 radio = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize LR1110 with default settings
Serial.print(F("[LR1110] Initializing ... "));
int state = radio.beginLRFHSS();
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// if needed, you can switch between any of the modems
//
// radio.begin() start LoRa modem (and disable LR-FHSS)
// radio.beginLRFHSS() start LR-FHSS modem (and disable LoRa)
// the following settings can also
// be modified at run-time
state = radio.setFrequency(433.5);
state = radio.setLrFhssConfig(RADIOLIB_LR11X0_LR_FHSS_BW_1523_4, // bandwidth
RADIOLIB_LR11X0_LR_FHSS_CR_1_2, // coding rate
3, // header count
0x13A); // hopping sequence seed
state = radio.setOutputPower(10.0);
state = radio.setSyncWord(0x12345678);
if (state != RADIOLIB_ERR_NONE) {
Serial.print(F("Unable to set configuration, code "));
Serial.println(state);
while (true);
}
#warning "This sketch is just an API guide! Read the note at line 6."
}
void loop() {
// LR-FHSS modem can use the same transmit/receive methods
// as the LoRa modem, even their interrupt-driven versions
// transmit LR-FHSS packet
int state = radio.transmit("Hello World!");
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
int state = radio.transmit(byteArr, 8);
*/
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("[LR1110] Packet transmitted successfully!"));
} else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
Serial.println(F("[LR1110] Packet too long!"));
} else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
Serial.println(F("[LR1110] Timed out while transmitting!"));
} else {
Serial.println(F("[LR1110] Failed to transmit packet, code "));
Serial.println(state);
}
// receive LR-FHSS packet
String str;
state = radio.receive(str);
/*
byte byteArr[8];
int state = radio.receive(byteArr, 8);
*/
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("[LR1110] Received packet!"));
Serial.print(F("[LR1110] Data:\t"));
Serial.println(str);
} else if (state == RADIOLIB_ERR_RX_TIMEOUT) {
Serial.println(F("[LR1110] Timed out while waiting for packet!"));
} else {
Serial.print(F("[LR1110] Failed to receive packet, code "));
Serial.println(state);
}
}

View file

@ -0,0 +1,104 @@
/*
RadioLib LR11x0 Blocking Receive Example
This example listens for LoRa transmissions using LR11x0 Lora modules.
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
Other modules from LR11x0 family can also be used.
Using blocking receive is not recommended, as it will lead
to significant amount of timeouts, inefficient use of processor
time and can some miss packets!
Instead, interrupt receive is recommended.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// LR1110 has the following connections:
// NSS pin: 10
// IRQ pin: 2
// NRST pin: 3
// BUSY pin: 9
LR1110 radio = new Module(10, 2, 3, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//LR1110 radio = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize LR1110 with default settings
Serial.print(F("[LR1110] Initializing ... "));
int state = radio.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("[LR1110] Waiting for incoming transmission ... "));
// you can receive data as an Arduino String
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("[LR1110] Data:\t\t"));
Serial.println(str);
// print the RSSI (Received Signal Strength Indicator)
// of the last received packet
Serial.print(F("[LR1110] 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("[LR1110] 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,138 @@
/*
RadioLib LR11x0 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
Other modules from LR11x0 family can also be used.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// LR1110 has the following connections:
// NSS pin: 10
// IRQ pin: 2
// NRST pin: 3
// BUSY pin: 9
LR1110 radio = new Module(10, 2, 3, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//LR1110 radio = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize LR1110 with default settings
Serial.print(F("[LR1110] Initializing ... "));
int state = radio.begin();
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.setPacketReceivedAction(setFlag);
// start listening for LoRa packets
Serial.print(F("[LR1110] 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.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!
#if defined(ESP8266) || defined(ESP32)
ICACHE_RAM_ATTR
#endif
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 numBytes = radio.getPacketLength();
int state = radio.readData(byteArr, numBytes);
*/
if (state == RADIOLIB_ERR_NONE) {
// packet was successfully received
Serial.println(F("[LR1110] Received packet!"));
// print data of the packet
Serial.print(F("[LR1110] Data:\t\t"));
Serial.println(str);
// print RSSI (Received Signal Strength Indicator)
Serial.print(F("[LR1110] RSSI:\t\t"));
Serial.print(radio.getRSSI());
Serial.println(F(" dBm"));
// print SNR (Signal-to-Noise Ratio)
Serial.print(F("[LR1110] 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);
}
}
}

View file

@ -0,0 +1,106 @@
/*
RadioLib LR11x0 Blocking Transmit Example
This example transmits packets using LR1110 LoRa radio module.
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)
Other modules from LR11x0 family can also be used.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// LR1110 has the following connections:
// NSS pin: 10
// IRQ pin: 2
// NRST pin: 3
// BUSY pin: 9
LR1110 radio = new Module(10, 2, 3, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//LR1110 radio = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize LR1110 with default settings
Serial.print(F("[LR1110] Initializing ... "));
int state = radio.begin();
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
delay(1000);
while (true);
}
// some modules have an external RF switch
// controlled via two pins (RX enable, TX enable)
// to enable automatic control of the switch,
// call the following method
// RX enable: 4
// TX enable: 5
/*
radio.setRfSwitchPins(4, 5);
*/
}
// counter to keep track of transmitted packets
int count = 0;
void loop() {
Serial.print(F("[LR1110] Transmitting packet ... "));
// you can transmit C-string or Arduino string up to
// 256 characters long
// NOTE: transmit() is a blocking method!
// See example LR11x0_Transmit_Interrupt for details
// on non-blocking transmission method.
String str = "Hello World! #" + String(count++);
int state = radio.transmit(str);
// 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("[LR1110] 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,131 @@
/*
RadioLib LR11x0 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)
Other modules from LR11x0 family can also be used.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// LR1110 has the following connections:
// NSS pin: 10
// IRQ pin: 2
// NRST pin: 3
// BUSY pin: 9
LR1110 radio = new Module(10, 2, 3, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//LR1110 radio = RadioShield.ModuleA;
// save transmission state between loops
int transmissionState = RADIOLIB_ERR_NONE;
void setup() {
Serial.begin(9600);
// initialize LR1110 with default settings
Serial.print(F("[LR1110] Initializing ... "));
int state = radio.begin();
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.setPacketSentAction(setFlag);
// start transmitting the first packet
Serial.print(F("[LR1110] 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!
#if defined(ESP8266) || defined(ESP32)
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// we sent a packet, set the flag
transmittedFlag = true;
}
// counter to keep track of transmitted packets
int count = 0;
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("[LR1110] Sending another packet ... "));
// you can transmit C-string or Arduino string up to
// 256 characters long
String str = "Hello World! #" + String(count++);
transmissionState = radio.startTransmit(str);
// you can also transmit byte array up to 256 bytes long
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
transmissionState = radio.startTransmit(byteArr, 8);
*/
}
}

View file

@ -0,0 +1,112 @@
/*
RadioLib LR11x0 WiFi scan Blocking Example
This example performs a passive scan of WiFi networks.
The scan shows basic information about the networks,
such as the frequency, country code and SSID.
Other modules from LR11x0 family can also be used.
Using blocking scan is not recommended, as depending
on the scan settings, the program may be blocked
for several seconds! Instead, interrupt scan is recommended.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---wifi-scan
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// LR1110 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// NRST pin: 3
// BUSY pin: 9
LR1110 radio = new Module(10, 2, 3, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//LR1110 radio = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize LR1110 with default settings
Serial.print(F("[LR1110] Initializing ... "));
int state = radio.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("[LR1110] Running WiFi scan ... "));
// scan all WiFi signals with default scan configuration
uint8_t count = 0;
int state = radio.wifiScan('*', &count);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
// print the table header
Serial.print(F("[LR1110] Reading "));
Serial.print(count);
Serial.println(F(" scan results:"));
Serial.println(F(" # | WiFi type\t| Frequency\t| MAC Address\t | Country\t| RSSI [dBm]\t| SSID"));
// read all results one by one
// this result type contains the most information, including the SSID
LR11x0WifiResultExtended_t result;
for(int i = 0; i < count; i++) {
if(i < 10) { Serial.print(" "); } Serial.print(i); Serial.print(" | ");
state = radio.getWifiScanResult(&result, i);
if(state != RADIOLIB_ERR_NONE) {
Serial.print(F("Failed to read result, code "));
Serial.println(state);
continue;
}
// print the basic information
Serial.print(F("802.11")); Serial.print(result.type); Serial.print("\t| ");
Serial.print(result.channelFreq); Serial.print(" MHz\t| ");
// print MAC address
for(int j = 0; j < 6; j++) {
if(result.mac[j] < 0x10) { Serial.print("0"); }
Serial.print(result.mac[j], HEX);
if(j < 5) { Serial.print(":"); }
}
Serial.print(" | ");
// print the two-letter country code
String country = result.countryCode;
Serial.print(country);
Serial.print(" \t| ");
// print the RSSI
Serial.print(result.rssi);
Serial.print("\t| ");
// print the network SSID
Serial.println((char*)result.ssid);
}
} else {
// some other error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
// wait for a second before scanning again
delay(1000);
}

View file

@ -0,0 +1,150 @@
/*
RadioLib LR11x0 WiFi scan Interrupt Example
This example performs a passive scan of WiFi networks.
The scan shows basic information about the networks,
such as the frequency, country code and SSID.
Other modules from LR11x0 family can also be used.
Using blocking scan is not recommended, as depending
on the scan settings, the program may be blocked
for several seconds! Instead, interrupt scan is recommended.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---wifi-scan
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// LR1110 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// NRST pin: 3
// BUSY pin: 9
LR1110 radio = new Module(10, 2, 3, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//LR1110 radio = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize LR1110 with default settings
Serial.print(F("[LR1110] Initializing ... "));
int state = radio.begin();
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 WiFi scan is complete
radio.setIrqAction(setFlag);
// scan all WiFi signals with default scan configuration
Serial.print(F("[LR1110] Starting passive WiFi scan ... "));
state = radio.startWifiScan('*');
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
}
}
// flag to indicate that a scan was completed
volatile bool scanFlag = false;
// this function is called when a scan is completed
// IMPORTANT: this function MUST be 'void' type
// and MUST NOT have any arguments!
#if defined(ESP8266) || defined(ESP32)
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// scan is complete, set the flag
scanFlag = true;
}
void loop() {
// check if the flag is set
if(scanFlag) {
// reset flag
scanFlag = false;
// get the number of scan results
uint8_t count = 0;
Serial.print(F("[LR1110] Reading WiFi scan results ... "));
int state = radio.getWifiScanResultsCount(&count);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
// print the table header
Serial.print(F("[LR1110] Reading "));
Serial.print(count);
Serial.println(F(" scan results:"));
Serial.println(F(" # | WiFi type\t| Frequency\t| MAC Address\t | Country\t| RSSI [dBm]\t| SSID"));
// read all results one by one
// this result type contains the most information, including the SSID
LR11x0WifiResultExtended_t result;
for(int i = 0; i < count; i++) {
if(i < 10) { Serial.print(" "); } Serial.print(i); Serial.print(" | ");
state = radio.getWifiScanResult(&result, i);
if(state != RADIOLIB_ERR_NONE) {
Serial.print(F("Failed to read result, code "));
Serial.println(state);
continue;
}
// print the basic information
Serial.print(F("802.11")); Serial.print(result.type); Serial.print("\t| ");
Serial.print(result.channelFreq); Serial.print(" MHz\t| ");
// print MAC address
for(int j = 0; j < 6; j++) {
if(result.mac[j] < 0x10) { Serial.print("0"); }
Serial.print(result.mac[j], HEX);
if(j < 5) { Serial.print(":"); }
}
Serial.print(" | ");
// print the two-letter country code
String country = result.countryCode;
Serial.print(country);
Serial.print(" \t| ");
// print the RSSI
Serial.print(result.rssi);
Serial.print("\t| ");
// print the network SSID
Serial.println((char*)result.ssid);
}
} else {
// some other error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
// start scanning again
Serial.print(F("[LR1110] Starting passive WiFi scan ... "));
state = radio.startWifiScan('*');
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
}
}
}

View file

@ -33,34 +33,34 @@
void setup() {
Serial.begin(115200);
while (!Serial);
while(!Serial);
delay(5000); // Give time to switch to the serial monitor
Serial.println(F("\nSetup ... "));
Serial.println(F("Initalise the radio"));
Serial.println(F("Initialise the radio"));
int state = radio.begin();
debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true);
debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true);
Serial.println(F("Initalise LoRaWAN Network credentials"));
state = node.beginABP(devAddr, NwkSEncKey, AppSKey, NwkSKey, SNwkSIntKey, true);
Serial.println(F("Initialise LoRaWAN Network credentials"));
state = node.beginABP(devAddr, fNwkSIntKey, sNwkSIntKey, nwkSEncKey, appSKey, true);
debug(state < RADIOLIB_ERR_NONE, F("Session setup failed"), state, true);
Serial.println(F("Ready!\n"));
}
void loop() {
Serial.println(F("Sending uplink"));
// Read some inputs
uint8_t Digital1 = digitalRead(2);
uint16_t Analog1 = analogRead(3);
// This is the place to gather the sensor inputs
// Instead of reading any real sensor, we just generate some random numbers as example
uint8_t value1 = radio.random(100);
uint16_t value2 = radio.random(2000);
// Build payload byte array
uint8_t uplinkPayload[3];
uplinkPayload[0] = Digital1;
uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions
uplinkPayload[2] = lowByte(Analog1);
uplinkPayload[0] = value1;
uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions
uplinkPayload[2] = lowByte(value2);
// Perform an uplink
int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload));

View file

@ -12,8 +12,8 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds
#define RADIOLIB_LORAWAN_DEV_ADDR 0x------
#endif
#ifndef RADIOLIB_LORAWAN_NWKS_KEY // Replace with your NwkS Key
#define RADIOLIB_LORAWAN_NWKS_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
#ifndef RADIOLIB_LORAWAN_FNWKSINT_KEY // Replace with your FNwkSInt Key
#define RADIOLIB_LORAWAN_FNWKSINT_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
#endif
#ifndef RADIOLIB_LORAWAN_SNWKSINT_KEY // Replace with your SNwkSInt Key
#define RADIOLIB_LORAWAN_SNWKSINT_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
@ -49,11 +49,12 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
// LilyGo
#elif defined(ARDUINO_TTGO_LORA32_V1)
#pragma message ("TTGO LoRa32 v1 - no Display")
#pragma message ("Using TTGO LoRa32 v1 - no Display")
SX1276 radio = new Module(18, 26, 14, 33);
#elif defined(ARDUINO_TTGO_LORA32_V2)
#pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map")
#pragma message ("Using TTGO LoRa32 v2 + Display")
SX1276 radio = new Module(18, 26, 12, RADIOLIB_NC);
#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1
#pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display")
@ -63,24 +64,41 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
#pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map")
#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276)
#pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display")
#pragma message ("Using TTGO T-Beam")
SX1276 radio = new Module(18, 26, 23, 33);
// Heltec
// HelTec: https://github.com/espressif/arduino-esp32/blob/master/variants/heltec_*/pins_arduino.h
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32)
#pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map")
#pragma message ("Using Heltec WiFi LoRa32")
SX1276 radio = new Module(18, 26, 14, 33);
#elif defined(ARDUINO_heltec_wifi_kit_32_V2)
#pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map")
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2)
#pragma message ("Using Heltec WiFi LoRa32 v2")
SX1276 radio = new Module(18, 26, 14, 35);
#elif defined(ARDUINO_heltec_wifi_kit_32_V3)
#pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C")
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V3)
#pragma message ("Using Heltec WiFi LoRa32 v3")
SX1262 radio = new Module(8, 14, 12, 13);
#elif defined (ARDUINO_HELTEC_WIRELESS_STICK)
#pragma message ("Using Heltec Wireless Stick")
SX1276 radio = new Module(18, 26, 14, 35);
#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_V3)
#pragma message ("Using Heltec Wireless Stick v3")
SX1262 radio = new Module(8, 14, 12, 13);
#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE)
#pragma message ("Using Heltec Wireless Stick Lite")
SX1276 radio = new Module(18, 26, 14, 35);
#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE_V3)
#pragma message ("Using Heltec Wireless Stick Lite v3")
SX1262 radio = new Module(34, 14, 12, 13);
#elif defined(ARDUINO_CUBECELL_BOARD)
#pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display")
#pragma message ("Using CubeCell")
SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE);
#elif defined(ARDUINO_CUBECELL_BOARD_V2)
@ -100,10 +118,10 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
// copy over the keys in to the something that will not compile if incorrectly formatted
uint32_t devAddr = RADIOLIB_LORAWAN_DEV_ADDR;
uint8_t NwkSKey[] = { RADIOLIB_LORAWAN_NWKS_KEY };
uint8_t SNwkSIntKey[] = { RADIOLIB_LORAWAN_SNWKSINT_KEY }; // Previously sNwkSIntKey
uint8_t NwkSEncKey[] = { RADIOLIB_LORAWAN_NWKSENC_KEY }; // Previously fNwkSIntKey
uint8_t AppSKey[] = { RADIOLIB_LORAWAN_APPS_KEY };
uint8_t fNwkSIntKey[] = { RADIOLIB_LORAWAN_FNWKSINT_KEY };
uint8_t sNwkSIntKey[] = { RADIOLIB_LORAWAN_SNWKSINT_KEY };
uint8_t nwkSEncKey[] = { RADIOLIB_LORAWAN_NWKSENC_KEY };
uint8_t appSKey[] = { RADIOLIB_LORAWAN_APPS_KEY };
// create the LoRaWAN node
LoRaWANNode node(&radio, &Region, subBand);

View file

@ -33,18 +33,17 @@
// include the library
#include <RadioLib.h>
void setup() {
Serial.begin(115200);
while (!Serial); // Wait for serial to be initalised
while(!Serial); // Wait for serial to be initialised
delay(5000); // Give time to switch to the serial monitor
Serial.println(F("\nSetup"));
int16_t state = 0; // return value for calls to RadioLib
Serial.println(F("Initalise the radio"));
Serial.println(F("Initialise the radio"));
state = radio.begin();
debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true);
debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true);
// Override the default join rate
// uint8_t joinDR = 3;
@ -60,13 +59,9 @@ void setup() {
// Disable the ADR algorithm (on by default which is preferable)
node.setADR(false);
// Set a fixed datarate & make it persistent (not normal)
// Set a fixed datarate
node.setDatarate(4);
// Enable CSMA which tries to minimize packet loss by searching
// for a free channel before actually sending an uplink
node.setCSMA(6, 2, true);
// Manages uplink intervals to the TTN Fair Use Policy
node.setDutyCycle(true, 1250);
@ -74,8 +69,7 @@ void setup() {
node.setDwellTime(true, 400);
Serial.println(F("Ready!\n"));
} // setup
}
void loop() {
int state = RADIOLIB_ERR_NONE;
@ -89,19 +83,19 @@ void loop() {
uint8_t battLevel = 146;
node.setDeviceStatus(battLevel);
// Read some inputs
uint8_t Digital1 = digitalRead(2);
uint16_t Analog1 = analogRead(3);
// This is the place to gather the sensor inputs
// Instead of reading any real sensor, we just generate some random numbers as example
uint8_t value1 = radio.random(100);
uint16_t value2 = radio.random(2000);
// Build payload byte array
uint8_t uplinkPayload[3];
uplinkPayload[0] = Digital1;
uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions
uplinkPayload[2] = lowByte(Analog1);
uplinkPayload[0] = value1;
uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions
uplinkPayload[2] = lowByte(value2);
uint8_t downlinkPayload[10]; // Make sure this fits your plans!
size_t downlinkSize; // To hold the actual payload size rec'd
size_t downlinkSize; // To hold the actual payload size received
// you can also retrieve additional information about an uplink or
// downlink by passing a reference to LoRaWANEvent_t structure
@ -111,13 +105,14 @@ void loop() {
uint8_t Port = 10;
// Retrieve the last uplink frame counter
uint32_t fcntUp = node.getFcntUp();
uint32_t fcntUp = node.getFCntUp();
// Send a confirmed uplink every 64th frame
// and also request the LinkCheck and DeviceTime MAC commands
if(fcntUp % 64 == 0) {
Serial.println(F("[LoRaWAN] Requesting LinkCheck and DeviceTime"));
node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK);
node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME);
node.sendMacCommandReq(RADIOLIB_LW_MAC_LINK_CHECK);
node.sendMacCommandReq(RADIOLIB_LW_MAC_DEVICE_TIME);
state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize, true, &uplinkDetails, &downlinkDetails);
} else {
state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize);
@ -127,7 +122,7 @@ void loop() {
// Check if downlink was received
if(state != RADIOLIB_LORAWAN_NO_DOWNLINK) {
// Did we get a downlink with data for us
if (downlinkSize > 0) {
if(downlinkSize > 0) {
Serial.println(F("Downlink data: "));
arrayDump(downlinkPayload, downlinkSize);
} else {
@ -164,9 +159,9 @@ void loop() {
Serial.print(downlinkDetails.power);
Serial.println(F(" dBm"));
Serial.print(F("[LoRaWAN] Frame count:\t"));
Serial.println(downlinkDetails.fcnt);
Serial.println(downlinkDetails.fCnt);
Serial.print(F("[LoRaWAN] Port:\t\t"));
Serial.println(downlinkDetails.port);
Serial.println(downlinkDetails.fPort);
uint8_t margin = 0;
uint8_t gwCnt = 0;
@ -198,5 +193,4 @@ void loop() {
Serial.println(F("s"));
delay(delayMs);
} // loop
}

View file

@ -44,11 +44,12 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
// LilyGo
#elif defined(ARDUINO_TTGO_LORA32_V1)
#pragma message ("TTGO LoRa32 v1 - no Display")
#pragma message ("Using TTGO LoRa32 v1 - no Display")
SX1276 radio = new Module(18, 26, 14, 33);
#elif defined(ARDUINO_TTGO_LORA32_V2)
#pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map")
#pragma message ("Using TTGO LoRa32 v2 + Display")
SX1276 radio = new Module(18, 26, 12, RADIOLIB_NC);
#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1
#pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display")
@ -58,24 +59,41 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
#pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map")
#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276)
#pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display")
#pragma message ("Using TTGO T-Beam")
SX1276 radio = new Module(18, 26, 23, 33);
// Heltec
// HelTec: https://github.com/espressif/arduino-esp32/blob/master/variants/heltec_*/pins_arduino.h
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32)
#pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map")
#pragma message ("Using Heltec WiFi LoRa32")
SX1276 radio = new Module(18, 26, 14, 33);
#elif defined(ARDUINO_heltec_wifi_kit_32_V2)
#pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map")
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2)
#pragma message ("Using Heltec WiFi LoRa32 v2")
SX1276 radio = new Module(18, 26, 14, 35);
#elif defined(ARDUINO_heltec_wifi_kit_32_V3)
#pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C")
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V3)
#pragma message ("Using Heltec WiFi LoRa32 v3")
SX1262 radio = new Module(8, 14, 12, 13);
#elif defined (ARDUINO_HELTEC_WIRELESS_STICK)
#pragma message ("Using Heltec Wireless Stick")
SX1276 radio = new Module(18, 26, 14, 35);
#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_V3)
#pragma message ("Using Heltec Wireless Stick v3")
SX1262 radio = new Module(8, 14, 12, 13);
#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE)
#pragma message ("Using Heltec Wireless Stick Lite")
SX1276 radio = new Module(18, 26, 14, 35);
#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE_V3)
#pragma message ("Using Heltec Wireless Stick Lite v3")
SX1262 radio = new Module(34, 14, 12, 13);
#elif defined(ARDUINO_CUBECELL_BOARD)
#pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display")
#pragma message ("Using CubeCell")
SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE);
#elif defined(ARDUINO_CUBECELL_BOARD_V2)

View file

@ -26,13 +26,13 @@
void setup() {
Serial.begin(115200);
while (!Serial);
while(!Serial);
delay(5000); // Give time to switch to the serial monitor
Serial.println(F("\nSetup ... "));
Serial.println(F("Initalise the radio"));
Serial.println(F("Initialise the radio"));
int state = radio.begin();
debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true);
debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true);
Serial.println(F("Join ('login') to the LoRaWAN Network"));
state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, true);
@ -41,19 +41,19 @@ void setup() {
Serial.println(F("Ready!\n"));
}
void loop() {
Serial.println(F("Sending uplink"));
// Read some inputs
uint8_t Digital1 = digitalRead(2);
uint16_t Analog1 = analogRead(3);
// This is the place to gather the sensor inputs
// Instead of reading any real sensor, we just generate some random numbers as example
uint8_t value1 = radio.random(100);
uint16_t value2 = radio.random(2000);
// Build payload byte array
uint8_t uplinkPayload[3];
uplinkPayload[0] = Digital1;
uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions
uplinkPayload[2] = lowByte(Analog1);
uplinkPayload[0] = value1;
uplinkPayload[1] = highByte(value2); // See notes for high/lowByte functions
uplinkPayload[2] = lowByte(value2);
// Perform an uplink
int state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload));

View file

@ -44,11 +44,12 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
// LilyGo
#elif defined(ARDUINO_TTGO_LORA32_V1)
#pragma message ("TTGO LoRa32 v1 - no Display")
#pragma message ("Using TTGO LoRa32 v1 - no Display")
SX1276 radio = new Module(18, 26, 14, 33);
#elif defined(ARDUINO_TTGO_LORA32_V2)
#pragma error ("ARDUINO_TTGO_LORA32_V2 awaiting pin map")
#pragma message ("Using TTGO LoRa32 v2 + Display")
SX1276 radio = new Module(18, 26, 12, RADIOLIB_NC);
#elif defined(ARDUINO_TTGO_LoRa32_v21new) // T3_V1.6.1
#pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display")
@ -58,24 +59,41 @@ const uint8_t subBand = 0; // For US915, change this to 2, otherwise leave on 0
#pragma error ("ARDUINO_TBEAM_USE_RADIO_SX1262 awaiting pin map")
#elif defined(ARDUINO_TBEAM_USE_RADIO_SX1276)
#pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display")
#pragma message ("Using TTGO T-Beam")
SX1276 radio = new Module(18, 26, 23, 33);
// Heltec
// HelTec: https://github.com/espressif/arduino-esp32/blob/master/variants/heltec_*/pins_arduino.h
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32)
#pragma error ("ARDUINO_HELTEC_WIFI_LORA_32 awaiting pin map")
#pragma message ("Using Heltec WiFi LoRa32")
SX1276 radio = new Module(18, 26, 14, 33);
#elif defined(ARDUINO_heltec_wifi_kit_32_V2)
#pragma message ("ARDUINO_heltec_wifi_kit_32_V2 awaiting pin map")
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V2)
#pragma message ("Using Heltec WiFi LoRa32 v2")
SX1276 radio = new Module(18, 26, 14, 35);
#elif defined(ARDUINO_heltec_wifi_kit_32_V3)
#pragma message ("Using Heltec WiFi LoRa32 v3 - Display + USB-C")
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32_V3)
#pragma message ("Using Heltec WiFi LoRa32 v3")
SX1262 radio = new Module(8, 14, 12, 13);
#elif defined (ARDUINO_HELTEC_WIRELESS_STICK)
#pragma message ("Using Heltec Wireless Stick")
SX1276 radio = new Module(18, 26, 14, 35);
#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_V3)
#pragma message ("Using Heltec Wireless Stick v3")
SX1262 radio = new Module(8, 14, 12, 13);
#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE)
#pragma message ("Using Heltec Wireless Stick Lite")
SX1276 radio = new Module(18, 26, 14, 35);
#elif defined (ARDUINO_HELTEC_WIRELESS_STICK_LITE_V3)
#pragma message ("Using Heltec Wireless Stick Lite v3")
SX1262 radio = new Module(34, 14, 12, 13);
#elif defined(ARDUINO_CUBECELL_BOARD)
#pragma message ("Using TTGO LoRa32 v2.1 marked T3_V1.6.1 + Display")
#pragma message ("Using CubeCell")
SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE);
#elif defined(ARDUINO_CUBECELL_BOARD_V2)

View file

@ -152,6 +152,10 @@ Prebuilt modules are easy - we can detect the board and setup the pinmap for you
* HELTEC_WIFI_LORA_32
* HELTEC_WIFI_LORA_32_V2
* HELTEC_WIFI_LORA_32_V3
* HELTEC_WIRELESS_STICK
* HELTEC_WIRELESS_STICK_V3
* HELTEC_WIRELESS_STICK_LITE
* HELTEC_WIRELESS_STICK_LITE_V3
If you have a TTGO T-Beam, you must choose the correct radio from the Board Revision sub-menu found under the main Tools menu.

View file

@ -1,18 +1,20 @@
# LoRaWAN examples
RadioLib LoRaWAN v1.1 examples.
* [LoRaWAN_Starter](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Starter): this is the recommended entry point for new users. Please read the `notes` that come with this example to learn more about LoRaWAN and how to use it in RadioLib!
* [LoRaWAN_Reference](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Reference): this sketch showcases most of the available API for LoRaWAN in RadioLib. Be frightened by the possibilities! It is recommended you have read all the `notes` for the Starter sketch first, as well as the [Learn section on The Things Network](https://www.thethingsnetwork.org/docs/lorawan/)!
* [LoRaWAN_Starter](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Starter): this is the recommended entry point for new users. Please read the [`notes`](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) that come with this example to learn more about LoRaWAN and how to use it in RadioLib!
* [LoRaWAN_Reference](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_Reference): this sketch showcases most of the available API for LoRaWAN in RadioLib. Be frightened by the possibilities! It is recommended you have read all the [`notes`](https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md) for the Starter sketch first, as well as the [Learn section on The Things Network](https://www.thethingsnetwork.org/docs/lorawan/)!
* [LoRaWAN_ABP](https://github.com/jgromes/RadioLib/tree/master/examples/LoRaWAN/LoRaWAN_ABP): if you wish to use ABP instead of OTAA (but why?), this example shows how you can do this using RadioLib.
---
All three of these examples do not fully comply with LoRaWAN v1.1: for that, persistent storage is necessary. As the implementation of persistent storage differs between different platforms, these are not given here, but in a separate repository, see below:
> [!WARNING]
> These examples do not fully comply with LoRaWAN v1.1: for that, persistent storage is necessary. As the implementation of persistent storage differs between different platforms, these are not given here, but in a separate repository, see below:
## RadioLib persistence
In [this repository](https://github.com/radiolib-org/radiolib-persistence), examples are provided that do comply with the required persistence of certain parameters for LoRaWAN v1.1. Examples are (or will become) available for some of the most popular platforms. **These examples assume you have successfully used the Starter sketch and understood (most of) the accompanying notes!**
Currently, examples are available for the following platforms:
* [LoRaWAN for ESP32](https://github.com/radiolib-org/radiolib-persistence/tree/main/examples/LoRaWAN_ESP32)
* [LoRaWAN for ESP8266](https://github.com/radiolib-org/radiolib-persistence/tree/main/examples/LoRaWAN_ESP8266)
_This list is last updated for RadioLib 6.5.0_
_This list is last updated at 30/03/2024._

View file

@ -14,6 +14,7 @@
- nRF24
- Si443x/RFM2x
- SX128x
- LR11x0
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration

View file

@ -18,4 +18,5 @@ add_executable(${PROJECT_NAME} main.cpp)
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)
#target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_BASIC RADIOLIB_DEBUG_SPI)
#target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_PORT=stdout)

View file

@ -7,6 +7,14 @@
// include the library for Raspberry GPIO pins
#include "pigpio.h"
// these should really be swapped, but for some reason,
// it seems like the change directions are inverted in gpioSetAlert functions
#define PI_RISING (FALLING_EDGE)
#define PI_FALLING (RISING_EDGE)
// forward declaration of alert handler that will be used to emulate interrupts
static void pigpioAlertHandler(int event, int level, uint32_t tick, void *userdata);
// create a new Raspberry Pi hardware abstraction layer
// using the pigpio library
// the HAL must inherit from the base RadioLibHal class
@ -15,7 +23,7 @@ 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),
: RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, PI_RISING, PI_FALLING),
_spiChannel(spiChannel),
_spiSpeed(spiSpeed) {
}
@ -71,38 +79,50 @@ class PiHal : public RadioLibHal {
}
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
if(interruptNum == RADIOLIB_NC) {
if((interruptNum == RADIOLIB_NC) || (interruptNum > PI_MAX_USER_GPIO)) {
return;
}
gpioSetISRFunc(interruptNum, mode, 0, (gpioISRFunc_t)interruptCb);
// enable emulated interrupt
interruptEnabled[interruptNum] = true;
interruptModes[interruptNum] = mode;
interruptCallbacks[interruptNum] = interruptCb;
// set pigpio alert callback
gpioSetAlertFuncEx(interruptNum, pigpioAlertHandler, (void*)this);
}
void detachInterrupt(uint32_t interruptNum) override {
if(interruptNum == RADIOLIB_NC) {
if((interruptNum == RADIOLIB_NC) || (interruptNum > PI_MAX_USER_GPIO)) {
return;
}
gpioSetISRFunc(interruptNum, 0, 0, NULL);
// clear emulated interrupt
interruptEnabled[interruptNum] = false;
interruptModes[interruptNum] = 0;
interruptCallbacks[interruptNum] = NULL;
// disable pigpio alert callback
gpioSetAlertFuncEx(interruptNum, NULL, NULL);
}
void delay(unsigned long ms) override {
void delay(RadioLibTime_t ms) override {
gpioDelay(ms * 1000);
}
void delayMicroseconds(unsigned long us) override {
void delayMicroseconds(RadioLibTime_t us) override {
gpioDelay(us);
}
unsigned long millis() override {
RadioLibTime_t millis() override {
return(gpioTick() / 1000);
}
unsigned long micros() override {
RadioLibTime_t micros() override {
return(gpioTick());
}
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
long pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout) override {
if(pin == RADIOLIB_NC) {
return(0);
}
@ -120,7 +140,7 @@ class PiHal : public RadioLibHal {
return(this->micros() - start);
}
void spiBegin() {
void spiBegin() {
if(_spiHandle < 0) {
_spiHandle = spiOpen(_spiChannel, _spiSpeed, 0);
}
@ -141,6 +161,12 @@ class PiHal : public RadioLibHal {
}
}
// interrupt emulation
bool interruptEnabled[PI_MAX_USER_GPIO + 1];
uint32_t interruptModes[PI_MAX_USER_GPIO + 1];
typedef void (*RadioLibISR)(void);
RadioLibISR interruptCallbacks[PI_MAX_USER_GPIO + 1];
private:
// the HAL can contain any additional private members
const unsigned int _spiSpeed;
@ -148,4 +174,21 @@ class PiHal : public RadioLibHal {
int _spiHandle = -1;
};
// this handler emulates interrupts
static void pigpioAlertHandler(int event, int level, uint32_t tick, void *userdata) {
if((event > PI_MAX_USER_GPIO) || (!userdata)) {
return;
}
// PiHal isntance is passed via the user data
PiHal* hal = (PiHal*)userdata;
// check the interrupt is enabled, the level matches and a callback exists
if((hal->interruptEnabled[event]) &&
(hal->interruptModes[event] == level) &&
(hal->interruptCallbacks[event])) {
hal->interruptCallbacks[event]();
}
}
#endif

View file

@ -6,3 +6,4 @@ cd build
cmake -G "CodeBlocks - Unix Makefiles" ..
make
cd ..
size build/rpi-sx1261

View file

@ -27,9 +27,13 @@ cmake_minimum_required(VERSION 3.18)
# create the project
project(tock-sx1261)
set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/userland_generic.ld)
set(LINKER_SCRIPT $ENV{LIBTOCK_C_DIRECTORY}/userland_generic.ld)
include("tock.cmake")
if (RISCV_BUILD)
include("tock-riscv.cmake")
else()
include("tock-arm.cmake")
endif()
# when using debuggers such as gdb, the following line can be used
#set(CMAKE_BUILD_TYPE Debug)
@ -43,18 +47,62 @@ add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CUR
add_executable(${PROJECT_NAME} main.cpp)
# link with RadioLib and libtock-c
target_link_libraries(${PROJECT_NAME} PUBLIC
RadioLib
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/cortex-m4/libtock.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libc++/cortex-m/libgcc.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libc++/cortex-m/libstdc++.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/newlib/cortex-m/v7-m/libc.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/newlib/cortex-m/v7-m/libm.a
)
# The build system for libtock-c is a bit odd and the version of libraries
# built changes based on compiler version.
if (RISCV_BUILD)
if(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0")
target_link_libraries(${PROJECT_NAME} PUBLIC
RadioLib
$ENV{LIBTOCK_C_DIRECTORY}/libtock/build/rv32imc/libtock.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0/riscv/lib/gcc/riscv64-unknown-elf/13.2.0/rv32i/ilp32/libgcc.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a
)
target_include_directories(RadioLib AFTER PUBLIC
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/include/
)
else()
target_link_libraries(${PROJECT_NAME} PUBLIC
RadioLib
$ENV{LIBTOCK_C_DIRECTORY}/libtock/build/rv32imc/libtock.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-10.5.0/riscv/lib/gcc/riscv64-unknown-elf/10.5.0/rv32i/ilp32/libgcc.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-10.5.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a
)
target_include_directories(RadioLib AFTER PUBLIC
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/include/
)
endif()
else()
if(EXISTS "$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0")
target_link_libraries(${PROJECT_NAME} PUBLIC
RadioLib
$ENV{LIBTOCK_C_DIRECTORY}/libtock/build/cortex-m4/libtock.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0/arm/lib/gcc/arm-none-eabi/13.2.0/libgcc.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-13.2.0/arm/arm-none-eabi/lib/libstdc++.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/arm/arm-none-eabi/lib/libc.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.3.0.20230120/arm/arm-none-eabi/lib/libm.a
)
else()
target_link_libraries(${PROJECT_NAME} PUBLIC
RadioLib
$ENV{LIBTOCK_C_DIRECTORY}/libtock/build/cortex-m4/libtock.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-10.5.0/arm/lib/gcc/arm-none-eabi/10.5.0/libgcc.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-libc++-10.5.0/arm/arm-none-eabi/lib/libstdc++.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/lib/libc.a
$ENV{LIBTOCK_C_DIRECTORY}/lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/lib/libm.a
)
endif()
endif()
target_include_directories(${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/
$ENV{LIBTOCK_C_DIRECTORY}
)
# you can also specify RadioLib compile-time flags here

View file

@ -13,16 +13,22 @@ This has been tested on the
but will work on any LoRa compatible Tock board (currently only the
expLoRaBLE board).
libtock-c by default is bulit for RISC-V and ARM. RadioLib is also built
for both architectures by default. You can skip the RISC-V RadioLib build
by setting the `SKIP_RISCV` varaible.
The RadioLib example can be built with:
```shell
$ git clone https://github.com/jgromes/RadioLib.git
$ cd RadioLib/examples/NonArduino/Tock/
$ ./build.sh
$ git clone https://github.com/tock/libtock-c.git
$ cd libtock-c; git checkout 44bf89c545953d8859faf101d4b4a4b6a151fe6c; cd ../
$ LIBTOCK_C_DIRECTORY="$(pwd)/libtock-c" ./build.sh
```
Then in the Tock repo you can flash the kernel and app with:
```shell
$ make flash; APP=RadioLib/examples/NonArduino/Tock/build/tock-sx1261.tbf make flash-app
$ make flash; APP=RadioLib/examples/NonArduino/Tock/build-arm/tock-sx1261.tbf make flash-app
```

View file

@ -1,20 +1,30 @@
#!/bin/bash
set -e
rm -rf ./build
rm -rf ./build-*
cd libtock-c/libtock
cd libtock-c/examples/cxx_hello
make -j4
cd ../../
cd ../../../
mkdir -p build
cd build
mkdir -p build-arm
cd build-arm
cmake -G "CodeBlocks - Unix Makefiles" ..
make -j4
cd ..
if ! env | grep SKIP_RISCV; then
mkdir -p build-riscv
cd build-riscv
cmake -G "CodeBlocks - Unix Makefiles" -DRISCV_BUILD=1 ..
make -j4
cd ..
fi
elf2tab -n radio-lib --stack 4096 --app-heap 2048 --kernel-heap 2048 \
--kernel-major 2 --kernel-minor 1 \
-v ./build/tock-sx1261
-v ./build-arm/tock-sx1261

View file

@ -25,8 +25,6 @@
# This is copied from https://github.com/Lora-net/LoRaMac-node/pull/1390
# and has been relicensed by the original author
include("toolchain-arm-none-eabi.cmake")
if(NOT DEFINED LINKER_SCRIPT)
message(FATAL_ERROR "No linker script defined")
endif(NOT DEFINED LINKER_SCRIPT)
@ -40,6 +38,22 @@ set(STACK_SIZE 4096)
set(APP_HEAP_SIZE 2048)
set(KERNEL_HEAP_SIZE 2048)
set(TOOLCHAIN arm-none-eabi)
find_program(TOOLCHAIN_PREFIX ${TOOLCHAIN}-gcc NO_CACHE)
get_filename_component(TOOLCHAIN_PREFIX ${TOOLCHAIN_PREFIX} DIRECTORY)
set(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_PREFIX}/../bin)
set(TOOLCHAIN_INC_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/include)
set(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/lib)
#---------------------------------------------------------------------------------------
# Set compilers
#---------------------------------------------------------------------------------------
set(CMAKE_C_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc CACHE INTERNAL "C Compiler")
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-g++ CACHE INTERNAL "C++ Compiler")
set(CMAKE_ASM_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc CACHE INTERNAL "ASM Compiler")
# Object build options
set(OBJECT_GEN_FLAGS "-mthumb -g2 -fno-builtin -mcpu=cortex-m4 -Wall -Wextra -pedantic -Wno-unused-parameter -ffunction-sections -fdata-sections -fomit-frame-pointer -mabi=aapcs -fno-unroll-loops -ffast-math -ftree-vectorize -frecord-gcc-switches -gdwarf-2 -Os -fdata-sections -ffunction-sections -fstack-usage -Wl,--emit-relocs -fPIC -mthumb -mfloat-abi=soft -msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -D__TOCK__ -DSVCALL_AS_NORMAL_FUNCTION -DSOFTDEVICE_s130")

View file

@ -0,0 +1,76 @@
# Tock target specific CMake file
#
# Licensed under the MIT License
#
# Copyright (c) 2023 Alistair Francis <alistair@alistair23.me>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# This is copied from https://github.com/Lora-net/LoRaMac-node/pull/1390
# and has been relicensed by the original author
if(NOT DEFINED LINKER_SCRIPT)
message(FATAL_ERROR "No linker script defined")
endif(NOT DEFINED LINKER_SCRIPT)
message("Linker script: ${LINKER_SCRIPT}")
#---------------------------------------------------------------------------------------
# Set compiler/linker flags
#---------------------------------------------------------------------------------------
set(STACK_SIZE 4096)
set(APP_HEAP_SIZE 2048)
set(KERNEL_HEAP_SIZE 2048)
find_program(TOOLCHAIN
NAMES
riscv64-none-elf-gcc
riscv32-none-elf-gcc
riscv64-elf-gcc
riscv32-unknown-elf-gcc
riscv64-unknown-elf-gcc
riscv64-unknown-elf-clang
riscv32-unknown-elf-clang
NO_CACHE)
get_filename_component(TOOLCHAIN_PREFIX ${TOOLCHAIN} DIRECTORY)
get_filename_component(TOOLCHAIN ${TOOLCHAIN} NAME)
string(REPLACE "-gcc" "" TOOLCHAIN ${TOOLCHAIN})
set(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_PREFIX}/../bin)
set(TOOLCHAIN_INC_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/include)
set(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/lib)
#---------------------------------------------------------------------------------------
# Set compilers
#---------------------------------------------------------------------------------------
set(CMAKE_C_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc CACHE INTERNAL "C Compiler")
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-g++ CACHE INTERNAL "C++ Compiler")
set(CMAKE_ASM_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc CACHE INTERNAL "ASM Compiler")
# Object build options
set(OBJECT_GEN_FLAGS "-march=rv32i -mabi=ilp32 -mcmodel=medlow -g2 -fno-builtin -Wall -Wextra -pedantic -Wno-unused-parameter -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-unroll-loops -ffast-math -ftree-vectorize -frecord-gcc-switches -gdwarf-2 -Os -fdata-sections -ffunction-sections -fstack-usage -Wl,--emit-relocs -D__TOCK__ -DSVCALL_AS_NORMAL_FUNCTION -DSOFTDEVICE_s130")
set(CMAKE_C_FLAGS "${OBJECT_GEN_FLAGS} -std=gnu99 " CACHE INTERNAL "C Compiler options")
set(CMAKE_CXX_FLAGS "${OBJECT_GEN_FLAGS} -std=c++20 " CACHE INTERNAL "C++ Compiler options")
set(CMAKE_ASM_FLAGS "${OBJECT_GEN_FLAGS} -x assembler-with-cpp " CACHE INTERNAL "ASM Compiler options")
# Linker flags
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections -march=rv32i -mabi=ilp32 -mcmodel=medlow -T${LINKER_SCRIPT} -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Xlinker --defsym=STACK_SIZE=${STACK_SIZE} -Xlinker --defsym=APP_HEAP_SIZE=${APP_HEAP_SIZE} -Xlinker --defsym=KERNEL_HEAP_SIZE=${KERNEL_HEAP_SIZE} -nostdlib -Wl,--start-group" CACHE INTERNAL "Linker options")

View file

@ -1,90 +0,0 @@
# Arm specific CMake file
#
# This is copied from:
# https://github.com/Lora-net/LoRaMac-node/blob/2bf36bde72f68257eb96b5c00900619546bedca8/cmake/toolchain-arm-none-eabi.cmake
#
# The below file is licensed as Revised BSD License
# See https://github.com/Lora-net/LoRaMac-node/blob/master/LICENSE for details
##
## ______ _
## / _____) _ | |
## ( (____ _____ ____ _| |_ _____ ____| |__
## \____ \| ___ | (_ _) ___ |/ ___) _ \
## _____) ) ____| | | || |_| ____( (___| | | |
## (______/|_____)_|_|_| \__)_____)\____)_| |_|
## (C)2013-2017 Semtech
## ___ _____ _ ___ _ _____ ___ ___ ___ ___
## / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
## \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
## |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
## embedded.connectivity.solutions.==============
##
## License: Revised BSD License, see LICENSE.TXT file included in the project
## Authors: Johannes Bruder ( STACKFORCE ), Miguel Luis ( Semtech )
##
##
## CMake arm-none-eabi toolchain file
##
# Append current directory to CMAKE_MODULE_PATH for making device specific cmake modules visible
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
# Target definition
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR ARM)
#---------------------------------------------------------------------------------------
# Set toolchain paths
#---------------------------------------------------------------------------------------
set(TOOLCHAIN arm-none-eabi)
find_program(TOOLCHAIN_PREFIX ${TOOLCHAIN}-gcc NO_CACHE)
get_filename_component(TOOLCHAIN_PREFIX ${TOOLCHAIN_PREFIX} DIRECTORY)
set(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_PREFIX}/../bin)
set(TOOLCHAIN_INC_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/include)
set(TOOLCHAIN_LIB_DIR ${TOOLCHAIN_PREFIX}/../${TOOLCHAIN}/lib)
# Set system depended extensions
if(WIN32)
set(TOOLCHAIN_EXT ".exe" )
else()
set(TOOLCHAIN_EXT "" )
endif()
# Perform compiler test with static library
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
#---------------------------------------------------------------------------------------
# Preset some general GCC Options
#---------------------------------------------------------------------------------------
# Options for DEBUG build
# -Og enables optimizations that do not interfere with debugging
# -g produce debugging information in the operating system's native format
set(CMAKE_C_FLAGS_DEBUG "-Og -g -DDEBUG" CACHE INTERNAL "C Compiler options for debug build type")
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g -DDEBUG" CACHE INTERNAL "C++ Compiler options for debug build type")
set(CMAKE_ASM_FLAGS_DEBUG "-g" CACHE INTERNAL "ASM Compiler options for debug build type")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "" CACHE INTERNAL "Linker options for debug build type")
# Options for RELEASE build
# -Os Optimize for size. -Os enables all -O2 optimizations
set(CMAKE_C_FLAGS_RELEASE "-Os" CACHE INTERNAL "C Compiler options for release build type")
set(CMAKE_CXX_FLAGS_RELEASE "-Os" CACHE INTERNAL "C++ Compiler options for release build type")
set(CMAKE_ASM_FLAGS_RELEASE "" CACHE INTERNAL "ASM Compiler options for release build type")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "" CACHE INTERNAL "Linker options for release build type")
#---------------------------------------------------------------------------------------
# Set compilers
#---------------------------------------------------------------------------------------
set(CMAKE_C_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc${TOOLCHAIN_EXT} CACHE INTERNAL "C Compiler")
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-g++${TOOLCHAIN_EXT} CACHE INTERNAL "C++ Compiler")
set(CMAKE_ASM_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc${TOOLCHAIN_EXT} CACHE INTERNAL "ASM Compiler")
set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_PREFIX}/${${TOOLCHAIN}} ${CMAKE_PREFIX_PATH})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

View file

@ -13,6 +13,7 @@
- nRF24
- Si443x/RFM2x
- SX128x
- LR11x0
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration

View file

@ -0,0 +1,108 @@
/*
RadioLib SX128x Channel Activity Detection Example
This example uses SX1280 to scan the current LoRa
channel and detect ongoing LoRa transmissions.
Other modules from SX128x family can also be used.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// SX1280 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// NRST pin: 3
// BUSY pin: 9
SX1280 radio = new Module(10, 2, 3, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//SX1280 radio = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize SX1280 with default settings
Serial.print(F("[SX1280] Initializing ... "));
int state = radio.begin();
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("[SX1280] 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!
#if defined(ESP8266) || defined(ESP32)
ICACHE_RAM_ATTR
#endif
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("[SX1280] Packet detected!"));
} else if (state == RADIOLIB_CHANNEL_FREE) {
// channel is free
Serial.println(F("[SX1280] Channel is free!"));
} else {
// some other error occurred
Serial.print(F("[SX1280] Failed, code "));
Serial.println(state);
}
// start scanning the channel again
Serial.print(F("[SX1280] 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,50 @@
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
import argparse
import numpy as np
from PIL import Image
from argparse import RawTextHelpFormatter
def main():
parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description='''
RadioLib image to array conversion tool.
Input is a PNG image to be transmitted via RadioLib SSTV.
The image must have correct size for the chose SSTV mode!
Output is a file (by default named "img.h") which can be included and transmitted.
The resulting array will be very large (typically 320 kB),
make sure your platform has sufficient Flash/RAM space.
''')
parser.add_argument('input',
type=str,
help='Input PNG file')
parser.add_argument('output',
type=str,
nargs='?',
default='img',
help='Output header file')
args = parser.parse_args()
outfile = f'{args.output}.h'
print(f'Converting "{args.input}" to "{outfile}"')
# open the image as numpy array
img = Image.open(args.input)
arr = np.array(img)
# open the output file
with open(outfile, 'w') as f:
print(f'const uint32_t img[{arr.shape[0]}][{arr.shape[1]}] = {{', file=f)
for row in arr:
print(' { ', end='', file=f)
for pix in row:
rgb = pix[0] << 16 | pix[1] << 8 | pix[2]
print(hex(rgb), end=', ', file=f)
print(' },', file=f)
print('};', file=f)
print('Done!')
if __name__ == "__main__":
main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

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

@ -0,0 +1,111 @@
import re, sys, argparse
from pathlib import Path
from argparse import RawTextHelpFormatter
'''
TODO list:
1. Parse macro values (the names of bits in all registers in header file)
2. Failed SPI write handling
3. SX126x/SX128x handling
'''
def get_macro_name(value, macros):
for macro in macros:
if macro[1] == value:
return macro[0]
return 'UNKNOWN_VALUE'
def get_macro_value(value):
return ' 0x{0:02X}\n'.format(int(value, 16))
parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description='''
RadioLib debug output decoder script. Turns RadioLib Serial dumps into readable text.
Step-by-step guid on how to use the decoder:
1. Uncomment lines 312 (#define RADIOLIB_DEBUG) and 313 (#define RADIOLIB_VERBOSE) in RadioLib/src/BuildOpt.h
2. Recompile and upload the failing Arduino sketch
3. Open Arduino IDE Serial Monitor and enable timestamps
4. Copy the Serial output and save it into a .txt file
5. Run this script
Output will be saved in the file specified by --out and printed to the terminal
''')
parser.add_argument('file', metavar='file', type=str, help='Text file of the debug output')
parser.add_argument('--out', metavar='out', default='./out.txt', type=str, help='Where to save the decoded file (defaults to ./out.txt)')
args = parser.parse_args()
# open the log file
log = open(args.file, 'r').readlines()
# find modules that are in use
used_modules = []
pattern_module = re.compile('(([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?.[0-9]{3} -> )?M\t')
for entry in log:
m = pattern_module.search(entry)
if m != None:
used_modules.append(entry[m.end():].rstrip())
# get paths to all relevant header files
header_files = []
for path in Path('../../src').rglob('*.h'):
for module in used_modules:
if module in path.name:
header_files.append(path)
# extract names of address macros from the header files
macro_addresses = []
pattern_define = re.compile('#define \w* +\w*(\n| +\/\/){1}')
for path in header_files:
file = open(path, 'r').readlines()
for line in file:
m = pattern_define.search(line)
if m != None:
s = re.split(' +', m.group().rstrip())
if (s.__len__() > 1) and ('_REG' in s[1]):
macro_addresses.append([s[1], int(s[2], 0)])
'''
# extract names of value macros for each adddress macro
macro_values = []
for path in header_files:
file = open(path, 'r').readlines()
for line in file:
for module in used_modules:
pattern_addr_macro = re.compile('\/\/ SI443X_REG_\w+'.format(module.capitalize()))
'''
# parse every line in the log file
out = []
pattern_debug = re.compile('(([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?.[0-9]{3} -> )?[RWM]\t.+')
for entry in log:
m = pattern_debug.search(entry)
if m != None:
s = re.split('( |\t)+', entry.rstrip())
cmd_len = int((s.__len__() - 7)/2)
new_entry = s[0] + s[1] + s[2] + s[3]
if s[4] == 'W':
macro_address = int(s[6], 16)
new_entry += 'write {0:>2} 0x{1:02X} {2}\n'.format(cmd_len, macro_address, get_macro_name(macro_address, macro_addresses))
for i in range(cmd_len):
new_entry += get_macro_value(s[8 + 2*i]);
elif s[4] == 'R':
macro_address = int(s[6], 16)
new_entry += 'read {0:>2} 0x{1:02X} {2}\n'.format(cmd_len, macro_address, get_macro_name(macro_address, macro_addresses))
for i in range(cmd_len):
new_entry += get_macro_value(s[8 + 2*i]);
elif s[4] == 'M':
new_entry += 'module {}\n'.format(s[6])
out.append(new_entry)
else:
out.append(entry)
# write the output file
out_file = open(args.out, 'w')
for line in out:
print(line, end='')
out_file.write(line)
out_file.close()

View file

@ -0,0 +1,22 @@
#include "<module_name>.h"
#if !defined(RADIOLIB_EXCLUDE_<module_name>)
<module_name>::<module_name>(Module* mod) {
/*
Constructor implementation MUST assign the provided "mod" pointer to the private "_mod" pointer.
*/
_mod = mod;
}
int16_t <module_name>::begin() {
/*
"begin" method implementation MUST call the "init" method with appropriate settings.
*/
_mod->init();
/*
"begin" method SHOULD implement some sort of mechanism to verify the connection between Arduino and the module.
For example, reading a version register
*/
}

View file

@ -0,0 +1,99 @@
/*
RadioLib Module Template header file
Before opening pull request, please make sure that:
1. All files MUST be compiled without errors using default Arduino IDE settings.
2. All files SHOULD be compiled without warnings with compiler warnings set to "All".
3. Example sketches MUST be working correctly and MUST be stable enough to run for prolonged periods of time.
4. Writing style SHOULD be consistent.
5. Comments SHOULD be in place for the most important chunks of code and SHOULD be free of typos.
6. To indent, 2 spaces MUST be used.
If at any point you are unsure about the required style, please refer to the rest of the modules.
*/
#if !defined(_RADIOLIB_<module_name>_H) && !defined(RADIOLIB_EXCLUDE_<module_name>)
#if !defined(_RADIOLIB_<module_name>_H)
#define _RADIOLIB_<module_name>_H
/*
Header file for each module MUST include Module.h and TypeDef.h in the src folder.
The header file MAY include additional header files.
*/
#include "../../Module.h"
#include "../../TypeDef.h"
/*
Only use the following include if the module implements methods for OSI physical layer control.
This concerns only modules similar to SX127x/RF69/CC1101 etc.
In this case, your class MUST implement all virtual methods of PhysicalLayer class.
*/
//#include "../../protocols/PhysicalLayer/PhysicalLayer.h"
/*
Register map
Definition of SPI register map SHOULD be placed here. The register map SHOULD have two parts:
1 - Address map: only defines register names and addresses. Register names MUST match names in
official documentation (datasheets etc.).
2 - Variable map: defines variables inside register. This functions as a bit range map for a specific register.
Bit range (MSB and LSB) as well as short description for each variable MUST be provided in a comment.
See RF69 and SX127x header files for examples of register maps.
*/
// <module_name> register map | spaces up to this point
#define RADIOLIB_<module_name>_REG_<register_name> 0x00
// <module_name>_REG_<register_name> MSB LSB DESCRIPTION
#define RADIOLIB_<module_name>_<register_variable> 0b00000000 // 7 0 <description>
/*
Module class definition
The module class MAY inherit from the following classes:
1 - PhysicalLayer: In case the module implements methods for OSI physical layer control (e.g. SX127x).
2 - Common class: In case the module further specifies some more generic class (e.g. SX127x/SX1278)
*/
class <module_name> {
public:
/*
Constructor MUST have only one parameter "Module* mod".
The class MAY implement additional overloaded constructors.
*/
// constructor
<module_name>(Module* mod);
/*
The class MUST implement at least one basic method called "begin".
The "begin" method MUST initialize the module and return the status as int16_t type.
*/
// basic methods
int16_t begin();
/*
The class MAY implement additional methods.
All implemented methods SHOULD return the status as int16_t type.
*/
#if !defined(RADIOLIB_GODMODE)
private:
#endif
/*
The class MUST contain private member "Module* _mod"
*/
Module* _mod;
/*
The class MAY contain additional private variables and/or methods.
Private member variables MUST have a name prefixed with "_" (underscore, ASCII 0x5F)
Usually, these are variables for saving module configuration, or methods that do not have to be exposed to the end user.
*/
};
#endif
#endif

View file

@ -1,6 +1,6 @@
version: "6.5.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.) and other protocols (Pagers, LoRaWAN)."
tags: "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, lorawan"
tags: "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, lorawan, lr1110, lr1120, lr1121"
url: "https://github.com/jgromes/RadioLib"
repository: "https://github.com/jgromes/RadioLib.git"
license: "MIT"

View file

@ -15,6 +15,9 @@ ArduinoHal KEYWORD1
# modules
CC1101 KEYWORD1
LLCC68 KEYWORD1
LR1110 KEYWORD1
LR1120 KEYWORD1
LR1121 KEYWORD1
nRF24 KEYWORD1
RF69 KEYWORD1
RFM22 KEYWORD1
@ -88,6 +91,11 @@ AS923 KEYWORD1
KR920 KEYWORD1
IN865 KEYWORD1
# LR11x0 scan results
LR11x0WifiResult_t KEYWORD1
LR11x0WifiResultFull_t KEYWORD1
LR11x0WifiResultExtended_t KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
@ -124,6 +132,7 @@ setCodingRate KEYWORD2
setFrequency KEYWORD2
setSyncWord KEYWORD2
setOutputPower KEYWORD2
checkOutputPower KEYWORD2
setCurrentLimit KEYWORD2
setPreambleLength KEYWORD2
setGain KEYWORD2
@ -134,6 +143,7 @@ getSNR KEYWORD2
getDataRate KEYWORD2
setBitRate KEYWORD2
setRxBandwidth KEYWORD2
autoSetRxBandwidth KEYWORD2
setAFCBandwidth KEYWORD2
setAFC KEYWORD2
setAFCAGCTrigger KEYWORD2
@ -224,6 +234,7 @@ spectralScanStart KEYWORD2
spectralScanAbort KEYWORD2
spectralScanGetStatus KEYWORD2
spectralScanGetResult KEYWORD2
setPaRampTime KEYWORD2
# nRF24
setIrqAction KEYWORD2
@ -234,6 +245,16 @@ disablePipe KEYWORD2
getStatus KEYWORD2
setAutoAck KEYWORD2
# LR11x0
beginLRFHSS KEYWORD2
setLrFhssConfig KEYWORD2
startWifiScan KEYWORD2
getWifiScanResultsCount KEYWORD2
getWifiScanResult KEYWORD2
wifiScan KEYWORD2
setWiFiScanAction KEYWORD2
clearWiFiScanAction KEYWORD2
# RTTY
idle KEYWORD2
byteArr KEYWORD2
@ -307,10 +328,10 @@ uplink KEYWORD2
downlink KEYWORD2
sendReceive KEYWORD2
setDeviceStatus KEYWORD2
getFcntUp KEYWORD2
getNFcntDown KEYWORD2
getAFcntDown KEYWORD2
resetFcntDown KEYWORD2
getFCntUp KEYWORD2
getNFCntDown KEYWORD2
getAFCntDown KEYWORD2
resetFCntDown KEYWORD2
setDatarate KEYWORD2
setADR KEYWORD2
setDutyCycle KEYWORD2
@ -319,10 +340,10 @@ timeUntilUplink KEYWORD2
setDwellTime KEYWORD2
maxPayloadDwellTime KEYWORD2
setTxPower KEYWORD2
setCSMA KEYWORD2
getMacLinkCheckAns KEYWORD2
getMacDeviceTimeAns KEYWORD2
getDevAddr KEYWORD2
getLastToA KEYWORD2
#######################################
# Constants (LITERAL1)

View file

@ -2,7 +2,7 @@
"name": "RadioLib",
"version": "6.5.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.) and other protocols (Pagers, LoRaWAN).",
"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, lorawan",
"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, lorawan, lr1110, lr1120, lr1121",
"homepage": "https://github.com/jgromes/RadioLib",
"repository":
{

View file

@ -3,7 +3,7 @@ version=6.5.0
author=Jan Gromes <gromes.jan@gmail.com>
maintainer=Jan Gromes <gromes.jan@gmail.com>
sentence=Universal wireless communication library
paragraph=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.) and other protocols (Pagers, LoRaWAN).
paragraph=User-friendly library for sub-GHz radio modules (SX1278, RF69, CC1101, SX1268, LR1110 and many others), as well as ham radio digital modes (RTTY, SSTV, AX.25 etc.) and other protocols (Pagers, LoRaWAN).
category=Communication
url=https://github.com/jgromes/RadioLib
architectures=*

View file

@ -53,7 +53,7 @@ void inline ArduinoHal::detachInterrupt(uint32_t interruptNum) {
::detachInterrupt(interruptNum);
}
void inline ArduinoHal::delay(unsigned long ms) {
void inline ArduinoHal::delay(RadioLibTime_t ms) {
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
::delay(ms);
#else
@ -61,7 +61,7 @@ void inline ArduinoHal::delay(unsigned long ms) {
#endif
}
void inline ArduinoHal::delayMicroseconds(unsigned long us) {
void inline ArduinoHal::delayMicroseconds(RadioLibTime_t us) {
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
::delayMicroseconds(us);
#else
@ -69,7 +69,7 @@ void inline ArduinoHal::delayMicroseconds(unsigned long us) {
#endif
}
unsigned long inline ArduinoHal::millis() {
RadioLibTime_t inline ArduinoHal::millis() {
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
return(::millis());
#else
@ -77,7 +77,7 @@ unsigned long inline ArduinoHal::millis() {
#endif
}
unsigned long inline ArduinoHal::micros() {
RadioLibTime_t inline ArduinoHal::micros() {
#if !defined(RADIOLIB_CLOCK_DRIFT_MS)
return(::micros());
#else
@ -85,7 +85,7 @@ unsigned long inline ArduinoHal::micros() {
#endif
}
long inline ArduinoHal::pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) {
long inline ArduinoHal::pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout) {
if(pin == RADIOLIB_NC) {
return 0;
}
@ -114,7 +114,7 @@ void inline ArduinoHal::spiEnd() {
spi->end();
}
void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) {
void inline ArduinoHal::tone(uint32_t pin, unsigned int frequency, RadioLibTime_t duration) {
#if !defined(RADIOLIB_TONE_UNSUPPORTED)
if(pin == RADIOLIB_NC) {
return;

View file

@ -32,7 +32,7 @@ class ArduinoHal : public RadioLibHal {
\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);
explicit ArduinoHal(SPIClass& spi, SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS);
// implementations of pure virtual RadioLibHal methods
void pinMode(uint32_t pin, uint32_t mode) override;
@ -40,11 +40,11 @@ class ArduinoHal : public RadioLibHal {
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 delay(RadioLibTime_t ms) override;
void delayMicroseconds(RadioLibTime_t us) override;
RadioLibTime_t millis() override;
RadioLibTime_t micros() override;
long pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout) override;
void spiBegin() override;
void spiBeginTransaction() override;
void spiTransfer(uint8_t* out, size_t len, uint8_t* in) override;
@ -54,13 +54,13 @@ class ArduinoHal : public RadioLibHal {
// 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 tone(uint32_t pin, unsigned int frequency, RadioLibTime_t duration = 0) override;
void noTone(uint32_t pin) override;
void yield() override;
uint32_t pinToInterrupt(uint32_t pin) override;
#if !RADIOLIB_GODMODE
private:
protected:
#endif
SPIClass* spi = NULL;
SPISettings spiSettings = RADIOLIB_DEFAULT_SPI_SETTINGS;

View file

@ -1,6 +1,8 @@
#if !defined(_RADIOLIB_BUILD_OPTIONS_H)
#define _RADIOLIB_BUILD_OPTIONS_H
#include "TypeDef.h"
/* RadioLib build configuration options */
/*
@ -350,12 +352,12 @@
// ... and for the grand finale, we have millis() and micros() DEFINED AS MACROS!
#if defined(millis)
#undef millis
inline unsigned long millis() { return((unsigned long)(STCV / 1000)); };
inline RadioLibTime_t millis() { return((RadioLibTime_t)(STCV / 1000)); };
#endif
#if defined(micros)
#undef micros
inline unsigned long micros() { return((unsigned long)(STCV)); };
inline RadioLibTime_t micros() { return((RadioLibTime_t)(STCV)); };
#endif
#elif defined(TEENSYDUINO)
@ -529,6 +531,17 @@
#define RADIOLIB_DEBUG_SPI_HEXDUMP(...) {}
#endif
// debug info strings
#define RADIOLIB_VALUE_TO_STRING(x) #x
#define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x)
#define RADIOLIB_INFO "\nRadioLib Info\nVersion: \"" \
RADIOLIB_VALUE(RADIOLIB_VERSION_MAJOR) "." \
RADIOLIB_VALUE(RADIOLIB_VERSION_MINOR) "." \
RADIOLIB_VALUE(RADIOLIB_VERSION_PATCH) "." \
RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\"\n" \
"Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "\n" \
"Compiled: " RADIOLIB_VALUE(__DATE__) " " RADIOLIB_VALUE(__TIME__)
/*!
\brief A simple assert macro, will return on error.
@ -563,4 +576,4 @@
#define RADIOLIB_VERSION (((RADIOLIB_VERSION_MAJOR) << 24) | ((RADIOLIB_VERSION_MINOR) << 16) | ((RADIOLIB_VERSION_PATCH) << 8) | (RADIOLIB_VERSION_EXTRA))
#endif
#endif

View file

@ -16,7 +16,7 @@ void RadioLibHal::term() {
}
void RadioLibHal::tone(uint32_t pin, unsigned int frequency, unsigned long duration) {
void RadioLibHal::tone(uint32_t pin, unsigned int frequency, RadioLibTime_t duration) {
(void)pin;
(void)frequency;
(void)duration;

View file

@ -104,28 +104,28 @@ class RadioLibHal {
Must be implemented by the platform-specific hardware abstraction!
\param ms Number of milliseconds to wait.
*/
virtual void delay(unsigned long ms) = 0;
virtual void delay(RadioLibTime_t 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;
virtual void delayMicroseconds(RadioLibTime_t 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;
virtual RadioLibTime_t 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;
virtual RadioLibTime_t micros() = 0;
/*!
\brief Measure the length of incoming digital pulse in microseconds.
@ -135,7 +135,7 @@ class RadioLibHal {
\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;
virtual long pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout) = 0;
/*!
\brief SPI initialization method.
@ -188,7 +188,7 @@ class RadioLibHal {
\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);
virtual void tone(uint32_t pin, unsigned int frequency, RadioLibTime_t duration = 0);
/*!
\brief Method to stop producing a tone.

View file

@ -31,8 +31,7 @@ Module::Module(const Module& mod) {
}
Module& Module::operator=(const Module& mod) {
this->SPIreadCommand = mod.SPIreadCommand;
this->SPIwriteCommand = mod.SPIwriteCommand;
memcpy((void*)&mod.spiConfig, &this->spiConfig, sizeof(SPIConfig_t));
this->csPin = mod.csPin;
this->irqPin = mod.irqPin;
this->rstPin = mod.rstPin;
@ -40,14 +39,12 @@ Module& Module::operator=(const Module& mod) {
return(*this);
}
static volatile const char info[] = RADIOLIB_INFO;
void Module::init() {
this->hal->init();
this->hal->pinMode(csPin, this->hal->GpioModeOutput);
this->hal->digitalWrite(csPin, this->hal->GpioLevelHigh);
RADIOLIB_DEBUG_BASIC_PRINTLN("RadioLib Debug Info");
RADIOLIB_DEBUG_BASIC_PRINTLN("Version: %d.%d.%d.%d", RADIOLIB_VERSION_MAJOR, RADIOLIB_VERSION_MINOR, RADIOLIB_VERSION_PATCH, RADIOLIB_VERSION_EXTRA);
RADIOLIB_DEBUG_BASIC_PRINTLN("Platform: " RADIOLIB_PLATFORM);
RADIOLIB_DEBUG_BASIC_PRINTLN("Compiled: " __DATE__ " " __TIME__ "\n");
RADIOLIB_DEBUG_BASIC_PRINTLN(RADIOLIB_INFO);
}
void Module::term() {
@ -55,7 +52,7 @@ void Module::term() {
this->hal->term();
}
int16_t Module::SPIgetRegValue(uint16_t reg, uint8_t msb, uint8_t lsb) {
int16_t Module::SPIgetRegValue(uint32_t reg, uint8_t msb, uint8_t lsb) {
if((msb > 7) || (lsb > 7) || (lsb > msb)) {
return(RADIOLIB_ERR_INVALID_BIT_RANGE);
}
@ -65,7 +62,7 @@ int16_t Module::SPIgetRegValue(uint16_t reg, uint8_t msb, uint8_t lsb) {
return(maskedValue);
}
int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t lsb, uint8_t checkInterval, uint8_t checkMask) {
int16_t Module::SPIsetRegValue(uint32_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);
}
@ -78,14 +75,19 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t
#if 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->hal->micros();
RadioLibTime_t start = this->hal->micros();
#if RADIOLIB_DEBUG_SPI
uint8_t readValue = 0x00;
#endif
while(this->hal->micros() - start < (checkInterval * 1000)) {
readValue = SPIreadRegister(reg);
if((readValue & checkMask) == (newValue & checkMask)) {
uint8_t val = SPIreadRegister(reg);
if((val & checkMask) == (newValue & checkMask)) {
// check passed, we can stop the loop
return(RADIOLIB_ERR_NONE);
}
#if RADIOLIB_DEBUG_SPI
readValue = val;
#endif
}
// check failed, print debug info
@ -104,47 +106,75 @@ int16_t Module::SPIsetRegValue(uint16_t reg, uint8_t value, uint8_t msb, uint8_t
#endif
}
void Module::SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inBytes) {
if(!SPIstreamType) {
SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes);
void Module::SPIreadRegisterBurst(uint32_t reg, size_t numBytes, uint8_t* inBytes) {
if(!this->spiConfig.stream) {
SPItransfer(this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ], 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 cmd[6];
uint8_t* cmdPtr = cmd;
for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
*(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] >> 8*i) & 0xFF;
}
for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) {
*(cmdPtr++) = (reg >> 8*i) & 0xFF;
}
SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, false, NULL, inBytes, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT);
}
}
uint8_t Module::SPIreadRegister(uint16_t reg) {
uint8_t Module::SPIreadRegister(uint32_t reg) {
uint8_t resp = 0;
if(!SPIstreamType) {
SPItransfer(SPIreadCommand, reg, NULL, &resp, 1);
if(!spiConfig.stream) {
SPItransfer(this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ], 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);
uint8_t cmd[6];
uint8_t* cmdPtr = cmd;
for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
*(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] >> 8*i) & 0xFF;
}
for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) {
*(cmdPtr++) = (reg >> 8*i) & 0xFF;
}
SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, false, NULL, &resp, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT);
}
return(resp);
}
void Module::SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes) {
if(!SPIstreamType) {
SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes);
void Module::SPIwriteRegisterBurst(uint32_t reg, uint8_t* data, size_t numBytes) {
if(!spiConfig.stream) {
SPItransfer(spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE], 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);
uint8_t cmd[6];
uint8_t* cmdPtr = cmd;
for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
*(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] >> 8*i) & 0xFF;
}
for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) {
*(cmdPtr++) = (reg >> 8*i) & 0xFF;
}
SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, true, data, NULL, numBytes, true, RADIOLIB_MODULE_SPI_TIMEOUT);
}
}
void Module::SPIwriteRegister(uint16_t reg, uint8_t data) {
if(!SPIstreamType) {
SPItransfer(SPIwriteCommand, reg, &data, NULL, 1);
void Module::SPIwriteRegister(uint32_t reg, uint8_t data) {
if(!spiConfig.stream) {
SPItransfer(spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE], 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);
uint8_t cmd[6];
uint8_t* cmdPtr = cmd;
for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
*(cmdPtr++) = (this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] >> 8*i) & 0xFF;
}
for(int8_t i = (int8_t)((this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8) - 1); i >= 0; i--) {
*(cmdPtr++) = (reg >> 8*i) & 0xFF;
}
SPItransferStream(cmd, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8, true, &data, NULL, 1, true, RADIOLIB_MODULE_SPI_TIMEOUT);
}
}
void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) {
void Module::SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) {
// prepare the buffers
size_t buffLen = this->SPIaddrWidth/8 + numBytes;
size_t buffLen = this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 + this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8 + numBytes;
#if RADIOLIB_STATIC_ONLY
uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE];
uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE];
@ -155,7 +185,8 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d
uint8_t* buffOutPtr = buffOut;
// copy the command
if(this->SPIaddrWidth <= 8) {
// TODO properly handle variable commands and addresses
if(this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] <= 8) {
*(buffOutPtr++) = reg | cmd;
} else {
*(buffOutPtr++) = (reg >> 8) | cmd;
@ -163,10 +194,10 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d
}
// copy the data
if(cmd == SPIwriteCommand) {
if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE]) {
memcpy(buffOutPtr, dataOut, numBytes);
} else {
memset(buffOutPtr, this->SPInopCommand, numBytes);
memset(buffOutPtr, this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP], numBytes);
}
// do the transfer
@ -177,19 +208,19 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d
this->hal->spiEndTransaction();
// copy the data
if(cmd == SPIreadCommand) {
memcpy(dataIn, &buffIn[this->SPIaddrWidth/8], numBytes);
if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ]) {
memcpy(dataIn, &buffIn[this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8], numBytes);
}
// print debug information
#if RADIOLIB_DEBUG_SPI
uint8_t* debugBuffPtr = NULL;
if(cmd == SPIwriteCommand) {
if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE]) {
RADIOLIB_DEBUG_SPI_PRINT("W\t%X\t", reg);
debugBuffPtr = &buffOut[this->SPIaddrWidth/8];
} else if(cmd == SPIreadCommand) {
debugBuffPtr = &buffOut[this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8];
} else if(cmd == spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ]) {
RADIOLIB_DEBUG_SPI_PRINT("R\t%X\t", reg);
debugBuffPtr = &buffIn[this->SPIaddrWidth/8];
debugBuffPtr = &buffIn[this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR]/8];
}
for(size_t n = 0; n < numBytes; n++) {
RADIOLIB_DEBUG_SPI_PRINT_NOTAG("%X\t", debugBuffPtr[n]);
@ -203,8 +234,13 @@ void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* d
#endif
}
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(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
uint8_t cmdBuf[2];
uint8_t* cmdPtr = cmdBuf;
for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
*(cmdPtr++) = (cmd >> 8*i) & 0xFF;
}
return(this->SPIreadStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify));
}
int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
@ -212,16 +248,27 @@ int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_
int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT);
RADIOLIB_ASSERT(state);
#if !RADIOLIB_SPI_PARANOID
(void)verify;
return(RADIOLIB_ERR_NONE);
#else
// check the status
if(verify) {
state = this->SPIcheckStream();
if(verify && (this->spiConfig.checkStatusCb != nullptr)) {
state = this->spiConfig.checkStatusCb(this);
}
return(state);
#endif
}
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(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
uint8_t cmdBuf[2];
uint8_t* cmdPtr = cmdBuf;
for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
*(cmdPtr++) = (cmd >> 8*i) & 0xFF;
}
return(this->SPIwriteStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, data, numBytes, waitForGpio, verify));
}
int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
@ -229,12 +276,18 @@ int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size
int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT);
RADIOLIB_ASSERT(state);
#if !RADIOLIB_SPI_PARANOID
(void)verify;
return(RADIOLIB_ERR_NONE);
#else
// check the status
if(verify) {
state = this->SPIcheckStream();
if(verify && (this->spiConfig.checkStatusCb != nullptr)) {
state = this->spiConfig.checkStatusCb(this);
}
return(state);
#endif
}
int16_t Module::SPIcheckStream() {
@ -243,31 +296,33 @@ int16_t Module::SPIcheckStream() {
#if RADIOLIB_SPI_PARANOID
// get the status
uint8_t spiStatus = 0;
uint8_t cmd = this->SPIstatusCommand;
state = this->SPItransferStream(&cmd, 1, false, NULL, &spiStatus, 0, true, RADIOLIB_MODULE_SPI_TIMEOUT);
uint8_t cmdBuf[2];
uint8_t* cmdPtr = cmdBuf;
for(int8_t i = (int8_t)this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8 - 1; i >= 0; i--) {
*(cmdPtr++) = ( this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] >> 8*i) & 0xFF;
}
state = this->SPItransferStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, 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);
if(this->spiConfig.parseStatusCb != nullptr) {
this->spiConfig.err = this->spiConfig.parseStatusCb(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) {
// prepare the buffers
int16_t Module::SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, RadioLibTime_t timeout) {
// prepare the output buffer
size_t buffLen = cmdLen + numBytes;
if(!write) {
buffLen++;
buffLen += (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8);
}
#if RADIOLIB_STATIC_ONLY
uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE];
uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* buffOut = new uint8_t[buffLen];
uint8_t* buffIn = new uint8_t[buffLen];
#endif
uint8_t* buffOutPtr = buffOut;
@ -280,27 +335,33 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint
if(write) {
memcpy(buffOutPtr, dataOut, numBytes);
} else {
memset(buffOutPtr, this->SPInopCommand, numBytes + 1);
memset(buffOutPtr, this->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP], numBytes + (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8));
}
// ensure GPIO is low
if(this->gpioPin == RADIOLIB_NC) {
this->hal->delay(1);
this->hal->delay(50);
} else {
uint32_t start = this->hal->millis();
RadioLibTime_t start = this->hal->millis();
while(this->hal->digitalRead(this->gpioPin)) {
this->hal->yield();
if(this->hal->millis() - start >= timeout) {
RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?");
#if !RADIOLIB_STATIC_ONLY
delete[] buffOut;
delete[] buffIn;
#endif
return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
}
}
}
// prepare the input buffer
#if RADIOLIB_STATIC_ONLY
uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE];
#else
uint8_t* buffIn = new uint8_t[buffLen];
#endif
// do the transfer
this->hal->spiBeginTransaction();
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow);
@ -314,7 +375,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint
this->hal->delay(1);
} else {
this->hal->delayMicroseconds(1);
uint32_t start = this->hal->millis();
RadioLibTime_t start = this->hal->millis();
while(this->hal->digitalRead(this->gpioPin)) {
this->hal->yield();
if(this->hal->millis() - start >= timeout) {
@ -331,14 +392,14 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint
// parse status
int16_t state = RADIOLIB_ERR_NONE;
if((this->SPIparseStatusCb != nullptr) && (numBytes > 0)) {
state = this->SPIparseStatusCb(buffIn[cmdLen]);
if((this->spiConfig.parseStatusCb != nullptr) && (numBytes > 0)) {
state = this->spiConfig.parseStatusCb(buffIn[this->spiConfig.statusPos]);
}
// copy the data
if(!write) {
// skip the first byte for read-type commands (status-only)
memcpy(dataIn, &buffIn[cmdLen + 1], numBytes);
// skip the status bytes if present
memcpy(dataIn, &buffIn[cmdLen + (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8)], numBytes);
}
// print debug information
@ -380,7 +441,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint
return(state);
}
void Module::waitForMicroseconds(uint32_t start, uint32_t len) {
void Module::waitForMicroseconds(RadioLibTime_t start, RadioLibTime_t len) {
#if RADIOLIB_INTERRUPT_TIMING
(void)start;
if((this->TimerSetupCb != nullptr) && (len != this->prevTimingLen)) {
@ -410,8 +471,8 @@ uint32_t Module::reflect(uint32_t in, uint8_t bits) {
void Module::hexdump(const char* level, 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, "%07" PRIx32 " ", i+offset);
char str[120];
sprintf(str, "%07" PRIx32 " ", (uint32_t)i+offset);
size_t line_len = 16;
if(rem_len < line_len) {
line_len = rem_len;
@ -436,15 +497,21 @@ void Module::hexdump(const char* level, uint8_t* data, size_t len, uint32_t offs
}
str[56] = '|';
str[57] = ' ';
// at this point we need to start escaping "%" characters
char* strPtr = &str[58];
for(size_t j = 0; j < line_len; j++) {
char c = data[i+j];
if((c < ' ') || (c > '~')) {
c = '.';
} else if(c == '%') {
*strPtr++ = '%';
}
sprintf(&str[58 + j], "%c", c);
sprintf(strPtr++, "%c", c);
}
for(size_t j = line_len; j < 16; j++) {
sprintf(&str[58 + j], " ");
sprintf(strPtr++, " ");
}
if(level) {
RADIOLIB_DEBUG_PRINT(level);
@ -487,7 +554,7 @@ size_t Module::serialPrintf(const char* format, ...) {
vsnprintf(buffer, len + 1, format, arg);
va_end(arg);
}
len = RADIOLIB_DEBUG_PORT.write((const uint8_t*)buffer, len);
len = RADIOLIB_DEBUG_PORT.write(reinterpret_cast<const uint8_t*>(buffer), len);
if (buffer != temp) {
delete[] buffer;
}

View file

@ -13,16 +13,53 @@
#endif
/*!
* Value to use as the last element in a mode table to indicate the
* end of the table.
*
* See setRfSwitchTable() for details.
\def END_OF_MODE_TABLE Value to use as the last element in a mode table to indicate the
end of the table. See \ref setRfSwitchTable for details.
*/
#define END_OF_MODE_TABLE { Module::MODE_END_OF_TABLE, {} }
// default timeout for SPI transfers
#define RADIOLIB_MODULE_SPI_TIMEOUT (1000)
/*!
\defgroup module_spi_command_pos Position of commands in Module::spiConfig command array.
\{
*/
/*! \def RADIOLIB_MODULE_SPI_COMMAND_READ Position of the read command. */
#define RADIOLIB_MODULE_SPI_COMMAND_READ (0)
/*! \def RADIOLIB_MODULE_SPI_COMMAND_WRITE Position of the write command. */
#define RADIOLIB_MODULE_SPI_COMMAND_WRITE (1)
/*! \def RADIOLIB_MODULE_SPI_COMMAND_NOP Position of the no-operation command. */
#define RADIOLIB_MODULE_SPI_COMMAND_NOP (2)
/*! \def RADIOLIB_MODULE_SPI_COMMAND_STATUS Position of the status command. */
#define RADIOLIB_MODULE_SPI_COMMAND_STATUS (3)
/*!
\}
*/
/*!
\defgroup module_spi_width_pos Position of bit field widths in Module::spiConfig width array.
\{
*/
/*! \def RADIOLIB_MODULE_SPI_WIDTH_ADDR Position of the address width. */
#define RADIOLIB_MODULE_SPI_WIDTH_ADDR (0)
/*! \def RADIOLIB_MODULE_SPI_WIDTH_CMD Position of the command width. */
#define RADIOLIB_MODULE_SPI_WIDTH_CMD (1)
/*! \def RADIOLIB_MODULE_SPI_WIDTH_STATUS Position of the status width. */
#define RADIOLIB_MODULE_SPI_WIDTH_STATUS (2)
/*!
\}
*/
/*!
\class Module
\brief Implements all common low-level methods to control the wireless module.
@ -31,43 +68,49 @@
class Module {
public:
/*!
* \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).
*/
\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;
/*!
* Description of RF switch pin states for a single mode.
*
* See setRfSwitchTable() for details.
*/
\struct RfSwitchMode_t
\brief Description of RF switch pin states for a single mode.
See \ref setRfSwitchTable for details.
*/
struct RfSwitchMode_t {
/*! \brief RF switching mode, one of \ref OpMode_t or a custom radio-defined value. */
uint8_t mode;
/*! \brief Output pin values */
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
\brief 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 \ref 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 */
/*!
\brief 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 */
/*! \brief Idle mode */
MODE_IDLE,
/*! Receive mode */
/*! \brief Receive mode */
MODE_RX,
/*! Transmission mode */
/*! \brief Transmission mode */
MODE_TX,
};
@ -111,62 +154,64 @@ class Module {
/*!
\brief Overload for assignment operator.
\param frame rvalue Module.
\param mod rvalue Module.
*/
Module& operator=(const Module& mod);
// public member variables
/*!
\brief Hardware abstraction layer to be used.
*/
/*! \brief Hardware abstraction layer to be used. */
RadioLibHal* hal = NULL;
/*!
\brief Basic SPI read command. Defaults to 0x00.
*/
uint8_t SPIreadCommand = 0b00000000;
/*!
\brief Basic SPI write command. Defaults to 0x80.
*/
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.
*/
/*! \brief Callback for parsing SPI status. */
typedef int16_t (*SPIparseStatusCb_t)(uint8_t in);
/*! \brief Callback for validation SPI status. */
typedef int16_t (*SPIcheckStatusCb_t)(Module* mod);
enum BitWidth_t {
BITS_0 = 0,
BITS_8 = 8,
BITS_16 = 16,
BITS_32 = 32,
};
/*!
\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).
\struct SPIConfig_t
\brief SPI configuration structure.
*/
SPIparseStatusCb_t SPIparseStatusCb = nullptr;
struct SPIConfig_t {
/*! \brief Whether the SPI module is stream-type (SX126x/8x) or registrer access type (SX127x, CC1101 etc). */
bool stream;
/*! \brief Last recorded SPI error - only updated for modules that return status during SPI transfers. */
int16_t err;
/*! \brief SPI commands */
uint16_t cmds[4];
/*! \brief Bit widths of SPI addresses, commands and status bytes */
BitWidth_t widths[3];
/*! \brief Byte position of status command in SPI stream */
uint8_t statusPos;
/*! \brief Callback for parsing SPI status. */
SPIparseStatusCb_t parseStatusCb;
/*! \brief Callback for validation SPI status. */
SPIcheckStatusCb_t checkStatusCb;
};
/*! \brief SPI configuration structure. The default configuration corresponds to register-access modules, such as SX127x. */
SPIConfig_t spiConfig = {
.stream = false,
.err = RADIOLIB_ERR_UNKNOWN,
.cmds = { 0x00, 0x80, 0x00, 0x00 },
.widths = { Module::BITS_8, Module::BITS_0, Module::BITS_8 },
.statusPos = 0,
.parseStatusCb = nullptr,
.checkStatusCb = nullptr,
};
#if RADIOLIB_INTERRUPT_TIMING
@ -208,7 +253,7 @@ class Module {
\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(uint16_t reg, uint8_t msb = 7, uint8_t lsb = 0);
int16_t SPIgetRegValue(uint32_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.
@ -220,7 +265,7 @@ class Module {
\param checkMask Mask of bits to check, only bits set to 1 will be verified.
\returns \ref status_codes
*/
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);
int16_t SPIsetRegValue(uint32_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.
@ -228,14 +273,14 @@ class Module {
\param numBytes Number of bytes that will be read.
\param inBytes Pointer to array that will hold the read data.
*/
void SPIreadRegisterBurst(uint16_t reg, size_t numBytes, uint8_t* inBytes);
void SPIreadRegisterBurst(uint32_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(uint16_t reg);
uint8_t SPIreadRegister(uint32_t reg);
/*!
\brief SPI burst write method.
@ -243,14 +288,14 @@ class Module {
\param data Pointer to array that holds the data that will be written.
\param numBytes Number of bytes that will be written.
*/
void SPIwriteRegisterBurst(uint16_t reg, uint8_t* data, size_t numBytes);
void SPIwriteRegisterBurst(uint32_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(uint16_t reg, uint8_t data);
void SPIwriteRegister(uint32_t reg, uint8_t data);
/*!
\brief SPI single transfer method.
@ -260,7 +305,7 @@ class Module {
\param dataIn Data that was transferred from slave to master.
\param numBytes Number of bytes to transfer.
*/
void SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes);
void SPItransfer(uint16_t cmd, uint32_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes);
/*!
\brief Method to check the result of last SPI stream transfer.
@ -277,7 +322,7 @@ class Module {
\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);
int16_t SPIreadStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true);
/*!
\brief Method to perform a read transaction with SPI stream.
@ -300,7 +345,7 @@ class Module {
\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);
int16_t SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio = true, bool verify = true);
/*!
\brief Method to perform a write transaction with SPI stream.
@ -326,7 +371,7 @@ class Module {
\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);
int16_t SPItransferStream(const uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, RadioLibTime_t timeout);
// pin number access methods
@ -438,7 +483,7 @@ class Module {
/*!
\brief Find a mode in the RfSwitchTable.
\param The mode to find.
\param mode 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.
@ -458,7 +503,7 @@ class Module {
\param start Waiting start timestamp, in microseconds.
\param len Waiting duration, in microseconds;
*/
void waitForMicroseconds(uint32_t start, uint32_t len);
void waitForMicroseconds(RadioLibTime_t start, RadioLibTime_t len);
/*!
\brief Function to reflect bits within a byte.

View file

@ -53,16 +53,7 @@
// print debug info
#if RADIOLIB_DEBUG
#define RADIOLIB_VALUE_TO_STRING(x) #x
#define RADIOLIB_VALUE(x) RADIOLIB_VALUE_TO_STRING(x)
#pragma message("\nRadioLib Debug Info\nVersion: \"" \
RADIOLIB_VALUE(RADIOLIB_VERSION_MAJOR) "." \
RADIOLIB_VALUE(RADIOLIB_VERSION_MINOR) "." \
RADIOLIB_VALUE(RADIOLIB_VERSION_PATCH) "." \
RADIOLIB_VALUE(RADIOLIB_VERSION_EXTRA) "\"\n" \
"Platform: " RADIOLIB_VALUE(RADIOLIB_PLATFORM) "\n" \
"Compiled: " RADIOLIB_VALUE(__DATE__) " " RADIOLIB_VALUE(__TIME__) \
)
#pragma message(RADIOLIB_INFO)
#endif
// check unknown/unsupported platform
@ -77,6 +68,9 @@
#include "modules/CC1101/CC1101.h"
#include "modules/LLCC68/LLCC68.h"
#include "modules/LR11x0/LR1110.h"
#include "modules/LR11x0/LR1120.h"
#include "modules/LR11x0/LR1121.h"
#include "modules/nRF24/nRF24.h"
#include "modules/RF69/RF69.h"
#include "modules/RFM2x/RFM22.h"

View file

@ -563,6 +563,28 @@
*/
#define RADIOLIB_LORAWAN_NO_DOWNLINK (-1116)
// LR11x0-specific status codes
/*!
\brief The selected 802.11 WiFi type is invalid.
*/
#define RADIOLIB_ERR_INVALID_WIFI_TYPE (-1200)
/*!
\}
*/
/*!
\defgroup typedefs Type aliases used by RadioLib.
\{
*/
/*!
\brief Type used for durations in RadioLib
*/
typedef unsigned long RadioLibTime_t;
/*!
\}
*/

View file

@ -8,8 +8,8 @@ CC1101::CC1101(Module* module) : PhysicalLayer(RADIOLIB_CC1101_FREQUENCY_STEP_SI
int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t pwr, uint8_t preambleLength) {
// set module properties
this->mod->SPIreadCommand = RADIOLIB_CC1101_CMD_READ;
this->mod->SPIwriteCommand = RADIOLIB_CC1101_CMD_WRITE;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_CC1101_CMD_READ;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_CC1101_CMD_WRITE;
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
@ -100,29 +100,29 @@ void CC1101::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)) / (this->bitRate * 1000.0)) * 5000000.0);
RadioLibTime_t timeout = 5 + (RadioLibTime_t)((((float)(len * 8)) / this->bitRate) * 5);
// start transmission
int16_t state = startTransmit(data, len, addr);
RADIOLIB_ASSERT(state);
// wait for transmission start or timeout
uint32_t start = this->mod->hal->micros();
RadioLibTime_t start = this->mod->hal->millis();
while(!this->mod->hal->digitalRead(this->mod->getGpio())) {
this->mod->hal->yield();
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
finishTransmit();
return(RADIOLIB_ERR_TX_TIMEOUT);
}
}
// wait for transmission end or timeout
start = this->mod->hal->micros();
start = this->mod->hal->millis();
while(this->mod->hal->digitalRead(this->mod->getGpio())) {
this->mod->hal->yield();
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
finishTransmit();
return(RADIOLIB_ERR_TX_TIMEOUT);
}
@ -133,18 +133,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/(this->bitRate*1000.0))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0);
RadioLibTime_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_CC1101_MAX_PACKET_LENGTH*400.0);
// start reception
int16_t state = startReceive();
RADIOLIB_ASSERT(state);
// wait for packet start or timeout
uint32_t start = this->mod->hal->micros();
RadioLibTime_t start = this->mod->hal->millis();
while(this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
standby();
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX);
return(RADIOLIB_ERR_RX_TIMEOUT);
@ -152,11 +152,11 @@ int16_t CC1101::receive(uint8_t* data, size_t len) {
}
// wait for packet end or timeout
start = this->mod->hal->micros();
start = this->mod->hal->millis();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
standby();
SPIsendCommand(RADIOLIB_CC1101_CMD_FLUSH_RX);
return(RADIOLIB_ERR_RX_TIMEOUT);
@ -172,7 +172,7 @@ int16_t CC1101::standby() {
SPIsendCommand(RADIOLIB_CC1101_CMD_IDLE);
// wait until idle is reached
uint32_t start = this->mod->hal->millis();
RadioLibTime_t start = this->mod->hal->millis();
while(SPIgetRegValue(RADIOLIB_CC1101_REG_MARCSTATE, 4, 0) != RADIOLIB_CC1101_MARC_STATE_IDLE) {
mod->hal->yield();
if(this->mod->hal->millis() - start > 100) {
@ -361,7 +361,7 @@ int16_t CC1101::startReceive() {
return(state);
}
int16_t CC1101::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) {
int16_t CC1101::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) {
(void)timeout;
(void)irqFlags;
(void)irqMask;
@ -489,6 +489,24 @@ int16_t CC1101::setRxBandwidth(float rxBw) {
return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
}
int16_t CC1101::autoSetRxBandwidth() {
// Uncertainty ~ +/- 40ppm for a cheap CC1101
// Uncertainty * 2 for both transmitter and receiver
float uncertainty = ((this->frequency) * 40 * 2);
uncertainty = (uncertainty/1000); //Since bitrate is in kBit
float minbw = ((this->bitRate) + uncertainty);
int possibles[16] = {58, 68, 81, 102, 116, 135, 162, 203, 232, 270, 325, 406, 464, 541, 650, 812};
for (int i = 0; i < 16; i++) {
if (possibles[i] > minbw) {
int16_t state = setRxBandwidth(possibles[i]);
return(state);
}
}
return(RADIOLIB_ERR_UNKNOWN);
}
int16_t CC1101::setFrequencyDeviation(float freqDev) {
// set frequency deviation to lowest available setting (required for digimodes)
float newFreqDev = freqDev;
@ -542,6 +560,62 @@ int16_t CC1101::getFrequencyDeviation(float *freqDev) {
}
int16_t CC1101::setOutputPower(int8_t pwr) {
// check if power value is configurable
uint8_t powerRaw = 0;
int16_t state = checkOutputPower(pwr, NULL, &powerRaw);
RADIOLIB_ASSERT(state);
// store the value
this->power = pwr;
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)
uint8_t paValues[2] = {0x00, powerRaw};
SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_PATABLE, paValues, 2);
return(RADIOLIB_ERR_NONE);
} else {
// Freq modulation:
// PA_TABLE[0] is the power to be used when transmitting.
return(SPIsetRegValue(RADIOLIB_CC1101_REG_PATABLE, powerRaw));
}
}
int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped) {
return(checkOutputPower(power, clipped, NULL));
}
int16_t CC1101::checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw) {
constexpr int8_t allowedPwrs[8] = { -30, -20, -15, -10, 0, 5, 7, 10 };
if(clipped) {
if(power <= -30) {
*clipped = -30;
} else if(power >= 10) {
*clipped = 10;
} else {
for(int i = 0; i < 8; i++) {
if(allowedPwrs[i] > power) {
break;
}
*clipped = allowedPwrs[i];
}
}
}
// if just a check occurs (and not requesting the raw power value), return now
if(!raw) {
for(int i = 0; i < 8; i++) {
if(allowedPwrs[i] == power) {
return(RADIOLIB_ERR_NONE);
}
}
return(RADIOLIB_ERR_INVALID_OUTPUT_POWER);
}
// round to the known frequency settings
uint8_t f;
if(this->frequency < 374.0) {
@ -568,53 +642,35 @@ int16_t CC1101::setOutputPower(int8_t pwr) {
{0xCB, 0xC8, 0xCB, 0xC7},
{0xC2, 0xC0, 0xC2, 0xC0}};
uint8_t powerRaw;
switch(pwr) {
case -30:
powerRaw = paTable[0][f];
switch(power) {
case allowedPwrs[0]: // -30
*raw = paTable[0][f];
break;
case -20:
powerRaw = paTable[1][f];
case allowedPwrs[1]: // -20
*raw = paTable[1][f];
break;
case -15:
powerRaw = paTable[2][f];
case allowedPwrs[2]: // -15
*raw = paTable[2][f];
break;
case -10:
powerRaw = paTable[3][f];
case allowedPwrs[3]: // -10
*raw = paTable[3][f];
break;
case 0:
powerRaw = paTable[4][f];
case allowedPwrs[4]: // 0
*raw = paTable[4][f];
break;
case 5:
powerRaw = paTable[5][f];
case allowedPwrs[5]: // 5
*raw = paTable[5][f];
break;
case 7:
powerRaw = paTable[6][f];
case allowedPwrs[6]: // 7
*raw = paTable[6][f];
break;
case 10:
powerRaw = paTable[7][f];
case allowedPwrs[7]: // 10
*raw = paTable[7][f];
break;
default:
return(RADIOLIB_ERR_INVALID_OUTPUT_POWER);
}
// store the value
this->power = pwr;
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)
uint8_t paValues[2] = {0x00, powerRaw};
SPIwriteRegisterBurst(RADIOLIB_CC1101_REG_PATABLE, paValues, 2);
return(RADIOLIB_ERR_NONE);
} else {
// Freq modulation:
// PA_TABLE[0] is the power to be used when transmitting.
return(SPIsetRegValue(RADIOLIB_CC1101_REG_PATABLE, powerRaw));
}
return(RADIOLIB_ERR_NONE);
}
int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, bool requireCarrierSense) {
@ -740,7 +796,7 @@ int16_t CC1101::setOOK(bool enableOOK) {
float CC1101::getRSSI() {
float rssi;
if (this->directModeEnabled) {
if(!this->directModeEnabled) {
if(this->rawRSSI >= 128) {
rssi = (((float)this->rawRSSI - 256.0)/2.0) - 74.0;
} else {
@ -748,12 +804,9 @@ float CC1101::getRSSI() {
}
} else {
uint8_t rawRssi = SPIreadRegister(RADIOLIB_CC1101_REG_RSSI);
if (rawRssi >= 128)
{
if(rawRssi >= 128) {
rssi = ((rawRssi - 256) / 2) - 74;
}
else
{
} else {
rssi = (rawRssi / 2) - 74;
}
}

View file

@ -537,8 +537,9 @@ class CC1101: public PhysicalLayer {
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
\param module Instance of Module that will be used to communicate with the radio.
*/
// cppcheck-suppress noExplicitConstructor
CC1101(Module* module);
// basic methods
@ -660,23 +661,23 @@ class CC1101: public PhysicalLayer {
\brief Sets interrupt service routine to call when a packet is received.
\param func ISR to call.
*/
void setPacketReceivedAction(void (*func)(void));
void setPacketReceivedAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a packet is received.
*/
void clearPacketReceivedAction();
void clearPacketReceivedAction() override;
/*!
\brief Sets interrupt service routine to call when a packet is sent.
\param func ISR to call.
*/
void setPacketSentAction(void (*func)(void));
void setPacketSentAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a packet is sent.
*/
void clearPacketSentAction();
void clearPacketSentAction() override;
/*!
\brief Interrupt-driven binary transmit method.
@ -698,7 +699,7 @@ class CC1101: public PhysicalLayer {
\brief Interrupt-driven receive method. GDO0 will be activated when full packet is received.
\returns \ref status_codes
*/
int16_t startReceive();
int16_t startReceive() override;
/*!
\brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer.
@ -708,7 +709,7 @@ class CC1101: public PhysicalLayer {
\param len Ignored.
\returns \ref status_codes
*/
int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len);
int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) override;
/*!
\brief Reads data received after calling startReceive method. When the packet length is not known in advance,
@ -728,14 +729,14 @@ class CC1101: public PhysicalLayer {
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
int16_t setFrequency(float freq) override;
/*!
\brief Sets bit rate. Allowed values range from 0.025 to 600.0 kbps.
\param br Bit rate to be set in kbps.
\returns \ref status_codes
*/
int16_t setBitRate(float br);
int16_t setBitRate(float br) override;
/*!
\brief Sets receiver bandwidth. Allowed values are 58, 68, 81, 102, 116, 135, 162,
@ -745,6 +746,14 @@ class CC1101: public PhysicalLayer {
*/
int16_t setRxBandwidth(float rxBw);
/*!
\brief calculates and sets Rx bandwidth based on the freq, baud and freq uncertainty.
Reimplement of atlas0fd00m's (RfCat) CalculatePktChanBw function.
Modified for worse ppm with the CC1101, and adjusted for the supportted CC1101 bw.
\returns \ref status_codes
*/
int16_t autoSetRxBandwidth();
/*!
\brief Sets frequency deviation. Allowed values range from 1.587 to 380.8 kHz.
\param freqDev Frequency deviation to be set in kHz.
@ -764,7 +773,25 @@ class CC1101: public PhysicalLayer {
\param pwr Output power to be set in dBm.
\returns \ref status_codes
*/
int16_t setOutputPower(int8_t pwr);
int16_t setOutputPower(int8_t pwr) override;
/*!
\brief Check if output power is configurable.
This method is needed for compatibility with PhysicalLayer::checkOutputPower.
\param power Output power in dBm.
\param clipped Clipped output power value to what is possible within the module's range.
\returns \ref status_codes
*/
int16_t checkOutputPower(int8_t power, int8_t* clipped) override;
/*!
\brief Check if output power is configurable.
\param power Output power in dBm.
\param clipped Clipped output power value to what is possible within the module's range.
\param raw Raw internal value.
\returns \ref status_codes
*/
int16_t checkOutputPower(int8_t power, int8_t* clipped, uint8_t* raw);
/*!
\brief Sets 16-bit sync word as a two byte value.
@ -789,6 +816,7 @@ class CC1101: public PhysicalLayer {
/*!
\brief Sets preamble length.
\param preambleLength Preamble length to be set (in bits), allowed values: 16, 24, 32, 48, 64, 96, 128 and 192.
\param qualityThreshold Preamble quality threshold (PQT) to set.
\returns \ref status_codes
*/
int16_t setPreambleLength(uint8_t preambleLength, uint8_t qualityThreshold);
@ -820,58 +848,58 @@ class CC1101: public PhysicalLayer {
In asynchronous direct mode, returns the current RSSI level.
\returns RSSI in dBm.
*/
float getRSSI();
float getRSSI() override;
/*!
\brief Gets LQI (Link Quality Indicator) of the last received packet.
\returns Last packet LQI (lower is better).
*/
uint8_t getLQI() const;
uint8_t getLQI() const;
/*!
/*!
\brief Query modem for the packet length of received payload.
\param update Update received packet length. Will return cached value when set to false.
\returns Length of last received packet in bytes.
*/
size_t getPacketLength(bool update = true) override;
/*!
/*!
\brief Set modem in fixed packet length mode.
\param len Packet length.
\returns \ref status_codes
*/
int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_CC1101_MAX_PACKET_LENGTH);
/*!
/*!
\brief Set modem in variable packet length mode.
\param len Maximum packet length.
\param maxLen Maximum packet length.
\returns \ref status_codes
*/
int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_CC1101_MAX_PACKET_LENGTH);
/*!
/*!
\brief Enable sync word filtering and generation.
\param numBits Sync word length in bits.
\param maxErrBits Maximum number of allowed error bits in sync word.
\param requireCarrierSense Require carrier sense above threshold in addition to sync word.
\returns \ref status_codes
*/
int16_t enableSyncWordFiltering(uint8_t maxErrBits = 0, bool requireCarrierSense = false);
/*!
/*!
\brief Disable preamble and sync word filtering and generation.
\param requireCarrierSense Require carrier sense above threshold.
\returns \ref status_codes
*/
int16_t disableSyncWordFiltering(bool requireCarrierSense = false);
/*!
/*!
\brief Enable CRC filtering and generation.
\param enable Set or unset CRC generation and filtering.
\returns \ref status_codes
*/
int16_t setCrcFiltering(bool enable = true);
/*!
/*!
\brief Set modem in "sniff" mode: no packet filtering (e.g., no preamble, sync word, address, CRC).
\param enable Set or unset promiscuous mode.
\param requireCarrierSense Set carriersense required above threshold, defaults to false.
@ -879,7 +907,7 @@ class CC1101: public PhysicalLayer {
*/
int16_t setPromiscuousMode(bool enable = true, bool requireCarrierSense = false);
/*!
/*!
\brief Get whether the modem is in promiscuous mode: no packet filtering
(e.g., no preamble, sync word, address, CRC).
\returns Whether the modem is in promiscuous mode.
@ -909,16 +937,16 @@ class CC1101: public PhysicalLayer {
void setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]);
/*!
\brief Get one truly random byte from RSSI noise.
\returns TRNG byte.
*/
uint8_t randomByte();
\brief Get one truly random byte from RSSI noise.
\returns TRNG byte.
*/
uint8_t randomByte() override;
/*!
\brief Read version SPI register. Should return CC1101_VERSION_LEGACY (0x04) or
CC1101_VERSION_CURRENT (0x14) if CC1101 is connected and working.
\returns Version register contents or \ref status_codes
*/
\brief Read version SPI register. Should return CC1101_VERSION_LEGACY (0x04) or
CC1101_VERSION_CURRENT (0x14) if CC1101 is connected and working.
\returns Version register contents or \ref status_codes
*/
int16_t getChipVersion();
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
@ -926,13 +954,13 @@ class CC1101: public PhysicalLayer {
\brief Set interrupt service routine function to call when data bit is receveid in direct mode.
\param func Pointer to interrupt service routine.
*/
void setDirectAction(void (*func)(void));
void setDirectAction(void (*func)(void)) override;
/*!
\brief Function to read and process data bit in direct reception mode.
\param pin Pin on which to read.
*/
void readBit(uint32_t pin);
void readBit(uint32_t pin) override;
#endif
/*!
@ -941,12 +969,12 @@ class CC1101: public PhysicalLayer {
\param value The value that indicates which function to place on that pin. See chip datasheet for details.
\returns \ref status_codes
*/
int16_t setDIOMapping(uint32_t pin, uint32_t value);
int16_t setDIOMapping(uint32_t pin, uint32_t value) override;
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
Module* getMod();
Module* getMod() override;
// SPI read overrides to set bit for burst write and status registers access
int16_t SPIgetRegValue(uint8_t reg, uint8_t msb = 7, uint8_t lsb = 0);

View file

@ -21,7 +21,7 @@ class LLCC68: public SX1262 {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
LLCC68(Module* mod);
LLCC68(Module* mod); // cppcheck-suppress noExplicitConstructor
/*!
\brief Initialization method for LoRa modem.

View file

@ -0,0 +1,55 @@
#include "LR1110.h"
#if !RADIOLIB_EXCLUDE_LR11X0
LR1110::LR1110(Module* mod) : LR11x0(mod) {
chipType = RADIOLIB_LR11X0_HW_LR1110;
}
int16_t LR1110::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) {
// execute common part
int16_t state = LR11x0::begin(bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
return(state);
}
int16_t LR1110::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) {
// execute common part
int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, power, preambleLength, tcxoVoltage);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
return(state);
}
int16_t LR1110::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) {
// execute common part
int16_t state = LR11x0::beginLRFHSS(bw, cr, power, tcxoVoltage);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
return(state);
}
int16_t LR1110::setFrequency(float freq) {
return(this->setFrequency(freq, true));
}
int16_t LR1110::setFrequency(float freq, bool calibrate, float band) {
RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY);
// calibrate image rejection
if(calibrate) {
int16_t state = LR11x0::calibImage(freq - band, freq + band);
RADIOLIB_ASSERT(state);
}
// set frequency
return(LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f)));
}
#endif

View file

@ -0,0 +1,98 @@
#if !defined(_RADIOLIB_LR1110_H)
#define _RADIOLIB_LR1110_H
#include "../../TypeDef.h"
#if !RADIOLIB_EXCLUDE_LR11X0
#include "../../Module.h"
#include "LR11x0.h"
/*!
\class LR1110
\brief Derived class for %LR1110 modules.
*/
class LR1110: public LR11x0 {
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
LR1110(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
/*!
\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 1-byte LoRa sync word. Defaults to RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12).
\param power 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. Defaults to 1.6 V.
If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
To use XTAL, either set this value to 0, or set LR11x0::XTAL to true.
\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_LR11X0_LORA_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6);
/*!
\brief Initialization method for FSK modem.
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param br FSK bit rate 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 156.2 kHz.
\param power Output power in dBm. Defaults to 10 dBm.
\param preambleLength FSK preamble length in bits. Defaults to 16 bits.
\param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V.
If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
To use XTAL, either set this value to 0, or set LR11x0::XTAL to true.
\returns \ref status_codes
*/
int16_t beginGFSK(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);
/*!
\brief Initialization method for LR-FHSS modem.
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. Defaults to 722.66 kHz.
\param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. Defaults to 2/3 coding rate.
\param power Output power in dBm. Defaults to 10 dBm.
\param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V.
If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
To use XTAL, either set this value to 0, or set LR11x0::XTAL to true.
\returns \ref status_codes
*/
int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LR11X0_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LR11X0_LR_FHSS_CR_2_3, int8_t power = 10, float tcxoVoltage = 1.6);
// configuration methods
/*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz.
Will also perform calibrations.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq) override;
/*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz.
\param freq Carrier frequency to be set in MHz.
\param calibrate Run image calibration.
\param band Half bandwidth for image calibration. For example,
if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate
for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz
\returns \ref status_codes
*/
int16_t setFrequency(float freq, bool calibrate, float band = 4);
#if !RADIOLIB_GODMODE
private:
#endif
};
#endif
#endif

View file

@ -0,0 +1,59 @@
#include "LR1120.h"
#if !RADIOLIB_EXCLUDE_LR11X0
LR1120::LR1120(Module* mod) : LR11x0(mod) {
chipType = RADIOLIB_LR11X0_HW_LR1120;
}
int16_t LR1120::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) {
// execute common part
int16_t state = LR11x0::begin(bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
return(state);
}
int16_t LR1120::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) {
// execute common part
int16_t state = LR11x0::beginGFSK(br, freqDev, rxBw, power, preambleLength, tcxoVoltage);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
return(state);
}
int16_t LR1120::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, int8_t power, float tcxoVoltage) {
// execute common part
int16_t state = LR11x0::beginLRFHSS(bw, cr, power, tcxoVoltage);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
return(state);
}
int16_t LR1120::setFrequency(float freq) {
return(this->setFrequency(freq, true));
}
int16_t LR1120::setFrequency(float freq, bool calibrate, float band) {
if(!(((freq >= 150.0) && (freq <= 960.0)) ||
((freq >= 1900.0) && (freq <= 2200.0)) ||
((freq >= 2400.0) && (freq <= 2500.0)))) {
return(RADIOLIB_ERR_INVALID_FREQUENCY);
}
// calibrate image rejection
if(calibrate) {
int16_t state = LR11x0::calibImage(freq - band, freq + band);
RADIOLIB_ASSERT(state);
}
// set frequency
return(LR11x0::setRfFrequency((uint32_t)(freq*1000000.0f)));
}
#endif

View file

@ -0,0 +1,99 @@
#if !defined(_RADIOLIB_LR1120_H)
#define _RADIOLIB_LR1120_H
#include "../../TypeDef.h"
#if !RADIOLIB_EXCLUDE_LR11X0
#include "../../Module.h"
#include "LR11x0.h"
/*!
\class LR1120
\brief Derived class for %LR1120 modules.
*/
class LR1120: public LR11x0 {
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
LR1120(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
/*!
\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 1-byte LoRa sync word. Defaults to RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE (0x12).
\param power 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. Defaults to 1.6 V.
If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
To use XTAL, either set this value to 0, or set LR11x0::XTAL to true.
\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_LR11X0_LORA_SYNC_WORD_PRIVATE, int8_t power = 10, uint16_t preambleLength = 8, float tcxoVoltage = 1.6);
/*!
\brief Initialization method for FSK modem.
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param br FSK bit rate 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 156.2 kHz.
\param power Output power in dBm. Defaults to 10 dBm.
\param preambleLength FSK preamble length in bits. Defaults to 16 bits.
\param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V.
If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
To use XTAL, either set this value to 0, or set LR11x0::XTAL to true.
\returns \ref status_codes
*/
int16_t beginGFSK(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);
/*!
\brief Initialization method for LR-FHSS modem.
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param bw LR-FHSS bandwidth, one of RADIOLIB_LR11X0_LR_FHSS_BW_* values. Defaults to 722.66 kHz.
\param cr LR-FHSS coding rate, one of RADIOLIB_LR11X0_LR_FHSS_CR_* values. Defaults to 2/3 coding rate.
\param power Output power in dBm. Defaults to 10 dBm.
\param tcxoVoltage TCXO reference voltage to be set. Defaults to 1.6 V.
If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
To use XTAL, either set this value to 0, or set LR11x0::XTAL to true.
\returns \ref status_codes
*/
int16_t beginLRFHSS(float freq = 434.0, uint8_t bw = RADIOLIB_LR11X0_LR_FHSS_BW_722_66, uint8_t cr = RADIOLIB_LR11X0_LR_FHSS_CR_2_3, int8_t power = 10, float tcxoVoltage = 1.6);
// configuration methods
/*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz,
1900 - 2200 MHz and 2400 - 2500 MHz. Will also perform calibrations.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq) override;
/*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz,
1900 - 2200 MHz and 2400 - 2500 MHz. Will also perform calibrations.
\param freq Carrier frequency to be set in MHz.
\param calibrate Run image calibration.
\param band Half bandwidth for image calibration. For example,
if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate
for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz
\returns \ref status_codes
*/
int16_t setFrequency(float freq, bool calibrate, float band = 4);
#if !RADIOLIB_GODMODE
private:
#endif
};
#endif
#endif

View file

@ -0,0 +1,8 @@
#include "LR1121.h"
#if !RADIOLIB_EXCLUDE_LR11X0
LR1121::LR1121(Module* mod) : LR1120(mod) {
chipType = RADIOLIB_LR11X0_HW_LR1121;
}
#endif

View file

@ -0,0 +1,35 @@
#if !defined(_RADIOLIB_LR1121_H)
#define _RADIOLIB_LR1121_H
#include "../../TypeDef.h"
#if !RADIOLIB_EXCLUDE_LR11X0
#include "../../Module.h"
#include "LR11x0.h"
#include "LR1120.h"
/*!
\class LR1121
\brief Derived class for %LR1121 modules.
*/
class LR1121: public LR1120 {
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
LR1121(Module* mod); // cppcheck-suppress noExplicitConstructor
// TODO this is where overrides to disable GNSS+WiFi scanning methods on LR1121
// will be put once those are implemented
#if !RADIOLIB_GODMODE
private:
#endif
};
#endif
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -100,18 +100,18 @@ void RF69::reset() {
int16_t RF69::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)) / (this->bitRate * 1000.0)) * 5000000.0);
RadioLibTime_t timeout = 5 + (RadioLibTime_t)((((float)(len * 8)) / this->bitRate) * 5);
// start transmission
int16_t state = startTransmit(data, len, addr);
RADIOLIB_ASSERT(state);
// wait for transmission end or timeout
uint32_t start = this->mod->hal->micros();
RadioLibTime_t start = this->mod->hal->millis();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
finishTransmit();
return(RADIOLIB_ERR_TX_TIMEOUT);
}
@ -122,18 +122,18 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) {
int16_t RF69::receive(uint8_t* data, size_t len) {
// calculate timeout (500 ms + 400 full 64-byte packets at current bit rate)
uint32_t timeout = 500000 + (1.0/(this->bitRate*1000.0))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0);
RadioLibTime_t timeout = 500 + (1.0/(this->bitRate))*(RADIOLIB_RF69_MAX_PACKET_LENGTH*400.0);
// start reception
int16_t state = startReceive();
RADIOLIB_ASSERT(state);
// wait for packet reception or timeout
uint32_t start = this->mod->hal->micros();
RadioLibTime_t start = this->mod->hal->millis();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
standby();
clearIRQFlags();
return(RADIOLIB_ERR_RX_TIMEOUT);
@ -259,7 +259,7 @@ int16_t RF69::startReceive() {
return(state);
}
int16_t RF69::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) {
int16_t RF69::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) {
(void)timeout;
(void)irqFlags;
(void)irqMask;
@ -566,9 +566,9 @@ int16_t RF69::setBitRate(float br) {
setMode(RADIOLIB_RF69_STANDBY);
// set bit rate
uint16_t bitRate = 32000 / br;
int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0);
state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0);
uint16_t bitRateRaw = 32000 / br;
int16_t state = this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_MSB, (bitRateRaw & 0xFF00) >> 8, 7, 0);
state |= this->mod->SPIsetRegValue(RADIOLIB_RF69_REG_BITRATE_LSB, bitRateRaw & 0x00FF, 7, 0);
if(state == RADIOLIB_ERR_NONE) {
this->bitRate = br;
}

View file

@ -486,9 +486,9 @@ class RF69: public PhysicalLayer {
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
\param module Instance of Module that will be used to communicate with the radio.
*/
RF69(Module* module);
RF69(Module* module); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -538,7 +538,7 @@ class RF69: public PhysicalLayer {
\brief Sets the module to sleep mode.
\returns \ref status_codes
*/
int16_t sleep();
int16_t sleep() override;
/*!
\brief Sets the module to standby mode.
@ -575,7 +575,7 @@ class RF69: public PhysicalLayer {
/*!
\brief Sets AES key.
\param Key to be used for AES encryption. Must be exactly 16 bytes long.
\param key Key to be used for AES encryption. Must be exactly 16 bytes long.
*/
void setAESKey(uint8_t* key);
@ -619,23 +619,23 @@ class RF69: public PhysicalLayer {
\brief Sets interrupt service routine to call when a packet is received.
\param func ISR to call.
*/
void setPacketReceivedAction(void (*func)(void));
void setPacketReceivedAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a packet is received.
*/
void clearPacketReceivedAction();
void clearPacketReceivedAction() override;
/*!
\brief Sets interrupt service routine to call when a packet is sent.
\param func ISR to call.
*/
void setPacketSentAction(void (*func)(void));
void setPacketSentAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a packet is sent.
*/
void clearPacketSentAction();
void clearPacketSentAction() override;
/*!
\brief Set interrupt service routine function to call when FIFO is empty.
@ -697,7 +697,7 @@ class RF69: public PhysicalLayer {
\brief Interrupt-driven receive method. GDO0 will be activated when full packet is received.
\returns \ref status_codes
*/
int16_t startReceive();
int16_t startReceive() override;
/*!
\brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer.
@ -707,7 +707,7 @@ class RF69: public PhysicalLayer {
\param len Ignored.
\returns \ref status_codes
*/
int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len);
int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) override;
/*!
\brief Reads data received after calling startReceive method. When the packet length is not known in advance,
@ -727,7 +727,7 @@ class RF69: public PhysicalLayer {
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
int16_t setFrequency(float freq) override;
/*!
\brief Gets carrier frequency.
@ -741,7 +741,7 @@ class RF69: public PhysicalLayer {
\param br Bit rate to be set in kbps.
\returns \ref status_codes
*/
int16_t setBitRate(float br);
int16_t setBitRate(float br) override;
/*!
\brief Sets receiver bandwidth. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6,
@ -872,14 +872,14 @@ class RF69: public PhysicalLayer {
/*!
\brief Set modem in variable packet length mode.
\param len Maximum packet length.
\param maxLen Maximum packet length.
\returns \ref status_codes
*/
int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_RF69_MAX_PACKET_LENGTH);
/*!
\brief Enable sync word filtering and generation.
\param numBits Sync word length in bits.
\param maxErrBits Maximum allowed number of error bits in sync word.
\returns \ref status_codes
*/
int16_t enableSyncWordFiltering(uint8_t maxErrBits = 0);
@ -944,7 +944,7 @@ class RF69: public PhysicalLayer {
\brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet.
\returns Last packet RSSI in dBm.
*/
float getRSSI();
float getRSSI() override;
/*!
\brief Sets the RSSI value above which the RSSI interrupt is signaled
@ -963,7 +963,7 @@ class RF69: public PhysicalLayer {
\brief Get one truly random byte from RSSI noise.
\returns TRNG byte.
*/
uint8_t randomByte();
uint8_t randomByte() override;
/*!
\brief Read version SPI register. Should return RF69_CHIP_VERSION (0x24) if SX127x is connected and working.
@ -976,13 +976,13 @@ class RF69: public PhysicalLayer {
\brief Set interrupt service routine function to call when data bit is received in direct mode.
\param func Pointer to interrupt service routine.
*/
void setDirectAction(void (*func)(void));
void setDirectAction(void (*func)(void)) override;
/*!
\brief Function to read and process data bit in direct reception mode.
\param pin Pin on which to read.
*/
void readBit(uint32_t pin);
void readBit(uint32_t pin) override;
#endif
/*!
@ -991,12 +991,12 @@ class RF69: public PhysicalLayer {
\param value The value that indicates which function to place on that pin. See chip datasheet for details.
\returns \ref status_codes
*/
int16_t setDIOMapping(uint32_t pin, uint32_t value);
int16_t setDIOMapping(uint32_t pin, uint32_t value) override;
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
Module* getMod();
Module* getMod() override;
#if !RADIOLIB_GODMODE
protected:

View file

@ -96,7 +96,7 @@ class SX1231: public RF69 {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1231(Module* mod);
SX1231(Module* mod); // cppcheck-suppress noExplicitConstructor
/*!
\brief Initialization method.
@ -111,7 +111,7 @@ class SX1231: public RF69 {
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);
#if !RADIOLIB_GODMODE
private:
protected:
#endif
uint8_t chipRevision = 0;
};

View file

@ -26,7 +26,7 @@ class SX1233: public SX1231 {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1233(Module* mod);
SX1233(Module* mod); // cppcheck-suppress noExplicitConstructor
/*!
\brief Initialization method.
@ -48,12 +48,12 @@ class SX1233: public SX1231 {
\param br Bit rate to be set in kbps.
\returns \ref status_codes
*/
int16_t setBitRate(float br);
int16_t setBitRate(float br) override;
#if !RADIOLIB_GODMODE
private:
#endif
uint8_t chipRevision = 0;
};
#endif

View file

@ -87,6 +87,7 @@ int16_t STM32WLx::setOutputPower(int8_t power) {
return(RADIOLIB_ERR_INVALID_OUTPUT_POWER);
}
RADIOLIB_ASSERT(state);
// Apply workaround for HP only
state = SX126x::fixPaClamping(use_hp);

View file

@ -39,7 +39,7 @@ class STM32WLx : public SX1262 {
\brief Default constructor.
\param mod Instance of STM32WLx_Module that will be used to communicate with the radio.
*/
STM32WLx(STM32WLx_Module* mod);
STM32WLx(STM32WLx_Module* mod); // cppcheck-suppress noExplicitConstructor
/*!
\brief Custom operation modes for STMWLx.
@ -124,34 +124,34 @@ class STM32WLx : public SX1262 {
\brief Sets interrupt service routine to call when a packet is received.
\param func ISR to call.
*/
void setPacketReceivedAction(void (*func)(void));
void setPacketReceivedAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a packet is received.
*/
void clearPacketReceivedAction();
void clearPacketReceivedAction() override;
/*!
\brief Sets interrupt service routine to call when a packet is sent.
\param func ISR to call.
*/
void setPacketSentAction(void (*func)(void));
void setPacketSentAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a packet is sent.
*/
void clearPacketSentAction();
void clearPacketSentAction() override;
/*!
\brief Sets interrupt service routine to call when a channel scan is finished.
\param func ISR to call.
*/
void setChannelScanAction(void (*func)(void));
void setChannelScanAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a channel scan is finished.
*/
void clearChannelScanAction();
void clearChannelScanAction() override;
#if !RADIOLIB_GODMODE
protected:

View file

@ -22,10 +22,19 @@ enum {
RADIOLIB_STM32WLx_VIRTUAL_PIN_RESET,
};
/*!
\class Stm32wlxHal
\brief Hardware Abstraction Layer for STM32WL.
*/
class Stm32wlxHal : public ArduinoHal {
public:
Stm32wlxHal(): ArduinoHal(SubGhz.SPI, SubGhz.spi_settings) {}
/*!
\brief Pin mode override to handle STM32WL virtual pins.
\param dwPin Pin to set.
\param dwMode Mode to set.
*/
void pinMode(uint32_t dwPin, uint32_t dwMode) {
switch(dwPin) {
case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS:
@ -40,6 +49,11 @@ class Stm32wlxHal : public ArduinoHal {
}
}
/*!
\brief Digital write override to handle STM32WL virtual pins.
\param dwPin Pin to set.
\param dwVal Value to set.
*/
void digitalWrite(uint32_t dwPin, uint32_t dwVal) {
switch (dwPin) {
case RADIOLIB_STM32WLx_VIRTUAL_PIN_NSS:
@ -61,6 +75,11 @@ class Stm32wlxHal : public ArduinoHal {
}
}
/*!
\brief Digital read override to handle STM32WL virtual pins.
\param ulPin Pin to read.
\returns Value read on the pin.
*/
uint32_t digitalRead(uint32_t ulPin) {
switch (ulPin) {
case RADIOLIB_STM32WLx_VIRTUAL_PIN_BUSY:

View file

@ -6,24 +6,33 @@ SX1261::SX1261(Module* mod): SX1262(mod) {
}
int16_t SX1261::setOutputPower(int8_t power) {
RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
// check if power value is configurable
int16_t state = checkOutputPower(power, NULL);
RADIOLIB_ASSERT(state);
// get current OCP configuration
uint8_t ocp = 0;
int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
RADIOLIB_ASSERT(state);
// set PA config
state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1261, 0x00);
RADIOLIB_ASSERT(state);
// set output power
/// \todo power ramp time configuration
state = SX126x::setTxParams(power);
// set output power with default 200us ramp
state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U);
RADIOLIB_ASSERT(state);
// restore OCP configuration
return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
}
int16_t SX1261::checkOutputPower(int8_t power, int8_t* clipped) {
if(clipped) {
*clipped = RADIOLIB_MAX(-17, RADIOLIB_MIN(14, power));
}
RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
return(RADIOLIB_ERR_NONE);
}
#endif

View file

@ -25,14 +25,22 @@ class SX1261 : public SX1262 {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1261(Module* mod);
SX1261(Module* mod); // cppcheck-suppress noExplicitConstructor
/*!
\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);
int16_t setOutputPower(int8_t power) override;
/*!
\brief Check if output power is configurable.
\param power Output power in dBm.
\param clipped Clipped output power value to what is possible within the module's range.
\returns \ref status_codes
*/
int16_t checkOutputPower(int8_t power, int8_t* clipped) override;
#if !RADIOLIB_GODMODE
private:

View file

@ -51,13 +51,46 @@ int16_t SX1262::setFrequency(float freq) {
return(setFrequency(freq, true));
}
int16_t SX1262::setFrequency(float freq, bool calibrate, float band) {
int16_t SX1262::setFrequency(float freq, bool calibrate) {
RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY);
// calibrate image rejection
if(calibrate) {
int16_t state = SX126x::calibrateImage(freq - band, freq + band);
uint8_t data[2] = { 0, 0 };
// try to match the frequency ranges
int freqBand = (int)freq;
if((freqBand >= 902) && (freqBand <= 928)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_2;
} else if((freqBand >= 863) && (freqBand <= 870)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_2;
} else if((freqBand >= 779) && (freqBand <= 787)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2;
} else if((freqBand >= 470) && (freqBand <= 510)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2;
} else if((freqBand >= 430) && (freqBand <= 440)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2;
}
int16_t state;
if(data[0]) {
// matched with predefined ranges, do the calibration
state = SX126x::calibrateImage(data);
} else {
// if nothing matched, try custom calibration - the may or may not work
RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to match predefined frequency range, trying custom");
state = SX126x::calibrateImageRejection(freq - 4.0f, freq + 4.0f);
}
RADIOLIB_ASSERT(state);
}
// set frequency
@ -65,24 +98,33 @@ int16_t SX1262::setFrequency(float freq, bool calibrate, float band) {
}
int16_t SX1262::setOutputPower(int8_t power) {
RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
// check if power value is configurable
int16_t state = checkOutputPower(power, NULL);
RADIOLIB_ASSERT(state);
// get current OCP configuration
uint8_t ocp = 0;
int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
RADIOLIB_ASSERT(state);
// set PA config
state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1262);
RADIOLIB_ASSERT(state);
// set output power
/// \todo power ramp time configuration
state = SX126x::setTxParams(power);
// set output power with default 200us ramp
state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U);
RADIOLIB_ASSERT(state);
// restore OCP configuration
return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
}
int16_t SX1262::checkOutputPower(int8_t power, int8_t* clipped) {
if(clipped) {
*clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power));
}
RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
return(RADIOLIB_ERR_NONE);
}
#endif

View file

@ -25,7 +25,7 @@ class SX1262: public SX126x {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1262(Module* mod);
SX1262(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -69,18 +69,15 @@ class SX1262: public SX126x {
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
int16_t setFrequency(float freq) override;
/*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz.
\param freq Carrier frequency to be set in MHz.
\param calibrate Run image calibration.
\param band Half bandwidth for image calibration. For example,
if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate
for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz
\returns \ref status_codes
*/
int16_t setFrequency(float freq, bool calibrate, float band = 4);
int16_t setFrequency(float freq, bool calibrate);
/*!
\brief Sets output power. Allowed values are in range from -9 to 22 dBm.
@ -88,7 +85,15 @@ class SX1262: public SX126x {
\param power Output power to be set in dBm.
\returns \ref status_codes
*/
virtual int16_t setOutputPower(int8_t power);
virtual int16_t setOutputPower(int8_t power) override;
/*!
\brief Check if output power is configurable.
\param power Output power in dBm.
\param clipped Clipped output power value to what is possible within the module's range.
\returns \ref status_codes
*/
int16_t checkOutputPower(int8_t power, int8_t* clipped) override;
#if !RADIOLIB_GODMODE
private:

View file

@ -52,13 +52,40 @@ int16_t SX1268::setFrequency(float freq) {
}
/// \todo integers only (all modules - frequency, data rate, bandwidth etc.)
int16_t SX1268::setFrequency(float freq, bool calibrate, float band) {
int16_t SX1268::setFrequency(float freq, bool calibrate) {
RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, RADIOLIB_ERR_INVALID_FREQUENCY);
// calibrate image rejection
if(calibrate) {
int16_t state = SX126x::calibrateImage(freq - band, freq + band);
uint8_t data[2] = { 0, 0 };
// try to match the frequency ranges
int freqBand = (int)freq;
if((freqBand >= 779) && (freqBand <= 787)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2;
} else if((freqBand >= 470) && (freqBand <= 510)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2;
} else if((freqBand >= 430) && (freqBand <= 440)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2;
}
int16_t state;
if(data[0]) {
// matched with predefined ranges, do the calibration
state = SX126x::calibrateImage(data);
} else {
// if nothing matched, try custom calibration - the may or may not work
RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to match predefined frequency range, trying custom");
state = SX126x::calibrateImageRejection(freq - 4.0f, freq + 4.0f);
}
RADIOLIB_ASSERT(state);
}
// set frequency
@ -66,24 +93,33 @@ int16_t SX1268::setFrequency(float freq, bool calibrate, float band) {
}
int16_t SX1268::setOutputPower(int8_t power) {
RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
// check if power value is configurable
int16_t state = checkOutputPower(power, NULL);
RADIOLIB_ASSERT(state);
// get current OCP configuration
uint8_t ocp = 0;
int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
RADIOLIB_ASSERT(state);
// set PA config
state = SX126x::setPaConfig(0x04, RADIOLIB_SX126X_PA_CONFIG_SX1268);
RADIOLIB_ASSERT(state);
// set output power
/// \todo power ramp time configuration
state = SX126x::setTxParams(power);
// set output power with default 200us ramp
state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U);
RADIOLIB_ASSERT(state);
// restore OCP configuration
return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
}
int16_t SX1268::checkOutputPower(int8_t power, int8_t* clipped) {
if(clipped) {
*clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power));
}
RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
return(RADIOLIB_ERR_NONE);
}
#endif

View file

@ -24,7 +24,7 @@ class SX1268: public SX126x {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1268(Module* mod);
SX1268(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -68,25 +68,30 @@ class SX1268: public SX126x {
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
int16_t setFrequency(float freq) override;
/*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz.
\param freq Carrier frequency to be set in MHz.
\param calibrate Run image calibration.
\param band Half bandwidth for image calibration. For example,
if carrier is 434 MHz and band is set to 4 MHz, then the image will be calibrate
for band 430 - 438 MHz. Unused if calibrate is set to false, defaults to 4 MHz
\returns \ref status_codes
*/
int16_t setFrequency(float freq, bool calibrate, float band = 4);
int16_t setFrequency(float freq, bool calibrate);
/*!
\brief Sets output power. Allowed values are in range from -9 to 22 dBm.
\param power Output power to be set in dBm.
\returns \ref status_codes
*/
int16_t setOutputPower(int8_t power);
int16_t setOutputPower(int8_t power) override;
/*!
\brief Check if output power is configurable.
\param power Output power in dBm.
\param clipped Clipped output power value to what is possible within the module's range.
\returns \ref status_codes
*/
int16_t checkOutputPower(int8_t power, int8_t* clipped) override;
#if !RADIOLIB_GODMODE
private:

View file

@ -14,12 +14,15 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
this->mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER;
this->mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER;
this->mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP;
this->mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS;
this->mod->SPIstreamType = true;
this->mod->SPIparseStatusCb = SPIparseStatus;
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
this->mod->spiConfig.statusPos = 1;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX126X_CMD_READ_REGISTER;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX126X_CMD_WRITE_REGISTER;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX126X_CMD_NOP;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX126X_CMD_GET_STATUS;
this->mod->spiConfig.stream = true;
this->mod->spiConfig.parseStatusCb = SPIparseStatus;
// try to find the SX126x chip
if(!SX126x::findChip(this->chipType)) {
@ -73,10 +76,11 @@ int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, flo
RADIOLIB_ASSERT(state);
if (useRegulatorLDO) {
state = setRegulatorLDO();
state = setRegulatorLDO();
} else {
state = setRegulatorDCDC();
state = setRegulatorDCDC();
}
RADIOLIB_ASSERT(state);
// set publicly accessible settings that are not a part of begin method
state = setCurrentLimit(60.0);
@ -99,12 +103,15 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
this->mod->SPIreadCommand = RADIOLIB_SX126X_CMD_READ_REGISTER;
this->mod->SPIwriteCommand = RADIOLIB_SX126X_CMD_WRITE_REGISTER;
this->mod->SPInopCommand = RADIOLIB_SX126X_CMD_NOP;
this->mod->SPIstatusCommand = RADIOLIB_SX126X_CMD_GET_STATUS;
this->mod->SPIstreamType = true;
this->mod->SPIparseStatusCb = SPIparseStatus;
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
this->mod->spiConfig.statusPos = 1;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX126X_CMD_READ_REGISTER;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX126X_CMD_WRITE_REGISTER;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX126X_CMD_NOP;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX126X_CMD_GET_STATUS;
this->mod->spiConfig.stream = true;
this->mod->spiConfig.parseStatusCb = SPIparseStatus;
// try to find the SX126x chip
if(!SX126x::findChip(this->chipType)) {
@ -201,7 +208,7 @@ int16_t SX126x::reset(bool verify) {
}
// set mode to standby - SX126x often refuses first few commands after reset
uint32_t start = this->mod->hal->millis();
RadioLibTime_t start = this->mod->hal->millis();
while(true) {
// try to set mode to standby
int16_t state = standby();
@ -231,41 +238,27 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
uint32_t timeout = 0;
// get currently active modem
uint8_t modem = getPacketType();
if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
// calculate timeout (150% of expected time-on-air)
timeout = (getTimeOnAir(len) * 3) / 2;
} else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
// calculate timeout (500% of expected time-on-air)
timeout = getTimeOnAir(len) * 5;
} else {
return(RADIOLIB_ERR_UNKNOWN);
}
RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout);
// calculate timeout in ms (500% of expected time-on-air)
RadioLibTime_t timeout = (getTimeOnAir(len) * 5) / 1000;
RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
// start transmission
state = startTransmit(data, len, addr);
RADIOLIB_ASSERT(state);
// wait for packet transmission or timeout
uint32_t start = this->mod->hal->micros();
RadioLibTime_t start = this->mod->hal->millis();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
finishTransmit();
return(RADIOLIB_ERR_TX_TIMEOUT);
}
}
uint32_t elapsed = this->mod->hal->micros() - start;
// update data rate
this->dataRateMeasured = (len*8.0)/((float)elapsed/1000000.0);
RadioLibTime_t elapsed = this->mod->hal->millis() - start;
this->dataRateMeasured = (len*8.0)/((float)elapsed/1000.0);
return(finishTransmit());
}
@ -275,14 +268,15 @@ int16_t SX126x::receive(uint8_t* data, size_t len) {
int16_t state = standby();
RADIOLIB_ASSERT(state);
uint32_t timeout = 0;
RadioLibTime_t timeout = 0;
// get currently active modem
uint8_t modem = getPacketType();
if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
// calculate timeout (100 LoRa symbols, the default for SX127x series)
float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz;
timeout = (uint32_t)(symbolLength * 100.0 * 1000.0);
timeout = (RadioLibTime_t)(symbolLength * 100.0);
} else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
// calculate timeout (500 % of expected time-one-air)
size_t maxLen = len;
@ -290,26 +284,27 @@ int16_t SX126x::receive(uint8_t* data, size_t len) {
maxLen = 0xFF;
}
float brBps = ((float)(RADIOLIB_SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)this->bitRate;
timeout = (uint32_t)(((maxLen * 8.0) / brBps) * 1000000.0 * 5.0);
timeout = (RadioLibTime_t)(((maxLen * 8.0) / brBps) * 1000.0 * 5.0);
} else {
return(RADIOLIB_ERR_UNKNOWN);
}
RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout);
RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
// start reception
uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625);
uint32_t timeoutValue = (uint32_t)(((float)timeout * 1000.0) / 15.625);
state = startReceive(timeoutValue);
RADIOLIB_ASSERT(state);
// wait for packet reception or timeout
bool softTimeout = false;
uint32_t start = this->mod->hal->micros();
RadioLibTime_t start = this->mod->hal->millis();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
// safety check, the timeout should be done by the radio
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
softTimeout = true;
break;
}
@ -586,7 +581,7 @@ int16_t SX126x::startReceive() {
return(this->startReceive(RADIOLIB_SX126X_RX_TIMEOUT_INF, RADIOLIB_SX126X_IRQ_RX_DEFAULT, RADIOLIB_SX126X_IRQ_RX_DONE, 0));
}
int16_t SX126x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) {
int16_t SX126x::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) {
(void)len;
int16_t state = startReceiveCommon(timeout, irqFlags, irqMask);
RADIOLIB_ASSERT(state);
@ -644,7 +639,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_
uint32_t symbolLength = ((uint32_t)(10 * 1000) << this->spreadingFactor) / (10 * this->bandwidthKhz);
uint32_t sleepPeriod = symbolLength * sleepSymbols;
RADIOLIB_DEBUG_BASIC_PRINTLN("Auto sleep period: %lu", sleepPeriod);
RADIOLIB_DEBUG_BASIC_PRINTLN("Auto sleep period: %lu", (long unsigned int)sleepPeriod);
// when the unit detects a preamble, it starts a timer that will timeout if it doesn't receive a header in time.
// the duration is sleepPeriod + 2 * wakePeriod.
@ -655,7 +650,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_
uint32_t wakePeriod = RADIOLIB_MAX(
(symbolLength * (senderPreambleLength + 1) - (sleepPeriod - 1000)) / 2, // (A)
symbolLength * (minSymbols + 1)); //(B)
RADIOLIB_DEBUG_BASIC_PRINTLN("Auto wake period: %lu", wakePeriod);
RADIOLIB_DEBUG_BASIC_PRINTLN("Auto wake period: %lu", (long unsigned int)wakePeriod);
// If our sleep period is shorter than our transition time, just use the standard startReceive
if(sleepPeriod < this->tcxoDelay + 1016) {
@ -1179,15 +1174,7 @@ int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) {
bytesLen++;
}
// write sync word
int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, bytesLen);
RADIOLIB_ASSERT(state);
// update packet parameters
this->syncWordLength = bitsLen;
state = setPacketParamsFSK(this->preambleLengthFSK, this->crcTypeFSK, this->syncWordLength, this->addrComp, this->whitening, this->packetType);
return(state);
return(setSyncWord(syncWord, bytesLen));
}
int16_t SX126x::setNodeAddress(uint8_t nodeAddr) {
@ -1419,7 +1406,7 @@ int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) {
return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen));
}
uint32_t SX126x::getTimeOnAir(size_t len) {
RadioLibTime_t SX126x::getTimeOnAir(size_t len) {
// everything is in microseconds to allow integer arithmetic
// some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact
if(getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
@ -1450,18 +1437,18 @@ uint32_t SX126x::getTimeOnAir(size_t len) {
return((symbolLength_us * nSymbol_x4) / 4);
} else {
return((len * 8 * this->bitRate) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 32));
return(((uint32_t)len * 8 * this->bitRate) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 32));
}
}
uint32_t SX126x::calculateRxTimeout(uint32_t timeoutUs) {
RadioLibTime_t SX126x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
// the timeout value is given in units of 15.625 microseconds
// the calling function should provide some extra width, as this number of units is truncated to integer
uint32_t timeout = timeoutUs / 15.625;
RadioLibTime_t timeout = timeoutUs / 15.625;
return(timeout);
}
int16_t SX126x::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) {
int16_t SX126x::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) {
irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT; // flags that can appear in the IRQ register
irqMask = RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT; // flags that will trigger DIO0
return(RADIOLIB_ERR_NONE);
@ -1583,7 +1570,7 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile)
// check the version
#if RADIOLIB_DEBUG_BASIC
char ver_pre[16];
this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_pre);
this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, reinterpret_cast<uint8_t*>(ver_pre));
RADIOLIB_DEBUG_BASIC_PRINTLN("Pre-update version string: %s", ver_pre);
#endif
@ -1615,7 +1602,7 @@ int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile)
// check the version again
#if RADIOLIB_DEBUG_BASIC
char ver_post[16];
this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_post);
this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, reinterpret_cast<uint8_t*>(ver_post));
RADIOLIB_DEBUG_BASIC_PRINTLN("Post-update version string: %s", ver_post);
#endif
@ -1742,7 +1729,7 @@ int16_t SX126x::setRx(uint32_t timeout) {
int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) {
// default CAD parameters are shown in Semtech AN1200.48, page 41.
uint8_t detPeakValues[6] = { 22, 22, 24, 25, 26, 30};
const uint8_t detPeakValues[6] = { 22, 22, 24, 25, 26, 30};
// CAD parameters aren't available for SF-6. Just to be safe.
if(this->spreadingFactor < 7) {
@ -1853,8 +1840,17 @@ int16_t SX126x::setRfFrequency(uint32_t frf) {
return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4));
}
int16_t SX126x::calibrateImage(float freqMin, float freqMax) {
int16_t SX126x::calibrateImageRejection(float freqMin, float freqMax) {
// calculate the calibration coefficients and calibrate image
uint8_t data[] = { (uint8_t)floor((freqMin - 1.0f) / 4.0f), (uint8_t)ceil((freqMax + 1.0f) / 4.0f) };
return(this->calibrateImage(data));
}
int16_t SX126x::setPaRampTime(uint8_t rampTime) {
return(this->setTxParams(this->pwr, rampTime));
}
int16_t SX126x::calibrateImage(uint8_t* data) {
int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2);
// if something failed, show the device errors
@ -1877,7 +1873,11 @@ uint8_t SX126x::getPacketType() {
int16_t SX126x::setTxParams(uint8_t pwr, uint8_t rampTime) {
uint8_t data[] = { pwr, rampTime };
return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2));
int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2);
if(state == RADIOLIB_ERR_NONE) {
this->pwr = pwr;
}
return(state);
}
int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) {
@ -2156,18 +2156,18 @@ bool SX126x::findChip(const char* verStr) {
// read the version string
char version[16];
this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)version);
this->mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, reinterpret_cast<uint8_t*>(version));
// check version register
if(strncmp(verStr, version, 6) == 0) {
RADIOLIB_DEBUG_BASIC_PRINTLN("Found SX126x: RADIOLIB_SX126X_REG_VERSION_STRING:");
RADIOLIB_DEBUG_BASIC_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING);
RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast<uint8_t*>(version), 16, RADIOLIB_SX126X_REG_VERSION_STRING);
RADIOLIB_DEBUG_BASIC_PRINTLN();
flagFound = true;
} else {
#if RADIOLIB_DEBUG_BASIC
RADIOLIB_DEBUG_BASIC_PRINTLN("SX126x not found! (%d of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING:", i + 1);
RADIOLIB_DEBUG_BASIC_HEXDUMP((uint8_t*)version, 16, RADIOLIB_SX126X_REG_VERSION_STRING);
RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast<uint8_t*>(version), 16, RADIOLIB_SX126X_REG_VERSION_STRING);
RADIOLIB_DEBUG_BASIC_PRINTLN("Expected string: %s", verStr);
#endif
this->mod->hal->delay(10);

View file

@ -188,6 +188,18 @@
#define RADIOLIB_SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled
#define RADIOLIB_SX126X_CALIBRATE_ALL 0b01111111 // 6 0 calibrate all blocks
//RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE
#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_1 0x6B
#define RADIOLIB_SX126X_CAL_IMG_430_MHZ_2 0x6F
#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_1 0x75
#define RADIOLIB_SX126X_CAL_IMG_470_MHZ_2 0x81
#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_1 0xC1
#define RADIOLIB_SX126X_CAL_IMG_779_MHZ_2 0xC5
#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_1 0xD7
#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB
#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1
#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9
//RADIOLIB_SX126X_CMD_SET_PA_CONFIG
#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07
#define RADIOLIB_SX126X_PA_CONFIG_PA_LUT 0x01
@ -440,7 +452,7 @@ class SX126x: public PhysicalLayer {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX126x(Module* mod);
explicit SX126x(Module* mod);
/*!
\brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false.
@ -574,34 +586,34 @@ class SX126x: public PhysicalLayer {
\brief Sets interrupt service routine to call when a packet is received.
\param func ISR to call.
*/
void setPacketReceivedAction(void (*func)(void));
void setPacketReceivedAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a packet is received.
*/
void clearPacketReceivedAction();
void clearPacketReceivedAction() override;
/*!
\brief Sets interrupt service routine to call when a packet is sent.
\param func ISR to call.
*/
void setPacketSentAction(void (*func)(void));
void setPacketSentAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a packet is sent.
*/
void clearPacketSentAction();
void clearPacketSentAction() override;
/*!
\brief Sets interrupt service routine to call when a channel scan is finished.
\param func ISR to call.
*/
void setChannelScanAction(void (*func)(void));
void setChannelScanAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a channel scan is finished.
*/
void clearChannelScanAction();
void clearChannelScanAction() override;
/*!
\brief Interrupt-driven binary transmit method.
@ -625,7 +637,7 @@ class SX126x: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t startReceive();
int16_t startReceive() override;
/*!
\brief Interrupt-driven receive method. DIO1 will be activated when full packet is received.
@ -642,7 +654,7 @@ class SX126x: public PhysicalLayer {
\param len Only for PhysicalLayer compatibility, not used.
\returns \ref status_codes
*/
int16_t startReceive(uint32_t timeout, uint16_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE, size_t len = 0);
int16_t startReceive(uint32_t timeout, uint32_t irqFlags = RADIOLIB_SX126X_IRQ_RX_DEFAULT, uint32_t irqMask = RADIOLIB_SX126X_IRQ_RX_DONE, size_t len = 0);
/*!
\brief Interrupt-driven receive method where the device mostly sleeps and periodically wakes to listen.
@ -774,7 +786,7 @@ class SX126x: public PhysicalLayer {
\param br FSK bit rate to be set in kbps.
\returns \ref status_codes
*/
int16_t setBitRate(float br);
int16_t setBitRate(float br) override;
/*!
\brief Set data.
@ -908,7 +920,7 @@ class SX126x: public PhysicalLayer {
\brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa modem.
\returns SNR of the last received packet in dB.
*/
float getSNR();
float getSNR() override;
/*!
\brief Gets frequency error of the latest received packet.
@ -935,7 +947,7 @@ class SX126x: public PhysicalLayer {
/*!
\brief Set modem in variable packet length mode. Available in FSK mode only.
\param len Maximum packet length.
\param maxLen Maximum packet length.
\returns \ref status_codes
*/
int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX126X_MAX_PACKET_LENGTH);
@ -945,14 +957,14 @@ class SX126x: public PhysicalLayer {
\param len Payload length in bytes.
\returns Expected time-on-air in microseconds.
*/
uint32_t getTimeOnAir(size_t len) override;
RadioLibTime_t getTimeOnAir(size_t len) override;
/*!
\brief Calculate the timeout value for this specific module / series (in number of symbols or units of time)
\param timeoutUs Timeout in microseconds to listen for
\returns Timeout value in a unit that is specific for the used module
*/
uint32_t calculateRxTimeout(uint32_t timeoutUs);
RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override;
/*!
\brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks
@ -960,13 +972,13 @@ class SX126x: public PhysicalLayer {
\param irqMask Mask indicating which IRQ triggers a DIO
\returns \ref status_codes
*/
int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask);
int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override;
/*!
\brief Check whether the IRQ bit for RxTimeout is set
\returns \ref RxTimeout IRQ is set
\returns Whether RxTimeout IRQ is set
*/
bool isRxTimeout();
bool isRxTimeout() override;
/*!
\brief Set implicit header mode for future reception/transmission.
@ -1028,7 +1040,7 @@ class SX126x: public PhysicalLayer {
\brief Get one truly random byte from RSSI noise.
\returns TRNG byte.
*/
uint8_t randomByte();
uint8_t randomByte() override;
/*!
\brief Enable/disable inversion of the I and Q signals
@ -1042,13 +1054,13 @@ class SX126x: public PhysicalLayer {
\brief Set interrupt service routine function to call when data bit is received in direct mode.
\param func Pointer to interrupt service routine.
*/
void setDirectAction(void (*func)(void));
void setDirectAction(void (*func)(void)) override;
/*!
\brief Function to read and process data bit in direct reception mode.
\param pin Pin on which to read.
*/
void readBit(uint32_t pin);
void readBit(uint32_t pin) override;
#endif
/*!
@ -1102,10 +1114,25 @@ class SX126x: public PhysicalLayer {
*/
int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = RADIOLIB_SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = RADIOLIB_SX126X_PA_CONFIG_PA_LUT);
/*!
\brief Perform image rejection calibration for the specified frequency band.
WARNING: Use at your own risk! Setting incorrect values may lead to decreased performance
\param freqMin Frequency band lower bound.
\param freqMax Frequency band upper bound.
\returns \ref status_codes
*/
int16_t calibrateImageRejection(float freqMin, float freqMax);
/*!
\brief Set PA ramp-up time. Set to 200us by default.
\returns \ref status_codes
*/
int16_t setPaRampTime(uint8_t rampTime);
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
Module* getMod();
Module* getMod() override;
// SX126x SPI command implementations
int16_t setFs();
@ -1119,9 +1146,9 @@ class SX126x: public PhysicalLayer {
int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = RADIOLIB_SX126X_IRQ_NONE, uint16_t dio3Mask = RADIOLIB_SX126X_IRQ_NONE);
virtual int16_t clearIrqStatus(uint16_t clearIrqParams = RADIOLIB_SX126X_IRQ_ALL);
int16_t setRfFrequency(uint32_t frf);
int16_t calibrateImage(float freqMin, float freqMax);
int16_t calibrateImage(uint8_t* data);
uint8_t getPacketType();
int16_t setTxParams(uint8_t power, uint8_t rampTime = RADIOLIB_SX126X_PA_RAMP_200U);
int16_t setTxParams(uint8_t power, uint8_t rampTime);
int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro);
int16_t setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev);
int16_t setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ);
@ -1136,7 +1163,7 @@ class SX126x: public PhysicalLayer {
#if !RADIOLIB_GODMODE
protected:
#endif
const char* chipType;
const char* chipType = NULL;
uint8_t bandwidth = 0;
// Allow subclasses to define different TX modes
@ -1166,6 +1193,7 @@ class SX126x: public PhysicalLayer {
float dataRateMeasured = 0;
uint32_t tcxoDelay = 0;
uint8_t pwr = 0;
size_t implicitLen = 0;
uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD;

View file

@ -280,15 +280,12 @@ int16_t SX1272::setOutputPower(int8_t power) {
}
int16_t SX1272::setOutputPower(int8_t power, bool useRfo) {
// check allowed power range
if(useRfo) {
RADIOLIB_CHECK_RANGE(power, -1, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
} else {
RADIOLIB_CHECK_RANGE(power, 2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
}
// check if power value is configurable
int16_t state = checkOutputPower(power, NULL, useRfo);
RADIOLIB_ASSERT(state);
// set mode to standby
int16_t state = SX127x::standby();
state = SX127x::standby();
Module* mod = this->getMod();
if(useRfo) {
@ -317,6 +314,26 @@ int16_t SX1272::setOutputPower(int8_t power, bool useRfo) {
return(state);
}
int16_t SX1272::checkOutputPower(int8_t power, int8_t* clipped) {
return(checkOutputPower(power, clipped, false));
}
int16_t SX1272::checkOutputPower(int8_t power, int8_t* clipped, bool useRfo) {
// check allowed power range
if(useRfo) {
if(clipped) {
*clipped = RADIOLIB_MAX(-1, RADIOLIB_MIN(14, power));
}
RADIOLIB_CHECK_RANGE(power, -1, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
} else {
if(clipped) {
*clipped = RADIOLIB_MAX(2, RADIOLIB_MIN(20, power));
}
RADIOLIB_CHECK_RANGE(power, 2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
}
return(RADIOLIB_ERR_NONE);
}
int16_t SX1272::setGain(uint8_t gain) {
// check allowed range
if(gain > 6) {
@ -419,6 +436,10 @@ int16_t SX1272::setDataShapingOOK(uint8_t sh) {
return(state);
}
float SX1272::getRSSI() {
return(SX1272::getRSSI(true, false));
}
float SX1272::getRSSI(bool packet, bool skipReceive) {
return(SX127x::getRSSI(packet, skipReceive, -139));
}

View file

@ -100,7 +100,7 @@ class SX1272: public SX127x {
\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.
*/
SX1272(Module* mod);
SX1272(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -111,8 +111,7 @@ class SX1272: public SX127x {
\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 currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
Set to 0 to disable OCP (not recommended).
\param 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.
@ -147,7 +146,7 @@ class SX1272: public SX127x {
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
int16_t setFrequency(float freq) override;
/*!
\brief Sets %LoRa link bandwidth. Allowed values are 125, 250 and 500 kHz. Only available in %LoRa mode.
@ -207,6 +206,24 @@ class SX1272: public SX127x {
*/
int16_t setOutputPower(int8_t power, bool useRfo);
/*!
\brief Check if output power is configurable.
This method is needed for compatibility with PhysicalLayer::checkOutputPower.
\param power Output power in dBm, assumes PA_BOOST pin.
\param clipped Clipped output power value to what is possible within the module's range.
\returns \ref status_codes
*/
int16_t checkOutputPower(int8_t power, int8_t* clipped) override;
/*!
\brief Check if output power is configurable.
\param power Output power in dBm.
\param clipped Clipped output power value to what is possible within the module's range.
\param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output.
\returns \ref status_codes
*/
int16_t checkOutputPower(int8_t power, int8_t* clipped, bool useRfo);
/*!
\brief Sets 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).
@ -232,13 +249,20 @@ class SX1272: public SX127x {
*/
int16_t setDataShapingOOK(uint8_t sh);
/*!
\brief Gets recorded signal strength indicator.
Overload with packet mode enabled for PhysicalLayer compatibility.
\returns RSSI value in dBm.
*/
float getRSSI() override;
/*!
\brief Gets recorded signal strength indicator.
\param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK.
\param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode.
\returns RSSI value in dBm.
*/
float getRSSI(bool packet = true, bool skipReceive = false);
float getRSSI(bool packet, bool skipReceive = false);
/*!
\brief Enables/disables CRC check of received packets.
@ -287,7 +311,7 @@ class SX1272: public SX127x {
int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF);
int16_t configFSK();
void errataFix(bool rx);
void errataFix(bool rx) override;
#if !RADIOLIB_GODMODE
private:

View file

@ -20,7 +20,7 @@ class SX1273: public SX1272 {
\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.
*/
SX1273(Module* mod);
SX1273(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods

View file

@ -20,7 +20,7 @@ class SX1276: 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.
*/
SX1276(Module* mod);
SX1276(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -61,7 +61,7 @@ class SX1276: public SX1278 {
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
int16_t setFrequency(float freq) override;
#if !RADIOLIB_GODMODE
private:

View file

@ -20,7 +20,7 @@ class SX1277: 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.
*/
SX1277(Module* mod);
SX1277(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -61,7 +61,7 @@ class SX1277: public SX1278 {
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
int16_t setFrequency(float freq) override;
/*!
\brief Sets %LoRa link spreading factor. Allowed values range from 6 to 9. Only available in %LoRa mode.

View file

@ -294,19 +294,12 @@ int16_t SX1278::setOutputPower(int8_t power) {
}
int16_t SX1278::setOutputPower(int8_t power, bool useRfo) {
// check allowed power range
if(useRfo) {
// RFO output
RADIOLIB_CHECK_RANGE(power, -3, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
} else {
// PA_BOOST output, check high-power operation
if(power != 20) {
RADIOLIB_CHECK_RANGE(power, 2, 17, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
}
}
// check if power value is configurable
int16_t state = checkOutputPower(power, NULL, useRfo);
RADIOLIB_ASSERT(state);
// set mode to standby
int16_t state = SX127x::standby();
state = SX127x::standby();
Module* mod = this->getMod();
if(useRfo) {
@ -342,6 +335,34 @@ int16_t SX1278::setOutputPower(int8_t power, bool useRfo) {
return(state);
}
int16_t SX1278::checkOutputPower(int8_t power, int8_t* clipped) {
return(checkOutputPower(power, clipped, false));
}
int16_t SX1278::checkOutputPower(int8_t power, int8_t* clipped, bool useRfo) {
// check allowed power range
if(useRfo) {
// RFO output
if(clipped) {
*clipped = RADIOLIB_MAX(-3, RADIOLIB_MIN(15, power));
}
RADIOLIB_CHECK_RANGE(power, -3, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
} else {
// PA_BOOST output, check high-power operation
if(clipped) {
if(power != 20) {
*clipped = RADIOLIB_MAX(2, RADIOLIB_MIN(17, power));
} else {
*clipped = 20;
}
}
if(power != 20) {
RADIOLIB_CHECK_RANGE(power, 2, 17, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
}
}
return(RADIOLIB_ERR_NONE);
}
int16_t SX1278::setGain(uint8_t gain) {
// check allowed range
if(gain > 6) {
@ -448,6 +469,10 @@ int16_t SX1278::setDataShapingOOK(uint8_t sh) {
return(state);
}
float SX1278::getRSSI() {
return(SX1278::getRSSI(true, false));
}
float SX1278::getRSSI(bool packet, bool skipReceive) {
int16_t offset = -157;
if(frequency < 868.0) {

View file

@ -111,7 +111,7 @@ class SX1278: public SX127x {
\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.
*/
SX1278(Module* mod);
SX1278(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -157,7 +157,7 @@ class SX1278: public SX127x {
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
int16_t setFrequency(float freq) override;
/*!
\brief Sets %LoRa link bandwidth. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. Only available in %LoRa mode.
@ -218,6 +218,24 @@ class SX1278: public SX127x {
*/
int16_t setOutputPower(int8_t power, bool useRfo);
/*!
\brief Check if output power is configurable.
This method is needed for compatibility with PhysicalLayer::checkOutputPower.
\param power Output power in dBm, assumes PA_BOOST pin.
\param clipped Clipped output power value to what is possible within the module's range.
\returns \ref status_codes
*/
int16_t checkOutputPower(int8_t power, int8_t* clipped) override;
/*!
\brief Check if output power is configurable.
\param power Output power in dBm.
\param clipped Clipped output power value to what is possible within the module's range.
\param useRfo Whether to use the RFO (true) or the PA_BOOST (false) pin for the RF output.
\returns \ref status_codes
*/
int16_t checkOutputPower(int8_t power, int8_t* clipped, bool useRfo);
/*!
\brief Sets 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).
@ -243,13 +261,20 @@ class SX1278: public SX127x {
*/
int16_t setDataShapingOOK(uint8_t sh);
/*!
\brief Gets recorded signal strength indicator.
Overload with packet mode enabled for PhysicalLayer compatibility.
\returns RSSI value in dBm.
*/
float getRSSI() override;
/*!
\brief Gets recorded signal strength indicator.
\param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK.
\param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode.
\returns RSSI value in dBm.
*/
float getRSSI(bool packet = true, bool skipReceive = false);
float getRSSI(bool packet, bool skipReceive = false);
/*!
\brief Enables/disables CRC check of received packets.
@ -298,7 +323,7 @@ class SX1278: public SX127x {
int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF);
int16_t configFSK();
void errataFix(bool rx);
void errataFix(bool rx) override;
#if !RADIOLIB_GODMODE
private:

View file

@ -20,7 +20,7 @@ class SX1279: 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.
*/
SX1279(Module* mod);
SX1279(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -61,7 +61,7 @@ class SX1279: public SX1278 {
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
int16_t setFrequency(float freq) override;
#if !RADIOLIB_GODMODE
private:

View file

@ -147,15 +147,16 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
RADIOLIB_ASSERT(state);
int16_t modem = getActiveModem();
uint32_t start = 0;
uint32_t timeout = 0;
RadioLibTime_t start = 0;
RadioLibTime_t timeout = 0;
RadioLibTime_t toa = getTimeOnAir(len);
if(modem == RADIOLIB_SX127X_LORA) {
// calculate timeout (150 % of expected time-on-air)
timeout = getTimeOnAir(len) * 1.5;
// calculate timeout in ms (150 % of expected time-on-air)
timeout = (toa * 1.5) / 1000;
} else if(modem == RADIOLIB_SX127X_FSK_OOK) {
// calculate timeout (5ms + 500 % of expected time-on-air)
timeout = 5000 + getTimeOnAir(len) * 5;
// calculate timeout in ms (5ms + 500 % of expected time-on-air)
timeout = 5 + (toa * 5) / 1000;
} else {
return(RADIOLIB_ERR_UNKNOWN);
@ -163,22 +164,23 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
}
// start transmission
RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
state = startTransmit(data, len, addr);
RADIOLIB_ASSERT(state);
// wait for packet transmission or timeout
start = this->mod->hal->micros();
start = this->mod->hal->millis();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
finishTransmit();
return(RADIOLIB_ERR_TX_TIMEOUT);
}
}
// update data rate
uint32_t elapsed = this->mod->hal->micros() - start;
this->dataRate = (len*8.0)/((float)elapsed/1000000.0);
RadioLibTime_t elapsed = this->mod->hal->millis() - start;
this->dataRate = (len*8.0)/((float)elapsed/1000.0);
return(finishTransmit());
}
@ -195,20 +197,20 @@ int16_t SX127x::receive(uint8_t* data, size_t len) {
RADIOLIB_ASSERT(state);
// if no DIO1 is provided, use software timeout (100 LoRa symbols, same as hardware timeout)
uint32_t timeout = 0;
RadioLibTime_t timeout = 0;
if(this->mod->getGpio() == RADIOLIB_NC) {
float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
timeout = (uint32_t)(symbolLength * 100.0 * 1000.0);
timeout = (RadioLibTime_t)(symbolLength * 100.0);
}
// wait for packet reception or timeout
uint32_t start = this->mod->hal->micros();
RadioLibTime_t start = this->mod->hal->millis();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
if(this->mod->getGpio() == RADIOLIB_NC) {
// no GPIO pin provided, use software timeout
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
clearIRQFlags();
return(RADIOLIB_ERR_RX_TIMEOUT);
}
@ -223,18 +225,18 @@ int16_t SX127x::receive(uint8_t* data, size_t len) {
}
} else if(modem == RADIOLIB_SX127X_FSK_OOK) {
// calculate timeout (500 % of expected time-on-air)
uint32_t timeout = getTimeOnAir(len) * 5;
// calculate timeout in ms (500 % of expected time-on-air)
RadioLibTime_t timeout = (getTimeOnAir(len) * 5) / 1000;
// set mode to receive
state = startReceive(len, RADIOLIB_SX127X_RX);
RADIOLIB_ASSERT(state);
// wait for packet reception or timeout
uint32_t start = this->mod->hal->micros();
RadioLibTime_t start = this->mod->hal->millis();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
clearIRQFlags();
return(RADIOLIB_ERR_RX_TIMEOUT);
}
@ -417,7 +419,7 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) {
return(setMode(mode));
}
int16_t SX127x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) {
int16_t SX127x::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) {
(void)irqFlags;
(void)irqMask;
uint8_t mode = RADIOLIB_SX127X_RXCONTINUOUS;
@ -903,13 +905,13 @@ int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) {
RADIOLIB_ASSERT(state);
// set bit rate
uint16_t bitRate = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / br;
state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0);
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0);
uint16_t bitRateRaw = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / br;
state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRateRaw & 0xFF00) >> 8, 7, 0);
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRateRaw & 0x00FF, 7, 0);
// set fractional part of bit rate
if(!ookEnabled) {
float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / (float)br) - (float)bitRate;
float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0) / (float)br) - (float)bitRateRaw;
uint8_t bitRateFrac = bitRateRem * 16;
state |= this->mod->SPIsetRegValue(fracRegAddr, bitRateFrac, 7, 0);
}
@ -1242,7 +1244,7 @@ float SX127x::getNumSymbols(size_t len) {
return(n_pre + n_pay + 4.25f);
}
uint32_t SX127x::getTimeOnAir(size_t len) {
RadioLibTime_t SX127x::getTimeOnAir(size_t len) {
// check active modem
uint8_t modem = getActiveModem();
if (modem == RADIOLIB_SX127X_LORA) {
@ -1252,43 +1254,42 @@ uint32_t SX127x::getTimeOnAir(size_t len) {
// get number of symbols
float n_sym = getNumSymbols(len);
// Get time-on-air in us
// get time-on-air in us
return ceil((double)symbolLength * (double)n_sym) * 1000;
} else if(modem == RADIOLIB_SX127X_FSK_OOK) {
// Get number of bits preamble
// get number of bits preamble
float n_pre = (float) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8;
//Get the number of bits of the sync word
// get the number of bits of the sync word
float n_syncWord = (float) (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8;
//Get CRC bits
// get CRC bits
float crc = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON) * 16;
if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) {
//If Packet size fixed -> len = fixed packet length
// if packet size fixed -> len = fixed packet length
len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK);
} else {
//if packet variable -> Add 1 extra byte for payload length
// if packet variable -> Add 1 extra byte for payload length
len += 1;
}
// Calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec)
return (uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (this->bitRate * 1000.0)) * 1000000.0);
} else {
return(RADIOLIB_ERR_UNKNOWN);
// calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec)
return((uint32_t) (((crc + n_syncWord + n_pre + (float) (len * 8)) / (this->bitRate * 1000.0)) * 1000000.0));
}
return(RADIOLIB_ERR_UNKNOWN);
}
uint32_t SX127x::calculateRxTimeout(uint32_t timeoutUs) {
RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
// the timeout is given as the number of symbols
// the calling function should provide some extra width, as this number of symbols is truncated to integer
// the order of operators is swapped here to decrease the effects of this truncation error
float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
uint32_t numSymbols = (timeoutUs / symbolLength) / 1000;
RadioLibTime_t numSymbols = (timeoutUs / symbolLength) / 1000;
return(numSymbols);
}
int16_t SX127x::irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask) {
int16_t SX127x::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) {
// IRQ flags/masks are inverted to what seems logical for SX127x (0 being activated, 1 being deactivated)
irqFlags = RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DEFAULT;
irqMask = RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_DONE & RADIOLIB_SX127X_MASK_IRQ_FLAG_RX_TIMEOUT;
@ -1334,8 +1335,14 @@ int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) {
RADIOLIB_CHECK_RANGE(offset, -16, 15, RADIOLIB_ERR_INVALID_RSSI_OFFSET);
// calculate the two's complement
uint8_t offsetRaw = RADIOLIB_ABS(offset);
offsetRaw ^= 0x1F;
offsetRaw += 1;
offsetRaw &= 0x1F;
// set new register values
state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offset << 3, 7, 3);
state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offsetRaw << 3, 7, 3);
state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, smoothingSamples, 2, 0);
return(state);
}
@ -1537,7 +1544,7 @@ int16_t SX127x::setPacketMode(uint8_t mode, uint8_t len) {
return(state);
}
bool SX127x::findChip(uint8_t* vers, uint8_t num) {
bool SX127x::findChip(const uint8_t* vers, uint8_t num) {
uint8_t i = 0;
bool flagFound = false;
while((i < 10) && !flagFound) {
@ -1546,8 +1553,8 @@ bool SX127x::findChip(uint8_t* vers, uint8_t num) {
// check version register
int16_t version = getChipVersion();
for(uint8_t i = 0; i < num; i++) {
if(version == vers[i]) {
for(uint8_t j = 0; j < num; j++) {
if(version == vers[j]) {
flagFound = true;
break;
}

View file

@ -594,13 +594,13 @@ class SX127x: public PhysicalLayer {
\brief Default constructor. Called internally when creating new LoRa instance.
\param mod Instance of Module that will be used to communicate with the %LoRa chip.
*/
SX127x(Module* mod);
explicit SX127x(Module* mod);
// basic methods
/*!
\brief Initialization method. Will be called with appropriate parameters when calling initialization method from derived class.
\param chipVersion Array of possible values in SPI version register. Used to verify the connection and hardware version.
\param chipVersions Array of possible values in SPI version register. Used to verify the connection and hardware version.
\param numVersions Number of possible chip versions.
\param syncWord %LoRa sync word.
\param preambleLength Length of %LoRa transmission preamble in symbols.
@ -615,7 +615,7 @@ class SX127x: public PhysicalLayer {
/*!
\brief Initialization method for FSK modem. Will be called with appropriate parameters when calling FSK initialization method from derived class.
\param chipVersion Array of possible values in SPI version register. Used to verify the connection and hardware version.
\param chipVersions Array of possible values in SPI version register. Used to verify the connection and hardware version.
\param numVersions Number of possible chip versions.
\param freqDev Frequency deviation of the FSK transmission in kHz.
\param rxBw Receiver bandwidth in kHz.
@ -655,7 +655,7 @@ class SX127x: public PhysicalLayer {
%Module will wake up automatically when methods like transmit or receive are called.
\returns \ref status_codes
*/
int16_t sleep();
int16_t sleep() override;
/*!
\brief Sets the %LoRa module to standby.
@ -721,34 +721,34 @@ class SX127x: public PhysicalLayer {
\brief Sets interrupt service routine to call when a packet is received.
\param func ISR to call.
*/
void setPacketReceivedAction(void (*func)(void));
void setPacketReceivedAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a packet is received.
*/
void clearPacketReceivedAction();
void clearPacketReceivedAction() override;
/*!
\brief Sets interrupt service routine to call when a packet is sent.
\param func ISR to call.
*/
void setPacketSentAction(void (*func)(void));
void setPacketSentAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a packet is sent.
*/
void clearPacketSentAction();
void clearPacketSentAction() override;
/*!
\brief Sets interrupt service routine to call when a channel scan is finished.
\param func ISR to call.
*/
void setChannelScanAction(void (*func)(void));
void setChannelScanAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a channel scan is finished.
*/
void clearChannelScanAction();
void clearChannelScanAction() override;
/*!
\brief Set interrupt service routine function to call when FIFO is empty.
@ -810,7 +810,7 @@ class SX127x: public PhysicalLayer {
Implemented for compatibility with PhysicalLayer.
\returns \ref status_codes
*/
int16_t startReceive();
int16_t startReceive() override;
/*!
\brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received.
@ -832,7 +832,7 @@ class SX127x: public PhysicalLayer {
\param len Expected length of packet to be received. Required for LoRa spreading factor 6.
\returns \ref status_codes
*/
int16_t startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len);
int16_t startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) override;
/*!
\brief Reads data that was received after calling startReceive method. When the packet length is not known in advance,
@ -904,7 +904,7 @@ class SX127x: public PhysicalLayer {
\brief Gets signal-to-noise ratio of the latest received packet. Only available in LoRa mode.
\returns Last packet signal-to-noise ratio (SNR).
*/
float getSNR();
float getSNR() override;
/*!
\brief Get data rate of the latest transmitted packet.
@ -928,7 +928,7 @@ class SX127x: public PhysicalLayer {
/*!
\brief Sets FSK automatic frequency correction bandwidth. Allowed values range from 2.6 to 250 kHz. Only available in FSK mode.
\param rxBw Receiver AFC bandwidth to be set (in kHz).
\param afcBw Receiver AFC bandwidth to be set (in kHz).
\returns \ref status_codes
*/
int16_t setAFCBandwidth(float afcBw);
@ -1038,7 +1038,7 @@ class SX127x: public PhysicalLayer {
/*!
\brief Set modem in variable packet length mode. Available in FSK mode only.
\param len Maximum packet length.
\param maxLen Maximum packet length.
\returns \ref status_codes
*/
int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK);
@ -1055,14 +1055,14 @@ class SX127x: public PhysicalLayer {
\param len Payload length in bytes.
\returns Expected time-on-air in microseconds.
*/
uint32_t getTimeOnAir(size_t len) override;
RadioLibTime_t getTimeOnAir(size_t len) override;
/*!
\brief Calculate the timeout value for this specific module / series (in number of symbols or units of time)
\param timeoutUs Timeout in microseconds to listen for
\returns Timeout value in a unit that is specific for the used module
*/
uint32_t calculateRxTimeout(uint32_t timeoutUs);
RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override;
/*!
\brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks
@ -1070,13 +1070,13 @@ class SX127x: public PhysicalLayer {
\param irqMask Mask indicating which IRQ triggers a DIO
\returns \ref status_codes
*/
int16_t irqRxDoneRxTimeout(uint16_t &irqFlags, uint16_t &irqMask);
int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override;
/*!
\brief Check whether the IRQ bit for RxTimeout is set
\returns \ref RxTimeout IRQ is set
\returns Whether RxTimeout IRQ is set
*/
bool isRxTimeout();
bool isRxTimeout() override;
/*!
\brief Enable CRC filtering and generation.
@ -1133,7 +1133,7 @@ class SX127x: public PhysicalLayer {
\brief Get one truly random byte from RSSI noise.
\returns TRNG byte.
*/
uint8_t randomByte();
uint8_t randomByte() override;
/*!
\brief Read version SPI register. Should return SX1278_CHIP_VERSION (0x12) or SX1272_CHIP_VERSION (0x22) if SX127x is connected and working.
@ -1153,13 +1153,13 @@ class SX127x: public PhysicalLayer {
\brief Set interrupt service routine function to call when data bit is received in direct mode.
\param func Pointer to interrupt service routine.
*/
void setDirectAction(void (*func)(void));
void setDirectAction(void (*func)(void)) override;
/*!
\brief Function to read and process data bit in direct reception mode.
\param pin Pin on which to read.
*/
void readBit(uint32_t pin);
void readBit(uint32_t pin) override;
#endif
/*!
@ -1192,7 +1192,7 @@ class SX127x: public PhysicalLayer {
\param value The value that indicates which function to place on that pin. See chip datasheet for details.
\returns \ref status_codes
*/
int16_t setDIOMapping(uint32_t pin, uint32_t value);
int16_t setDIOMapping(uint32_t pin, uint32_t value) override;
/*!
\brief Configure DIO mapping to use RSSI or Preamble Detect for pins that support it.
@ -1201,14 +1201,6 @@ class SX127x: public PhysicalLayer {
*/
int16_t setDIOPreambleDetect(bool usePreambleDetect);
/*!
\brief Gets recorded signal strength indicator.
\param packet Whether to read last packet RSSI, or the current value. LoRa mode only, ignored for FSK.
\param skipReceive Set to true to skip putting radio in receive mode for the RSSI measurement in FSK/OOK mode.
\returns RSSI value in dBm.
*/
float getRSSI(bool packet, bool skipReceive, int16_t offset);
/*!
\brief Sets the RSSI value above which the RSSI interrupt is signaled
\param dbm A dBm value between -127.5 and 0 inclusive
@ -1229,7 +1221,7 @@ class SX127x: public PhysicalLayer {
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
Module* getMod();
Module* getMod() override;
#if !RADIOLIB_GODMODE
protected:
@ -1246,6 +1238,7 @@ class SX127x: public PhysicalLayer {
int16_t getActiveModem();
int16_t setFrequencyRaw(float newFreq);
int16_t setBitRateCommon(float br, uint8_t fracRegAddr);
float getRSSI(bool packet, bool skipReceive, int16_t offset);
#if !RADIOLIB_GODMODE
private:
@ -1261,7 +1254,7 @@ class SX127x: public PhysicalLayer {
int16_t config();
int16_t directMode();
int16_t setPacketMode(uint8_t mode, uint8_t len);
bool findChip(uint8_t* vers, uint8_t num);
bool findChip(const uint8_t* vers, uint8_t num);
int16_t setMode(uint8_t mode);
int16_t setActiveModem(uint8_t modem);
void clearIRQFlags();

View file

@ -13,7 +13,7 @@ int16_t SX1280::range(bool master, uint32_t addr, uint16_t calTable[3][6]) {
// wait until ranging is finished
Module* mod = this->getMod();
uint32_t start = mod->hal->millis();
RadioLibTime_t start = mod->hal->millis();
while(!mod->hal->digitalRead(mod->getIrq())) {
mod->hal->yield();
if(mod->hal->millis() - start > 10000) {

View file

@ -19,7 +19,7 @@ class SX1280: public SX1281 {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1280(Module* mod);
SX1280(Module* mod); // cppcheck-suppress noExplicitConstructor
/*!
\brief Blocking ranging method.

View file

@ -18,7 +18,7 @@ class SX1281: public SX128x {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1281(Module* mod);
SX1281(Module* mod); // cppcheck-suppress noExplicitConstructor
#if !RADIOLIB_GODMODE
private:

View file

@ -19,7 +19,7 @@ class SX1282: public SX1280 {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1282(Module* mod);
SX1282(Module* mod); // cppcheck-suppress noExplicitConstructor
#if !RADIOLIB_GODMODE
private:

View file

@ -11,12 +11,15 @@ int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER;
this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP;
this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS;
this->mod->SPIstreamType = true;
this->mod->SPIparseStatusCb = SPIparseStatus;
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
this->mod->spiConfig.statusPos = 1;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS;
this->mod->spiConfig.stream = true;
this->mod->spiConfig.parseStatusCb = SPIparseStatus;
RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x");
// initialize LoRa modulation variables
@ -72,12 +75,15 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, ui
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER;
this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP;
this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS;
this->mod->SPIstreamType = true;
this->mod->SPIparseStatusCb = SPIparseStatus;
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
this->mod->spiConfig.statusPos = 1;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS;
this->mod->spiConfig.stream = true;
this->mod->spiConfig.parseStatusCb = SPIparseStatus;
RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x");
// initialize GFSK modulation variables
@ -141,12 +147,15 @@ int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uin
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER;
this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP;
this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS;
this->mod->SPIstreamType = true;
this->mod->SPIparseStatusCb = SPIparseStatus;
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
this->mod->spiConfig.statusPos = 1;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS;
this->mod->spiConfig.stream = true;
this->mod->spiConfig.parseStatusCb = SPIparseStatus;
RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x");
// initialize BLE modulation variables
@ -196,12 +205,15 @@ int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint1
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
this->mod->SPIreadCommand = RADIOLIB_SX128X_CMD_READ_REGISTER;
this->mod->SPIwriteCommand = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
this->mod->SPInopCommand = RADIOLIB_SX128X_CMD_NOP;
this->mod->SPIstatusCommand = RADIOLIB_SX128X_CMD_GET_STATUS;
this->mod->SPIstreamType = true;
this->mod->SPIparseStatusCb = SPIparseStatus;
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
this->mod->spiConfig.statusPos = 1;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS;
this->mod->spiConfig.stream = true;
this->mod->spiConfig.parseStatusCb = SPIparseStatus;
RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x");
// initialize FLRC modulation variables
@ -269,7 +281,7 @@ int16_t SX128x::reset(bool verify) {
}
// set mode to standby
uint32_t start = this->mod->hal->millis();
RadioLibTime_t start = this->mod->hal->millis();
while(true) {
// try to set mode to standby
int16_t state = standby();
@ -305,20 +317,19 @@ int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) {
int16_t state = standby();
RADIOLIB_ASSERT(state);
// calculate timeout (500% of expected time-on-air)
uint32_t timeout = getTimeOnAir(len) * 5;
RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout);
// calculate timeout in ms (500% of expected time-on-air)
RadioLibTime_t timeout = (getTimeOnAir(len) * 5) / 1000;
RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
// start transmission
state = startTransmit(data, len, addr);
RADIOLIB_ASSERT(state);
// wait for packet transmission or timeout
uint32_t start = this->mod->hal->micros();
RadioLibTime_t start = this->mod->hal->millis();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
finishTransmit();
return(RADIOLIB_ERR_TX_TIMEOUT);
}
@ -339,9 +350,8 @@ int16_t SX128x::receive(uint8_t* data, size_t len) {
RADIOLIB_ASSERT(state);
// calculate timeout (1000% of expected time-on-air)
uint32_t timeout = getTimeOnAir(len) * 10;
RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout);
RadioLibTime_t timeout = getTimeOnAir(len) * 10;
RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
// start reception
uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625);
@ -350,11 +360,11 @@ int16_t SX128x::receive(uint8_t* data, size_t len) {
// wait for packet reception or timeout
bool softTimeout = false;
uint32_t start = this->mod->hal->micros();
RadioLibTime_t start = this->mod->hal->millis();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
// safety check, the timeout should be done by the radio
if(this->mod->hal->micros() - start > timeout) {
if(this->mod->hal->millis() - start > timeout) {
softTimeout = true;
break;
}
@ -401,28 +411,8 @@ int16_t SX128x::receiveDirect() {
}
int16_t SX128x::scanChannel() {
// check active modem
if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// set DIO pin mapping
state = setDioIrqParams(RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE, RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE);
RADIOLIB_ASSERT(state);
// clear interrupt flags
state = clearIrqStatus();
RADIOLIB_ASSERT(state);
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_RX);
// set mode to CAD
state = setCad();
int16_t state = startChannelScan();
RADIOLIB_ASSERT(state);
// wait for channel activity detected or timeout
@ -431,18 +421,7 @@ int16_t SX128x::scanChannel() {
}
// check CAD result
uint16_t cadResult = getIrqStatus();
if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DETECTED) {
// detected some LoRa activity
clearIrqStatus();
return(RADIOLIB_LORA_DETECTED);
} else if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DONE) {
// channel is free
clearIrqStatus();
return(RADIOLIB_CHANNEL_FREE);
}
return(RADIOLIB_ERR_UNKNOWN);
return(getChannelScanResult());
}
int16_t SX128x::sleep(bool retainConfig) {
@ -578,7 +557,7 @@ int16_t SX128x::startReceive() {
return(this->startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_SX128X_IRQ_RX_DEFAULT, RADIOLIB_SX128X_IRQ_RX_DONE, 0));
}
int16_t SX128x::startReceive(uint16_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) {
int16_t SX128x::startReceive(uint16_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) {
(void)len;
// check active modem
@ -654,6 +633,52 @@ int16_t SX128x::readData(uint8_t* data, size_t len) {
return(state);
}
int16_t SX128x::startChannelScan() {
// check active modem
if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// set DIO pin mapping
state = setDioIrqParams(RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE, RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE);
RADIOLIB_ASSERT(state);
// clear interrupt flags
state = clearIrqStatus();
RADIOLIB_ASSERT(state);
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_RX);
// set mode to CAD
return(setCad());
}
int16_t SX128x::getChannelScanResult() {
// check active modem
if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
// check CAD result
uint16_t cadResult = getIrqStatus();
int16_t state = RADIOLIB_ERR_UNKNOWN;
if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DETECTED) {
// detected some LoRa activity
state = RADIOLIB_LORA_DETECTED;
} else if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DONE) {
// channel is free
state = RADIOLIB_CHANNEL_FREE;
}
clearIrqStatus();
return(state);
}
int16_t SX128x::setFrequency(float freq) {
RADIOLIB_CHECK_RANGE(freq, 2400.0, 2500.0, RADIOLIB_ERR_INVALID_FREQUENCY);
@ -755,11 +780,22 @@ int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) {
}
int16_t SX128x::setOutputPower(int8_t pwr) {
RADIOLIB_CHECK_RANGE(pwr, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
// check if power value is configurable
int16_t state = checkOutputPower(power, NULL);
RADIOLIB_ASSERT(state);
this->power = pwr + 18;
return(setTxParams(this->power));
}
int16_t SX128x::checkOutputPower(int8_t power, int8_t* clipped) {
if(clipped) {
*clipped = RADIOLIB_MAX(-18, RADIOLIB_MIN(13, power));
}
RADIOLIB_CHECK_RANGE(power, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
return(RADIOLIB_ERR_NONE);
}
int16_t SX128x::setPreambleLength(uint32_t preambleLength) {
uint8_t modem = getPacketType();
if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
@ -888,13 +924,13 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) {
}
// update modulation parameters
uint8_t modIndex = (uint8_t)((8.0 * (newFreqDev / (float)this->bitRateKbps)) - 1.0);
if(modIndex > RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00) {
uint8_t modInd = (uint8_t)((8.0 * (newFreqDev / (float)this->bitRateKbps)) - 1.0);
if(modInd > RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00) {
return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
}
// update modulation parameters
this->modIndex = modIndex;
this->modIndex = modInd;
return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
}
@ -928,7 +964,7 @@ int16_t SX128x::setDataShaping(uint8_t sh) {
}
}
int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) {
int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) {
// check active modem
uint8_t modem = getPacketType();
if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) {
@ -1225,7 +1261,7 @@ size_t SX128x::getPacketLength(bool update) {
return((size_t)rxBufStatus[0]);
}
uint32_t SX128x::getTimeOnAir(size_t len) {
RadioLibTime_t SX128x::getTimeOnAir(size_t len) {
// check active modem
uint8_t modem = getPacketType();
if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {

View file

@ -359,7 +359,7 @@ class SX128x: public PhysicalLayer {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX128x(Module* mod);
explicit SX128x(Module* mod);
// basic methods
@ -455,7 +455,7 @@ class SX128x: public PhysicalLayer {
\brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload.
\returns \ref status_codes
*/
int16_t scanChannel();
int16_t scanChannel() override;
/*!
\brief Sets the module to sleep mode. To wake the device up, call standby().
@ -497,23 +497,23 @@ class SX128x: public PhysicalLayer {
\brief Sets interrupt service routine to call when a packet is received.
\param func ISR to call.
*/
void setPacketReceivedAction(void (*func)(void));
void setPacketReceivedAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a packet is received.
*/
void clearPacketReceivedAction();
void clearPacketReceivedAction() override;
/*!
\brief Sets interrupt service routine to call when a packet is sent.
\param func ISR to call.
*/
void setPacketSentAction(void (*func)(void));
void setPacketSentAction(void (*func)(void)) override;
/*!
\brief Clears interrupt service routine to call when a packet is sent.
*/
void clearPacketSentAction();
void clearPacketSentAction() override;
/*!
\brief Interrupt-driven binary transmit method.
@ -537,7 +537,7 @@ class SX128x: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t startReceive();
int16_t startReceive() override;
/*!
\brief Interrupt-driven receive method. DIO1 will be activated when full packet is received.
@ -551,7 +551,7 @@ class SX128x: public PhysicalLayer {
\param len Only for PhysicalLayer compatibility, not used.
\returns \ref status_codes
*/
int16_t startReceive(uint16_t timeout, uint16_t irqFlags = RADIOLIB_SX128X_IRQ_RX_DEFAULT, uint16_t irqMask = RADIOLIB_SX128X_IRQ_RX_DONE, size_t len = 0);
int16_t startReceive(uint16_t timeout, uint32_t irqFlags = RADIOLIB_SX128X_IRQ_RX_DEFAULT, uint32_t irqMask = RADIOLIB_SX128X_IRQ_RX_DONE, size_t len = 0);
/*!
\brief Reads the current IRQ status.
@ -568,6 +568,19 @@ class SX128x: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t readData(uint8_t* data, size_t len) override;
/*!
\brief Interrupt-driven channel activity detection method. DIO1 will be activated
when LoRa preamble is detected, or upon timeout. Defaults to CAD parameter values recommended by AN1200.48.
\returns \ref status_codes
*/
int16_t startChannelScan() override;
/*!
\brief Read the channel scan result
\returns \ref status_codes
*/
int16_t getChannelScanResult() override;
// configuration methods
@ -576,7 +589,7 @@ class SX128x: public PhysicalLayer {
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq);
int16_t setFrequency(float freq) override;
/*!
\brief Sets LoRa bandwidth. Allowed values are 203.125, 406.25, 812.5 and 1625.0 kHz.
@ -606,7 +619,15 @@ class SX128x: public PhysicalLayer {
\param pwr Output power to be set in dBm.
\returns \ref status_codes
*/
int16_t setOutputPower(int8_t pwr);
int16_t setOutputPower(int8_t pwr) override;
/*!
\brief Check if output power is configurable.
\param power Output power in dBm.
\param clipped Clipped output power value to what is possible within the module's range.
\returns \ref status_codes
*/
int16_t checkOutputPower(int8_t power, int8_t* clipped) override;
/*!
\brief Sets preamble length for currently active modem. Allowed values range from 1 to 65535.
@ -621,7 +642,7 @@ class SX128x: public PhysicalLayer {
\param br FSK/FLRC bit rate to be set in kbps.
\returns \ref status_codes
*/
int16_t setBitRate(float br);
int16_t setBitRate(float br) override;
/*!
\brief Sets FSK frequency deviation. Allowed values range from 0.0 to 3200.0 kHz.
@ -645,7 +666,7 @@ class SX128x: public PhysicalLayer {
\param len Sync word length in bytes.
\returns \ref status_codes
*/
int16_t setSyncWord(uint8_t* syncWord, uint8_t len);
int16_t setSyncWord(const uint8_t* syncWord, uint8_t len);
/*!
\brief Sets LoRa sync word.
@ -696,13 +717,13 @@ class SX128x: public PhysicalLayer {
\brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet.
\returns RSSI of the last received packet in dBm.
*/
float getRSSI();
float getRSSI() override;
/*!
\brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa or ranging modem.
\returns SNR of the last received packet in dB.
*/
float getSNR();
float getSNR() override;
/*!
\brief Gets frequency error of the latest received packet.
@ -722,7 +743,7 @@ class SX128x: public PhysicalLayer {
\param len Payload length in bytes.
\returns Expected time-on-air in microseconds.
*/
uint32_t getTimeOnAir(size_t len);
RadioLibTime_t getTimeOnAir(size_t len) override;
/*!
\brief Set implicit header mode for future reception/transmission.
@ -754,33 +775,33 @@ class SX128x: public PhysicalLayer {
\brief Dummy random method, to ensure PhysicalLayer compatibility.
\returns Always returns 0.
*/
uint8_t randomByte();
uint8_t randomByte() override;
/*!
\brief Enable/disable inversion of the I and Q signals
\param enable QI inversion enabled (true) or disabled (false);
\returns \ref status_codes
*/
int16_t invertIQ(bool enable);
int16_t invertIQ(bool enable) override;
#if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
/*!
\brief Dummy method, to ensure PhysicalLayer compatibility.
\param func Ignored.
*/
void setDirectAction(void (*func)(void));
void setDirectAction(void (*func)(void)) override;
/*!
\brief Dummy method, to ensure PhysicalLayer compatibility.
\param pin Ignored.
*/
void readBit(uint32_t pin);
void readBit(uint32_t pin) override;
#endif
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
Module* getMod();
Module* getMod() override;
// cached LoRa parameters
float bandwidthKhz = 0;

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