Merge branch 'jgromes:master' into Buffer-Pull

This commit is contained in:
Crsarmv7l 2024-05-19 14:27:50 -04:00 committed by GitHub
commit 5ce49b9933
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
122 changed files with 78710 additions and 1984 deletions

3
.gitattributes vendored Normal file
View file

@ -0,0 +1,3 @@
# exclude binary patch files from language detection
src/modules/SX126x/patches/*.h linguist-detectable=false
src/modules/LR11x0/firmware/*.h linguist-detectable=false

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

@ -46,15 +46,16 @@ jobs:
# platform-dependent settings - extra board options, board index URLs, skip patterns etc.
include:
- id: arduino:avr:uno
run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN)" >> $GITHUB_OUTPUT
run: echo "skip-pattern=(STM32WL|SSTV|LoRaWAN|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT
- id: arduino:avr:mega
run: echo "options=':cpu=atmega2560'" >> $GITHUB_OUTPUT
echo "skip-pattern=(STM32WL|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT
- id: arduino:mbed:nano33ble
- id: arduino:mbed:envie_m4
- id: arduino:megaavr:uno2018
run: |
echo "options=':mode=on'" >> $GITHUB_OUTPUT
echo "skip-pattern=(STM32WL|LoRaWAN)" >> $GITHUB_OUTPUT
echo "skip-pattern=(STM32WL|LoRaWAN|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT
- id: arduino:sam:arduino_due_x
- id: arduino:samd:arduino_zero_native
- id: adafruit:samd:adafruit_feather_m0
@ -110,7 +111,7 @@ jobs:
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
echo "skip-pattern=(STM32WL|LoRaWAN|LR11x0_Firmware_Update)" >> $GITHUB_OUTPUT
runs-on: ubuntu-latest
name: ${{ matrix.id }}
@ -170,7 +171,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
@ -226,13 +227,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 dbee65a56d74b4bad166317f199e80b959f7c82c; cd ../
LIBTOCK_C_DIRECTORY="$(pwd)/libtock-c" ./build.sh
rpi-build:
runs-on: [self-hosted, ARM64]

3
.gitmodules vendored
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

@ -0,0 +1,132 @@
/*
RadioLib LR11x0 Firmware Update Example
This example updates the internal LR1110 firmware.
Newer versions of the firmware introduce fixes
and possibly even new features, so it is recommended
to use the latest available firmware version
when possible.
Other modules from LR11x0 family can also be used.
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// select the firmware image you want to upload
// WARNING: Make sure you select the correct firmware
// for your device! Uploading incorrect firmware
// (e.g. LR1110 firmware to LR1120 device)
// may damage your hardware!
//#define RADIOLIB_LR1110_FIRMWARE_0303
//#define RADIOLIB_LR1110_FIRMWARE_0304
//#define RADIOLIB_LR1110_FIRMWARE_0305
//#define RADIOLIB_LR1110_FIRMWARE_0306
//#define RADIOLIB_LR1110_FIRMWARE_0307
#define RADIOLIB_LR1110_FIRMWARE_0401
//#define RADIOLIB_LR1120_FIRMWARE_0101
//#define RADIOLIB_LR1120_FIRMWARE_0102
//#define RADIOLIB_LR1120_FIRMWARE_0201
//#define RADIOLIB_LR1121_FIRMWARE_0102
//#define RADIOLIB_LR1121_FIRMWARE_0103
// enable this macro if you want to store the image in host
// MCU RAM instead of Flash.
// NOTE: the firmware images are very large, up to 240 kB!
//#define RADIOLIB_LR1110_FIRMWARE_IN_RAM
// include the firmware image
#include <modules/LR11x0/LR11x0_firmware.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);
}
// print the firmware versions before the update
printVersions();
// prompt the user
Serial.println(F("[LR1110] Send any character to start the update"));
while(!Serial.available()) { yield(); }
// upload update into LR11x0 non-volatile memory
Serial.print(F("[LR1110] Updating firmware, this may take several seconds ... "));
state = radio.updateFirmware(lr11xx_firmware_image, RADIOLIB_LR11X0_FIRMWARE_IMAGE_SIZE);
/*
use the following if you enabled RADIOLIB_LR1110_FIRMWARE_IN_RAM
state = radio.updateFirmware(lr11xx_firmware_image, RADIOLIB_LR11X0_FIRMWARE_IMAGE_SIZE, false);
*/
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// print the firmware versions after the update
printVersions();
}
void printVersions() {
LR11x0VersionInfo_t version;
Serial.print(F("[LR1110] Reading firmware versions ... "));
int16_t state = radio.getVersionInfo(&version);
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
Serial.print(F("[LR1110] Device: "));
Serial.println(version.device);
Serial.print(F("[LR1110] Base firmware: "));
Serial.print(version.fwMajor);
Serial.print('.');
Serial.println(version.fwMinor);
Serial.print(F("[LR1110] WiFi firmware: "));
Serial.print(version.fwMajorWiFi);
Serial.print('.');
Serial.println(version.fwMinorWiFi);
Serial.print(F("[LR1110] GNSS firmware: "));
Serial.print(version.fwGNSS);
Serial.print('.');
Serial.println(version.almanacGNSS);
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
}
void loop() {
}

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

@ -42,7 +42,7 @@ void setup() {
debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true);
Serial.println(F("Initialise LoRaWAN Network credentials"));
state = node.beginABP(devAddr, NwkSEncKey, AppSKey, NwkSKey, SNwkSIntKey, true);
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"));

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

@ -105,14 +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);
@ -159,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;

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

@ -1,2 +1,2 @@
build/
build-*
TockApp.tab

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,66 @@ 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}/libtock-sync/build/rv32imc/libtocksync.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}/libtock-sync/build/rv32imc/libtocksync.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}/libtock-sync/build/cortex-m4/libtocksync.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}/libtock-sync/build/cortex-m4/libtocksync.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 dbee65a56d74b4bad166317f199e80b959f7c82c; 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

@ -1 +0,0 @@
Subproject commit 1c1f4c0810aa0fbd50aa91a11aaa7c05d2abb1bc

View file

