Porównaj commity

...

8 Commity

Autor SHA1 Wiadomość Data
jgromes 7209690bf6 [Mod] Fixed hexdump not escaping format specifiers 2024-05-01 19:12:22 +01:00
jgromes 92cb09a932 [CC1101] Resolve issues reported by cppcheck 2024-05-01 18:05:16 +01:00
jgromes 809025eba6 [Mod] Fix issues from cppcheck scan 2024-05-01 15:51:01 +01:00
jgromes cb9cb87556 [HAL] Make ArduinoHal constructor explicit 2024-05-01 15:41:24 +01:00
jgromes 97adb260ce [CI] Enable cppcheck inline suppression and suppres unchecked config 2024-05-01 15:40:08 +01:00
jgromes 05e35407f4 [FSK4] Use abs macro instead of abs function 2024-05-01 15:14:44 +02:00
Alistair Francis 2f85326fec
examples/NonArduino/Tock: Support RISC-V and bump libtock-c (#1082)
* examples/NonArduino/Tock: Support building for RISC-V

Signed-off-by: Alistair Francis <alistair@alistair23.me>

* examples/NonArduino/Tock: Update to newer libtock-c

Signed-off-by: Alistair Francis <alistair@alistair23.me>

---------

Signed-off-by: Alistair Francis <alistair@alistair23.me>
2024-05-01 15:12:05 +02:00
StevenCellist 1b2b8bd67b
[LoRaWAN] Improve PHY behaviour, update beginABP, bugfixes (#1080)
* [LoRaWAN] Add getter for ToA, prevent MAC queue overflow

* [LoRaWAN] Permute arguments to beginABP

* Implement & split off checkOutputPower

* [LoRaWAN] Configure physical layer on each up/downlink

* [LoRaWAN] Remove unnecessary dynamic array

* [LoRaWAN] Improve downlink handling

* Resolve return-warnings in checkOutputPower()

* [LoRaWAN] Improve buffer definition

* [LoRaWAN] Prevent requesting repeated MAC commands

* Update keywords.txt

* [CC1101] Resolve unused variable warning

* [CC1101] Update checkOutputPower

* [SX1278] Fix variable assignment

* Update keywords.txt

* [CC1101] Added checkOutputPower override for PHY compatibility

* [LR11x0] Added checkOutputPower override for PHY compatibility

* [SX127x] Added checkOutputPower override for PHY compatibility

---------

Co-authored-by: jgromes <jan.gromes@gmail.com>
2024-05-01 13:35:22 +02:00
35 zmienionych plików z 780 dodań i 432 usunięć

Wyświetl plik

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

Wyświetl plik

@ -170,7 +170,7 @@ jobs:
else
# apply special flags for LoRaWAN
if [[ ${example} =~ "LoRaWAN" ]]; then
flags="-DRADIOLIB_LORAWAN_DEV_ADDR=0 -DRADIOLIB_LORAWAN_NWKS_KEY=0 -DRADIOLIB_LORAWAN_SNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_NWKSENC_KEY=0 -DRADIOLIB_LORAWAN_APPS_KEY=0 -DRADIOLIB_LORAWAN_APP_KEY=0 -DRADIOLIB_LORAWAN_NWK_KEY=0 -DRADIOLIB_LORAWAN_DEV_EUI=0 -DARDUINO_TTGO_LORA32_V1"
flags="-DRADIOLIB_LORAWAN_DEV_ADDR=0 -DRADIOLIB_LORAWAN_FNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_SNWKSINT_KEY=0 -DRADIOLIB_LORAWAN_NWKSENC_KEY=0 -DRADIOLIB_LORAWAN_APPS_KEY=0 -DRADIOLIB_LORAWAN_APP_KEY=0 -DRADIOLIB_LORAWAN_NWK_KEY=0 -DRADIOLIB_LORAWAN_DEV_EUI=0 -DARDUINO_TTGO_LORA32_V1"
fi
# build sketch
@ -226,7 +226,7 @@ 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

Wyświetl plik

@ -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,7 +118,7 @@ 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 NwkSKey[] = { RADIOLIB_LORAWAN_FNWKSINT_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 };

Wyświetl plik

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

Wyświetl plik

@ -29,7 +29,11 @@ project(tock-sx1261)
set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/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,17 +47,61 @@ 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 "${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0")
target_link_libraries(${PROJECT_NAME} PUBLIC
RadioLib
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/rv32imc/libtock.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0/riscv/lib/gcc/riscv64-unknown-elf/13.2.0/rv32i/ilp32/libgcc.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a
)
target_include_directories(RadioLib AFTER PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/riscv/riscv64-unknown-elf/include/
)
else()
target_link_libraries(${PROJECT_NAME} PUBLIC
RadioLib
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/rv32imc/libtock.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-10.5.0/riscv/lib/gcc/riscv64-unknown-elf/10.5.0/rv32i/ilp32/libgcc.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-10.5.0/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a
)
target_include_directories(RadioLib AFTER PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/riscv/riscv64-unknown-elf/include/
)
endif()
else()
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0")
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/lib/libtock-libc++-13.2.0/arm/lib/gcc/arm-none-eabi/13.2.0/libgcc.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0/arm/arm-none-eabi/lib/libstdc++.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/arm/arm-none-eabi/lib/libc.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.3.0.20230120/arm/arm-none-eabi/lib/libm.a
)
else()
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/lib/libtock-libc++-10.5.0/arm/lib/gcc/arm-none-eabi/10.5.0/libgcc.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-10.5.0/arm/arm-none-eabi/lib/libstdc++.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-newlib-4.2.0.20211231/arm/arm-none-eabi/lib/libc.a
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/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}/../../../src/
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c
)

