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
|
- name: Run cppcheck
|
||||||
run:
|
run:
|
||||||
cppcheck src --enable=all --force
|
cppcheck src --enable=all --force --inline-suppr --suppress=ConfigurationNotChecked
|
||||||
|
|
|
@ -170,7 +170,7 @@ jobs:
|
||||||
else
|
else
|
||||||
# apply special flags for LoRaWAN
|
# apply special flags for LoRaWAN
|
||||||
if [[ ${example} =~ "LoRaWAN" ]]; then
|
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
|
fi
|
||||||
|
|
||||||
# build sketch
|
# build sketch
|
||||||
|
@ -226,7 +226,7 @@ jobs:
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
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
|
cargo install elf2tab
|
||||||
|
|
||||||
- name: Build the example
|
- name: Build the example
|
||||||
|
|
|
@ -12,8 +12,8 @@ const uint32_t uplinkIntervalSeconds = 5UL * 60UL; // minutes x seconds
|
||||||
#define RADIOLIB_LORAWAN_DEV_ADDR 0x------
|
#define RADIOLIB_LORAWAN_DEV_ADDR 0x------
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef RADIOLIB_LORAWAN_NWKS_KEY // Replace with your NwkS Key
|
#ifndef RADIOLIB_LORAWAN_FNWKSINT_KEY // Replace with your FNwkSInt Key
|
||||||
#define RADIOLIB_LORAWAN_NWKS_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
|
#define RADIOLIB_LORAWAN_FNWKSINT_KEY 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
|
||||||
#endif
|
#endif
|
||||||
#ifndef RADIOLIB_LORAWAN_SNWKSINT_KEY // Replace with your SNwkSInt Key
|
#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--
|
#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
|
// copy over the keys in to the something that will not compile if incorrectly formatted
|
||||||
uint32_t devAddr = RADIOLIB_LORAWAN_DEV_ADDR;
|
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 SNwkSIntKey[] = { RADIOLIB_LORAWAN_SNWKSINT_KEY }; // Previously sNwkSIntKey
|
||||||
uint8_t NwkSEncKey[] = { RADIOLIB_LORAWAN_NWKSENC_KEY }; // Previously fNwkSIntKey
|
uint8_t NwkSEncKey[] = { RADIOLIB_LORAWAN_NWKSENC_KEY }; // Previously fNwkSIntKey
|
||||||
uint8_t AppSKey[] = { RADIOLIB_LORAWAN_APPS_KEY };
|
uint8_t AppSKey[] = { RADIOLIB_LORAWAN_APPS_KEY };
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
build/
|
build-*
|
||||||
TockApp.tab
|
TockApp.tab
|
||||||
|
|
|
@ -29,7 +29,11 @@ project(tock-sx1261)
|
||||||
|
|
||||||
set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/userland_generic.ld)
|
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
|
# when using debuggers such as gdb, the following line can be used
|
||||||
#set(CMAKE_BUILD_TYPE Debug)
|
#set(CMAKE_BUILD_TYPE Debug)
|
||||||
|
@ -43,17 +47,61 @@ add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CUR
|
||||||
add_executable(${PROJECT_NAME} main.cpp)
|
add_executable(${PROJECT_NAME} main.cpp)
|
||||||
|
|
||||||
# link with RadioLib and libtock-c
|
# 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
|
||||||
RadioLib
|
# built changes based on compiler version.
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libtock/build/cortex-m4/libtock.a
|
if (RISCV_BUILD)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libc++/cortex-m/libgcc.a
|
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/lib/libtock-libc++-13.2.0")
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/libc++/cortex-m/libstdc++.a
|
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/newlib/cortex-m/v7-m/libc.a
|
RadioLib
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c/newlib/cortex-m/v7-m/libm.a
|
${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
|
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/libtock-c
|
${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
|
but will work on any LoRa compatible Tock board (currently only the
|
||||||
expLoRaBLE board).
|
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:
|
The RadioLib example can be built with:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
@ -24,5 +28,5 @@ $ ./build.sh
|
||||||
Then in the Tock repo you can flash the kernel and app with:
|
Then in the Tock repo you can flash the kernel and app with:
|
||||||
|
|
||||||
```shell
|
```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
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
rm -rf ./build
|
rm -rf ./build-*
|
||||||
|
|
||||||
cd libtock-c/libtock
|
cd libtock-c/examples/cxx_hello
|
||||||
make -j4
|
make -j4
|
||||||
cd ../../
|
cd ../../../
|
||||||
|
|
||||||
mkdir -p build
|
mkdir -p build-arm
|
||||||
cd build
|
cd build-arm
|
||||||
|
|
||||||
cmake -G "CodeBlocks - Unix Makefiles" ..
|
cmake -G "CodeBlocks - Unix Makefiles" ..
|
||||||
make -j4
|
make -j4
|
||||||
|
|
||||||
cd ..
|
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 \
|
elf2tab -n radio-lib --stack 4096 --app-heap 2048 --kernel-heap 2048 \
|
||||||
--kernel-major 2 --kernel-minor 1 \
|
--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
|
# This is copied from https://github.com/Lora-net/LoRaMac-node/pull/1390
|
||||||
# and has been relicensed by the original author
|
# and has been relicensed by the original author
|
||||||
|
|
||||||
include("toolchain-arm-none-eabi.cmake")
|
|
||||||
|
|
||||||
if(NOT DEFINED LINKER_SCRIPT)
|
if(NOT DEFINED LINKER_SCRIPT)
|
||||||
message(FATAL_ERROR "No linker script defined")
|
message(FATAL_ERROR "No linker script defined")
|
||||||
endif(NOT DEFINED LINKER_SCRIPT)
|
endif(NOT DEFINED LINKER_SCRIPT)
|
||||||
|
@ -40,6 +38,22 @@ set(STACK_SIZE 4096)
|
||||||
set(APP_HEAP_SIZE 2048)
|
set(APP_HEAP_SIZE 2048)
|
||||||
set(KERNEL_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
|
# 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")
|
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
|
setFrequency KEYWORD2
|
||||||
setSyncWord KEYWORD2
|
setSyncWord KEYWORD2
|
||||||
setOutputPower KEYWORD2
|
setOutputPower KEYWORD2
|
||||||
|
checkOutputPower KEYWORD2
|
||||||
setCurrentLimit KEYWORD2
|
setCurrentLimit KEYWORD2
|
||||||
setPreambleLength KEYWORD2
|
setPreambleLength KEYWORD2
|
||||||
setGain KEYWORD2
|
setGain KEYWORD2
|
||||||
|
@ -328,10 +329,10 @@ timeUntilUplink KEYWORD2
|
||||||
setDwellTime KEYWORD2
|
setDwellTime KEYWORD2
|
||||||
maxPayloadDwellTime KEYWORD2
|
maxPayloadDwellTime KEYWORD2
|
||||||
setTxPower KEYWORD2
|
setTxPower KEYWORD2
|
||||||
setCSMA KEYWORD2
|
|
||||||
getMacLinkCheckAns KEYWORD2
|
getMacLinkCheckAns KEYWORD2
|
||||||
getMacDeviceTimeAns KEYWORD2
|
getMacDeviceTimeAns KEYWORD2
|
||||||
getDevAddr KEYWORD2
|
getDevAddr KEYWORD2
|
||||||
|
getLastToA KEYWORD2
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Constants (LITERAL1)
|
# Constants (LITERAL1)
|
||||||
|
|
|
@ -32,7 +32,7 @@ class ArduinoHal : public RadioLibHal {
|
||||||
\param spi SPI interface to be used, can also use software SPI implementations.
|
\param spi SPI interface to be used, can also use software SPI implementations.
|
||||||
\param spiSettings SPI interface settings.
|
\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
|
// implementations of pure virtual RadioLibHal methods
|
||||||
void pinMode(uint32_t pin, uint32_t mode) override;
|
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
|
// 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)
|
// some registers need a bit of time to process the change (e.g. SX127X_REG_OP_MODE)
|
||||||
RadioLibTime_t start = this->hal->micros();
|
RadioLibTime_t start = this->hal->micros();
|
||||||
|
#if RADIOLIB_DEBUG_SPI
|
||||||
uint8_t readValue = 0x00;
|
uint8_t readValue = 0x00;
|
||||||
|
#endif
|
||||||
while(this->hal->micros() - start < (checkInterval * 1000)) {
|
while(this->hal->micros() - start < (checkInterval * 1000)) {
|
||||||
readValue = SPIreadRegister(reg);
|
uint8_t val = SPIreadRegister(reg);
|
||||||
if((readValue & checkMask) == (newValue & checkMask)) {
|
if((val & checkMask) == (newValue & checkMask)) {
|
||||||
// check passed, we can stop the loop
|
// check passed, we can stop the loop
|
||||||
return(RADIOLIB_ERR_NONE);
|
return(RADIOLIB_ERR_NONE);
|
||||||
}
|
}
|
||||||
|
#if RADIOLIB_DEBUG_SPI
|
||||||
|
readValue = val;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// check failed, print debug info
|
// 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) {
|
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;
|
size_t buffLen = cmdLen + numBytes;
|
||||||
if(!write) {
|
if(!write) {
|
||||||
buffLen += (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8);
|
buffLen += (this->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] / 8);
|
||||||
}
|
}
|
||||||
#if RADIOLIB_STATIC_ONLY
|
#if RADIOLIB_STATIC_ONLY
|
||||||
uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE];
|
uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE];
|
||||||
uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE];
|
|
||||||
#else
|
#else
|
||||||
uint8_t* buffOut = new uint8_t[buffLen];
|
uint8_t* buffOut = new uint8_t[buffLen];
|
||||||
uint8_t* buffIn = new uint8_t[buffLen];
|
|
||||||
#endif
|
#endif
|
||||||
uint8_t* buffOutPtr = buffOut;
|
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?");
|
RADIOLIB_DEBUG_BASIC_PRINTLN("GPIO pre-transfer timeout, is it connected?");
|
||||||
#if !RADIOLIB_STATIC_ONLY
|
#if !RADIOLIB_STATIC_ONLY
|
||||||
delete[] buffOut;
|
delete[] buffOut;
|
||||||
delete[] buffIn;
|
|
||||||
#endif
|
#endif
|
||||||
return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
|
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
|
// do the transfer
|
||||||
this->hal->spiBeginTransaction();
|
this->hal->spiBeginTransaction();
|
||||||
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow);
|
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) {
|
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;
|
size_t rem_len = len;
|
||||||
for(size_t i = 0; i < len; i+=16) {
|
for(size_t i = 0; i < len; i+=16) {
|
||||||
char str[80];
|
char str[120];
|
||||||
sprintf(str, "%07" PRIx32 " ", i+offset);
|
sprintf(str, "%07" PRIx32 " ", i+offset);
|
||||||
size_t line_len = 16;
|
size_t line_len = 16;
|
||||||
if(rem_len < line_len) {
|
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[56] = '|';
|
||||||
str[57] = ' ';
|
str[57] = ' ';
|
||||||
|
|
||||||
|
// at this point we need to start escaping "%" characters
|
||||||
|
char* strPtr = &str[58];
|
||||||
for(size_t j = 0; j < line_len; j++) {
|
for(size_t j = 0; j < line_len; j++) {
|
||||||
char c = data[i+j];
|
char c = data[i+j];
|
||||||
if((c < ' ') || (c > '~')) {
|
if((c < ' ') || (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++) {
|
for(size_t j = line_len; j < 16; j++) {
|
||||||
sprintf(&str[58 + j], " ");
|
sprintf(strPtr++, " ");
|
||||||
}
|
}
|
||||||
if(level) {
|
if(level) {
|
||||||
RADIOLIB_DEBUG_PRINT(level);
|
RADIOLIB_DEBUG_PRINT(level);
|
||||||
|
@ -539,7 +554,7 @@ size_t Module::serialPrintf(const char* format, ...) {
|
||||||
vsnprintf(buffer, len + 1, format, arg);
|
vsnprintf(buffer, len + 1, format, arg);
|
||||||
va_end(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) {
|
if (buffer != temp) {
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -560,6 +560,62 @@ int16_t CC1101::getFrequencyDeviation(float *freqDev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t CC1101::setOutputPower(int8_t pwr) {
|
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
|
// round to the known frequency settings
|
||||||
uint8_t f;
|
uint8_t f;
|
||||||
if(this->frequency < 374.0) {
|
if(this->frequency < 374.0) {
|
||||||
|
@ -586,53 +642,35 @@ int16_t CC1101::setOutputPower(int8_t pwr) {
|
||||||
{0xCB, 0xC8, 0xCB, 0xC7},
|
{0xCB, 0xC8, 0xCB, 0xC7},
|
||||||
{0xC2, 0xC0, 0xC2, 0xC0}};
|
{0xC2, 0xC0, 0xC2, 0xC0}};
|
||||||
|
|
||||||
uint8_t powerRaw;
|
switch(power) {
|
||||||
switch(pwr) {
|
case allowedPwrs[0]: // -30
|
||||||
case -30:
|
*raw = paTable[0][f];
|
||||||
powerRaw = paTable[0][f];
|
|
||||||
break;
|
break;
|
||||||
case -20:
|
case allowedPwrs[1]: // -20
|
||||||
powerRaw = paTable[1][f];
|
*raw = paTable[1][f];
|
||||||
break;
|
break;
|
||||||
case -15:
|
case allowedPwrs[2]: // -15
|
||||||
powerRaw = paTable[2][f];
|
*raw = paTable[2][f];
|
||||||
break;
|
break;
|
||||||
case -10:
|
case allowedPwrs[3]: // -10
|
||||||
powerRaw = paTable[3][f];
|
*raw = paTable[3][f];
|
||||||
break;
|
break;
|
||||||
case 0:
|
case allowedPwrs[4]: // 0
|
||||||
powerRaw = paTable[4][f];
|
*raw = paTable[4][f];
|
||||||
break;
|
break;
|
||||||
case 5:
|
case allowedPwrs[5]: // 5
|
||||||
powerRaw = paTable[5][f];
|
*raw = paTable[5][f];
|
||||||
break;
|
break;
|
||||||
case 7:
|
case allowedPwrs[6]: // 7
|
||||||
powerRaw = paTable[6][f];
|
*raw = paTable[6][f];
|
||||||
break;
|
break;
|
||||||
case 10:
|
case allowedPwrs[7]: // 10
|
||||||
powerRaw = paTable[7][f];
|
*raw = paTable[7][f];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return(RADIOLIB_ERR_INVALID_OUTPUT_POWER);
|
return(RADIOLIB_ERR_INVALID_OUTPUT_POWER);
|
||||||
}
|
}
|
||||||
|
return(RADIOLIB_ERR_NONE);
|
||||||
// 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) {
|
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.
|
\brief Default constructor.
|
||||||
\param module Instance of Module that will be used to communicate with the radio.
|
\param module Instance of Module that will be used to communicate with the radio.
|
||||||
*/
|
*/
|
||||||
|
// cppcheck-suppress noExplicitConstructor
|
||||||
CC1101(Module* module);
|
CC1101(Module* module);
|
||||||
|
|
||||||
// basic methods
|
// basic methods
|
||||||
|
@ -660,23 +661,23 @@ class CC1101: public PhysicalLayer {
|
||||||
\brief Sets interrupt service routine to call when a packet is received.
|
\brief Sets interrupt service routine to call when a packet is received.
|
||||||
\param func ISR to call.
|
\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.
|
\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.
|
\brief Sets interrupt service routine to call when a packet is sent.
|
||||||
\param func ISR to call.
|
\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.
|
\brief Clears interrupt service routine to call when a packet is sent.
|
||||||
*/
|
*/
|
||||||
void clearPacketSentAction();
|
void clearPacketSentAction() override;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Interrupt-driven binary transmit method.
|
\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.
|
\brief Interrupt-driven receive method. GDO0 will be activated when full packet is received.
|
||||||
\returns \ref status_codes
|
\returns \ref status_codes
|
||||||
*/
|
*/
|
||||||
int16_t startReceive();
|
int16_t startReceive() override;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer.
|
\brief Interrupt-driven receive method, implemented for compatibility with PhysicalLayer.
|
||||||
|
@ -708,7 +709,7 @@ class CC1101: public PhysicalLayer {
|
||||||
\param len Ignored.
|
\param len Ignored.
|
||||||
\returns \ref status_codes
|
\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,
|
\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.
|
\param freq Carrier frequency to be set in MHz.
|
||||||
\returns \ref status_codes
|
\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.
|
\brief Sets bit rate. Allowed values range from 0.025 to 600.0 kbps.
|
||||||
\param br Bit rate to be set in kbps.
|
\param br Bit rate to be set in kbps.
|
||||||
\returns \ref status_codes
|
\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,
|
\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.
|
\param pwr Output power to be set in dBm.
|
||||||
\returns \ref status_codes
|
\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.
|
\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.
|
In asynchronous direct mode, returns the current RSSI level.
|
||||||
\returns RSSI in dBm.
|
\returns RSSI in dBm.
|
||||||
*/
|
*/
|
||||||
float getRSSI();
|
float getRSSI() override;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Gets LQI (Link Quality Indicator) of the last received packet.
|
\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.
|
\brief Get one truly random byte from RSSI noise.
|
||||||
\returns TRNG byte.
|
\returns TRNG byte.
|
||||||
*/
|
*/
|
||||||
uint8_t randomByte();
|
uint8_t randomByte() override;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Read version SPI register. Should return CC1101_VERSION_LEGACY (0x04) or
|
\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.
|
\brief Set interrupt service routine function to call when data bit is receveid in direct mode.
|
||||||
\param func Pointer to interrupt service routine.
|
\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.
|
\brief Function to read and process data bit in direct reception mode.
|
||||||
\param pin Pin on which to read.
|
\param pin Pin on which to read.
|
||||||
*/
|
*/
|
||||||
void readBit(uint32_t pin);
|
void readBit(uint32_t pin) override;
|
||||||
#endif
|
#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.
|
\param value The value that indicates which function to place on that pin. See chip datasheet for details.
|
||||||
\returns \ref status_codes
|
\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
|
#if !RADIOLIB_GODMODE && !RADIOLIB_LOW_LEVEL
|
||||||
protected:
|
protected:
|
||||||
#endif
|
#endif
|
||||||
Module* getMod();
|
Module* getMod() override;
|
||||||
|
|
||||||
// SPI read overrides to set bit for burst write and status registers access
|
// 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);
|
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) {
|
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
|
// determine whether to use HP or LP PA and check range accordingly
|
||||||
bool useHp = forceHighPower || (power > 14);
|
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?
|
// TODO how and when to configure OCP?
|
||||||
|
|
||||||
// update PA config - always use VBAT for high-power PA
|
// 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);
|
RADIOLIB_ASSERT(state);
|
||||||
|
|
||||||
// set output power
|
// set output power
|
||||||
|
@ -616,6 +611,27 @@ int16_t LR11x0::setOutputPower(int8_t power, bool forceHighPower) {
|
||||||
return(state);
|
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) {
|
int16_t LR11x0::setBandwidth(float bw) {
|
||||||
// check active modem
|
// check active modem
|
||||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||||
|
|
|
@ -802,6 +802,25 @@ class LR11x0: public PhysicalLayer {
|
||||||
*/
|
*/
|
||||||
int16_t setOutputPower(int8_t power, bool forceHighPower);
|
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.
|
\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.
|
\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) {
|
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
|
// get current OCP configuration
|
||||||
uint8_t ocp = 0;
|
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);
|
RADIOLIB_ASSERT(state);
|
||||||
|
|
||||||
// set PA config
|
// set PA config
|
||||||
|
@ -25,4 +27,12 @@ int16_t SX1261::setOutputPower(int8_t power) {
|
||||||
return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
|
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
|
#endif
|
||||||
|
|
|
@ -34,6 +34,14 @@ class SX1261 : public SX1262 {
|
||||||
*/
|
*/
|
||||||
int16_t setOutputPower(int8_t power);
|
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
|
#if !RADIOLIB_GODMODE
|
||||||
private:
|
private:
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -98,11 +98,13 @@ int16_t SX1262::setFrequency(float freq, bool calibrate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t SX1262::setOutputPower(int8_t power) {
|
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
|
// get current OCP configuration
|
||||||
uint8_t ocp = 0;
|
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);
|
RADIOLIB_ASSERT(state);
|
||||||
|
|
||||||
// set PA config
|
// set PA config
|
||||||
|
@ -117,4 +119,12 @@ int16_t SX1262::setOutputPower(int8_t power) {
|
||||||
return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
|
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
|
#endif
|
||||||
|
|
|
@ -87,6 +87,14 @@ class SX1262: public SX126x {
|
||||||
*/
|
*/
|
||||||
virtual int16_t setOutputPower(int8_t power);
|
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
|
#if !RADIOLIB_GODMODE
|
||||||
private:
|
private:
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -93,11 +93,13 @@ int16_t SX1268::setFrequency(float freq, bool calibrate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t SX1268::setOutputPower(int8_t power) {
|
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
|
// get current OCP configuration
|
||||||
uint8_t ocp = 0;
|
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);
|
RADIOLIB_ASSERT(state);
|
||||||
|
|
||||||
// set PA config
|
// set PA config
|
||||||
|
@ -112,4 +114,12 @@ int16_t SX1268::setOutputPower(int8_t power) {
|
||||||
return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
|
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
|
#endif
|
||||||
|
|
|
@ -85,6 +85,14 @@ class SX1268: public SX126x {
|
||||||
*/
|
*/
|
||||||
int16_t setOutputPower(int8_t power);
|
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
|
#if !RADIOLIB_GODMODE
|
||||||
private:
|
private:
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -280,15 +280,12 @@ int16_t SX1272::setOutputPower(int8_t power) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t SX1272::setOutputPower(int8_t power, bool useRfo) {
|
int16_t SX1272::setOutputPower(int8_t power, bool useRfo) {
|
||||||
// check allowed power range
|
// check if power value is configurable
|
||||||
if(useRfo) {
|
int16_t state = checkOutputPower(power, NULL, useRfo);
|
||||||
RADIOLIB_CHECK_RANGE(power, -1, 14, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
|
RADIOLIB_ASSERT(state);
|
||||||
} else {
|
|
||||||
RADIOLIB_CHECK_RANGE(power, 2, 20, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set mode to standby
|
// set mode to standby
|
||||||
int16_t state = SX127x::standby();
|
state = SX127x::standby();
|
||||||
Module* mod = this->getMod();
|
Module* mod = this->getMod();
|
||||||
|
|
||||||
if(useRfo) {
|
if(useRfo) {
|
||||||
|
@ -317,6 +314,26 @@ int16_t SX1272::setOutputPower(int8_t power, bool useRfo) {
|
||||||
return(state);
|
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) {
|
int16_t SX1272::setGain(uint8_t gain) {
|
||||||
// check allowed range
|
// check allowed range
|
||||||
if(gain > 6) {
|
if(gain > 6) {
|
||||||
|
|
|
@ -206,6 +206,24 @@ class SX1272: public SX127x {
|
||||||
*/
|
*/
|
||||||
int16_t setOutputPower(int8_t power, bool useRfo);
|
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.
|
\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).
|
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) {
|
int16_t SX1278::setOutputPower(int8_t power, bool useRfo) {
|
||||||
// check allowed power range
|
// check if power value is configurable
|
||||||
if(useRfo) {
|
int16_t state = checkOutputPower(power, NULL, useRfo);
|
||||||
// RFO output
|
RADIOLIB_ASSERT(state);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set mode to standby
|
// set mode to standby
|
||||||
int16_t state = SX127x::standby();
|
state = SX127x::standby();
|
||||||
Module* mod = this->getMod();
|
Module* mod = this->getMod();
|
||||||
|
|
||||||
if(useRfo) {
|
if(useRfo) {
|
||||||
|
@ -342,6 +335,34 @@ int16_t SX1278::setOutputPower(int8_t power, bool useRfo) {
|
||||||
return(state);
|
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) {
|
int16_t SX1278::setGain(uint8_t gain) {
|
||||||
// check allowed range
|
// check allowed range
|
||||||
if(gain > 6) {
|
if(gain > 6) {
|
||||||
|
|
|
@ -218,6 +218,24 @@ class SX1278: public SX127x {
|
||||||
*/
|
*/
|
||||||
int16_t setOutputPower(int8_t power, bool useRfo);
|
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.
|
\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).
|
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) {
|
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;
|
this->power = pwr + 18;
|
||||||
return(setTxParams(this->power));
|
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) {
|
int16_t SX128x::setPreambleLength(uint32_t preambleLength) {
|
||||||
uint8_t modem = getPacketType();
|
uint8_t modem = getPacketType();
|
||||||
if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
|
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);
|
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.
|
\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).
|
\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());
|
int32_t step = round(phyLayer->getFreqStep());
|
||||||
|
|
||||||
// check minimum shift value
|
// check minimum shift value
|
||||||
if(abs(shift) < step / 2) {
|
if(RADIOLIB_ABS(shift) < step / 2) {
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// round shift to multiples of frequency step size
|
// round shift to multiples of frequency step size
|
||||||
if(abs(shift) % step < (step / 2)) {
|
if(RADIOLIB_ABS(shift) % step < (step / 2)) {
|
||||||
return(shift / step);
|
return(shift / step);
|
||||||
}
|
}
|
||||||
if(shift < 0) {
|
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
|
// copy uplink MAC command queue back in place
|
||||||
memcpy(&this->commandsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL], sizeof(LoRaWANMacCommandQueue_t));
|
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
|
// 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]);
|
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
|
// setup all MAC properties to default values
|
||||||
this->beginCommon(joinDr);
|
this->beginCommon(joinDr);
|
||||||
|
|
||||||
// set the physical layer configuration
|
|
||||||
state = this->setPhyProperties();
|
|
||||||
RADIOLIB_ASSERT(state);
|
|
||||||
|
|
||||||
// select a random pair of Tx/Rx channels
|
// select a random pair of Tx/Rx channels
|
||||||
state = this->selectChannels();
|
state = this->selectChannels();
|
||||||
RADIOLIB_ASSERT(state);
|
RADIOLIB_ASSERT(state);
|
||||||
|
|
||||||
// configure for uplink with default configuration
|
// set the physical layer configuration for uplink
|
||||||
state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK);
|
state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK);
|
||||||
RADIOLIB_ASSERT(state);
|
RADIOLIB_ASSERT(state);
|
||||||
|
|
||||||
// copy devNonce currently in use
|
// 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);
|
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 not forced and already joined, don't do anything
|
||||||
if(!force && this->isJoined()) {
|
if(!force && this->isJoined()) {
|
||||||
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("beginABP(): Did not rejoin: session already active");
|
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
|
// check if we actually need to restart from a clean session
|
||||||
uint16_t checkSum = 0;
|
uint16_t checkSum = 0;
|
||||||
checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast<uint8_t*>(&addr), 4);
|
checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast<uint8_t*>(&addr), 4);
|
||||||
checkSum ^= LoRaWANNode::checkSum16(nwkSKey, 16);
|
checkSum ^= LoRaWANNode::checkSum16(nwkSEncKey, 16);
|
||||||
checkSum ^= LoRaWANNode::checkSum16(appSKey, 16);
|
checkSum ^= LoRaWANNode::checkSum16(appSKey, 16);
|
||||||
if(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); }
|
if(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); }
|
||||||
if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 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;
|
this->devAddr = addr;
|
||||||
memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE);
|
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) {
|
if(fNwkSIntKey) {
|
||||||
this->rev = 1;
|
this->rev = 1;
|
||||||
memcpy(this->fNwkSIntKey, fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE);
|
memcpy(this->fNwkSIntKey, fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE);
|
||||||
} else {
|
} else {
|
||||||
memcpy(this->fNwkSIntKey, nwkSKey, RADIOLIB_AES128_KEY_SIZE);
|
memcpy(this->fNwkSIntKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE);
|
||||||
}
|
}
|
||||||
if(sNwkSIntKey) {
|
if(sNwkSIntKey) {
|
||||||
memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE);
|
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
|
// setup all MAC properties to default values
|
||||||
this->beginCommon(initialDr);
|
this->beginCommon(initialDr);
|
||||||
|
|
||||||
// set the physical layer configuration
|
|
||||||
state = this->setPhyProperties();
|
|
||||||
RADIOLIB_ASSERT(state);
|
|
||||||
|
|
||||||
// reset all frame counters
|
// reset all frame counters
|
||||||
this->fcntUp = 0;
|
this->fcntUp = 0;
|
||||||
this->aFcntDown = 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();
|
this->selectChannels();
|
||||||
state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK);
|
state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK);
|
||||||
RADIOLIB_ASSERT(state);
|
RADIOLIB_ASSERT(state);
|
||||||
|
|
||||||
// if dwell time is imposed, calculated expected time on air and cancel if exceeds
|
// 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
|
// check if we have some MAC commands to append
|
||||||
if(foptsLen > 0) {
|
if(foptsLen > 0) {
|
||||||
#if RADIOLIB_STATIC_ONLY
|
|
||||||
// assume maximum possible buffer size
|
// assume maximum possible buffer size
|
||||||
uint8_t foptsBuff[RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN];
|
uint8_t foptsBuff[RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN];
|
||||||
#else
|
|
||||||
uint8_t* foptsBuff = new uint8_t[foptsLen];
|
|
||||||
#endif
|
|
||||||
uint8_t* foptsPtr = foptsBuff;
|
uint8_t* foptsPtr = foptsBuff;
|
||||||
|
|
||||||
// append all MAC replies into fopts buffer
|
// 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
|
// encrypt it
|
||||||
processAES(foptsBuff, foptsLen, this->nwkSEncKey, &uplinkMsg[RADIOLIB_LORAWAN_FHDR_FOPTS_POS], this->fcntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x01, true);
|
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
|
// 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() {
|
int16_t LoRaWANNode::downlinkCommon() {
|
||||||
Module* mod = this->phyLayer->getMod();
|
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
|
// 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 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 between start of Rx1 and end of Rx2, wait until Rx2 closes
|
||||||
if(mod->hal->millis() - this->rxDelayStart < this->rxDelays[1]) {
|
if(now < this->rxDelayStart + this->rxDelays[1]) {
|
||||||
mod->hal->delay(this->rxDelays[1] + this->rxDelayStart - mod->hal->millis());
|
mod->hal->delay(this->rxDelays[1] + this->rxDelayStart - now);
|
||||||
}
|
}
|
||||||
// update the end timestamp in case user got stuck between uplink and downlink
|
// update the end timestamp in case user got stuck between uplink and downlink
|
||||||
this->rxDelayEnd = mod->hal->millis();
|
this->rxDelayEnd = mod->hal->millis();
|
||||||
return(RADIOLIB_ERR_NO_RX_WINDOW);
|
return(RADIOLIB_ERR_NO_RX_WINDOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure for downlink
|
// set the physical layer configuration for downlink
|
||||||
int16_t state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK);
|
int16_t state = this->setPhyProperties(RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK);
|
||||||
RADIOLIB_ASSERT(state);
|
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
|
// create the masks that are required for receiving downlinks
|
||||||
uint16_t irqFlags = 0x0000;
|
uint16_t irqFlags = 0x0000;
|
||||||
uint16_t irqMask = 0x0000;
|
uint16_t irqMask = 0x0000;
|
||||||
|
@ -1182,14 +1162,16 @@ int16_t LoRaWANNode::downlinkCommon() {
|
||||||
downlinkAction = false;
|
downlinkAction = false;
|
||||||
|
|
||||||
// calculate the Rx timeout
|
// 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 timeoutHost = this->phyLayer->getTimeOnAir(0) + 2*scanGuard*1000;
|
||||||
RadioLibTime_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost);
|
RadioLibTime_t timeoutMod = this->phyLayer->calculateRxTimeout(timeoutHost);
|
||||||
|
|
||||||
// wait for the start of the Rx window
|
// 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
|
// 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) {
|
if(waitLen > scanGuard) {
|
||||||
waitLen -= scanGuard;
|
waitLen -= scanGuard;
|
||||||
}
|
}
|
||||||
|
@ -1215,7 +1197,8 @@ int16_t LoRaWANNode::downlinkCommon() {
|
||||||
RADIOLIB_ASSERT(state);
|
RADIOLIB_ASSERT(state);
|
||||||
|
|
||||||
DataRate_t dataRate;
|
DataRate_t dataRate;
|
||||||
findDataRate(this->rx2.drMax, &dataRate);
|
state = findDataRate(this->rx2.drMax, &dataRate);
|
||||||
|
RADIOLIB_ASSERT(state);
|
||||||
state = this->phyLayer->setDataRate(dataRate);
|
state = this->phyLayer->setDataRate(dataRate);
|
||||||
RADIOLIB_ASSERT(state);
|
RADIOLIB_ASSERT(state);
|
||||||
}
|
}
|
||||||
|
@ -1687,16 +1670,51 @@ bool LoRaWANNode::verifyMIC(uint8_t* msg, size_t len, uint8_t* key) {
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t LoRaWANNode::setPhyProperties() {
|
int16_t LoRaWANNode::setPhyProperties(uint8_t dir) {
|
||||||
// set the physical layer configuration
|
// set the physical layer configuration
|
||||||
int8_t pwr = this->txPowerMax - this->txPowerCur * 2;
|
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("");
|
||||||
int16_t state = RADIOLIB_ERR_INVALID_OUTPUT_POWER;
|
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: Frequency %cL = %6.3f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq);
|
||||||
while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) {
|
int16_t state = this->phyLayer->setFrequency(this->currentChannels[dir].freq);
|
||||||
// go from the highest power and lower it until we hit one supported by the module
|
|
||||||
state = this->phyLayer->setOutputPower(pwr--);
|
|
||||||
}
|
|
||||||
RADIOLIB_ASSERT(state);
|
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 syncWord[3] = { 0 };
|
||||||
uint8_t syncWordLen = 0;
|
uint8_t syncWordLen = 0;
|
||||||
size_t preLen = 0;
|
size_t preLen = 0;
|
||||||
|
@ -1987,7 +2005,8 @@ void LoRaWANNode::setDwellTime(bool enable, RadioLibTime_t msPerUplink) {
|
||||||
uint8_t LoRaWANNode::maxPayloadDwellTime() {
|
uint8_t LoRaWANNode::maxPayloadDwellTime() {
|
||||||
// configure current datarate
|
// configure current datarate
|
||||||
DataRate_t dr;
|
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);
|
(void)this->phyLayer->setDataRate(dr);
|
||||||
uint8_t minPayLen = 0;
|
uint8_t minPayLen = 0;
|
||||||
uint8_t maxPayLen = 255;
|
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 LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) {
|
||||||
|
int16_t state = RADIOLIB_ERR_UNKNOWN;
|
||||||
|
|
||||||
uint8_t dataRateBand = this->band->dataRates[dr];
|
uint8_t dataRateBand = this->band->dataRates[dr];
|
||||||
|
|
||||||
if(dataRateBand & RADIOLIB_LORAWAN_DATA_RATE_FSK_50_K) {
|
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.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6;
|
||||||
dataRate->lora.codingRate = (dataRateBand & 0x03) + 5;
|
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);
|
state = this->phyLayer->checkDataRate(*dataRate);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(state);
|
return(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoRaWANNode::sendMacCommandReq(uint8_t cid) {
|
int16_t LoRaWANNode::sendMacCommandReq(uint8_t cid) {
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) {
|
for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_MAC_COMMANDS; i++) {
|
||||||
if(MacTable[i].cid == cid) {
|
if(MacTable[i].cid == cid) {
|
||||||
valid = MacTable[i].user;
|
valid = MacTable[i].user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!valid)
|
if(!valid) {
|
||||||
return(false);
|
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 = {
|
LoRaWANMacCommand_t cmd = {
|
||||||
.cid = cid,
|
.cid = cid,
|
||||||
|
@ -2182,8 +2190,6 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
|
||||||
case(RADIOLIB_LORAWAN_MAC_LINK_ADR): {
|
case(RADIOLIB_LORAWAN_MAC_LINK_ADR): {
|
||||||
int16_t state = RADIOLIB_ERR_UNKNOWN;
|
int16_t state = RADIOLIB_ERR_UNKNOWN;
|
||||||
// get the ADR configuration
|
// 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 drUp = (cmd->payload[0] & 0xF0) >> 4;
|
||||||
uint8_t txSteps = cmd->payload[0] & 0x0F;
|
uint8_t txSteps = cmd->payload[0] & 0x0F;
|
||||||
bool isInternalTxDr = cmd->payload[3] >> 7;
|
bool isInternalTxDr = cmd->payload[3] >> 7;
|
||||||
|
@ -2193,19 +2199,15 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
|
||||||
uint8_t nbTrans = cmd->payload[3] & 0x0F;
|
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);
|
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;
|
uint8_t drAck = 0;
|
||||||
if(drUp == 0x0F) { // keep the same
|
if(drUp == 0x0F) { // keep the same
|
||||||
drAck = 1;
|
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) {
|
} else if (this->band->dataRates[drUp] != RADIOLIB_LORAWAN_DATA_RATE_UNUSED) {
|
||||||
// check if the module supports this data rate
|
// check if the module supports this data rate
|
||||||
DataRate_t dr;
|
DataRate_t dr;
|
||||||
findDataRate(drUp, &dr);
|
state = findDataRate(drUp, &dr);
|
||||||
state = this->phyLayer->checkDataRate(dr);
|
|
||||||
if(state == RADIOLIB_ERR_NONE) {
|
if(state == RADIOLIB_ERR_NONE) {
|
||||||
uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase,
|
uint8_t drDown = getDownlinkDataRate(drUp, this->rx1DrOffset, this->band->rx1DataRateBase,
|
||||||
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin,
|
this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].drMin,
|
||||||
|
@ -2215,6 +2217,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
|
||||||
drAck = 1;
|
drAck = 1;
|
||||||
} else {
|
} else {
|
||||||
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("ADR failed to configure dataRate %d, code %d!", drUp, state);
|
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) {
|
if(txSteps == 0x0F) {
|
||||||
pwrAck = 1;
|
pwrAck = 1;
|
||||||
|
|
||||||
// replace the 'placeholder' with the current actual value for saving
|
|
||||||
cmd->payload[0] = (cmd->payload[0] & 0xF0) | this->txPowerCur;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
int8_t pwr = this->txPowerMax - 2*txSteps;
|
int8_t power = this->txPowerMax - 2*txSteps;
|
||||||
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("PHY: TX = %d dBm", pwr);
|
int8_t powerActual = 0;
|
||||||
state = RADIOLIB_ERR_INVALID_OUTPUT_POWER;
|
state = this->phyLayer->checkOutputPower(power, &powerActual);
|
||||||
while(state == RADIOLIB_ERR_INVALID_OUTPUT_POWER) {
|
// only acknowledge if the radio is able to operate at or below the requested power level
|
||||||
// go from the highest power and lower it until we hit one supported by the module
|
if(state == RADIOLIB_ERR_NONE || (state == RADIOLIB_ERR_INVALID_OUTPUT_POWER && powerActual < power)) {
|
||||||
state = this->phyLayer->setOutputPower(pwr--);
|
|
||||||
}
|
|
||||||
// only acknowledge if the requested datarate was succesfully configured
|
|
||||||
if(state == RADIOLIB_ERR_NONE) {
|
|
||||||
pwrAck = 1;
|
pwrAck = 1;
|
||||||
this->txPowerCur = txSteps;
|
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;
|
uint8_t chMaskAck = 1;
|
||||||
// only apply channel mask when the RFU bit is not set
|
// only apply channel mask when the RFU bit is not set
|
||||||
// (which is only set in internal MAC commands for changing Tx/Dr)
|
// (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
|
if(nbTrans) { // if there is a value for NbTrans, set this value
|
||||||
cmd->payload[3] = (cmd->payload[3] & 0xF0) | this->nbTrans; // set current number of retransmissions for saving
|
|
||||||
} else {
|
|
||||||
this->nbTrans = nbTrans;
|
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(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 RFU bit is set, this is just a change in Datarate or TxPower, so read ADR command and overwrite first byte
|
||||||
if(isInternalTxDr) {
|
if(isInternalTxDr) {
|
||||||
|
@ -2801,6 +2810,10 @@ uint64_t LoRaWANNode::getDevAddr() {
|
||||||
return(this->devAddr);
|
return(this->devAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RadioLibTime_t LoRaWANNode::getLastToA() {
|
||||||
|
return(this->lastToA);
|
||||||
|
}
|
||||||
|
|
||||||
// The following function enables LMAC, a CSMA scheme for LoRa as specified
|
// The following function enables LMAC, a CSMA scheme for LoRa as specified
|
||||||
// in the LoRa Alliance Technical Recommendation #13.
|
// in the LoRa Alliance Technical Recommendation #13.
|
||||||
// A user may enable CSMA to provide frames an additional layer of protection from interference.
|
// 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_DATA_RATE_POS (3)
|
||||||
#define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4)
|
#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
|
// MAC commands
|
||||||
#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16)
|
#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16)
|
||||||
|
|
||||||
|
@ -179,15 +185,6 @@
|
||||||
#define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F)
|
#define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F)
|
||||||
#define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80)
|
#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
|
// the length of internal MAC command queue - hopefully this is enough for most use cases
|
||||||
#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (9)
|
#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (9)
|
||||||
|
|
||||||
|
@ -217,74 +214,109 @@ struct LoRaWANMacSpec_t {
|
||||||
const bool user;
|
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
|
{ 0x00, 0, 0, false }, // not an actual MAC command, exists for index offsetting
|
||||||
{ RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false },
|
{ RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true },
|
{ RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true },
|
||||||
{ RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false },
|
{ RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false },
|
{ RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false },
|
{ RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false },
|
{ RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false },
|
{ RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false },
|
{ RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false },
|
{ RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false },
|
{ RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false },
|
{ RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false },
|
{ RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true },
|
{ RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true },
|
||||||
{ RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false },
|
{ RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false },
|
{ RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false },
|
||||||
{ RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true }
|
{ 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)
|
#define RADIOLIB_LORAWAN_NONCES_VERSION_VAL (0x0001)
|
||||||
|
|
||||||
enum LoRaWANSchemeBase_t {
|
enum LoRaWANSchemeBase_t {
|
||||||
RADIOLIB_LORAWAN_NONCES_VERSION = 0x00, // 2 bytes
|
RADIOLIB_LORAWAN_NONCES_START = 0x00,
|
||||||
RADIOLIB_LORAWAN_NONCES_MODE = 0x02, // 2 bytes
|
RADIOLIB_LORAWAN_NONCES_VERSION = RADIOLIB_LORAWAN_NONCES_START, // 2 bytes
|
||||||
RADIOLIB_LORAWAN_NONCES_CLASS = 0x04, // 1 byte
|
RADIOLIB_LORAWAN_NONCES_MODE = RADIOLIB_LORAWAN_NONCES_VERSION + sizeof(uint16_t), // 2 bytes
|
||||||
RADIOLIB_LORAWAN_NONCES_PLAN = 0x05, // 1 byte
|
RADIOLIB_LORAWAN_NONCES_CLASS = RADIOLIB_LORAWAN_NONCES_MODE + sizeof(uint16_t), // 1 byte
|
||||||
RADIOLIB_LORAWAN_NONCES_CHECKSUM = 0x06, // 2 bytes
|
RADIOLIB_LORAWAN_NONCES_PLAN = RADIOLIB_LORAWAN_NONCES_CLASS + sizeof(uint8_t), // 1 byte
|
||||||
RADIOLIB_LORAWAN_NONCES_DEV_NONCE = 0x08, // 2 bytes
|
RADIOLIB_LORAWAN_NONCES_CHECKSUM = RADIOLIB_LORAWAN_NONCES_PLAN + sizeof(uint8_t), // 2 bytes
|
||||||
RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = 0x0A, // 3 bytes
|
RADIOLIB_LORAWAN_NONCES_DEV_NONCE = RADIOLIB_LORAWAN_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes
|
||||||
RADIOLIB_LORAWAN_NONCES_ACTIVE = 0x0D, // 1 byte
|
RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = RADIOLIB_LORAWAN_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes
|
||||||
RADIOLIB_LORAWAN_NONCES_SIGNATURE = 0x0E, // 2 bytes
|
RADIOLIB_LORAWAN_NONCES_ACTIVE = RADIOLIB_LORAWAN_NONCES_JOIN_NONCE + 3, // 1 byte
|
||||||
RADIOLIB_LORAWAN_NONCES_BUF_SIZE = 0x10 // = 16 bytes
|
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 {
|
enum LoRaWANSchemeSession_t {
|
||||||
RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = 0x00, // 16 bytes
|
RADIOLIB_LORAWAN_SESSION_START = 0x00,
|
||||||
RADIOLIB_LORAWAN_SESSION_APP_SKEY = 0x10, // 16 bytes
|
RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = RADIOLIB_LORAWAN_SESSION_START, // 16 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = 0x20, // 16 bytes
|
RADIOLIB_LORAWAN_SESSION_APP_SKEY = RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = 0x30, // 16 bytes
|
RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_APP_SKEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_DEV_ADDR = 0x40, // 4 bytes
|
RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 16 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = 0x44, // 2 bytes
|
RADIOLIB_LORAWAN_SESSION_DEV_ADDR = RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY + RADIOLIB_AES128_BLOCK_SIZE, // 4 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = 0x46, // 4 bytes
|
RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE = RADIOLIB_LORAWAN_SESSION_DEV_ADDR + sizeof(uint32_t), // 2 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = 0x4A, // 4 bytes
|
RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_NONCES_SIGNATURE + sizeof(uint16_t), // 4 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = 0x4E, // 4 bytes
|
RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP = RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN + sizeof(uint32_t), // 4 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = 0x52, // 2 bytes
|
RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP + sizeof(uint32_t), // 4 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = 0x54, // 2 bytes
|
RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 = RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN + sizeof(uint32_t), // 2 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_HOMENET_ID = 0x56, // 4 bytes
|
RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 = RADIOLIB_LORAWAN_SESSION_RJ_COUNT0 + sizeof(uint16_t), // 2 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_VERSION = 0x5A, // 1 byte
|
RADIOLIB_LORAWAN_SESSION_HOMENET_ID = RADIOLIB_LORAWAN_SESSION_RJ_COUNT1 + sizeof(uint16_t), // 4 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = 0x5B, // 1 byte
|
RADIOLIB_LORAWAN_SESSION_VERSION = RADIOLIB_LORAWAN_SESSION_HOMENET_ID + sizeof(uint32_t), // 1 byte
|
||||||
RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP = 0x5C, // 4 bytes
|
RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE = RADIOLIB_LORAWAN_SESSION_VERSION + sizeof(uint8_t), // 1 byte
|
||||||
RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP = 0x60, // 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_TX_PARAM_SETUP = 0x61, // 1 byte
|
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_ADR_PARAM_SETUP = 0x62, // 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_REJOIN_PARAM_SETUP = 0x63, // 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_BEACON_FREQ = 0x64, // 3 bytes
|
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_PING_SLOT_CHANNEL = 0x67, // 4 bytes
|
RADIOLIB_LORAWAN_SESSION_BEACON_FREQ = RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP + MacTable[RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP].lenDn, // 3 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_PERIODICITY = 0x6B, // 1 byte
|
RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL = RADIOLIB_LORAWAN_SESSION_BEACON_FREQ + 3, // 4 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_LAST_TIME = 0x6C, // 4 bytes
|
RADIOLIB_LORAWAN_SESSION_PERIODICITY = RADIOLIB_LORAWAN_SESSION_PING_SLOT_CHANNEL + 4, // 1 byte
|
||||||
RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = 0x70, // 16*8 bytes
|
RADIOLIB_LORAWAN_SESSION_LAST_TIME = RADIOLIB_LORAWAN_SESSION_PERIODICITY + 1, // 4 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_DL_CHANNELS = 0xF0, // 16*4 bytes
|
RADIOLIB_LORAWAN_SESSION_UL_CHANNELS = RADIOLIB_LORAWAN_SESSION_LAST_TIME + 4, // 16*5 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL = 0x0130, // 9*8+2 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_N_FCNT_DOWN = 0x017A, // 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_ADR_FCNT = 0x017E, // 4 bytes
|
RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN = RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_UL + sizeof(LoRaWANMacCommandQueue_t), // 4 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_LINK_ADR = 0x0182, // 4 bytes
|
RADIOLIB_LORAWAN_SESSION_ADR_FCNT = RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN + sizeof(uint32_t), // 4 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_FCNT_UP = 0x0186, // 4 bytes
|
RADIOLIB_LORAWAN_SESSION_LINK_ADR = RADIOLIB_LORAWAN_SESSION_ADR_FCNT + sizeof(uint32_t), // 4 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_SIGNATURE = 0x018A, // 2 bytes
|
RADIOLIB_LORAWAN_SESSION_FCNT_UP = RADIOLIB_LORAWAN_SESSION_LINK_ADR + MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn, // 4 bytes
|
||||||
RADIOLIB_LORAWAN_SESSION_BUF_SIZE = 0x018C // 396 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
|
// array of currently supported bands
|
||||||
extern const LoRaWANBand_t* LoRaWANBands[];
|
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
|
\struct LoRaWANEvent_t
|
||||||
\brief Structure to save extra information about uplink/downlink event.
|
\brief Structure to save extra information about uplink/downlink event.
|
||||||
|
@ -567,15 +567,16 @@ class LoRaWANNode {
|
||||||
\brief Join network by performing activation by personalization.
|
\brief Join network by performing activation by personalization.
|
||||||
In this procedure, all necessary configuration must be provided by the user.
|
In this procedure, all necessary configuration must be provided by the user.
|
||||||
\param addr Device address.
|
\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 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 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)
|
\param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled)
|
||||||
\returns \ref status_codes
|
\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 */
|
/*! \brief Whether there is an ongoing session active */
|
||||||
bool isJoined();
|
bool isJoined();
|
||||||
|
@ -591,9 +592,9 @@ class LoRaWANNode {
|
||||||
Only LinkCheck and DeviceTime are available to the user.
|
Only LinkCheck and DeviceTime are available to the user.
|
||||||
Other commands are ignored; duplicate MAC commands are discarded.
|
Other commands are ignored; duplicate MAC commands are discarded.
|
||||||
\param cid ID of the MAC command
|
\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)
|
#if defined(RADIOLIB_BUILD_ARDUINO)
|
||||||
/*!
|
/*!
|
||||||
|
@ -835,6 +836,12 @@ class LoRaWANNode {
|
||||||
*/
|
*/
|
||||||
uint64_t getDevAddr();
|
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
|
#if !RADIOLIB_GODMODE
|
||||||
private:
|
private:
|
||||||
#endif
|
#endif
|
||||||
|
@ -964,7 +971,7 @@ class LoRaWANNode {
|
||||||
|
|
||||||
// configure the common physical layer properties (preamble, sync word etc.)
|
// configure the common physical layer properties (preamble, sync word etc.)
|
||||||
// channels must be configured separately by setupChannelsDyn()!
|
// channels must be configured separately by setupChannelsDyn()!
|
||||||
int16_t setPhyProperties();
|
int16_t setPhyProperties(uint8_t dir);
|
||||||
|
|
||||||
// setup uplink/downlink channel data rates and frequencies
|
// setup uplink/downlink channel data rates and frequencies
|
||||||
// for dynamic channels, there is a small set of predefined channels
|
// 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
|
// find the first usable data rate for the given band
|
||||||
int16_t findDataRate(uint8_t dr, DataRate_t* dataRate);
|
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
|
// restore all available channels from persistent storage
|
||||||
int16_t restoreChannels();
|
int16_t restoreChannels();
|
||||||
|
|
||||||
|
|
|
@ -256,6 +256,12 @@ int16_t PhysicalLayer::setOutputPower(int8_t power) {
|
||||||
return(RADIOLIB_ERR_UNSUPPORTED);
|
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) {
|
int16_t PhysicalLayer::setSyncWord(uint8_t* sync, size_t len) {
|
||||||
(void)sync;
|
(void)sync;
|
||||||
(void)len;
|
(void)len;
|
||||||
|
|
|
@ -276,6 +276,14 @@ class PhysicalLayer {
|
||||||
*/
|
*/
|
||||||
virtual int16_t setOutputPower(int8_t power);
|
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.
|
\brief Set sync word. Must be implemented in module class if the module supports it.
|
||||||
\param sync Pointer to the sync word.
|
\param sync Pointer to the sync word.
|
||||||
|
|
Ładowanie…
Reference in New Issue