kopia lustrzana https://github.com/jgromes/RadioLib
Porównaj commity
8 Commity
841b283c0f
...
7209690bf6
Autor | SHA1 | Data |
---|---|---|
jgromes | 7209690bf6 | |
jgromes | 92cb09a932 | |
jgromes | 809025eba6 | |
jgromes | cb9cb87556 | |
jgromes | 97adb260ce | |
jgromes | 05e35407f4 | |
Alistair Francis | 2f85326fec | |
StevenCellist | 1b2b8bd67b |
|
@ -24,4 +24,4 @@ jobs:
|
|||
|
||||
- name: Run cppcheck
|
||||
run:
|
||||
cppcheck src --enable=all --force
|
||||
cppcheck src --enable=all --force --inline-suppr --suppress=ConfigurationNotChecked
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
build/
|
||||
build-*
|
||||
TockApp.tab
|
||||
|
|
|
@ -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
|
||||
# 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/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
|
||||
)
|
||||
${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
|
||||
)
|
||||
|
||||
|
|
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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
|
|
@ -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")
|
||||
|
|
@ -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")
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
int16_t CC1101::setSyncWord(uint8_t* syncWord, uint8_t len, uint8_t maxErrBits, bool requireCarrierSense) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,7 +214,7 @@ 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 },
|
||||
|
@ -237,54 +234,89 @@ const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = {
|
|||
{ 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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
Ładowanie…
Reference in New Issue