@ -31,10 +31,12 @@
#include <RadioLib.h>
// include all the dependencies
#include "libtock/lora_phy.h"
#include "libtock/gpio.h"
#include "libtock/timer.h"
#include "libtock/read_only_state.h"
#include "libtock/net/lora_phy.h"
#include "libtock/net/syscalls/lora_phy_syscalls.h"
#include "libtock-sync/net/lora_phy.h"
#include "libtock/peripherals/gpio.h"
#include "libtock-sync/services/alarm.h"
#include "libtock/kernel/read_only_state.h"
#define RADIO_BUSY 1
#define RADIO_DIO_1 2
@ -99,9 +101,9 @@ class TockHal : public RadioLibHal {
}
if (mode == PIN_OUTPUT) {
lora_phy_gpio_enable_output(pin);
libtock_lora_phy_gpio_enable_output(pin);
} else if (mode == PIN_INPUT) {
lora_phy_gpio_enable_input(pin, PullDown);
libtock_lora_phy_gpio_enable_input(pin, libtock_pull_down);
}
}
@ -111,9 +113,9 @@ class TockHal : public RadioLibHal {
}
if (value) {
lora_phy_gpio_set(pin);
libtock_lora_phy_gpio_set(pin);
} else {
lora_phy_gpio_clear(pin);
libtock_lora_phy_gpio_clear(pin);
}
}
@ -124,7 +126,7 @@ class TockHal : public RadioLibHal {
return 0;
}
lora_phy_gpio_read(pin, &value);
libtock_lora_phy_gpio_read(pin, &value);
return value;
}
@ -134,11 +136,11 @@ class TockHal : public RadioLibHal {
return;
}
lora_phy_gpio_interrupt_callback(lora_phy_gpio_Callback, &interruptCb);
libtock_lora_phy_gpio_command_interrupt_callback(lora_phy_gpio_Callback, &interruptCb);
// set GPIO as input and enable interrupts on it
lora_phy_gpio_enable_input(interruptNum, PullDown);
lora_phy_gpio_enable_interrupt(interruptNum, Change);
libtock_lora_phy_gpio_enable_input(interruptNum, libtock_pull_down);
libtock_lora_phy_gpio_enable_interrupt(interruptNum, libtock_change);
}
void detachInterrupt(uint32_t interruptNum) override {
@ -146,15 +148,15 @@ class TockHal : public RadioLibHal {
return;
}
lora_phy_gpio_disable_interrupt(interruptNum);
libtock_lora_phy_gpio_disable_interrupt(interruptNum);
}
void delay(unsigned long ms) override {
delay_ms( ms );
libtocksync_alarm_delay_ms( ms );
}
void delayMicroseconds(unsigned long us) override {
delay_ms( us / 1000 );
libtocksync_alarm_delay_ms( us / 1000 );
}
unsigned long millis() override {
@ -181,7 +183,7 @@ class TockHal : public RadioLibHal {
}
void spiTransfer(uint8_t* out, size_t len, uint8_t* in) {
lora_phy_read_write_sync((const char*) out, (char*) in, len);
libtocksync_lora_phy_read_write(out, in, len);
}
void spiEndTransaction() {

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

@ -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,4 @@
# ignore all output files
*.h
*.png
!radiolib.png

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

@ -91,6 +91,12 @@ AS923 KEYWORD1
KR920 KEYWORD1
IN865 KEYWORD1
# LR11x0 structures
LR11x0WifiResult_t KEYWORD1
LR11x0WifiResultFull_t KEYWORD1
LR11x0WifiResultExtended_t KEYWORD1
LR11x0VersionInfo_t KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
@ -127,6 +133,7 @@ setCodingRate KEYWORD2
setFrequency KEYWORD2
setSyncWord KEYWORD2
setOutputPower KEYWORD2
checkOutputPower KEYWORD2
setCurrentLimit KEYWORD2
setPreambleLength KEYWORD2
setGain KEYWORD2
@ -242,6 +249,14 @@ setAutoAck KEYWORD2
# LR11x0
beginLRFHSS KEYWORD2
setLrFhssConfig KEYWORD2
startWifiScan KEYWORD2
getWifiScanResultsCount KEYWORD2
getWifiScanResult KEYWORD2
wifiScan KEYWORD2
setWiFiScanAction KEYWORD2
clearWiFiScanAction KEYWORD2
getVersionInfo KEYWORD2
updateFirmware KEYWORD2
# RTTY
idle KEYWORD2
@ -316,10 +331,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
@ -328,10 +343,10 @@ timeUntilUplink KEYWORD2
setDwellTime KEYWORD2
maxPayloadDwellTime KEYWORD2
setTxPower KEYWORD2
setCSMA KEYWORD2
getMacLinkCheckAns KEYWORD2
getMacDeviceTimeAns KEYWORD2
getDevAddr KEYWORD2
getLastToA KEYWORD2
#######################################
# Constants (LITERAL1)
@ -447,3 +462,17 @@ RADIOLIB_ERR_DATA_RATE_INVALID LITERAL1
RADIOLIB_ERR_DWELL_TIME_EXCEEDED LITERAL1
RADIOLIB_ERR_CHECKSUM_MISMATCH LITERAL1
RADIOLIB_LORAWAN_NO_DOWNLINK LITERAL1
RADIOLIB_LR1110_FIRMWARE_IN_RAM LITERAL1
RADIOLIB_LR11X0_FIRMWARE_IMAGE_SIZE LITERAL1
RADIOLIB_LR1110_FIRMWARE_0303 LITERAL1
RADIOLIB_LR1110_FIRMWARE_0304 LITERAL1
RADIOLIB_LR1110_FIRMWARE_0305 LITERAL1
RADIOLIB_LR1110_FIRMWARE_0306 LITERAL1
RADIOLIB_LR1110_FIRMWARE_0307 LITERAL1
RADIOLIB_LR1110_FIRMWARE_0401 LITERAL1
RADIOLIB_LR1120_FIRMWARE_0101 LITERAL1
RADIOLIB_LR1120_FIRMWARE_0102 LITERAL1
RADIOLIB_LR1120_FIRMWARE_0201 LITERAL1
RADIOLIB_LR1121_FIRMWARE_0102 LITERAL1
RADIOLIB_LR1121_FIRMWARE_0103 LITERAL1

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;

View file

@ -76,13 +76,18 @@ int16_t Module::SPIsetRegValue(uint32_t reg, uint8_t value, uint8_t msb, uint8_t
// check register value each millisecond until check interval is reached
// some registers need a bit of time to process the change (e.g. SX127X_REG_OP_MODE)
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
@ -113,7 +118,7 @@ void Module::SPIreadRegisterBurst(uint32_t reg, size_t numBytes, uint8_t* inByte
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);
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);
}
}
@ -130,7 +135,7 @@ uint8_t Module::SPIreadRegister(uint32_t reg) {
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);
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);
}
return(resp);
}
@ -147,7 +152,7 @@ void Module::SPIwriteRegisterBurst(uint32_t reg, uint8_t* data, size_t numBytes)
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);
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);
}
}
@ -163,7 +168,7 @@ void Module::SPIwriteRegister(uint32_t reg, uint8_t data) {
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);
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);
}
}
@ -240,7 +245,7 @@ int16_t Module::SPIreadStream(uint16_t cmd, uint8_t* data, size_t numBytes, bool
int16_t Module::SPIreadStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
// send the command
int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT);
int16_t state = this->SPItransferStream(cmd, cmdLen, false, NULL, data, numBytes, waitForGpio);
RADIOLIB_ASSERT(state);
#if !RADIOLIB_SPI_PARANOID
@ -268,7 +273,7 @@ int16_t Module::SPIwriteStream(uint16_t cmd, uint8_t* data, size_t numBytes, boo
int16_t Module::SPIwriteStream(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) {
// send the command
int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio, RADIOLIB_MODULE_SPI_TIMEOUT);
int16_t state = this->SPItransferStream(cmd, cmdLen, true, data, NULL, numBytes, waitForGpio);
RADIOLIB_ASSERT(state);
#if !RADIOLIB_SPI_PARANOID
@ -296,7 +301,7 @@ int16_t Module::SPIcheckStream() {
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);
state = this->SPItransferStream(cmdBuf, this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD]/8, false, NULL, &spiStatus, 1, true);
RADIOLIB_ASSERT(state);
// translate to RadioLib status code
@ -308,18 +313,16 @@ int16_t Module::SPIcheckStream() {
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, RadioLibTime_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) {
// prepare the output buffer
size_t buffLen = cmdLen + numBytes;
if(!write) {
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;
@ -342,17 +345,23 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint
RadioLibTime_t start = this->hal->millis();
while(this->hal->digitalRead(this->gpioPin)) {
this->hal->yield();
if(this->hal->millis() - start >= timeout) {
if(this->hal->millis() - start >= this->spiConfig.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);
@ -369,7 +378,7 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint
RadioLibTime_t start = this->hal->millis();
while(this->hal->digitalRead(this->gpioPin)) {
this->hal->yield();
if(this->hal->millis() - start >= timeout) {
if(this->hal->millis() - start >= this->spiConfig.timeout) {
RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO post-transfer timeout, is it connected?");
#if !RADIOLIB_STATIC_ONLY
delete[] buffOut;
@ -462,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;
@ -488,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);
@ -539,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

@ -18,9 +18,6 @@
*/
#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.
\{
@ -200,6 +197,9 @@ class Module {
/*! \brief Callback for validation SPI status. */
SPIcheckStatusCb_t checkStatusCb;
/*! \brief Timeout in ms when waiting for GPIO signals. */
RadioLibTime_t timeout;
};
/*! \brief SPI configuration structure. The default configuration corresponds to register-access modules, such as SX127x. */
@ -211,6 +211,7 @@ class Module {
.statusPos = 0,
.parseStatusCb = nullptr,
.checkStatusCb = nullptr,
.timeout = 1000,
};
#if RADIOLIB_INTERRUPT_TIMING
@ -368,10 +369,9 @@ class Module {
\param dataIn Data that was transferred from slave to master.
\param numBytes Number of bytes to transfer.
\param waitForGpio Whether to wait for some GPIO at the end of transfer (e.g. BUSY line on SX126x/SX128x).
\param 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, RadioLibTime_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);
// pin number access methods

View file

@ -563,6 +563,13 @@
*/
#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)
/*!
\}
*/

View file

@ -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;
@ -560,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) {
@ -586,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) {

View file

@ -539,6 +539,7 @@ class CC1101: public PhysicalLayer {
\brief Default constructor.
\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,
@ -772,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.
@ -829,7 +848,7 @@ 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.
@ -921,7 +940,7 @@ class CC1101: 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 CC1101_VERSION_LEGACY (0x04) or
@ -935,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
/*!
@ -950,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

@ -2,7 +2,7 @@
#if !RADIOLIB_EXCLUDE_LR11X0
LR1110::LR1110(Module* mod) : LR11x0(mod) {
chipType = RADIOLIB_LR11X0_HW_LR1110;
chipType = RADIOLIB_LR11X0_DEVICE_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) {

View file

@ -18,7 +18,7 @@ class LR1110: public LR11x0 {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
LR1110(Module* mod);
LR1110(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -74,7 +74,7 @@ class LR1110: public LR11x0 {
\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.

View file

@ -2,7 +2,7 @@
#if !RADIOLIB_EXCLUDE_LR11X0
LR1120::LR1120(Module* mod) : LR11x0(mod) {
chipType = RADIOLIB_LR11X0_HW_LR1120;
chipType = RADIOLIB_LR11X0_DEVICE_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) {

View file

@ -18,7 +18,7 @@ class LR1120: public LR11x0 {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
LR1120(Module* mod);
LR1120(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -74,7 +74,7 @@ class LR1120: public LR11x0 {
\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,

View file

@ -2,7 +2,7 @@
#if !RADIOLIB_EXCLUDE_LR11X0
LR1121::LR1121(Module* mod) : LR1120(mod) {
chipType = RADIOLIB_LR11X0_HW_LR1121;
chipType = RADIOLIB_LR11X0_DEVICE_LR1121;
}
#endif

View file

@ -19,7 +19,7 @@ class LR1121: public LR1120 {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
LR1121(Module* mod);
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

View file

@ -143,6 +143,7 @@ int16_t LR11x0::transmit(uint8_t* data, size_t len, uint8_t addr) {
// get currently active modem
uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
state = getPacketType(&modem);
RADIOLIB_ASSERT(state);
RadioLibTime_t timeout = getTimeOnAir(len);
if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
// calculate timeout (150% of expected time-on-air)
@ -189,6 +190,7 @@ int16_t LR11x0::receive(uint8_t* data, size_t len) {
// get currently active modem
uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
state = getPacketType(&modem);
RADIOLIB_ASSERT(state);
if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
// calculate timeout (100 LoRa symbols, the default for SX127x series)
float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float)this->bandwidthKhz;
@ -312,6 +314,10 @@ int16_t LR11x0::standby(uint8_t mode, bool wakeup) {
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_STANDBY, true, buff, 1));
}
int16_t LR11x0::sleep() {
return(LR11x0::sleep(true, 0));
}
int16_t LR11x0::sleep(bool retainConfig, uint32_t sleepTime) {
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_IDLE);
@ -396,6 +402,7 @@ int16_t LR11x0::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// in LR-FHSS mode, the packet is built by the device
// TODO add configurable grid step and device offset
state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC, true, this->lrFhssBw, this->lrFhssHopSeq, 0, data, len);
RADIOLIB_ASSERT(state);
} else {
// write packet to buffer
@ -432,10 +439,11 @@ int16_t LR11x0::finishTransmit() {
}
int16_t LR11x0::startReceive() {
return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_LR11X0_IRQ_RX_DONE, 0));
return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_LR11X0_IRQ_RX_DONE, 0, 0));
}
int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, size_t len) {
int16_t LR11x0::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) {
(void)irqMask;
(void)len;
// check active modem
@ -481,7 +489,7 @@ uint32_t LR11x0::getIrqStatus() {
// there is no dedicated "get IRQ" command, the IRQ bits are sent after the status bytes
uint8_t buff[6] = { 0 };
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0;
mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true, RADIOLIB_MODULE_SPI_TIMEOUT);
mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true);
this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8;
uint32_t irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5];
return(irq);
@ -593,22 +601,17 @@ int16_t LR11x0::setOutputPower(int8_t power) {
}
int16_t LR11x0::setOutputPower(int8_t power, bool forceHighPower) {
// check if power value is configurable
int16_t state = checkOutputPower(power, NULL, forceHighPower);
RADIOLIB_ASSERT(state);
// determine whether to use HP or LP PA and check range accordingly
bool useHp = forceHighPower || (power > 14);
if(useHp) {
RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
useHp = true;
} else {
RADIOLIB_CHECK_RANGE(power, -17, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
useHp = false;
}
// TODO how and when to configure OCP?
// update PA config - always use VBAT for high-power PA
int16_t state = setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07);
state = setPaConfig((uint8_t)useHp, (uint8_t)useHp, 0x04, 0x07);
RADIOLIB_ASSERT(state);
// set output power
@ -616,6 +619,27 @@ int16_t LR11x0::setOutputPower(int8_t power, bool forceHighPower) {
return(state);
}
int16_t LR11x0::checkOutputPower(int8_t power, int8_t* clipped) {
return(checkOutputPower(power, clipped, false));
}
int16_t LR11x0::checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower) {
if(forceHighPower || (power > 14)) {
if(clipped) {
*clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power));
}
RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
} else {
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);
}
int16_t LR11x0::setBandwidth(float bw) {
// check active modem
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
@ -833,8 +857,16 @@ int16_t LR11x0::setSyncWord(uint8_t* syncWord, size_t len) {
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
int16_t state = getPacketType(&type);
RADIOLIB_ASSERT(state);
if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
// with length set to 1 and LoRa modem active, assume it is the LoRa sync word
if(len > 1) {
return(RADIOLIB_ERR_INVALID_SYNC_WORD);
}
return(setSyncWord(syncWord[0]));
} else if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
// update sync word length
@ -1177,12 +1209,12 @@ float LR11x0::getRSSI() {
// check active modem
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
getPacketType(&type);
(void)getPacketType(&type);
if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
getPacketStatusLoRa(&val, NULL, NULL);
(void)getPacketStatusLoRa(&val, NULL, NULL);
} else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
getPacketStatusGFSK(NULL, &val, NULL, NULL);
(void)getPacketStatusGFSK(NULL, &val, NULL, NULL);
}
@ -1194,9 +1226,9 @@ float LR11x0::getSNR() {
// check active modem
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
getPacketType(&type);
(void)getPacketType(&type);
if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
getPacketStatusLoRa(NULL, &val, NULL);
(void)getPacketStatusLoRa(NULL, &val, NULL);
}
return(val);
@ -1229,7 +1261,7 @@ size_t LR11x0::getPacketLength(bool update, uint8_t* offset) {
RadioLibTime_t LR11x0::getTimeOnAir(size_t len) {
// check active modem
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
getPacketType(&type);
(void)getPacketType(&type);
if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
// calculate number of symbols
float N_symbol = 0;
@ -1294,6 +1326,39 @@ RadioLibTime_t LR11x0::getTimeOnAir(size_t len) {
return(0);
}
RadioLibTime_t LR11x0::calculateRxTimeout(RadioLibTime_t timeoutUs) {
// the timeout value is given in units of 30.52 microseconds
// the calling function should provide some extra width, as this number of units is truncated to integer
RadioLibTime_t timeout = timeoutUs / 30.52;
return(timeout);
}
int16_t LR11x0::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) {
irqFlags = RADIOLIB_LR11X0_IRQ_RX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT; // flags that can appear in the IRQ register
irqMask = irqFlags; // on LR11x0, these are the same
return(RADIOLIB_ERR_NONE);
}
bool LR11x0::isRxTimeout() {
uint32_t irq = getIrqStatus();
bool rxTimedOut = irq & RADIOLIB_LR11X0_IRQ_TIMEOUT;
return(rxTimedOut);
}
uint8_t LR11x0::randomByte() {
uint32_t num = 0;
(void)getRandomNumber(&num);
return((uint8_t)num);
}
int16_t LR11x0::implicitHeader(size_t len) {
return(this->setHeaderType(RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT, len));
}
int16_t LR11x0::explicitHeader() {
return(this->setHeaderType(RADIOLIB_LR11X0_LORA_HEADER_EXPLICIT));
}
float LR11x0::getDataRate() const {
return(this->dataRateMeasured);
}
@ -1319,6 +1384,240 @@ int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16
return(RADIOLIB_ERR_NONE);
}
int16_t LR11x0::startWifiScan(char wifiType, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) {
uint8_t type;
switch(wifiType) {
case('b'):
type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_B;
break;
case('g'):
type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_G;
break;
case('n'):
type = RADIOLIB_LR11X0_WIFI_SCAN_802_11_N;
break;
case('*'):
type = RADIOLIB_LR11X0_WIFI_SCAN_ALL;
break;
default:
return(RADIOLIB_ERR_INVALID_WIFI_TYPE);
}
// go to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// reset cumulative timings
state = wifiResetCumulTimings();
RADIOLIB_ASSERT(state);
// set DIO mapping
state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_WIFI_DONE, 0);
RADIOLIB_ASSERT(state);
// start scan with the maximum number of results and abort on timeout
this->wifiScanMode = mode;
state = wifiScan(type, chanMask, this->wifiScanMode, RADIOLIB_LR11X0_WIFI_MAX_NUM_RESULTS, numScans, timeout, RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED);
return(state);
}
void LR11x0::setWiFiScanAction(void (*func)(void)) {
this->setIrqAction(func);
}
void LR11x0::clearWiFiScanAction() {
this->clearIrqAction();
}
int16_t LR11x0::getWifiScanResultsCount(uint8_t* count) {
// clear IRQ first, as this is likely to be called right after scan has finished
int16_t state = clearIrq(RADIOLIB_LR11X0_IRQ_ALL);
RADIOLIB_ASSERT(state);
uint8_t buff[1] = { 0 };
state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS, false, buff, sizeof(buff));
// pass the replies
if(count) { *count = buff[0]; }
return(state);
}
int16_t LR11x0::getWifiScanResult(LR11x0WifiResult_t* result, uint8_t index, bool brief) {
if(!result) {
return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
}
// read a single result
uint8_t format = brief ? RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC : RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE;
uint8_t raw[RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN] = { 0 };
int16_t state = wifiReadResults(index, 1, format, raw);
RADIOLIB_ASSERT(state);
// parse the information
switch(raw[0] & 0x03) {
case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_B):
result->type = 'b';
break;
case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_G):
result->type = 'g';
break;
case(RADIOLIB_LR11X0_WIFI_SCAN_802_11_N):
result->type = 'n';
break;
}
result->dataRateId = (raw[0] & 0xFC) >> 2;
result->channelFreq = 2407 + (raw[1] & 0x0F)*5;
result->origin = (raw[1] & 0x30) >> 4;
result->ap = (raw[1] & 0x40) != 0;
result->rssi = (float)raw[2] / -2.0f;;
memcpy(result->mac, &raw[3], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
if(!brief) {
if(this->wifiScanMode == RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON) {
LR11x0WifiResultExtended_t* resultExtended = reinterpret_cast<LR11x0WifiResultExtended_t*>(result);
resultExtended->rate = raw[3];
resultExtended->service = (((uint16_t)raw[4] << 8) | ((uint16_t)raw[5]));
resultExtended->length = (((uint16_t)raw[6] << 8) | ((uint16_t)raw[7]));
resultExtended->frameType = raw[9] & 0x03;
resultExtended->frameSubType = (raw[9] & 0x3C) >> 2;
resultExtended->toDistributionSystem = (raw[9] & 0x40) != 0;
resultExtended->fromDistributionSystem = (raw[9] & 0x80) != 0;
memcpy(resultExtended->mac0, &raw[10], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
memcpy(resultExtended->mac, &raw[16], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
memcpy(resultExtended->mac2, &raw[22], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
resultExtended->timestamp = (((uint64_t)raw[28] << 56) | ((uint64_t)raw[29] << 48)) |
(((uint64_t)raw[30] << 40) | ((uint64_t)raw[31] << 32)) |
(((uint64_t)raw[32] << 24) | ((uint64_t)raw[33] << 16)) |
(((uint64_t)raw[34] << 8) | (uint64_t)raw[35]);
resultExtended->periodBeacon = (((uint16_t)raw[36] << 8) | ((uint16_t)raw[37])) * 1024UL;
resultExtended->seqCtrl = (((uint16_t)raw[38] << 8) | ((uint16_t)raw[39]));
memcpy(resultExtended->ssid, &raw[40], RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN);
resultExtended->currentChannel = raw[72];
memcpy(resultExtended->countryCode, &raw[73], 2);
resultExtended->countryCode[2] = '\0';
resultExtended->ioReg = raw[75];
resultExtended->fcsCheckOk = (raw[76] != 0);
resultExtended->phiOffset = (((uint16_t)raw[77] << 8) | ((uint16_t)raw[78]));
return(RADIOLIB_ERR_NONE);
}
LR11x0WifiResultFull_t* resultFull = reinterpret_cast<LR11x0WifiResultFull_t*>(result);
resultFull->frameType = raw[3] & 0x03;
resultFull->frameSubType = (raw[3] & 0x3C) >> 2;
resultFull->toDistributionSystem = (raw[3] & 0x40) != 0;
resultFull->fromDistributionSystem = (raw[3] & 0x80) != 0;
memcpy(resultFull->mac, &raw[4], RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN);
resultFull->phiOffset = (((uint16_t)raw[10] << 8) | ((uint16_t)raw[11]));
resultFull->timestamp = (((uint64_t)raw[12] << 56) | ((uint64_t)raw[13] << 48)) |
(((uint64_t)raw[14] << 40) | ((uint64_t)raw[15] << 32)) |
(((uint64_t)raw[16] << 24) | ((uint64_t)raw[17] << 16)) |
(((uint64_t)raw[18] << 8) | (uint64_t)raw[19]);
resultFull->periodBeacon = (((uint16_t)raw[20] << 8) | ((uint16_t)raw[21])) * 1024UL;
}
return(RADIOLIB_ERR_NONE);
}
int16_t LR11x0::wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode, uint16_t chanMask, uint8_t numScans, uint16_t timeout) {
if(!count) {
return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
}
// start scan
RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan start");
int16_t state = startWifiScan(wifiType, mode, chanMask, numScans, timeout);
RADIOLIB_ASSERT(state);
// wait for scan finished or timeout
RadioLibTime_t softTimeout = 30UL * 1000UL;
RadioLibTime_t start = this->mod->hal->millis();
while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
this->mod->hal->yield();
if(this->mod->hal->millis() - start > softTimeout) {
RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout waiting for IRQ");
this->standby();
return(RADIOLIB_ERR_RX_TIMEOUT);
}
}
RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi scan done in %lu ms", (long unsigned int)(this->mod->hal->millis() - start));
// read number of results
return(getWifiScanResultsCount(count));
}
int16_t LR11x0::getVersionInfo(LR11x0VersionInfo_t* info) {
if(!info) {
return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
}
int16_t state = this->getVersion(&info->hardware, &info->device, &info->fwMajor, &info->fwMinor);
RADIOLIB_ASSERT(state);
state = this->wifiReadVersion(&info->fwMajorWiFi, &info->fwMinorWiFi);
RADIOLIB_ASSERT(state);
return(this->gnssReadVersion(&info->fwGNSS, &info->almanacGNSS));
}
int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolatile) {
if(!image) {
return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
}
// put the device to bootloader mode
int16_t state = this->reboot(true);
RADIOLIB_ASSERT(state);
this->mod->hal->delay(500);
// check we're in bootloader
uint8_t device = 0xFF;
state = this->getVersion(NULL, &device, NULL, NULL);
RADIOLIB_ASSERT(state);
if(device != RADIOLIB_LR11X0_DEVICE_BOOT) {
RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to put device to bootloader mode, %02x != %02x", device, RADIOLIB_LR11X0_DEVICE_BOOT);
return(RADIOLIB_ERR_CHIP_NOT_FOUND);
}
// erase the image
state = this->bootEraseFlash();
RADIOLIB_ASSERT(state);
// wait for BUSY to go low
RadioLibTime_t start = this->mod->hal->millis();
while(this->mod->hal->digitalRead(this->mod->getGpio())) {
this->mod->hal->yield();
if(this->mod->hal->millis() - start >= 3000) {
RADIOLIB_DEBUG_BASIC_PRINTLN("BUSY pin timeout after erase!");
return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
}
}
// upload the new image
const size_t maxLen = 64;
size_t rem = size % maxLen;
size_t numWrites = (rem == 0) ? (size / maxLen) : ((size / maxLen) + 1);
RADIOLIB_DEBUG_BASIC_PRINTLN("Writing image in %lu chunks, last chunk size is %lu words", (unsigned long)numWrites, (unsigned long)rem);
for(size_t i = 0; i < numWrites; i ++) {
uint32_t offset = i * maxLen;
uint32_t len = (i == (numWrites - 1)) ? rem : maxLen;
RADIOLIB_DEBUG_BASIC_PRINTLN("Writing chunk %d at offset %08lx (%u words)", (int)i, (unsigned long)offset, (unsigned int)len);
this->bootWriteFlashEncrypted(offset*sizeof(uint32_t), (uint32_t*)&image[offset], len, nonvolatile);
}
// kick the device from bootloader
state = this->reset();
RADIOLIB_ASSERT(state);
// verify we are no longer in bootloader
state = this->getVersion(NULL, &device, NULL, NULL);
RADIOLIB_ASSERT(state);
if(device == RADIOLIB_LR11X0_DEVICE_BOOT) {
RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to kick device from bootloader mode, %02x == %02x", device, RADIOLIB_LR11X0_DEVICE_BOOT);
return(RADIOLIB_ERR_CHIP_NOT_FOUND);
}
return(state);
}
int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) {
this->mod->init();
this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
@ -1374,7 +1673,7 @@ int16_t LR11x0::SPIcheckStatus(Module* mod) {
// it also seems to ignore the actual command, and just sending in bunch of NOPs will work
uint8_t buff[6] = { 0 };
mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0;
int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true, RADIOLIB_MODULE_SPI_TIMEOUT);
int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true);
mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8;
RADIOLIB_ASSERT(state);
return(LR11x0::SPIparseStatus(buff[0]));
@ -1410,12 +1709,16 @@ bool LR11x0::findChip(uint8_t ver) {
reset();
// read the version
uint8_t device = 0xFF;
if((this->getVersion(NULL, &device, NULL, NULL) == RADIOLIB_ERR_NONE) && (device == ver)) {
RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", device);
LR11x0VersionInfo_t info;
int16_t state = getVersionInfo(&info);
if((state == RADIOLIB_ERR_NONE) && (info.device == ver)) {
RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", info.device);
RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)info.fwMajor, (int)info.fwMinor);
RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi FW version: %d.%d", (int)info.fwMajorWiFi, (int)info.fwMinorWiFi);
RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS FW version: %d.%d", (int)info.fwGNSS, (int)info.almanacGNSS);
flagFound = true;
} else {
RADIOLIB_DEBUG_BASIC_PRINTLN("LR11x0 not found! (%d of 10 tries) RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", i + 1, device);
RADIOLIB_DEBUG_BASIC_PRINTLN("LR11x0 not found! (%d of 10 tries) RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", i + 1, info.device);
RADIOLIB_DEBUG_BASIC_PRINTLN("Expected: 0x%02x", ver);
this->mod->hal->delay(10);
i++;
@ -1438,7 +1741,7 @@ int16_t LR11x0::config(uint8_t modem) {
RADIOLIB_ASSERT(state);
// calibrate all blocks
state = this->calibrate(RADIOLIB_LR11X0_CALIBRATE_ALL);
(void)this->calibrate(RADIOLIB_LR11X0_CALIBRATE_ALL);
// wait for calibration completion
this->mod->hal->delay(5);
@ -1496,7 +1799,7 @@ int16_t LR11x0::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) {
num = 2;
}
uint8_t detPeakValues[8] = { 48, 48, 50, 55, 55, 59, 61, 65 };
const uint8_t detPeakValues[8] = { 48, 48, 50, 55, 55, 59, 61, 65 };
uint8_t peak = detPeak;
if(peak == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) {
peak = detPeakValues[this->spreadingFactor - 5];
@ -1516,6 +1819,26 @@ int16_t LR11x0::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) {
return(setCad());
}
int16_t LR11x0::setHeaderType(uint8_t hdrType, size_t len) {
// check active modem
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
int16_t state = getPacketType(&type);
RADIOLIB_ASSERT(state);
if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
// set requested packet mode
state = setPacketParamsLoRa(this->preambleLengthLoRa, hdrType, len, this->crcTypeLoRa, this->invertIQEnabled);
RADIOLIB_ASSERT(state);
// update cached value
this->headerType = hdrType;
this->implicitLen = len;
return(state);
}
Module* LR11x0::getMod() {
return(this->mod);
}
@ -1525,7 +1848,7 @@ int16_t LR11x0::writeRegMem32(uint32_t addr, uint32_t* data, size_t len) {
if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
return(RADIOLIB_ERR_SPI_CMD_INVALID);
}
return(this->writeCommon(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len));
return(this->writeCommon(RADIOLIB_LR11X0_CMD_WRITE_REG_MEM, addr, data, len, false));
}
int16_t LR11x0::readRegMem32(uint32_t addr, uint32_t* data, size_t len) {
@ -1618,7 +1941,7 @@ int16_t LR11x0::getStatus(uint8_t* stat1, uint8_t* stat2, uint32_t* irq) {
// the status check command doesn't return status in the same place as other read commands
// but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used
// it also seems to ignore the actual command, and just sending in bunch of NOPs will work
int16_t state = this->mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true, RADIOLIB_MODULE_SPI_TIMEOUT);
int16_t state = this->mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true);
// pass the replies
if(stat1) { *stat1 = buff[0]; }
@ -1671,8 +1994,8 @@ int16_t LR11x0::calibImage(float freq1, float freq2) {
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_CALIB_IMAGE, true, buff, sizeof(buff)));
}
int16_t LR11x0::setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t gnssCfg, uint8_t wifiCfg) {
uint8_t buff[7] = { en, stbyCfg, rxCfg, txCfg, txHpCfg, gnssCfg, wifiCfg };
int16_t LR11x0::setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg) {
uint8_t buff[8] = { en, stbyCfg, rxCfg, txCfg, txHpCfg, txHfCfg, gnssCfg, wifiCfg };
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_DIO_AS_RF_SWITCH, true, buff, sizeof(buff)));
}
@ -1703,8 +2026,8 @@ int16_t LR11x0::setTcxoMode(uint8_t tune, uint32_t delay) {
}
int16_t LR11x0::reboot(bool stay) {
uint8_t buff[1] = { (uint8_t)stay };
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_REBOOT, true, buff, sizeof(buff)));
uint8_t buff[1] = { (uint8_t)(stay*3) };
return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_REBOOT, buff, sizeof(buff), true, false));
}
int16_t LR11x0::getVbat(float* vbat) {
@ -1750,7 +2073,7 @@ int16_t LR11x0::eraseInfoPage(void) {
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_ERASE_INFO_PAGE, true, buff, sizeof(buff)));
}
int16_t LR11x0::writeInfoPage(uint16_t addr, uint32_t* data, size_t len) {
int16_t LR11x0::writeInfoPage(uint16_t addr, const uint32_t* data, size_t len) {
// check maximum size
if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
return(RADIOLIB_ERR_SPI_CMD_INVALID);
@ -1779,7 +2102,7 @@ int16_t LR11x0::writeInfoPage(uint16_t addr, uint32_t* data, size_t len) {
}
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WRITE_INFO_PAGE, true, dataBuff, buffLen);
#if RADIOLIB_STATIC_ONLY
#if !RADIOLIB_STATIC_ONLY
delete[] dataBuff;
#endif
return(state);
@ -2112,7 +2435,7 @@ int16_t LR11x0::setRangingReqAddr(uint32_t addr) {
int16_t LR11x0::getRangingResult(uint8_t type, float* res) {
uint8_t reqBuff[1] = { type };
uint8_t rplBuff[4] = { 0 };
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_NOP, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_RANGING_RESULT, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
RADIOLIB_ASSERT(state);
if(res) {
@ -2164,6 +2487,22 @@ int16_t LR11x0::setRangingParameter(uint8_t symbolNum) {
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER, true, buff, sizeof(buff)));
}
int16_t LR11x0::setRssiCalibration(int8_t* tune, int16_t gainOffset) {
uint8_t buff[11] = {
(uint8_t)((tune[0] & 0x0F) | (uint8_t)(tune[1] & 0x0F) << 4),
(uint8_t)((tune[2] & 0x0F) | (uint8_t)(tune[3] & 0x0F) << 4),
(uint8_t)((tune[4] & 0x0F) | (uint8_t)(tune[5] & 0x0F) << 4),
(uint8_t)((tune[6] & 0x0F) | (uint8_t)(tune[7] & 0x0F) << 4),
(uint8_t)((tune[8] & 0x0F) | (uint8_t)(tune[9] & 0x0F) << 4),
(uint8_t)((tune[10] & 0x0F) | (uint8_t)(tune[11] & 0x0F) << 4),
(uint8_t)((tune[12] & 0x0F) | (uint8_t)(tune[13] & 0x0F) << 4),
(uint8_t)((tune[14] & 0x0F) | (uint8_t)(tune[15] & 0x0F) << 4),
(uint8_t)((tune[16] & 0x0F) | (uint8_t)(tune[17] & 0x0F) << 4),
(uint8_t)(((uint16_t)gainOffset >> 8) & 0xFF), (uint8_t)(gainOffset & 0xFF),
};
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION, true, buff, sizeof(buff)));
}
int16_t LR11x0::setLoRaSyncWord(uint8_t sync) {
uint8_t buff[1] = { sync };
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD, true, buff, sizeof(buff)));
@ -2202,7 +2541,7 @@ int16_t LR11x0::lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, boo
memcpy(&dataBuff[9], payload, len);
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME, true, dataBuff, buffLen);
#if RADIOLIB_STATIC_ONLY
#if !RADIOLIB_STATIC_ONLY
delete[] dataBuff;
#endif
return(state);
@ -2253,7 +2592,7 @@ int16_t LR11x0::bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, si
memcpy(&dataBuff[1], payload, len);
int16_t state = this->SPIcommand(cmd, true, dataBuff, sizeof(uint8_t) + len);
#if RADIOLIB_STATIC_ONLY
#if !RADIOLIB_STATIC_ONLY
delete[] dataBuff;
#endif
return(state);
@ -2266,7 +2605,9 @@ int16_t LR11x0::wifiScan(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t n
(uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF),
abortOnTimeout
};
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_SCAN, true, buff, sizeof(buff)));
// call the SPI write stream directly to skip waiting for BUSY - it will be set to high once the scan starts
return(this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_WIFI_SCAN, buff, sizeof(buff), false, false));
}
int16_t LR11x0::wifiScanTimeLimit(uint8_t type, uint16_t mask, uint8_t acqMode, uint8_t nbMaxRes, uint16_t timePerChan, uint16_t timeout) {
@ -2299,19 +2640,9 @@ int16_t LR11x0::wifiCountryCodeTimeLimit(uint16_t mask, uint8_t nbMaxRes, uint16
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_COUNTRY_CODE_TIME_LIMIT, true, buff, sizeof(buff)));
}
int16_t LR11x0::wifiGetNbResults(uint8_t* nbResults) {
uint8_t buff[1] = { 0 };
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_GET_NB_RESULTS, false, buff, sizeof(buff));
// pass the replies
if(nbResults) { *nbResults = buff[0]; }
return(state);
}
int16_t LR11x0::wifiReadResults(uint8_t index, uint8_t nbResults, uint8_t format, uint8_t* results) {
uint8_t reqBuff[3] = { index, nbResults, format };
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS, false, results, nbResults, reqBuff, sizeof(reqBuff)));
uint8_t buff[3] = { index, nbResults, format };
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS, false, results, RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN, buff, sizeof(buff)));
}
int16_t LR11x0::wifiResetCumulTimings(void) {
@ -2481,7 +2812,7 @@ int16_t LR11x0::gnssGetContextStatus(uint8_t* fwVersion, uint32_t* almanacCrc, u
// read the result - this requires some magic bytes first, that's why LR11x0::SPIcommand cannot be used
uint8_t cmd_buff[3] = { 0x00, 0x02, 0x18 };
uint8_t buff[9] = { 0 };
state = this->mod->SPItransferStream(cmd_buff, sizeof(cmd_buff), false, NULL, buff, sizeof(buff), true, RADIOLIB_MODULE_SPI_TIMEOUT);
state = this->mod->SPItransferStream(cmd_buff, sizeof(cmd_buff), false, NULL, buff, sizeof(buff), true);
// pass the replies
if(fwVersion) { *fwVersion = buff[0]; }
@ -2526,7 +2857,7 @@ int16_t LR11x0::gnssGetSvDetected(uint8_t* svId, uint8_t* snr, uint16_t* doppler
}
}
#if RADIOLIB_STATIC_ONLY
#if !RADIOLIB_STATIC_ONLY
delete[] dataBuff;
#endif
return(state);
@ -2589,6 +2920,196 @@ int16_t LR11x0::gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t co
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE, false, nbSv, 1, reqBuff, sizeof(reqBuff)));
}
// TODO check version > 02.01
int16_t LR11x0::gnssScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax) {
uint8_t buff[3] = { effort, resMask, nbSvMax };
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SCAN, true, buff, sizeof(buff)));
}
int16_t LR11x0::gnssReadLastScanModeLaunched(uint8_t* lastScanMode) {
uint8_t buff[1] = { 0 };
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED, false, buff, sizeof(buff));
// pass the replies
if(lastScanMode) { *lastScanMode = buff[0]; }
return(state);
}
int16_t LR11x0::gnssFetchTime(uint8_t effort, uint8_t opt) {
uint8_t buff[2] = { effort, opt };
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME, true, buff, sizeof(buff)));
}
int16_t LR11x0::gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint32_t* timeAccuracy) {
uint8_t buff[12] = { 0 };
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_TIME, false, buff, sizeof(buff));
// pass the replies
if(err) { *err = buff[0]; }
if(time) { *time = ((uint32_t)(buff[1]) << 24) | ((uint32_t)(buff[2]) << 16) | ((uint32_t)(buff[3]) << 8) | (uint32_t)buff[4]; }
if(nbUs) { *nbUs = ((uint32_t)(buff[5]) << 16) | ((uint32_t)(buff[6]) << 8) | (uint32_t)buff[7]; }
if(timeAccuracy) { *timeAccuracy = ((uint32_t)(buff[8]) << 24) | ((uint32_t)(buff[9]) << 16) | ((uint32_t)(buff[10]) << 8) | (uint32_t)buff[11]; }
return(state);
}
int16_t LR11x0::gnssResetTime(void) {
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME, true, NULL, 0));
}
int16_t LR11x0::gnssResetPosition(void) {
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION, true, NULL, 0));
}
int16_t LR11x0::gnssReadDemodStatus(int8_t* status, uint8_t* info) {
uint8_t buff[2] = { 0 };
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS, false, buff, sizeof(buff));
// pass the replies
if(status) { *status = (int8_t)buff[0]; }
if(info) { *info = buff[1]; }
return(state);
}
int16_t LR11x0::gnssReadCumulTiming(uint32_t* timing, uint8_t* constDemod) {
uint8_t rplBuff[125] = { 0 };
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_READ_REG_MEM, false, rplBuff, 125);
RADIOLIB_ASSERT(state);
// convert endians
if(timing) {
for(size_t i = 0; i < 31; i++) {
timing[i] = ((uint32_t)rplBuff[i*sizeof(uint32_t)] << 24) | ((uint32_t)rplBuff[1 + i*sizeof(uint32_t)] << 16) | ((uint32_t)rplBuff[2 + i*sizeof(uint32_t)] << 8) | (uint32_t)rplBuff[3 + i*sizeof(uint32_t)];
}
}
if(constDemod) { *constDemod = rplBuff[124]; }
return(state);
}
int16_t LR11x0::gnssSetTime(uint32_t time, uint16_t accuracy) {
uint8_t buff[6] = {
(uint8_t)((time >> 24) & 0xFF), (uint8_t)((time >> 16) & 0xFF),
(uint8_t)((time >> 8) & 0xFF), (uint8_t)(time & 0xFF),
(uint8_t)((accuracy >> 8) & 0xFF), (uint8_t)(accuracy & 0xFF),
};
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_SET_TIME, true, buff, sizeof(buff)));
}
int16_t LR11x0::gnssReadDopplerSolverRes(uint8_t* error, uint8_t* nbSvUsed, float* lat, float* lon, uint16_t* accuracy, uint16_t* xtal, float* latFilt, float* lonFilt, uint16_t* accuracyFilt, uint16_t* xtalFilt) {
uint8_t buff[18] = { 0 };
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES, false, buff, sizeof(buff));
// pass the replies
if(error) { *error = buff[0]; }
if(nbSvUsed) { *nbSvUsed = buff[1]; }
if(lat) {
uint16_t latRaw = ((uint16_t)(buff[2]) << 8) | (uint16_t)buff[3];
*lat = ((float)latRaw * 90.0f)/2048.0f;
}
if(lon) {
uint16_t lonRaw = ((uint16_t)(buff[4]) << 8) | (uint16_t)buff[5];
*lon = ((float)lonRaw * 180.0f)/2048.0f;
}
if(accuracy) { *accuracy = ((uint16_t)(buff[6]) << 8) | (uint16_t)buff[7]; }
if(xtal) { *xtal = ((uint16_t)(buff[8]) << 8) | (uint16_t)buff[9]; }
if(latFilt) {
uint16_t latRaw = ((uint16_t)(buff[10]) << 8) | (uint16_t)buff[11];
*latFilt = ((float)latRaw * 90.0f)/2048.0f;
}
if(lonFilt) {
uint16_t lonRaw = ((uint16_t)(buff[12]) << 8) | (uint16_t)buff[13];
*lonFilt = ((float)lonRaw * 180.0f)/2048.0f;
}
if(accuracyFilt) { *accuracyFilt = ((uint16_t)(buff[14]) << 8) | (uint16_t)buff[15]; }
if(xtalFilt) { *xtalFilt = ((uint16_t)(buff[16]) << 8) | (uint16_t)buff[17]; }
return(state);
}
int16_t LR11x0::gnssReadDelayResetAP(uint32_t* delay) {
uint8_t buff[3] = { 0 };
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP, false, buff, sizeof(buff));
if(delay) { *delay = ((uint32_t)(buff[0]) << 16) | ((uint32_t)(buff[1]) << 8) | (uint32_t)buff[2]; }
return(state);
}
int16_t LR11x0::gnssAlmanacUpdateFromSat(uint8_t effort, uint8_t bitMask) {
uint8_t buff[2] = { effort, bitMask };
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT, true, buff, sizeof(buff)));
}
int16_t LR11x0::gnssReadAlmanacStatus(uint8_t* status) {
// TODO parse the reply into some structure
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS, false, status, 53));
}
int16_t LR11x0::gnssConfigAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t period) {
uint8_t buff[4] = { bitMask, svType, (uint8_t)((period >> 8) & 0xFF), (uint8_t)(period & 0xFF) };
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD, true, buff, sizeof(buff)));
}
int16_t LR11x0::gnssReadAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t* period) {
uint8_t reqBuff[2] = { bitMask, svType };
uint8_t rplBuff[2] = { 0 };
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
RADIOLIB_ASSERT(state);
if(period) { *period = ((uint16_t)(rplBuff[0]) << 8) | (uint16_t)rplBuff[1]; }
return(state);
}
int16_t LR11x0::gnssConfigDelayResetAP(uint32_t delay) {
uint8_t buff[3] = { (uint8_t)((delay >> 16) & 0xFF), (uint8_t)((delay >> 8) & 0xFF), (uint8_t)(delay & 0xFF) };
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP, true, buff, sizeof(buff)));
}
int16_t LR11x0::gnssGetSvWarmStart(uint8_t bitMask, uint8_t* sv, uint8_t nbVisSat) {
uint8_t reqBuff[1] = { bitMask };
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START, false, sv, nbVisSat, reqBuff, sizeof(reqBuff)));
}
int16_t LR11x0::gnssReadWNRollover(uint8_t* status, uint8_t* rollover) {
uint8_t buff[2] = { 0 };
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WN_ROLLOVER, false, buff, sizeof(buff));
if(status) { *status = buff[0]; }
if(rollover) { *rollover = buff[1]; }
return(state);
}
int16_t LR11x0::gnssReadWarmStartStatus(uint8_t bitMask, uint8_t* nbVisSat, uint32_t* timeElapsed) {
uint8_t reqBuff[1] = { bitMask };
uint8_t rplBuff[5] = { 0 };
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS, false, rplBuff, sizeof(rplBuff), reqBuff, sizeof(reqBuff));
RADIOLIB_ASSERT(state);
if(nbVisSat) { *nbVisSat = rplBuff[0]; }
if(timeElapsed) { *timeElapsed = ((uint32_t)(rplBuff[1]) << 24) | ((uint32_t)(rplBuff[2]) << 16) | ((uint32_t)(rplBuff[3]) << 8) | (uint32_t)rplBuff[4]; }
return(state);
}
int16_t LR11x0::gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1) {
uint8_t reqBuff[1] = { bitMask };
uint8_t rplBuff[8] = { 0 };
size_t rplLen = (bitMask & 0x01) ? 8 : 4; // GPS only has the first bit mask
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS, false, rplBuff, rplLen, reqBuff, sizeof(reqBuff));
RADIOLIB_ASSERT(state);
if(bitMaskActivated0) { *bitMaskActivated0 = ((uint32_t)(rplBuff[0]) << 24) | ((uint32_t)(rplBuff[1]) << 16) | ((uint32_t)(rplBuff[2]) << 8) | (uint32_t)rplBuff[3]; }
if(bitMaskActivated1) { *bitMaskActivated1 = ((uint32_t)(rplBuff[4]) << 24) | ((uint32_t)(rplBuff[5]) << 16) | ((uint32_t)(rplBuff[6]) << 8) | (uint32_t)rplBuff[7]; }
return(state);
}
int16_t LR11x0::cryptoSetKey(uint8_t keyId, uint8_t* key) {
if(!key) {
return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
@ -2670,7 +3191,7 @@ int16_t LR11x0::cryptoComputeAesCmac(uint8_t keyId, uint8_t* data, size_t len, u
memcpy(&reqBuff[1], data, len);
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_COMPUTE_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen);
#if RADIOLIB_STATIC_ONLY
#if !RADIOLIB_STATIC_ONLY
delete[] reqBuff;
#endif
@ -2701,7 +3222,7 @@ int16_t LR11x0::cryptoVerifyAesCmac(uint8_t keyId, uint32_t micExp, uint8_t* dat
memcpy(&reqBuff[5], data, len);
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_CRYPTO_VERIFY_AES_CMAC, false, rplBuff, sizeof(rplBuff), reqBuff, reqLen);
#if RADIOLIB_STATIC_ONLY
#if !RADIOLIB_STATIC_ONLY
delete[] reqBuff;
#endif
@ -2753,13 +3274,12 @@ int16_t LR11x0::cryptoGetParam(uint8_t id, uint32_t* value) {
return(state);
}
int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len) {
int16_t LR11x0::cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile) {
// check maximum size
if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
return(RADIOLIB_ERR_SPI_CMD_INVALID);
}
return(this->writeCommon(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len));
return(this->writeCommon(RADIOLIB_LR11X0_CMD_CRYPTO_CHECK_ENCRYPTED_FIRMWARE_IMAGE, offset, data, len, nonvolatile));
}
int16_t LR11x0::cryptoCheckEncryptedFirmwareImageResult(bool* result) {
@ -2773,12 +3293,20 @@ int16_t LR11x0::cryptoCheckEncryptedFirmwareImageResult(bool* result) {
}
int16_t LR11x0::bootEraseFlash(void) {
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH, true, NULL, 0));
// erasing flash takes about 2.5 seconds, temporarily tset SPI timeout to 3 seconds
RadioLibTime_t timeout = this->mod->spiConfig.timeout;
this->mod->spiConfig.timeout = 3000;
int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_BOOT_ERASE_FLASH, NULL, 0, false, false);
this->mod->spiConfig.timeout = timeout;
return(state);
}
int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len) {
RADIOLIB_CHECK_RANGE(len, 1, 32, RADIOLIB_ERR_SPI_CMD_INVALID);
return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len));
int16_t LR11x0::bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile) {
// check maximum size
if(len > (RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN/sizeof(uint32_t))) {
return(RADIOLIB_ERR_SPI_CMD_INVALID);
}
return(this->writeCommon(RADIOLIB_LR11X0_CMD_BOOT_WRITE_FLASH_ENCRYPTED, offset, data, len, nonvolatile));
}
int16_t LR11x0::bootReboot(bool stay) {
@ -2807,7 +3335,7 @@ int16_t LR11x0::bootGetJoinEui(uint8_t* eui) {
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_BOOT_GET_JOIN_EUI, false, eui, RADIOLIB_LR11X0_EUI_LEN));
}
int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, uint32_t* data, size_t len) {
int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile) {
// build buffers - later we need to ensure endians are correct,
// so there is probably no way to do this without copying buffers and iterating
size_t buffLen = sizeof(uint32_t) + len*sizeof(uint32_t);
@ -2825,14 +3353,20 @@ int16_t LR11x0::writeCommon(uint16_t cmd, uint32_t addrOffset, uint32_t* data, s
// convert endians
for(size_t i = 0; i < len; i++) {
dataBuff[4 + i] = (uint8_t)((data[i] >> 24) & 0xFF);
dataBuff[5 + i] = (uint8_t)((data[i] >> 16) & 0xFF);
dataBuff[6 + i] = (uint8_t)((data[i] >> 8) & 0xFF);
dataBuff[7 + i] = (uint8_t)(data[i] & 0xFF);
uint32_t bin = 0;
if(nonvolatile) {
bin = RADIOLIB_NONVOLATILE_READ_DWORD(data + i);
} else {
bin = data[i];
}
dataBuff[4 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 24) & 0xFF);
dataBuff[5 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 16) & 0xFF);
dataBuff[6 + i*sizeof(uint32_t)] = (uint8_t)((bin >> 8) & 0xFF);
dataBuff[7 + i*sizeof(uint32_t)] = (uint8_t)(bin & 0xFF);
}
int16_t state = this->SPIcommand(cmd, true, dataBuff, buffLen);
#if RADIOLIB_STATIC_ONLY
int16_t state = this->mod->SPIwriteStream(cmd, dataBuff, buffLen, true, false);
#if !RADIOLIB_STATIC_ONLY
delete[] dataBuff;
#endif
return(state);

View file

@ -84,6 +84,7 @@
#define RADIOLIB_LR11X0_CMD_SET_GFSK_WHIT_PARAMS (0x0225)
#define RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED (0x0227)
#define RADIOLIB_LR11X0_CMD_SET_RANGING_PARAMETER (0x0228)
#define RADIOLIB_LR11X0_CMD_SET_RSSI_CALIBRATION (0x0229)
#define RADIOLIB_LR11X0_CMD_SET_LORA_SYNC_WORD (0x022B)
#define RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME (0x022C)
#define RADIOLIB_LR11X0_CMD_LR_FHSS_SET_SYNC_WORD (0x022D)
@ -111,6 +112,10 @@
#define RADIOLIB_LR11X0_CMD_GNSS_SET_MODE (0x0408)
#define RADIOLIB_LR11X0_CMD_GNSS_AUTONOMOUS (0x0409)
#define RADIOLIB_LR11X0_CMD_GNSS_ASSISTED (0x040A)
#define RADIOLIB_LR11X0_CMD_GNSS_SCAN (0x040B)
#define RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE (0x040C)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS (0x040D)
#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE (0x040E)
#define RADIOLIB_LR11X0_CMD_GNSS_SET_ASSISTANCE_POSITION (0x0410)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_ASSISTANCE_POSITION (0x0411)
#define RADIOLIB_LR11X0_CMD_GNSS_PUSH_SOLVER_MSG (0x0414)
@ -119,10 +124,26 @@
#define RADIOLIB_LR11X0_CMD_GNSS_GET_NB_SV_DETECTED (0x0417)
#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_DETECTED (0x0418)
#define RADIOLIB_LR11X0_CMD_GNSS_GET_CONSUMPTION (0x0419)
#define RADIOLIB_LR11X0_CMD_GNSS_GET_RESULT_SIZE (0x040C)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_RESULTS (0x040D)
#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_FULL_UPDATE (0x040E)
#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_VISIBLE (0x041F)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_LAST_SCAN_MODE_LAUNCHED (0x0426)
#define RADIOLIB_LR11X0_CMD_GNSS_FETCH_TIME (0x0432)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_TIME (0x0434)
#define RADIOLIB_LR11X0_CMD_GNSS_RESET_TIME (0x0435)
#define RADIOLIB_LR11X0_CMD_GNSS_RESET_POSITION (0x0437)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_DEMOD_STATUS (0x0439)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_CUMUL_TIMING (0x044A)
#define RADIOLIB_LR11X0_CMD_GNSS_SET_TIME (0x044B)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_DOPPLER_SOLVER_RES (0x044F)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_DELAY_RESET_AP (0x0453)
#define RADIOLIB_LR11X0_CMD_GNSS_ALMANAC_UPDATE_FROM_SAT (0x0455)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_STATUS (0x0457)
#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_ALMANAC_UPDATE_PERIOD (0x0463)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_ALMANAC_UPDATE_PERIOD (0x0464)
#define RADIOLIB_LR11X0_CMD_GNSS_CONFIG_DELAY_RESET_AP (0x0465)
#define RADIOLIB_LR11X0_CMD_GNSS_GET_SV_WARM_START (0x0466)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_WN_ROLLOVER (0x0467)
#define RADIOLIB_LR11X0_CMD_GNSS_READ_WARM_START_STATUS (0x0469)
#define RADIOLIB_LR11X0_CMD_GNSS_WRITE_BIT_MASK_SAT_ACTIVATED (0x0472)
#define RADIOLIB_LR11X0_CMD_CRYPTO_SET_KEY (0x0502)
#define RADIOLIB_LR11X0_CMD_CRYPTO_DERIVE_KEY (0x0503)
#define RADIOLIB_LR11X0_CMD_CRYPTO_PROCESS_JOIN_ACCEPT (0x0504)
@ -147,6 +168,7 @@
// LR11X0 register map
#define RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT (0x00F20414)
#define RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX (0x00F30054)
// TODO add fix for br 600/1200 bps
// LR11X0 SPI command variables
@ -178,10 +200,10 @@
#define RADIOLIB_LR11X0_SPI_MAX_READ_WRITE_LEN (256) // 7 0 maximum length of read/write SPI payload in bytes
// RADIOLIB_LR11X0_CMD_GET_VERSION
#define RADIOLIB_LR11X0_HW_LR1110 (0x01UL << 0) // 7 0 HW version: LR1110
#define RADIOLIB_LR11X0_HW_LR1120 (0x02UL << 0) // 7 0 LR1120
#define RADIOLIB_LR11X0_HW_LR1121 (0x03UL << 0) // 7 0 LR1121
#define RADIOLIB_LR11X0_HW_BOOT (0xDFUL << 0) // 7 0 bootloader mode
#define RADIOLIB_LR11X0_DEVICE_LR1110 (0x01UL << 0) // 7 0 HW device: LR1110
#define RADIOLIB_LR11X0_DEVICE_LR1120 (0x02UL << 0) // 7 0 LR1120
#define RADIOLIB_LR11X0_DEVICE_LR1121 (0x03UL << 0) // 7 0 LR1121
#define RADIOLIB_LR11X0_DEVICE_BOOT (0xDFUL << 0) // 7 0 bootloader mode
// RADIOLIB_LR11X0_CMD_GET_ERRORS
#define RADIOLIB_LR11X0_ERROR_STAT_LF_RC_CALIB_ERR (0x01UL << 0) // 15 0 error: low frequency RC not calibrated
@ -472,10 +494,15 @@
#define RADIOLIB_LR11X0_WIFI_ACQ_MODE_SSID_BEACON (0x05UL << 0) // 7 0 SSID beacon
#define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_ENABLED (0x01UL << 0) // 7 0 abort scanning on preamble timeout: enabled
#define RADIOLIB_LR11X0_WIFI_ABORT_ON_TIMEOUT_DISABLED (0x00UL << 0) // 7 0 disabled
#define RADIOLIB_LR11X0_WIFI_MAX_NUM_RESULTS (32) // 7 0 maximum possible number of Wi-Fi scan results
#define RADIOLIB_LR11X0_WIFI_ALL_CHANNELS (0x3FFFUL) // 16 0 scan all channels
// RADIOLIB_LR11X0_CMD_WIFI_READ_RESULTS
#define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_COMPLETE (0x01UL << 0) // 7 0 Wi-Fi scan result type: complete
#define RADIOLIB_LR11X0_WIFI_RESULT_TYPE_BASIC (0x04UL << 0) // 7 0 basic
#define RADIOLIB_LR11X0_WIFI_RESULT_MAX_LEN (79) // 7 0 maximum possible Wi-Fi scan size
#define RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN (6) // 7 0 MAC address length in bytes
#define RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN (32) // 7 0 SSID length in bytes
// RADIOLIB_LR11X0_CMD_GNSS_SET_CONSTELLATION_TO_USE
#define RADIOLIB_LR11X0_GNSS_CONSTELLATION_GPS (0x01UL << 0) // 7 0 GNSS constellation to use: GPS
@ -536,10 +563,138 @@
// RADIOLIB_LR11X0_REG_LORA_HIGH_POWER_FIX
#define RADIOLIB_LR11X0_LORA_HIGH_POWER_FIX (0x00UL << 30) // 30 30 fix for errata
/*!
\struct LR11x0WifiResult_t
\brief Structure to save result of passive WiFi scan.
This result only saves the basic information.
*/
struct LR11x0WifiResult_t {
/*! \brief WiFi (802.11) signal type, 'b', 'n' or 'g' */
char type;
/*! \brief Data rate ID holding information about modulation and coding rate. See LR11x0 user manual for details. */
uint8_t dataRateId;
/*! \brief Channel frequency in MHz */
uint16_t channelFreq;
/*! \brief MAC address origin: from gateway (1), phone (2) or undetermined (3) */
uint8_t origin;
/*! \brief Whether this signal was sent by an access point (true) or end device (false) */
bool ap;
/*! \brief RSSI in dBm */
float rssi;
/*! \brief MAC address */
uint8_t mac[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN];
};
/*!
\struct LR11x0WifiResultFull_t
\brief Structure to save result of passive WiFi scan.
This result saves additional information alongside that in LR11x0WifiResult_t.
*/
struct LR11x0WifiResultFull_t: public LR11x0WifiResult_t {
/*! \brief Frame type. See LR11x0 user manual for details. */
uint8_t frameType;
/*! \brief Frame sub type. See LR11x0 user manual for details. */
uint8_t frameSubType;
/*! \brief Frame sent from client station to distribution system. */
bool toDistributionSystem;
/*! \brief Frame sent from distribution system to client station. */
bool fromDistributionSystem;
/*! \brief See LR11x0 user manual for details. */
uint16_t phiOffset;
/*! \brief Number of microseconds the AP has been active. */
uint64_t timestamp;
/*! \brief Beacon period in microseconds. */
uint32_t periodBeacon;
};
/*!
\struct LR11x0WifiResultExtended_t
\brief Structure to save result of passive WiFi scan.
This result saves additional information alongside that in LR11x0WifiResultFull_t.
Only scans performed with RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON acquisition mode
can yield this result!
*/
struct LR11x0WifiResultExtended_t: public LR11x0WifiResultFull_t {
/*! \brief Data rate. See LR11x0 user manual for details. */
uint8_t rate;
/*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */
uint16_t service;
/*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */
uint16_t length;
/*! \brief MAC address 0 */
uint8_t mac0[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN];
/*! \brief MAC address 2 */
uint8_t mac2[RADIOLIB_LR11X0_WIFI_RESULT_MAC_LEN];
/*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */
uint16_t seqCtrl;
/*! \brief SSID */
uint8_t ssid[RADIOLIB_LR11X0_WIFI_RESULT_SSID_LEN];
/*! \brief WiFi channel number */
uint8_t currentChannel;
/*! \brief Two-letter country code (null-terminated string). */
char countryCode[3];
/*! \brief Refer to IEEE Std 802.11, 2016, Part 11: Wireless LAN MAC and PHY Spec. */
uint8_t ioReg;
/*! \brief True if frame check sequences is valid, false otherwise. */
bool fcsCheckOk;
};
/*!
\struct LR11x0VersionInfo_t
\brief Structure to report information about versions of the LR11x0 hardware and firmware.
*/
struct LR11x0VersionInfo_t {
/*! \brief Hardware revision. */
uint8_t hardware;
/*! \brief Which device this is - one of RADIOLIB_LR11X0_DEVICE_* macros. */
uint8_t device;
/*! \brief Major revision of the base firmware. */
uint8_t fwMajor;
/*! \brief Minor revision of the base firmware. */
uint8_t fwMinor;
/*! \brief Major revision of the WiFi firmware. */
uint8_t fwMajorWiFi;
/*! \brief Minor revision of the WiFi firmware. */
uint8_t fwMinorWiFi;
/*! \brief Revision of the GNSS firmware. */
uint8_t fwGNSS;
/*! \brief Almanac revision of the GNSS firmware. */
uint8_t almanacGNSS;
};
/*!
\class LR11x0
\brief
\brief Base class for %LR11x0 series. All derived classes for %LR11x0 (e.g. LR1110 or LR1120) inherit from this base class.
This class should not be instantiated directly from user code, only from its derived classes.
*/
class LR11x0: public PhysicalLayer {
public:
@ -553,7 +708,7 @@ class LR11x0: public PhysicalLayer {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
LR11x0(Module* mod);
explicit LR11x0(Module* mod);
/*!
\brief Whether the module has an XTAL (true) or TCXO (false). Defaults to false.
@ -664,6 +819,13 @@ class LR11x0: public PhysicalLayer {
*/
int16_t standby(uint8_t mode, bool wakeup = true);
/*!
\brief Sets the module to sleep mode. To wake the device up, call standby().
Overload with warm start enabled for PhysicalLayer compatibility.
\returns \ref status_codes
*/
int16_t sleep();
/*!
\brief Sets the module to sleep mode. To wake the device up, call standby().
\param retainConfig Set to true to retain configuration of the currently active modem ("warm start")
@ -671,7 +833,7 @@ class LR11x0: public PhysicalLayer {
\param sleepTime Sleep duration (enables automatic wakeup), in multiples of 30.52 us. Ignored if set to 0.
\returns \ref status_codes
*/
int16_t sleep(bool retainConfig = true, uint32_t sleepTime = 0);
int16_t sleep(bool retainConfig, uint32_t sleepTime);
// interrupt methods
@ -690,23 +852,23 @@ class LR11x0: 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.
@ -730,7 +892,7 @@ class LR11x0: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t startReceive();
int16_t startReceive() override;
/*!
\brief Interrupt-driven receive method. IRQ1 will be activated when full packet is received.
@ -740,10 +902,11 @@ class LR11x0: public PhysicalLayer {
If timeout other than infinite is set, signal will be generated on IRQ1.
\param irqFlags Sets the IRQ flags that will trigger IRQ1, defaults to RADIOLIB_LR11X0_IRQ_RX_DONE.
\param irqMask Only for PhysicalLayer compatibility, not used.
\param len Only for PhysicalLayer compatibility, not used.
\returns \ref status_codes
*/
int16_t startReceive(uint32_t timeout, uint32_t irqFlags = RADIOLIB_LR11X0_IRQ_RX_DONE, size_t len = 0);
int16_t startReceive(uint32_t timeout, uint32_t irqFlags = RADIOLIB_LR11X0_IRQ_RX_DONE, uint32_t irqMask = 0, size_t len = 0);
/*!
\brief Reads the current IRQ status.
@ -791,7 +954,7 @@ class LR11x0: public PhysicalLayer {
\param power Output power to be set in dBm, output PA is determined automatically preferring the low-power PA.
\returns \ref status_codes
*/
int16_t setOutputPower(int8_t power);
int16_t setOutputPower(int8_t power) override;
/*!
\brief Sets output power. Allowed values are in range from -9 to 22 dBm (high-power PA) or -17 to 14 dBm (low-power PA).
@ -802,6 +965,25 @@ class LR11x0: public PhysicalLayer {
*/
int16_t setOutputPower(int8_t power, bool forceHighPower);
/*!
\brief Check if output power is configurable.
This method is needed for compatibility with PhysicalLayer::checkOutputPower.
\param power Output power in dBm, PA will be determined automatically.
\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 forceHighPower Force using the high-power PA. If set to false, PA will be determined automatically
based on configured output power, preferring the low-power PA. If set to true, only high-power PA will be used.
\returns \ref status_codes
*/
int16_t checkOutputPower(int8_t power, int8_t* clipped, bool forceHighPower);
/*!
\brief Sets LoRa bandwidth. Allowed values are 62.5, 125.0, 250.0 and 500.0 kHz.
\param bw LoRa bandwidth to be set in kHz.
@ -838,7 +1020,7 @@ class LR11x0: 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 Sets GFSK frequency deviation. Allowed values range from 0.0 to 200.0 kHz.
@ -984,13 +1166,13 @@ class LR11x0: public PhysicalLayer {
\brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. Only available for LoRa or GFSK modem.
\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 modem.
\returns SNR of the last received packet in dB.
*/
float getSNR();
float getSNR() override;
/*!
\brief Gets frequency error of the latest received packet.
@ -1019,6 +1201,46 @@ class LR11x0: public PhysicalLayer {
*/
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
*/
RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override;
/*!
\brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks
\param irqFlags The flags for which IRQs must be triggered
\param irqMask Mask indicating which IRQ triggers a DIO
\returns \ref status_codes
*/
int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override;
/*!
\brief Check whether the IRQ bit for RxTimeout is set
\returns Whether RxTimeout IRQ is set
*/
bool isRxTimeout() override;
/*!
\brief Get one truly random byte from RSSI noise.
\returns TRNG byte.
*/
uint8_t randomByte() override;
/*!
\brief Set implicit header mode for future reception/transmission.
\param len Payload length in bytes.
\returns \ref status_codes
*/
int16_t implicitHeader(size_t len);
/*!
\brief Set explicit header mode for future reception/transmission.
\returns \ref status_codes
*/
int16_t explicitHeader();
/*!
\brief Gets effective data rate for the last transmitted packet. The value is calculated only for payload bytes.
\returns Effective data rate in bps.
@ -1035,10 +1257,92 @@ class LR11x0: public PhysicalLayer {
*/
int16_t setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount = 3, uint16_t hopSeed = 0x13A);
/*!
\brief Start passive WiFi scan. BUSY pin will be de-activated when the scan is finished.
\param wifiType Type of WiFi (802.11) signals to scan, 'b', 'n', 'g' or '*' for all signals.
\param mode Scan acquisition mode, one of RADIOLIB_LR11X0_WIFI_ACQ_MODE_*.
The type of results available after the scan depends on this mode.
Defaults to RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON, which provides the most information.
\param chanMask Bit mask of WiFi channels to scan, defaults to all channels.
More channels leads to longer overall scan duration.
\param numScans Number of scans to perform per each enabled channel. Defaults to 16 scans.
More scans leads to longer overall scan duration.
\param timeout Timeout of each scan in milliseconds. Defaults to 100 ms
Longer timeout leads to longer overall scan duration.
\returns \ref status_codes
*/
int16_t startWifiScan(char wifiType, uint8_t mode = RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON, uint16_t chanMask = RADIOLIB_LR11X0_WIFI_ALL_CHANNELS, uint8_t numScans = 16, uint16_t timeout = 100);
/*!
\brief Sets interrupt service routine to call when a WiFi scan is completed.
\param func ISR to call.
*/
void setWiFiScanAction(void (*func)(void));
/*!
\brief Clears interrupt service routine to call when a WiFi scan is completed.
*/
void clearWiFiScanAction();
/*!
\brief Get number of WiFi scan results after the scan is finished.
\param count Pointer to a variable that will hold the number of scan results.
\returns \ref status_codes
*/
int16_t getWifiScanResultsCount(uint8_t* count);
/*!
\brief Retrieve passive WiFi scan result.
\param result Pointer to structure to hold the result data.
\param index Result index, starting from 0. The number of scan results can be retrieved by calling getWifiScanResultsCount.
\param brief Whether to only retrieve the results in brief format. If set to false, only information in LR11x0WifiResult_t
will be retrieved. If set to true, information in LR11x0WifiResultFull_t will be retrieved. In addition, if WiFi scan mode
was set to RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON, all information in LR11x0WifiResultExtended_t will be retrieved.
\returns \ref status_codes
*/
int16_t getWifiScanResult(LR11x0WifiResult_t* result, uint8_t index, bool brief = false);
/*!
\brief Blocking WiFi scan method. Performs a full passive WiFi scan.
This method may block for several seconds!
\param wifiType Type of WiFi (802.11) signals to scan, 'b', 'n', 'g' or '*' for all signals.
\param count Pointer to a variable that will hold the number of scan results.
\param mode Scan acquisition mode, one of RADIOLIB_LR11X0_WIFI_ACQ_MODE_*.
The type of results available after the scan depends on this mode.
Defaults to RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON, which provides the most information.
\param chanMask Bit mask of WiFi channels to scan, defaults to all channels.
More channels leads to longer overall scan duration.
\param numScans Number of scans to perform per each enabled channel. Defaults to 16 scans.
More scans leads to longer overall scan duration.
\param timeout Timeout of each scan in milliseconds. Defaults to 100 ms
Longer timeout leads to longer overall scan duration.
\returns \ref status_codes
*/
int16_t wifiScan(uint8_t wifiType, uint8_t* count, uint8_t mode = RADIOLIB_LR11X0_WIFI_ACQ_MODE_FULL_BEACON, uint16_t chanMask = RADIOLIB_LR11X0_WIFI_ALL_CHANNELS, uint8_t numScans = 16, uint16_t timeout = 100);
/*!
\brief Retrieve LR11x0 hardware, device and firmware version information.
\param info Pointer to LR11x0VersionInfo_t structure to populate.
\returns \ref status_codes
*/
int16_t getVersionInfo(LR11x0VersionInfo_t* info);
/*!
\brief Method to upload new firmware image to the device.
The device will be automatically erased, a new firmware will be uploaded,
written to flash and executed.
\param image Pointer to the image to upload.
\param size Size of the image in 32-bit words.
\param nonvolatile Set to true when the image is saved in non-volatile memory of the host processor,
or to false when the patch is in its RAM. Defaults to true.
\returns \ref status_codes
*/
int16_t updateFirmware(const uint32_t* image, size_t size, bool nonvolatile = true);
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
Module* getMod();
Module* getMod() override;
// LR11x0 SPI command implementations
int16_t writeRegMem32(uint32_t addr, uint32_t* data, size_t len);
@ -1055,7 +1359,7 @@ class LR11x0: public PhysicalLayer {
int16_t calibrate(uint8_t params);
int16_t setRegMode(uint8_t mode);
int16_t calibImage(float freq1, float freq2);
int16_t setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t gnssCfg, uint8_t wifiCfg);
int16_t setDioAsRfSwitch(uint8_t en, uint8_t stbyCfg, uint8_t rxCfg, uint8_t txCfg, uint8_t txHpCfg, uint8_t txHfCfg, uint8_t gnssCfg, uint8_t wifiCfg);
int16_t setDioIrqParams(uint32_t irq1, uint32_t irq2);
int16_t clearIrq(uint32_t irq);
int16_t configLfClock(uint8_t setup);
@ -1066,7 +1370,7 @@ class LR11x0: public PhysicalLayer {
int16_t setFs(void);
int16_t getRandomNumber(uint32_t* rnd);
int16_t eraseInfoPage(void);
int16_t writeInfoPage(uint16_t addr, uint32_t* data, size_t len);
int16_t writeInfoPage(uint16_t addr, const uint32_t* data, size_t len);
int16_t readInfoPage(uint16_t addr, uint32_t* data, size_t len);
int16_t getChipEui(uint8_t* eui);
int16_t getSemtechJoinEui(uint8_t* eui);
@ -1114,6 +1418,7 @@ class LR11x0: public PhysicalLayer {
int16_t setGfskWhitParams(uint16_t seed);
int16_t setRxBoosted(bool en);
int16_t setRangingParameter(uint8_t symbolNum);
int16_t setRssiCalibration(int8_t* tune, int16_t gainOffset);
int16_t setLoRaSyncWord(uint8_t sync);
int16_t lrFhssBuildFrame(uint8_t hdrCount, uint8_t cr, uint8_t grid, bool hop, uint8_t bw, uint16_t hopSeq, int8_t devOffset, uint8_t* payload, size_t len);
int16_t lrFhssSetSyncWord(uint32_t sync);
@ -1156,6 +1461,26 @@ class LR11x0: public PhysicalLayer {
int16_t gnssAlmanacFullUpdateHeader(uint16_t date, uint32_t globalCrc);
int16_t gnssAlmanacFullUpdateSV(uint8_t svn, uint8_t* svnAlmanac);
int16_t gnssGetSvVisible(uint32_t time, float lat, float lon, uint8_t constellation, uint8_t* nbSv);
int16_t gnssScan(uint8_t effort, uint8_t resMask, uint8_t nbSvMax);
int16_t gnssReadLastScanModeLaunched(uint8_t* lastScanMode);
int16_t gnssFetchTime(uint8_t effort, uint8_t opt);
int16_t gnssReadTime(uint8_t* err, uint32_t* time, uint32_t* nbUs, uint32_t* timeAccuracy);
int16_t gnssResetTime(void);
int16_t gnssResetPosition(void);
int16_t gnssReadDemodStatus(int8_t* status, uint8_t* info);
int16_t gnssReadCumulTiming(uint32_t* timing, uint8_t* constDemod);
int16_t gnssSetTime(uint32_t time, uint16_t accuracy);
int16_t gnssReadDopplerSolverRes(uint8_t* error, uint8_t* nbSvUsed, float* lat, float* lon, uint16_t* accuracy, uint16_t* xtal, float* latFilt, float* lonFilt, uint16_t* accuracyFilt, uint16_t* xtalFilt);
int16_t gnssReadDelayResetAP(uint32_t* delay);
int16_t gnssAlmanacUpdateFromSat(uint8_t effort, uint8_t bitMask);
int16_t gnssReadAlmanacStatus(uint8_t* status);
int16_t gnssConfigAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t period);
int16_t gnssReadAlmanacUpdatePeriod(uint8_t bitMask, uint8_t svType, uint16_t* period);
int16_t gnssConfigDelayResetAP(uint32_t delay);
int16_t gnssGetSvWarmStart(uint8_t bitMask, uint8_t* sv, uint8_t nbVisSat);
int16_t gnssReadWNRollover(uint8_t* status, uint8_t* rollover);
int16_t gnssReadWarmStartStatus(uint8_t bitMask, uint8_t* nbVisSat, uint32_t* timeElapsed);
int16_t gnssWriteBitMaskSatActivated(uint8_t bitMask, uint32_t* bitMaskActivated0, uint32_t* bitMaskActivated1);
int16_t cryptoSetKey(uint8_t keyId, uint8_t* key);
int16_t cryptoDeriveKey(uint8_t srcKeyId, uint8_t dstKeyId, uint8_t* key);
@ -1169,11 +1494,11 @@ class LR11x0: public PhysicalLayer {
int16_t cryptoRestoreFromFlash(void);
int16_t cryptoSetParam(uint8_t id, uint32_t value);
int16_t cryptoGetParam(uint8_t id, uint32_t* value);
int16_t cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len);
int16_t cryptoCheckEncryptedFirmwareImage(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile);
int16_t cryptoCheckEncryptedFirmwareImageResult(bool* result);
int16_t bootEraseFlash(void);
int16_t bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len);
int16_t bootWriteFlashEncrypted(uint32_t offset, uint32_t* data, size_t len, bool nonvolatile);
int16_t bootReboot(bool stay);
int16_t bootGetPin(uint8_t* pin);
int16_t bootGetChipEui(uint8_t* eui);
@ -1184,7 +1509,7 @@ class LR11x0: public PhysicalLayer {
#if !RADIOLIB_GODMODE
protected:
#endif
uint8_t chipType;
uint8_t chipType = 0;
#if !RADIOLIB_GODMODE
private:
@ -1210,6 +1535,8 @@ class LR11x0: public PhysicalLayer {
float dataRateMeasured = 0;
uint8_t wifiScanMode = 0;
int16_t modSetup(float tcxoVoltage, uint8_t modem);
static int16_t SPIparseStatus(uint8_t in);
static int16_t SPIcheckStatus(Module* mod);
@ -1217,10 +1544,11 @@ class LR11x0: public PhysicalLayer {
int16_t config(uint8_t modem);
int16_t setPacketMode(uint8_t mode, uint8_t len);
int16_t startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin);
int16_t setHeaderType(uint8_t hdrType, size_t len = 0xFF);
// common methods to avoid some copy-paste
int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len);
int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, uint32_t* data, size_t len);
int16_t writeCommon(uint16_t cmd, uint32_t addrOffset, const uint32_t* data, size_t len, bool nonvolatile);
int16_t cryptoCommon(uint16_t cmd, uint8_t keyId, uint8_t* dataIn, size_t len, uint8_t* dataOut);
};

View file

@ -0,0 +1,38 @@
#if !defined(_RADIOLIB_LR11X0_FIRMWARE_H)
#define _RADIOLIB_LR11X0_FIRMWARE_H
#if defined(RADIOLIB_LR1110_FIRMWARE_IN_RAM)
#define RADIOLIB_LR1110_FIRMWARE_ATTR
#else
#define RADIOLIB_LR1110_FIRMWARE_ATTR RADIOLIB_NONVOLATILE
#endif
#define RADIOLIB_LR11X0_FIRMWARE_IMAGE_SIZE LR11XX_FIRMWARE_IMAGE_SIZE
#if defined(RADIOLIB_LR1110_FIRMWARE_0303)
#include "firmware/lr1110_transceiver_0303.h"
#elif defined(RADIOLIB_LR1110_FIRMWARE_0304)
#include "firmware/lr1110_transceiver_0304.h"
#elif defined(RADIOLIB_LR1110_FIRMWARE_0305)
#include "firmware/lr1110_transceiver_0305.h"
#elif defined(RADIOLIB_LR1110_FIRMWARE_0306)
#include "firmware/lr1110_transceiver_0306.h"
#elif defined(RADIOLIB_LR1110_FIRMWARE_0307)
#include "firmware/lr1110_transceiver_0307.h"
#elif defined(RADIOLIB_LR1110_FIRMWARE_0401)
#include "firmware/lr1110_transceiver_0401.h"
#elif defined(RADIOLIB_LR1120_FIRMWARE_0101)
#include "firmware/lr1120_transceiver_0101.h"
#elif defined(RADIOLIB_LR1120_FIRMWARE_0102)
#include "firmware/lr1120_transceiver_0102.h"
#elif defined(RADIOLIB_LR1120_FIRMWARE_0201)
#include "firmware/lr1120_transceiver_0201.h"
#elif defined(RADIOLIB_LR1121_FIRMWARE_0102)
#include "firmware/lr1121_transceiver_0102.h"
#elif defined(RADIOLIB_LR1121_FIRMWARE_0103)
#include "firmware/lr1121_transceiver_0103.h"
#else
#error "No LR11x0 firmware image selected!"
#endif
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

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

@ -488,7 +488,7 @@ class RF69: public PhysicalLayer {
\brief Default constructor.
\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.
@ -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,
@ -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,14 +87,14 @@ 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);
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

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

@ -6,11 +6,13 @@ 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
@ -25,4 +27,12 @@ int16_t SX1261::setOutputPower(int8_t power) {
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

@ -98,11 +98,13 @@ int16_t SX1262::setFrequency(float freq, bool calibrate) {
}
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
@ -117,4 +119,12 @@ int16_t SX1262::setOutputPower(int8_t power) {
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,7 +69,7 @@ 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.
@ -85,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

@ -93,11 +93,13 @@ int16_t SX1268::setFrequency(float freq, bool calibrate) {
}
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
@ -112,4 +114,12 @@ int16_t SX1268::setOutputPower(int8_t power) {
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,7 +68,7 @@ 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.
@ -83,7 +83,15 @@ class SX1268: public SX126x {
\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

@ -76,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);
@ -441,6 +442,11 @@ int16_t SX126x::scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin)
return(getChannelScanResult());
}
int16_t SX126x::sleep() {
return(SX126x::sleep(true));
}
int16_t SX126x::sleep(bool retainConfig) {
// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_IDLE);
@ -580,7 +586,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);
@ -638,7 +644,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.
@ -649,7 +655,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) {
@ -1173,15 +1179,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) {
@ -1455,7 +1453,7 @@ RadioLibTime_t SX126x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
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);
@ -1577,7 +1575,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
@ -1609,7 +1607,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
@ -1736,7 +1734,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) {
@ -1850,6 +1848,8 @@ int16_t SX126x::setRfFrequency(uint32_t frf) {
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) };
data[0] = (data[0] % 2) ? data[0] : data[0] - 1;
data[1] = (data[1] % 2) ? data[1] : data[1] + 1;
return(this->calibrateImage(data));
}
@ -2163,18 +2163,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

@ -452,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.
@ -546,13 +546,20 @@ class SX126x: public PhysicalLayer {
*/
int16_t scanChannel(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin);
/*!
\brief Sets the module to sleep mode. To wake the device up, call standby().
Overload with warm start enabled for PhysicalLayer compatibility.
\returns \ref status_codes
*/
int16_t sleep();
/*!
\brief Sets the module to sleep mode. To wake the device up, call standby().
\param retainConfig Set to true to retain configuration of the currently active modem ("warm start")
or to false to discard current configuration ("cold start"). Defaults to true.
\returns \ref status_codes
*/
int16_t sleep(bool retainConfig = true);
int16_t sleep(bool retainConfig);
/*!
\brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator).
@ -586,34 +593,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.
@ -637,7 +644,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.
@ -654,7 +661,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.
@ -786,7 +793,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.
@ -920,7 +927,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.
@ -964,7 +971,7 @@ class SX126x: public PhysicalLayer {
\param timeoutUs Timeout in microseconds to listen for
\returns Timeout value in a unit that is specific for the used module
*/
RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs);
RadioLibTime_t calculateRxTimeout(RadioLibTime_t timeoutUs) override;
/*!
\brief Create the flags that make up RxDone and RxTimeout used for receiving downlinks
@ -972,13 +979,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 Whether RxTimeout IRQ is set
*/
bool isRxTimeout();
bool isRxTimeout() override;
/*!
\brief Set implicit header mode for future reception/transmission.
@ -1040,7 +1047,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
@ -1054,13 +1061,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
/*!
@ -1132,7 +1139,7 @@ class SX126x: public PhysicalLayer {
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
Module* getMod();
Module* getMod() override;
// SX126x SPI command implementations
int16_t setFs();
@ -1163,7 +1170,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

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) {

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
@ -146,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.
@ -206,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).
@ -236,7 +254,7 @@ class SX1272: public SX127x {
Overload with packet mode enabled for PhysicalLayer compatibility.
\returns RSSI value in dBm.
*/
float getRSSI();
float getRSSI() override;
/*!
\brief Gets recorded signal strength indicator.
@ -293,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) {

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).
@ -248,7 +266,7 @@ class SX1278: public SX127x {
Overload with packet mode enabled for PhysicalLayer compatibility.
\returns RSSI value in dBm.
*/
float getRSSI();
float getRSSI() override;
/*!
\brief Gets recorded signal strength indicator.
@ -305,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

@ -419,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;
@ -905,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);
}
@ -1289,7 +1289,7 @@ RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
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;
@ -1335,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);
}
@ -1538,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) {
@ -1547,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,7 +594,7 @@ 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
@ -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.
@ -1062,7 +1062,7 @@ class SX127x: public PhysicalLayer {
\param timeoutUs Timeout in microseconds to listen for
\returns Timeout value in a unit that is specific for the used module
*/
RadioLibTime_t calculateRxTimeout(RadioLibTime_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 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.
@ -1221,7 +1221,7 @@ class SX127x: public PhysicalLayer {
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
Module* getMod();
Module* getMod() override;
#if !RADIOLIB_GODMODE
protected:
@ -1254,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

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

@ -411,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
@ -441,18 +421,11 @@ 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(getChannelScanResult());
}
return(RADIOLIB_ERR_UNKNOWN);
int16_t SX128x::sleep() {
return(SX128x::sleep(true));
}
int16_t SX128x::sleep(bool retainConfig) {
@ -588,7 +561,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
@ -664,6 +637,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);
@ -765,11 +784,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)) {
@ -898,13 +928,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));
}
@ -938,7 +968,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))) {

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,14 @@ 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().
Overload for PhysicalLayer compatibility.
\returns \ref status_codes
*/
int16_t sleep();
/*!
\brief Sets the module to sleep mode. To wake the device up, call standby().
@ -463,7 +470,7 @@ class SX128x: public PhysicalLayer {
to discard current configuration and data buffer. Defaults to true.
\returns \ref status_codes
*/
int16_t sleep(bool retainConfig = true);
int16_t sleep(bool retainConfig);
/*!
\brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator).
@ -497,23 +504,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 +544,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 +558,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.
@ -569,6 +576,19 @@ class SX128x: public PhysicalLayer {
*/
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 +596,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 +626,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 +649,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 +673,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 +724,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 +750,7 @@ class SX128x: public PhysicalLayer {
\param len Payload length in bytes.
\returns Expected time-on-air in microseconds.
*/
RadioLibTime_t getTimeOnAir(size_t len);
RadioLibTime_t getTimeOnAir(size_t len) override;
/*!
\brief Set implicit header mode for future reception/transmission.
@ -754,33 +782,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;

View file

@ -21,7 +21,7 @@ class Si4430: public Si4432 {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio chip.
*/
Si4430(Module* mod);
Si4430(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -44,14 +44,14 @@ class Si4430: public Si4432 {
\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 output power. Allowed values range from -8 to 13 dBm in 3 dBm steps.
\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;
#if !RADIOLIB_GODMODE
protected:

View file

@ -21,7 +21,7 @@ class Si4431: public Si4432 {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio chip.
*/
Si4431(Module* mod);
Si4431(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -44,7 +44,7 @@ class Si4431: public Si4432 {
\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;
#if !RADIOLIB_GODMODE
protected:

View file

@ -21,7 +21,7 @@ class Si4432: public Si443x {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio chip.
*/
Si4432(Module* mod);
Si4432(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -44,14 +44,14 @@ class Si4432: public Si443x {
\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 output power. Allowed values range from -1 to 20 dBm in 3 dBm steps.
\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;
#if !RADIOLIB_GODMODE
protected:

View file

@ -300,7 +300,7 @@ int16_t Si443x::startReceive() {
return(state);
}
int16_t Si443x::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) {
int16_t Si443x::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) {
(void)timeout;
(void)irqFlags;
(void)irqMask;
@ -558,11 +558,11 @@ int16_t Si443x::setEncoding(uint8_t encoding) {
/// \todo - add inverted Manchester?
switch(encoding) {
case RADIOLIB_ENCODING_NRZ:
return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0));
return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0));
case RADIOLIB_ENCODING_MANCHESTER:
return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_ON | RADIOLIB_SI443X_WHITENING_OFF, 2, 0));
return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_ON | RADIOLIB_SI443X_WHITENING_OFF, 2, 0));
case RADIOLIB_ENCODING_WHITENING:
return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0));
return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0));
default:
return(RADIOLIB_ERR_INVALID_ENCODING);
}
@ -577,12 +577,8 @@ int16_t Si443x::setDataShaping(uint8_t sh) {
switch(sh) {
case RADIOLIB_SHAPING_NONE:
return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_OFF, 2, 0));
case RADIOLIB_SHAPING_0_3:
return(RADIOLIB_ERR_INVALID_ENCODING);
case RADIOLIB_SHAPING_0_5:
return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_2, RADIOLIB_SI443X_MODULATION_GFSK, 1, 0));
case RADIOLIB_SHAPING_1_0:
return(this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_MODULATION_MODE_CONTROL_1, RADIOLIB_SI443X_MANCHESTER_INVERTED_OFF | RADIOLIB_SI443X_MANCHESTER_OFF | RADIOLIB_SI443X_WHITENING_ON, 2, 0));
default:
return(RADIOLIB_ERR_INVALID_ENCODING);
}
@ -771,7 +767,7 @@ int16_t Si443x::updateClockRecovery() {
// print that whole mess
RADIOLIB_DEBUG_BASIC_PRINTLN("%X\n%X\n%X", bypass, decRate, manch);
RADIOLIB_DEBUG_BASIC_PRINT_FLOAT(rxOsr, 2);
RADIOLIB_DEBUG_BASIC_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, ncoOff, ncoOff, crGain, crGain);
RADIOLIB_DEBUG_BASIC_PRINTLN("\t%d\t%X\n%lu\t%lX\n%d\t%X", rxOsr_fixed, rxOsr_fixed, (long unsigned int)ncoOff, (long unsigned int)ncoOff, crGain, crGain);
// update oversampling ratio
int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5);