Wyświetl plik

@ -13,6 +13,10 @@ 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
@ -24,5 +28,5 @@ $ ./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
```

Wyświetl plik

@ -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 +1 @@
Subproject commit 1c1f4c0810aa0fbd50aa91a11aaa7c05d2abb1bc
Subproject commit 44bf89c545953d8859faf101d4b4a4b6a151fe6c

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -127,6 +127,7 @@ setCodingRate KEYWORD2
setFrequency KEYWORD2
setSyncWord KEYWORD2
setOutputPower KEYWORD2
checkOutputPower KEYWORD2
setCurrentLimit KEYWORD2
setPreambleLength KEYWORD2
setGain KEYWORD2
@ -328,10 +329,10 @@ timeUntilUplink KEYWORD2
setDwellTime KEYWORD2
maxPayloadDwellTime KEYWORD2
setTxPower KEYWORD2
setCSMA KEYWORD2
getMacLinkCheckAns KEYWORD2
getMacDeviceTimeAns KEYWORD2
getDevAddr KEYWORD2
getLastToA KEYWORD2
#######################################
# Constants (LITERAL1)

Wyświetl plik

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

Wyświetl plik

@ -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
@ -309,17 +314,15 @@ int16_t Module::SPIcheckStream() {
}
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
// 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;
@ -346,13 +349,19 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint
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);
@ -462,7 +471,7 @@ 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];
char str[120];
sprintf(str, "%07" PRIx32 " ", i+offset);
size_t line_len = 16;
if(rem_len < line_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;
}

Wyświetl plik

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

Wyświetl plik

@ -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, uint16_t irqFlags, uint16_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);

Wyświetl plik

@ -593,22 +593,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 +611,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;

Wyświetl plik

@ -802,6 +802,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.

Wyświetl plik

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

Wyświetl plik

@ -34,6 +34,14 @@ class SX1261 : public SX1262 {
*/
int16_t setOutputPower(int8_t power);
/*!
\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);
#if !RADIOLIB_GODMODE
private:
#endif

Wyświetl plik

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

Wyświetl plik

@ -87,6 +87,14 @@ class SX1262: public SX126x {
*/
virtual int16_t setOutputPower(int8_t power);
/*!
\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);
#if !RADIOLIB_GODMODE
private:
#endif

Wyświetl plik

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

Wyświetl plik

@ -85,6 +85,14 @@ class SX1268: public SX126x {
*/
int16_t setOutputPower(int8_t power);
/*!
\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);
#if !RADIOLIB_GODMODE
private:
#endif

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -765,11 +765,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)) {

Wyświetl plik

@ -608,6 +608,14 @@ class SX128x: public PhysicalLayer {
*/
int16_t setOutputPower(int8_t pwr);
/*!
\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);
/*!
\brief Sets preamble length for currently active modem. Allowed values range from 1 to 65535.
\param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK/BLE/FLRC).

Wyświetl plik

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

Wyświetl plik

@ -241,9 +241,6 @@ int16_t LoRaWANNode::restore(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass
// copy uplink MAC command queue back in place
memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t));
state = this->setPhyProperties();
RADIOLIB_ASSERT(state);
// full session is restored, so set joined flag to whichever mode is restored
this->activeMode = LoRaWANNode::ntoh<uint16_t>(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_MODE]);
@ -498,16 +495,12 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
// setup all MAC properties to default values
this->beginCommon(joinDr);
// set the physical layer configuration
state = this->setPhyProperties();
RADIOLIB_ASSERT(state);
// select a random pair of Tx/Rx channels
state = this->selectChannels();
RADIOLIB_ASSERT(state);
// configure for uplink with default configuration
state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK);
// set the physical layer configuration for uplink
state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK);
RADIOLIB_ASSERT(state);
// copy devNonce currently in use
@ -732,7 +725,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
return(RADIOLIB_ERR_NONE);
}
int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, bool force, uint8_t initialDr) {
int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey, bool force, uint8_t initialDr) {
// if not forced and already joined, don't do anything
if(!force && this->isJoined()) {
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("beginABP(): Did not rejoin: session already active");
@ -744,7 +737,7 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey,
// check if we actually need to restart from a clean session
uint16_t checkSum = 0;
checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast<uint8_t*>(&addr), 4);
checkSum ^= LoRaWANNode::checkSum16(nwkSKey, 16);
checkSum ^= LoRaWANNode::checkSum16(nwkSEncKey, 16);
checkSum ^= LoRaWANNode::checkSum16(appSKey, 16);
if(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); }
if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); }
@ -763,12 +756,12 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey,
this->devAddr = addr;
memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE);
memcpy(this->nwkSEncKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE);
memcpy(this->nwkSEncKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE);
if(fNwkSIntKey) {
this->rev = 1;
memcpy(this->fNwkSIntKey, fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE);
} else {
memcpy(this->fNwkSIntKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE);
memcpy(this->fNwkSIntKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE);
}
if(sNwkSIntKey) {
memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE);
@ -784,10 +777,6 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey,
// setup all MAC properties to default values
this->beginCommon(initialDr);
// set the physical layer configuration
state = this->setPhyProperties();
RADIOLIB_ASSERT(state);
// reset all frame counters
this->fcntUp = 0;
this->aFcntDown = 0;
@ -970,9 +959,9 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf
}
}
// configure for uplink
// set the physical layer configuration for uplink
this->selectChannels();
state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK);
state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK);
RADIOLIB_ASSERT(state);
// if dwell time is imposed, calculated expected time on air and cancel if exceeds
@ -1019,12 +1008,8 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf
// check if we have some MAC commands to append
if(foptsLen > 0) {
#if RADIOLIB_STATIC_ONLY
// assume maximum possible buffer size
uint8_t foptsBuff[RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN];
#else
uint8_t* foptsBuff = new uint8_t[foptsLen];
#endif
uint8_t* foptsPtr = foptsBuff;
// append all MAC replies into fopts buffer
@ -1052,9 +1037,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf
// encrypt it
processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fcntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true);
#if !RADIOLIB_STATIC_ONLY
delete[] foptsBuff;
#endif
}
// set the port
@ -1146,30 +1128,28 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf
int16_t LoRaWANNode::downlinkCommon() {
Module* mod = this->phyLayer->getMod();
const RadioLibTime_t scanGuard = 10;
// according to the spec, the Rx window must be at least enough time to effectively detect a preamble
// but we pad it a bit on both sides (start and end) to make sure it is wide enough
const RadioLibTime_t scanGuard = 10; // Rx window padding in milliseconds
// check if there are any upcoming Rx windows
// if the Rx1 window has already started, you're too late, because most downlinks happen in Rx1
if(mod->hal->millis() - this->rxDelayStart > (this->rxDelays[0] - scanGuard)) {
RadioLibTime_t now = mod->hal->millis(); // Fix the current timestamp to prevent negative delays
if(now > this->rxDelayStart + this->rxDelays[0] - scanGuard) {
// if between start of Rx1 and end of Rx2, wait until Rx2 closes
if(mod->hal->millis() - this->rxDelayStart < this->rxDelays[1]) {
mod->hal->delay(this->rxDelays[1] + this->rxDelayStart - mod->hal->millis());
if(now < this->rxDelayStart + this->rxDelays[1]) {
mod->hal->delay(this->rxDelays[1] + this->rxDelayStart - now);
}
// update the end timestamp in case user got stuck between uplink and downlink
this->rxDelayEnd = mod->hal->millis();
return(RADIOLIB_ERR_NO_RX_WINDOW);
}
// configure for downlink
int16_t state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK);
// set the physical layer configuration for downlink
int16_t state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK);
RADIOLIB_ASSERT(state);
// downlink messages are sent with inverted IQ
if(!this->FSK) {
state = this->phyLayer->invertIQ(true);
RADIOLIB_ASSERT(state);
}
// create the masks that are required for receiving downlinks
uint16_t irqFlags = 0x0000;
uint16_t irqMask = 0x0000;
@ -1182,14 +1162,16 @@ int16_t LoRaWANNode::downlinkCommon() {
downlinkAction = false;
// calculate the Rx timeout
// according to the spec, this must be at least enough time to effectively detect a preamble
// but pad it a bit on both sides (start and end) to make sure it is wide enough
RadioLibTime_t timeoutHost = this->phyLayer->getTimeOnAir(0) + 2*scanGuard*1000;
RadioLibTime_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost);
// wait for the start of the Rx window
RadioLibTime_t waitLen = this->rxDelayStart + this->rxDelays[i] - mod->hal->millis();
// make sure that no underflow occured; if so, clip the delay (although this will likely miss any downlink)
if(waitLen > this->rxDelays[i]) {
waitLen = this->rxDelays[i];
}
// the waiting duration is shortened a bit to cover any possible timing errors
RadioLibTime_t waitLen = this->rxDelays[i] - (mod->hal->millis() - this->rxDelayStart);
if(waitLen > scanGuard) {
waitLen -= scanGuard;
}
@ -1215,7 +1197,8 @@ int16_t LoRaWANNode::downlinkCommon() {
RADIOLIB_ASSERT(state);
DataRate_t dataRate;
findDataRate(this->rx2.drMax, &dataRate);
state = findDataRate(this->rx2.drMax, &dataRate);
RADIOLIB_ASSERT(state);
state = this->phyLayer->setDataRate(dataRate);
RADIOLIB_ASSERT(state);
}
@ -1687,16 +1670,51 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) {
return(true);
}
int16_t LoRaWANNode::setPhyProperties() {
int16_t LoRaWANNode::setPhyProperties(uint8_t dir) {
// set the physical layer configuration
int8_t pwr = this->txPowerMax - this->txPowerCur * 2;
int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER;
while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) {
// go from the highest power and lower it until we hit one supported by the module
state = this->phyLayer->setOutputPower(pwr--);
}
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("");
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq);
int16_t state = this->phyLayer->setFrequency(this->currentChannels[dir].freq);
RADIOLIB_ASSERT(state);
// if this channel is an FSK channel, toggle the FSK switch
if(this->band->dataRates[this->dataRates[dir]] == RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) {
this->FSK = true;
} else {
this->FSK = false;
}
int8_t pwr = this->txPowerMax - this->txPowerCur * 2;
// at this point, assume that Tx power value is already checked, so ignore the return value
(void)this->phyLayer->checkOutputPower(pwr, &pwr);
state = this->phyLayer->setOutputPower(pwr);
RADIOLIB_ASSERT(state);
DataRate_t dr;
state = findDataRate(this->dataRates[dir], &dr);
RADIOLIB_ASSERT(state);
state = this->phyLayer->setDataRate(dr);
RADIOLIB_ASSERT(state);
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: SF = %d, TX = %d dBm, BW = %6.3f kHz, CR = 4/%d",
dr.lora.spreadingFactor, pwr, dr.lora.bandwidth, dr.lora.codingRate);
if(this->FSK) {
state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0);
RADIOLIB_ASSERT(state);
state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING);
}
// downlink messages are sent with inverted IQ
if(dir == RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK) {
if(!this->FSK) {
state = this->phyLayer->invertIQ(true);
RADIOLIB_ASSERT(state);
}
}
// this only needs to be done once-ish
uint8_t syncWord[3] = { 0 };
uint8_t syncWordLen = 0;
size_t preLen = 0;
@ -1987,7 +2005,8 @@ void LoRaWANNode::setDwellTime(bool enable, RadioLibTime_t msPerUplink) {
uint8_t LoRaWANNode::maxPayloadDwellTime() {
// configure current datarate
DataRate_t dr;
findDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], &dr);
// TODO this may fail horribly?
(void)findDataRate(this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK], &dr);
(void)this->phyLayer->setDataRate(dr);
uint8_t minPayLen = 0;
uint8_t maxPayLen = 255;
@ -2035,6 +2054,8 @@ int16_t LoRaWANNode::setTxPower(int8_t txPower) {
}
int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) {
int16_t state = RADIOLIB_ERR_UNKNOWN;
uint8_t dataRateBand = this->band->dataRates[dr];
if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) {
@ -2059,50 +2080,37 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) {
dataRate->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6;
dataRate->lora.codingRate = (dataRateBand & 0x03) + 5;
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: SF = %d, BW = %6.3f kHz, CR = 4/%d",
dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate);
}
return(RADIOLIB_ERR_NONE);
}
int16_t LoRaWANNode::configureChannel(uint8_t dir) {
// set the frequency
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("");
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq);
int state = this->phyLayer->setFrequency(this->currentChannels[dir].freq);
RADIOLIB_ASSERT(state);
// if this channel is an FSK channel, toggle the FSK switch
if(this->band->dataRates[this->dataRates[dir]] == RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) {
this->FSK = true;
} else {
this->FSK = false;
}
DataRate_t dr;
findDataRate(this->dataRates[dir], &dr);
state = this->phyLayer->setDataRate(dr);
RADIOLIB_ASSERT(state);
if(this->FSK) {
state = this->phyLayer->setDataShaping(RADIOLIB_SHAPING_1_0);
RADIOLIB_ASSERT(state);
state = this->phyLayer->setEncoding(RADIOLIB_ENCODING_WHITENING);
}
state = this->phyLayer->checkDataRate(*dataRate);
return(state);
}
bool LoRaWANNode::sendMacCommandReq(uint8_t cid) {
int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) {
bool valid = false;
for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) {
if(MacTable[i].cid == cid) {
valid = MacTable[i].user;
}
}
if(!valid)
return(false);
if(!valid) {
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("You are not allowed to request this MAC command");
return(RADIOLIB_ERR_INVALID_CID);
}
// if there are already 15 MAC bytes in the uplink queue, we can't add a new one
if(this->commandsUp.len + 1 > RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN) {
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The maximum number of FOpts payload was reached");
return(RADIOLIB_ERR_COMMAND_QUEUE_FULL);
}
if(this->commandsUp.numCommands > RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE) {
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("The RadioLib internal MAC command queue was full");
return(RADIOLIB_ERR_COMMAND_QUEUE_FULL);
}
// delete any prior requests for this MAC command, in case this is requested more than once
(void)deleteMacCommand(cid, &this->commandsUp);
LoRaWANMacCommand_t cmd = {
.cid = cid,
@ -2182,8 +2190,6 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
case(RADIOLIB_LORAWAN_MAC_LINK_ADR): {
int16_t state = RADIOLIB_ERR_UNKNOWN;
// get the ADR configuration
// per spec, all these configuration should only be set if all ACKs are set, otherwise retain previous state
// but we don't bother and try to set each individual command
uint8_t drUp = (cmd->payload[0] & 0xF0) >> 4;
uint8_t txSteps = cmd->payload[0] & 0x0F;
bool isInternalTxDr = cmd->payload[3] >> 7;
@ -2193,19 +2199,15 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
uint8_t nbTrans = cmd->payload[3] & 0x0F;
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("LinkADRReq: dataRate = %d, txSteps = %d, chMask = 0x%04x, chMaskCntl = %d, nbTrans = %d", drUp, txSteps, chMask, chMaskCntl, nbTrans);
// apply the configuration
// try to apply the datarate configuration
uint8_t drAck = 0;
if(drUp == 0x0F) { // keep the same
drAck = 1;
// replace the 'placeholder' with the current actual value for saving
cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4);
} else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) {
// check if the module supports this data rate
DataRate_t dr;
findDataRate(drUp, &dr);
state = this->phyLayer->checkDataRate(dr);
state = findDataRate(drUp, &dr);
if(state == RADIOLIB_ERR_NONE) {
uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase,
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin,
@ -2215,6 +2217,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
drAck = 1;
} else {
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure dataRate %d, code %d!", drUp, state);
drUp = 0x0F; // set value to 'keep the same'
}
}
@ -2224,25 +2227,20 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
if(txSteps == 0x0F) {
pwrAck = 1;
// replace the 'placeholder' with the current actual value for saving
cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerCur;
} else {
int8_t pwr = this->txPowerMax - 2*txSteps;
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: TX = %d dBm", pwr);
state = RADIOLIB_ERR_INVALID_OUTPUT_POWER;
while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) {
// go from the highest power and lower it until we hit one supported by the module
state = this->phyLayer->setOutputPower(pwr--);
}
// only acknowledge if the requested datarate was succesfully configured
if(state == RADIOLIB_ERR_NONE) {
int8_t power = this->txPowerMax - 2*txSteps;
int8_t powerActual = 0;
state = this->phyLayer->checkOutputPower(power, &powerActual);
// only acknowledge if the radio is able to operate at or below the requested power level
if(state == RADIOLIB_ERR_NONE || (state == RADIOLIB_ERR_INVALID_OUTPUT_POWER && powerActual < power)) {
pwrAck = 1;
this->txPowerCur = txSteps;
} else {
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure Tx power %d, code %d!", power, state);
txSteps = 0x0F; // set value to 'keep the same'
}
}
uint8_t chMaskAck = 1;
// only apply channel mask when the RFU bit is not set
// (which is only set in internal MAC commands for changing Tx/Dr)
@ -2269,12 +2267,23 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
}
}
if(nbTrans == 0) { // keep the same
cmd->payload[3] = (cmd->payload[3] & 0xF0) | this->nbTrans; // set current number of retransmissions for saving
} else {
if(nbTrans) { // if there is a value for NbTrans, set this value
this->nbTrans = nbTrans;
}
// replace 'placeholder' or failed values with the current values for saving
// per spec, all these configuration should only be set if all ACKs are set, otherwise retain previous state
// but we don't bother and try to set each individual command
if(drUp == 0x0F || !drAck) {
cmd->payload[0] = (cmd->payload[0] & 0x0F) | (this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK] << 4);
}
if(txSteps == 0x0F || !pwrAck) {
cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerCur;
}
if(nbTrans == 0) {
cmd->payload[3] = (cmd->payload[3] & 0xF0) | this->nbTrans;
}
if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
// if RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte
if(isInternalTxDr) {
@ -2801,6 +2810,10 @@ uint64_t LoRaWANNode::getDevAddr() {
return(this->devAddr);
}
RadioLibTime_t LoRaWANNode::getLastToA() {
return(this->lastToA);
}
// The following function enables LMAC, a CSMA scheme for LoRa as specified
// in the LoRa Alliance Technical Recommendation #13.
// A user may enable CSMA to provide frames an additional layer of protection from interference.

Wyświetl plik

@ -159,6 +159,12 @@
#define RADIOLIB_LORAWAN_MIC_DATA_RATE_POS (3)
#define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4)
// maximum allowed dwell time on bands that implement dwell time limitations
#define RADIOLIB_LORAWAN_DWELL_TIME (400)
// unused frame counter value
#define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF)
// MAC commands
#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16)
@ -179,15 +185,6 @@
#define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F)
#define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80)
// maximum allowed dwell time on bands that implement dwell time limitations
#define RADIOLIB_LORAWAN_DWELL_TIME (400)
// unused LoRaWAN version
#define RADIOLIB_LORAWAN_VERSION_NONE (0xFF)
// unused frame counter value
#define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF)
// the length of internal MAC command queue - hopefully this is enough for most use cases
#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (9)
@ -217,74 +214,109 @@ struct LoRaWANMacSpec_t {
const bool user;
};
const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = {
constexpr LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = {
{ 0x00, 0, 0, false }, // not an actual MAC command, exists for index offsetting
{ RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false },
{ RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true },
{ RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false },
{ RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false },
{ RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false },
{ RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false },
{ RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false },
{ RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false },
{ RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false },
{ RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false },
{ RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false },
{ RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false },
{ RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true },
{ RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false },
{ RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false },
{ RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true }
{ RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false },
{ RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true },
{ RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false },
{ RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false },
{ RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false },
{ RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false },
{ RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false },
{ RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false },
{ RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false },
{ RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false },
{ RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false },
{ RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false },
{ RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true },
{ RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false },
{ RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false },
{ RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true }
};
/*!
\struct LoRaWANMacCommand_t
\brief Structure to save information about MAC command
*/
struct LoRaWANMacCommand_t {
/*! \brief The command ID */
uint8_t cid;
/*! \brief Payload buffer (5 bytes is the longest possible) */
uint8_t payload[5];
/*! \brief Length of the payload */
uint8_t len;
/*! \brief Repetition counter (the command will be uplinked repeat + 1 times) */
uint8_t repeat;
};
/*!
\struct LoRaWANMacCommandQueue_t
\brief Structure to hold information about a queue of MAC commands
*/
struct LoRaWANMacCommandQueue_t {
/*! \brief Number of commands in the queue */
uint8_t numCommands;
/*! \brief Total length of the queue */
uint8_t len;
/*! \brief MAC command buffer */
LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE];
};
#define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0001)
enum LoRaWANSchemeBase_t {
RADIOLIB_LORAWAN_NONCES_VERSION = 0x00, // 2 bytes
RADIOLIB_LORAWAN_NONCES_MODE = 0x02, // 2 bytes
RADIOLIB_LORAWAN_NONCES_CLASS = 0x04, // 1 byte
RADIOLIB_LORAWAN_NONCES_PLAN = 0x05, // 1 byte
RADIOLIB_LORAWAN_NONCES_CHECKSUM = 0x06, // 2 bytes
RADIOLIB_LORAWAN_NONCES_DEV_NONCE = 0x08, // 2 bytes
RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = 0x0A, // 3 bytes
RADIOLIB_LORAWAN_NONCES_ACTIVE = 0x0D, // 1 byte
RADIOLIB_LORAWAN_NONCES_SIGNATURE = 0x0E, // 2 bytes
RADIOLIB_LORAWAN_NONCES_BUF_SIZE = 0x10 // = 16 bytes
RADIOLIB_LORAWAN_NONCES_START = 0x00,
RADIOLIB_LORAWAN_NONCES_VERSION = RADIOLIB_LORAWAN_NONCES_START, // 2 bytes
RADIOLIB_LORAWAN_NONCES_MODE = RADIOLIB_LORAWAN_NONCES_VERSION + sizeof(uint16_t), // 2 bytes
RADIOLIB_LORAWAN_NONCES_CLASS = RADIOLIB_LORAWAN_NONCES_MODE + sizeof(uint16_t), // 1 byte
RADIOLIB_LORAWAN_NONCES_PLAN = RADIOLIB_LORAWAN_NONCES_CLASS + sizeof(uint8_t), // 1 byte
RADIOLIB_LORAWAN_NONCES_CHECKSUM = RADIOLIB_LORAWAN_NONCES_PLAN + sizeof(uint8_t), // 2 bytes
RADIOLIB_LORAWAN_NONCES_DEV_NONCE = RADIOLIB_LORAWAN_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes
RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = RADIOLIB_LORAWAN_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes
RADIOLIB_LORAWAN_NONCES_ACTIVE = RADIOLIB_LORAWAN_NONCES_JOIN_NONCE + 3, // 1 byte
RADIOLIB_LORAWAN_NONCES_SIGNATURE = RADIOLIB_LORAWAN_NONCES_ACTIVE + sizeof(uint8_t), // 2 bytes
RADIOLIB_LORAWAN_NONCES_BUF_SIZE = RADIOLIB_LORAWAN_NONCES_SIGNATURE + sizeof(uint16_t) // Nonces buffer size
};
enum LoRaWANSchemeSession_t {
RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = 0x00, // 16 bytes
RADIOLIB_LORAWAN_SESSION_APP_SKEY = 0x10, // 16 bytes
RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = 0x20, // 16 bytes
RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = 0x30, // 16 bytes
RADIOLIB_LORAWAN_SESSION_DEV_ADDR = 0x40, // 4 bytes
RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = 0x44, // 2 bytes
RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = 0x46, // 4 bytes
RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = 0x4A, // 4 bytes
RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = 0x4E, // 4 bytes
RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = 0x52, // 2 bytes
RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = 0x54, // 2 bytes
RADIOLIB_LORAWAN_SESSION_HOMENET_ID = 0x56, // 4 bytes
RADIOLIB_LORAWAN_SESSION_VERSION = 0x5A, // 1 byte
RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = 0x5B, // 1 byte
RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = 0x5C, // 4 bytes
RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = 0x60, // 1 byte
RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = 0x61, // 1 byte
RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = 0x62, // 1 byte
RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = 0x63, // 1 byte
RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = 0x64, // 3 bytes
RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = 0x67, // 4 bytes
RADIOLIB_LORAWAN_SESSION_PERIODICITY = 0x6B, // 1 byte
RADIOLIB_LORAWAN_SESSION_LAST_TIME = 0x6C, // 4 bytes
RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = 0x70, // 16*8 bytes
RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = 0xF0, // 16*4 bytes
RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL = 0x0130, // 9*8+2 bytes
RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = 0x017A, // 4 bytes
RADIOLIB_LORAWAN_SESSION_ADR_FCNT = 0x017E, // 4 bytes
RADIOLIB_LORAWAN_SESSION_LINK_ADR = 0x0182, // 4 bytes
RADIOLIB_LORAWAN_SESSION_FCNT_UP = 0x0186, // 4 bytes
RADIOLIB_LORAWAN_SESSION_SIGNATURE = 0x018A, // 2 bytes
RADIOLIB_LORAWAN_SESSION_BUF_SIZE = 0x018C // 396 bytes
RADIOLIB_LORAWAN_SESSION_START = 0x00,
RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = RADIOLIB_LORAWAN_SESSION_START, // 16 bytes
RADIOLIB_LORAWAN_SESSION_APP_SKEY = RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes
RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_APP_SKEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes
RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes
RADIOLIB_LORAWAN_SESSION_DEV_ADDR = RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 4 bytes
RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = RADIOLIB_LORAWAN_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes
RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE + sizeof(uint16_t), // 4 bytes
RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN + sizeof(uint32_t), // 4 bytes
RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP + sizeof(uint32_t), // 4 bytes
RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN + sizeof(uint32_t), // 2 bytes
RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 + sizeof(uint16_t), // 2 bytes
RADIOLIB_LORAWAN_SESSION_HOMENET_ID = RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 + sizeof(uint16_t), // 4 bytes
RADIOLIB_LORAWAN_SESSION_VERSION = RADIOLIB_LORAWAN_SESSION_HOMENET_ID + sizeof(uint32_t), // 1 byte
RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = RADIOLIB_LORAWAN_SESSION_VERSION + sizeof(uint8_t), // 1 byte
RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE + MacTable[RADIOLIB_LORAWAN_MAC_DUTY_CYCLE].lenDn, // 4 bytes
RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP].lenDn, // 1 byte
RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP].lenDn, // 1 byte
RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP].lenDn, // 1 byte
RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP = RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP].lenDn, // 1 byte
RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn, // 3 bytes
RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = RADIOLIB_LORAWAN_SESSION_BEACON_FREQ + 3, // 4 bytes
RADIOLIB_LORAWAN_SESSION_PERIODICITY = RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL + 4, // 1 byte
RADIOLIB_LORAWAN_SESSION_LAST_TIME = RADIOLIB_LORAWAN_SESSION_PERIODICITY + 1, // 4 bytes
RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = RADIOLIB_LORAWAN_SESSION_LAST_TIME + 4, // 16*5 bytes
RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = RADIOLIB_LORAWAN_SESSION_UL_CHANNELS + 16*MacTable[RADIOLIB_LORAWAN_MAC_NEW_CHANNEL].lenDn, // 16*4 bytes
RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL = RADIOLIB_LORAWAN_SESSION_DL_CHANNELS + 16*MacTable[RADIOLIB_LORAWAN_MAC_DL_CHANNEL].lenDn, // 9*8+2 bytes
RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL + sizeof(LoRaWANMacCommandQueue_t), // 4 bytes
RADIOLIB_LORAWAN_SESSION_ADR_FCNT = RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN + sizeof(uint32_t), // 4 bytes
RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_ADR_FCNT + sizeof(uint32_t), // 4 bytes
RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_LINK_ADR + MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, // 4 bytes
RADIOLIB_LORAWAN_SESSION_SIGNATURE = RADIOLIB_LORAWAN_SESSION_FCNT_UP + sizeof(uint32_t), // 2 bytes
RADIOLIB_LORAWAN_SESSION_BUF_SIZE = RADIOLIB_LORAWAN_SESSION_SIGNATURE + sizeof(uint16_t) // Session buffer size
};
/*!
@ -428,38 +460,6 @@ enum LoRaWANBandNum_t {
// array of currently supported bands
extern const LoRaWANBand_t* LoRaWANBands[];
/*!
\struct LoRaWANMacCommand_t
\brief Structure to save information about MAC command
*/
struct LoRaWANMacCommand_t {
/*! \brief The command ID */
uint8_t cid;
/*! \brief Payload buffer (5 bytes is the longest possible) */
uint8_t payload[5];
/*! \brief Length of the payload */
uint8_t len;
/*! \brief Repetition counter (the command will be uplinked repeat + 1 times) */
uint8_t repeat;
};
/*!
\struct LoRaWANMacCommandQueue_t
\brief Structure to hold information about a queue of MAC commands
*/
struct LoRaWANMacCommandQueue_t {
/*! \brief Number of commands in the queue */
uint8_t numCommands;
/*! \brief Total length of the queue */
uint8_t len;
/*! \brief MAC command buffer */
LoRaWANMacCommand_t commands[RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE];
};
/*!
\struct LoRaWANEvent_t
\brief Structure to save extra information about uplink/downlink event.
@ -567,15 +567,16 @@ class LoRaWANNode {
\brief Join network by performing activation by personalization.
In this procedure, all necessary configuration must be provided by the user.
\param addr Device address.
\param nwkSKey Pointer to the network session AES-128 key (LoRaWAN 1.0) or MAC command network session key (LoRaWAN 1.1).
\param fNwkSIntKey Pointer to the Forwarding network session (LoRaWAN 1.1), NULL for LoRaWAN 1.0.
\param sNwkSIntKey Pointer to the Serving network session (LoRaWAN 1.1), NULL for LoRaWAN 1.0.
\param nwkSEncKey Pointer to the MAC command network session key [NwkSEncKey] (LoRaWAN 1.1)
or network session AES-128 key [NwkSKey] (LoRaWAN 1.0).
\param appSKey Pointer to the application session AES-128 key.
\param fNwkSIntKey Pointer to the Forwarding network session (LoRaWAN 1.1), unused for LoRaWAN 1.0.
\param sNwkSIntKey Pointer to the Serving network session (LoRaWAN 1.1), unused for LoRaWAN 1.0.
\param force Set to true to force a new session, even if one exists.
\param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled)
\returns \ref status_codes
*/
int16_t beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, uint8_t* fNwkSIntKey = NULL, uint8_t* sNwkSIntKey = NULL, bool force = false, uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED);
int16_t beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey, bool force = false, uint8_t initialDr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED);
/*! \brief Whether there is an ongoing session active */
bool isJoined();
@ -591,9 +592,9 @@ class LoRaWANNode {
Only LinkCheck and DeviceTime are available to the user.
Other commands are ignored; duplicate MAC commands are discarded.
\param cid ID of the MAC command
\returns Whether or not the MAC command was added to the queue.
\returns \ref status_codes
*/
bool sendMacCommandReq(uint8_t cid);
int16_t sendMacCommandReq(uint8_t cid);
#if defined(RADIOLIB_BUILD_ARDUINO)
/*!
@ -835,6 +836,12 @@ class LoRaWANNode {
*/
uint64_t getDevAddr();
/*!
\brief Get the Time-on-air of the last uplink message
\returns (RadioLibTime_t) time-on-air (ToA) of last uplink message
*/
RadioLibTime_t getLastToA();
#if !RADIOLIB_GODMODE
private:
#endif
@ -964,7 +971,7 @@ class LoRaWANNode {
// configure the common physical layer properties (preamble, sync word etc.)
// channels must be configured separately by setupChannelsDyn()!
int16_t setPhyProperties();
int16_t setPhyProperties(uint8_t dir);
// setup uplink/downlink channel data rates and frequencies
// for dynamic channels, there is a small set of predefined channels
@ -984,9 +991,6 @@ class LoRaWANNode {
// find the first usable data rate for the given band
int16_t findDataRate(uint8_t dr, DataRate_t* dataRate);
// configure channel based on cached data rate ID and frequency
int16_t configureChannel(uint8_t dir);
// restore all available channels from persistent storage
int16_t restoreChannels();

Wyświetl plik

@ -256,6 +256,12 @@ int16_t PhysicalLayer::setOutputPower(int8_t power) {
return(RADIOLIB_ERR_UNSUPPORTED);
}
int16_t PhysicalLayer::checkOutputPower(int8_t power, int8_t* clipped) {
(void)power;
(void)clipped;
return(RADIOLIB_ERR_UNSUPPORTED);
}
int16_t PhysicalLayer::setSyncWord(uint8_t* sync, size_t len) {
(void)sync;
(void)len;

Wyświetl plik

@ -276,6 +276,14 @@ class PhysicalLayer {
*/
virtual int16_t setOutputPower(int8_t power);
/*!
\brief Check if output power is configurable. Must be implemented in module class if the module supports it.
\param power Output power in dBm. The allowed range depends on the module used.
\param clipped Clipped output power value to what is possible within the module's range.
\returns \ref status_codes
*/
virtual int16_t checkOutputPower(int8_t power, int8_t* clipped);
/*!
\brief Set sync word. Must be implemented in module class if the module supports it.
\param sync Pointer to the sync word.