View file

@ -564,7 +564,7 @@ class Si443x: public PhysicalLayer {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
Si443x(Module* mod);
explicit Si443x(Module* mod);
// basic methods
@ -607,7 +607,7 @@ class Si443x: 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 module to standby (with XTAL on).
@ -658,23 +658,23 @@ class Si443x: 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. Will start transmitting arbitrary binary data up to 64 bytes long.
@ -695,7 +695,7 @@ class Si443x: public PhysicalLayer {
\brief Interrupt-driven receive method. IRQ will be activated when full valid packet is received.
\returns \ref status_codes
*/
int16_t startReceive();
int16_t startReceive() override;
/*!
\brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer.
@ -705,7 +705,7 @@ class Si443x: 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 that was received after calling startReceive method. When the packet length is not known in advance,
@ -724,7 +724,7 @@ class Si443x: 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 FSK frequency deviation from carrier frequency. Allowed values range from 0.625 to 320.0 kHz.
@ -745,7 +745,7 @@ class Si443x: public PhysicalLayer {
\param syncWord Pointer to the array of sync word bytes.
\param len Sync word length in bytes.
*/
int16_t setSyncWord(uint8_t* syncWord, size_t len);
int16_t setSyncWord(uint8_t* syncWord, size_t len) override;
/*!
\brief Sets preamble length.
@ -787,7 +787,7 @@ class Si443x: 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 RADIOLIB_SI443X_DEVICE_VERSION (0x06) if Si443x is connected and working.
@ -800,13 +800,13 @@ class Si443x: 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
/*!
@ -826,7 +826,7 @@ class Si443x: public PhysicalLayer {
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
Module* getMod();
Module* getMod() override;
#if !RADIOLIB_GODMODE
protected:

View file

@ -249,7 +249,7 @@ int16_t nRF24::startReceive() {
return(state);
}
int16_t nRF24::startReceive(uint32_t timeout, uint16_t irqFlags, uint16_t irqMask, size_t len) {
int16_t nRF24::startReceive(uint32_t timeout, uint32_t irqFlags, uint32_t irqMask, size_t len) {
(void)timeout;
(void)irqFlags;
(void)irqMask;
@ -298,14 +298,14 @@ int16_t nRF24::setBitRate(float br) {
RADIOLIB_ASSERT(state);
// set data rate
uint16_t dataRate = (uint16_t)br;
if(dataRate == 250) {
uint16_t bitRate = (uint16_t)br;
if(bitRate == 250) {
state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 5, 5);
state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_250_KBPS, 3, 3);
} else if(dataRate == 1000) {
} else if(bitRate == 1000) {
state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_1_MBPS, 5, 5);
state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_1_MBPS, 3, 3);
} else if(dataRate == 2000) {
} else if(bitRate == 2000) {
state = this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_2_MBPS, 5, 5);
state |= this->mod->SPIsetRegValue(RADIOLIB_NRF24_REG_RF_SETUP, RADIOLIB_NRF24_DR_2_MBPS, 3, 3);
} else {
@ -313,7 +313,7 @@ int16_t nRF24::setBitRate(float br) {
}
if(state == RADIOLIB_ERR_NONE) {
this->dataRate = dataRate;
this->dataRate = bitRate;
}

View file

@ -193,7 +193,7 @@ class nRF24: public PhysicalLayer {
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
nRF24(Module* mod);
nRF24(Module* mod); // cppcheck-suppress noExplicitConstructor
// basic methods
@ -215,7 +215,7 @@ class nRF24: 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.
@ -279,23 +279,23 @@ class nRF24: 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. IRQ will be activated when full packet is transmitted.
@ -317,7 +317,7 @@ class nRF24: public PhysicalLayer {
\brief Interrupt-driven receive method. IRQ 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.
@ -327,7 +327,7 @@ class nRF24: 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,
@ -345,21 +345,21 @@ class nRF24: 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 are 2000, 1000 or 250 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 output power. Allowed values are -18, -12, -6 or 0 dBm.
\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 Sets address width of transmit and receive pipes in bytes. Allowed values are 3, 4 or 5 bytes.
@ -468,7 +468,7 @@ class nRF24: public PhysicalLayer {
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
protected:
#endif
Module* getMod();
Module* getMod() override;
void SPIreadRxPayload(uint8_t* data, uint8_t numBytes);
void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes);

View file

@ -26,7 +26,7 @@ class AFSKClient {
\brief Copy contructor.
\param aud Pointer to the AFSKClient instance to copy.
*/
AFSKClient(AFSKClient* aud);
explicit AFSKClient(AFSKClient* aud);
/*!
\brief Initialization method.

View file

@ -49,22 +49,28 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat
#endif
// build the info field
if((msg == NULL) && (time == NULL)) {
// no message, no timestamp
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_NO_MSG "%s%c%s%c", lat, table, lon, symbol);
} else if((msg != NULL) && (time == NULL)) {
// message, no timestamp
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_MSG "%s%c%s%c%s", lat, table, lon, symbol, msg);
} else if((msg == NULL) && (time != NULL)) {
// timestamp, no message
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_NO_MSG "%s%s%c%s%c", time, lat, table, lon, symbol);
if(msg != NULL) {
if(time != NULL) {
// timestamp and message
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "%s%s%c%s%c%s", time, lat, table, lon, symbol, msg);
} else {
// message, no timestamp
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_MSG "%s%c%s%c%s", lat, table, lon, symbol, msg);
}
} else {
// timestamp and message
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "%s%s%c%s%c%s", time, lat, table, lon, symbol, msg);
if(time != NULL) {
// timestamp, no message
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_NO_MSG "%s%s%c%s%c", time, lat, table, lon, symbol);
} else {
// no message, no timestamp
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_NO_MSG "%s%c%s%c", lat, table, lon, symbol);
}
}
info[len] = '\0';
// send the frame
info[len] = '\0';
int16_t state = sendFrame(destCallsign, destSSID, info);
#if !RADIOLIB_STATIC_ONLY
delete[] info;
@ -244,9 +250,9 @@ int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info)
char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1];
axClient->getCallsign(srcCallsign);
AX25Frame frameUI(destCallsign, destSSID, srcCallsign, axClient->getSSID(), RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION |
RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME,
RADIOLIB_AX25_PID_NO_LAYER_3, (const char*)info);
AX25Frame frameUI(destCallsign, destSSID, srcCallsign, axClient->getSSID(),
RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME,
RADIOLIB_AX25_PID_NO_LAYER_3, const_cast<char*>(info));
return(axClient->sendFrame(&frameUI));
@ -256,7 +262,7 @@ int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info)
char* buff = new char[len];
snprintf(buff, len, RADIOLIB_APRS_LORA_HEADER "%s-%d>%s,WIDE%d-%d:%s", this->src, this->id, destCallsign, destSSID, destSSID, info);
int16_t res = this->phyLayer->transmit((uint8_t*)buff, strlen(buff));
int16_t res = this->phyLayer->transmit(reinterpret_cast<uint8_t*>(buff), strlen(buff));
delete[] buff;
return(res);
}

View file

@ -8,7 +8,7 @@ AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* src
}
AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, const char* info)
: AX25Frame(destCallsign, destSSID, srcCallsign, srcSSID, control, protocolID, (uint8_t*)info, strlen(info)) {
: AX25Frame(destCallsign, destSSID, srcCallsign, srcSSID, control, protocolID, reinterpret_cast<uint8_t*>(const_cast<char*>(info)), strlen(info)) {
}
@ -50,8 +50,41 @@ AX25Frame::AX25Frame(const char* destCallsign, uint8_t destSSID, const char* src
}
}
AX25Frame::AX25Frame(const AX25Frame& frame) {
*this = frame;
AX25Frame::AX25Frame(const AX25Frame& frame)
: destSSID(frame.destSSID),
srcSSID(frame.srcSSID),
numRepeaters(frame.numRepeaters),
control(frame.control),
protocolID(frame.protocolID),
infoLen(frame.infoLen),
rcvSeqNumber(frame.rcvSeqNumber),
sendSeqNumber(frame.sendSeqNumber) {
strncpy(this->destCallsign, frame.destCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1);
strncpy(this->srcCallsign, frame.srcCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1);
if(frame.infoLen) {
#if !RADIOLIB_STATIC_ONLY
this->info = new uint8_t[frame.infoLen];
#endif
memcpy(this->info, frame.info, frame.infoLen);
}
if(frame.numRepeaters) {
#if !RADIOLIB_STATIC_ONLY
this->repeaterCallsigns = new char*[frame.numRepeaters];
for(uint8_t i = 0; i < frame.numRepeaters; i++) {
this->repeaterCallsigns[i] = new char[strlen(frame.repeaterCallsigns[i]) + 1];
}
this->repeaterSSIDs = new uint8_t[frame.numRepeaters];
#endif
this->numRepeaters = frame.numRepeaters;
for(uint8_t i = 0; i < frame.numRepeaters; i++) {
memcpy(this->repeaterCallsigns[i], frame.repeaterCallsigns[i], strlen(frame.repeaterCallsigns[i]));
this->repeaterCallsigns[i][strlen(frame.repeaterCallsigns[i])] = '\0';
}
memcpy(this->repeaterSSIDs, frame.repeaterSSIDs, frame.numRepeaters);
}
}
AX25Frame::~AX25Frame() {
@ -154,17 +187,46 @@ void AX25Frame::setSendSequence(uint8_t seqNumber) {
AX25Client::AX25Client(PhysicalLayer* phy) {
phyLayer = phy;
#if !RADIOLIB_EXCLUDE_AFSK
audio = nullptr;
bellModem = nullptr;
#endif
}
#if !RADIOLIB_EXCLUDE_AFSK
AX25Client::AX25Client(AFSKClient* audio) {
phyLayer = audio->phyLayer;
bellModem = new BellClient(audio);
AX25Client::AX25Client(AFSKClient* aud)
: audio(aud) {
phyLayer = this->audio->phyLayer;
bellModem = new BellClient(this->audio);
bellModem->setModem(Bell202);
}
AX25Client::AX25Client(const AX25Client& ax25)
: phyLayer(ax25.phyLayer),
sourceSSID(ax25.sourceSSID),
preambleLen(ax25.preambleLen) {
strncpy(sourceCallsign, ax25.sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1);
#if !RADIOLIB_EXCLUDE_AFSK
if(ax25.bellModem) {
this->audio = ax25.audio;
this->bellModem = new BellClient(ax25.audio);
}
#endif
}
AX25Client& AX25Client::operator=(const AX25Client& ax25) {
this->phyLayer = ax25.phyLayer;
this->sourceSSID = ax25.sourceSSID;
this->preambleLen = ax25.preambleLen;
strncpy(sourceCallsign, ax25.sourceCallsign, RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1);
#if !RADIOLIB_EXCLUDE_AFSK
if(ax25.bellModem) {
this->audio = ax25.audio;
this->bellModem = new BellClient(ax25.audio);
}
#endif
return(*this);
}
int16_t AX25Client::setCorrection(int16_t mark, int16_t space, float length) {
BellModem_t modem;
modem.freqMark = Bell202.freqMark + mark;
@ -205,10 +267,12 @@ int16_t AX25Client::transmit(String& str, const char* destCallsign, uint8_t dest
int16_t AX25Client::transmit(const char* str, const char* destCallsign, uint8_t destSSID) {
// create control field
uint8_t controlField = RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION | RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME;
uint8_t controlField = RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME;
// build the frame
AX25Frame frame(destCallsign, destSSID, sourceCallsign, sourceSSID, controlField, RADIOLIB_AX25_PID_NO_LAYER_3, (uint8_t*)str, strlen(str));
AX25Frame frame(destCallsign, destSSID, sourceCallsign, sourceSSID, controlField,
RADIOLIB_AX25_PID_NO_LAYER_3,
reinterpret_cast<uint8_t*>(const_cast<char*>(str)), strlen(str));
// send Unnumbered Information frame
return(sendFrame(&frame));

View file

@ -246,9 +246,21 @@ class AX25Client {
#if !RADIOLIB_EXCLUDE_AFSK
/*!
\brief Constructor for AFSK mode.
\param audio Pointer to the AFSK instance providing audio.
\param aud Pointer to the AFSK instance providing audio.
*/
explicit AX25Client(AFSKClient* audio);
explicit AX25Client(AFSKClient* aud);
/*!
\brief Copy constructor.
\param ax25 AX25Client instance to copy.
*/
AX25Client(const AX25Client& ax25);
/*!
\brief Overload for assignment operator.
\param ax25 rvalue AX25Client.
*/
AX25Client& operator=(const AX25Client& ax25);
/*!
\brief Set AFSK tone correction offset. On some platforms, this is required to get the audio produced
@ -310,10 +322,11 @@ class AX25Client {
PhysicalLayer* phyLayer;
#if !RADIOLIB_EXCLUDE_AFSK
AFSKClient* audio;
BellClient* bellModem;
#endif
char sourceCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = {0, 0, 0, 0, 0, 0, 0};
char sourceCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = { 0 };
uint8_t sourceSSID = 0;
uint16_t preambleLen = 0;

View file

@ -58,7 +58,7 @@ size_t BellClient::write(uint8_t b) {
uint16_t toneSpace = this->modemType.freqSpace;
if(this->reply) {
toneMark = this->modemType.freqMarkReply;
toneMark = this->modemType.freqSpaceReply;
toneSpace = this->modemType.freqSpaceReply;
}
// get the Module pointer to access HAL

View file

@ -75,7 +75,7 @@ class BellClient: public AFSKClient, public RadioLibPrint {
\brief Audio-client constructor. Can be used when AFSKClient instance already exists.
\param aud Audio client to use.
*/
BellClient(AFSKClient* aud);
explicit BellClient(AFSKClient* aud);
/*!
\brief Initialization method.
@ -104,7 +104,7 @@ class BellClient: public AFSKClient, public RadioLibPrint {
\param b Byte to write.
\returns 1 if the byte was written, 0 otherwise.
*/
size_t write(uint8_t b);
size_t write(uint8_t b) override;
/*!
\brief Set the modem to idle (ready to transmit).
@ -119,7 +119,7 @@ class BellClient: public AFSKClient, public RadioLibPrint {
#if !RADIOLIB_GODMODE
private:
#endif
BellModem_t modemType;
BellModem_t modemType = Bell101;
float correction = 1.0;
uint16_t toneLen = 0;
bool autoStart = true;

View file

@ -14,6 +14,27 @@ ExternalRadio::ExternalRadio(RadioLibHal *hal, uint32_t pin) : PhysicalLayer(1,
this->prevFrf = 0;
}
ExternalRadio::ExternalRadio(const ExternalRadio& ext) : PhysicalLayer(1, 0) {
this->prevFrf = ext.prevFrf;
if(ext.mod) {
this->mod = new Module(ext.mod->hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, ext.mod->getGpio());
}
}
ExternalRadio& ExternalRadio::operator=(const ExternalRadio& ext) {
this->prevFrf = ext.prevFrf;
if(ext.mod) {
this->mod = new Module(ext.mod->hal, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, ext.mod->getGpio());
}
return(*this);
}
ExternalRadio::~ExternalRadio() {
if(this->mod) {
delete this->mod;
}
}
Module* ExternalRadio::getMod() {
return(mod);
}

View file

@ -20,7 +20,7 @@ class ExternalRadio: public PhysicalLayer {
\brief Default constructor.
\param pin Output pin when using direct transmission, defaults to unused pin.
*/
ExternalRadio(uint32_t pin = RADIOLIB_NC);
ExternalRadio(uint32_t pin = RADIOLIB_NC); // cppcheck-suppress noExplicitConstructor
#endif
/*!
@ -28,13 +28,30 @@ class ExternalRadio: public PhysicalLayer {
\param hal Pointer to the hardware abstraction layer to use.
\param pin Output pin when using direct transmission, defaults to unused pin.
*/
ExternalRadio(RadioLibHal *hal, uint32_t pin = RADIOLIB_NC);
ExternalRadio(RadioLibHal *hal, uint32_t pin = RADIOLIB_NC); // cppcheck-suppress noExplicitConstructor
/*!
\brief Copy constructor.
\param ext ExternalRadio instance to copy.
*/
ExternalRadio(const ExternalRadio& ext);
/*!
\brief Overload for assignment operator.
\param ext rvalue ExternalRadio.
*/
ExternalRadio& operator=(const ExternalRadio& ext);
/*!
\brief Default destructor.
*/
~ExternalRadio();
/*!
\brief Method to retrieve pointer to the underlying Module instance.
\returns Pointer to the Module instance.
*/
Module* getMod();
Module* getMod() override;
/*!
\brief Dummy implementation overriding PhysicalLayer.
@ -63,7 +80,7 @@ class ExternalRadio: public PhysicalLayer {
the output pin will be set to logic high. Otherwise it will be set to logic low.
\returns \ref status_codes
*/
int16_t transmitDirect(uint32_t frf = 0);
int16_t transmitDirect(uint32_t frf = 0) override;
private:
Module* mod;

View file

@ -112,12 +112,12 @@ int32_t FSK4Client::getRawShift(int32_t shift) {
int32_t step = round(phyLayer->getFreqStep());
// check minimum shift value
if(abs(shift) < step / 2) {
if(RADIOLIB_ABS(shift) < step / 2) {
return(0);
}
// round shift to multiples of frequency step size
if(abs(shift) % step < (step / 2)) {
if(RADIOLIB_ABS(shift) % step < (step / 2)) {
return(shift / step);
}
if(shift < 0) {

View file

@ -85,8 +85,8 @@ class FSK4Client {
uint32_t baseFreq = 0, baseFreqHz = 0;
uint32_t shiftFreq = 0, shiftFreqHz = 0;
RadioLibTime_t bitDuration = 0;
uint32_t tones[4];
uint32_t tonesHz[4];
uint32_t tones[4] = { 0 };
uint32_t tonesHz[4] = { 0 };
void tone(uint8_t i);

View file

@ -30,7 +30,7 @@ int16_t HellClient::begin(float base, float rate) {
return(phyLayer->startDirect());
}
size_t HellClient::printGlyph(uint8_t* buff) {
size_t HellClient::printGlyph(const uint8_t* buff) {
// print the character
Module* mod = phyLayer->getMod();
bool transmitting = false;

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