diff --git a/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvoptx b/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvoptx
index 256096aa..943a2c4e 100644
--- a/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvoptx
+++ b/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvoptx
@@ -103,7 +103,7 @@
1
0
0
- 0
+ 6
@@ -114,9 +114,34 @@
- BIN\UL2CM3.DLL
+ STLink\ST-LINKIII-KEIL_SWO.dll
+
+ 0
+ ARMRTXEVENTFLAGS
+ -L70 -Z18 -C0 -M0 -T1
+
+
+ 0
+ DLGTARM
+ (1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1012=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)
+
+
+ 0
+ ARMDBGFLAGS
+
+
+
+ 0
+ DLGUARM
+ (105=-1,-1,-1,-1,0)
+
+
+ 0
+ ST-LINKIII-KEIL_SWO
+ -U066DFF495056805087213734 -O206 -SF4000 -C0 -A0 -I0 -HNlocalhost -HP7184 -P1 -N00("ARM CoreSight SW-DP") -D00(0BC11477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD20000000 -FC1000 -FN1 -FF0STM32L0xx_128.FLM -FS08000000 -FL020000 -FP0($$Device:STM32L072CBTx$CMSIS\Flash\STM32L0xx_128.FLM)
+
0
UL2CM3
@@ -130,12 +155,12 @@
0
0
- 0
+ 1
0
0
0
0
- 0
+ 1
0
0
0
@@ -198,7 +223,7 @@
Application/User
- 1
+ 0
0
0
0
@@ -1002,7 +1027,7 @@
lorawan/mac
- 0
+ 1
0
0
0
@@ -1085,18 +1110,6 @@
0
0
0
- ..\..\..\components\connectivity\LoraWAN\mac\LoRaMacFCntHandler.c
- LoRaMacFCntHandler.c
- 0
- 0
-
-
- 5
- 74
- 1
- 0
- 0
- 0
..\..\..\components\connectivity\LoraWAN\mac\LoRaMacParser.c
LoRaMacParser.c
0
@@ -1104,7 +1117,7 @@
5
- 75
+ 74
1
0
0
@@ -1116,7 +1129,7 @@
5
- 76
+ 75
1
0
0
@@ -1128,7 +1141,7 @@
5
- 77
+ 76
1
0
0
@@ -1140,7 +1153,7 @@
5
- 78
+ 77
1
0
0
@@ -1150,6 +1163,18 @@
0
0
+
+ 5
+ 78
+ 1
+ 0
+ 0
+ 0
+ ..\..\..\components\connectivity\LoraWAN\peripherals\soft-se\soft-se-hal.c
+ soft-se-hal.c
+ 0
+ 0
+
diff --git a/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvprojx b/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvprojx
index 80697145..b6487bbd 100644
--- a/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvprojx
+++ b/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvprojx
@@ -762,11 +762,6 @@
1
..\..\..\components\connectivity\LoraWAN\mac\LoRaMacCrypto.c
-
- LoRaMacFCntHandler.c
- 1
- ..\..\..\components\connectivity\LoraWAN\mac\LoRaMacFCntHandler.c
-
LoRaMacParser.c
1
@@ -792,6 +787,11 @@
1
..\..\..\components\connectivity\LoraWAN\peripherals\soft-se\soft-se.c
+
+ soft-se-hal.c
+ 1
+ ..\..\..\components\connectivity\LoraWAN\peripherals\soft-se\soft-se-hal.c
+
diff --git a/board/RHF76_STM32L072CBxx_Lora/Src/CMakeLists.txt b/board/RHF76_STM32L072CBxx_Lora/Src/CMakeLists.txt
new file mode 100644
index 00000000..3a832fd1
--- /dev/null
+++ b/board/RHF76_STM32L072CBxx_Lora/Src/CMakeLists.txt
@@ -0,0 +1,84 @@
+##
+## ______ _
+## / _____) _ | |
+## ( (____ _____ ____ _| |_ _____ ____| |__
+## \____ \| ___ | (_ _) ___ |/ ___) _ \
+## _____) ) ____| | | || |_| ____( (___| | | |
+## (______/|_____)_|_|_| \__)_____)\____)_| |_|
+## (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)
+##
+project(B-L072Z-LRWAN1)
+cmake_minimum_required(VERSION 3.6)
+enable_language(ASM)
+
+#---------------------------------------------------------------------------------------
+# Target
+#---------------------------------------------------------------------------------------
+
+list(APPEND ${PROJECT_NAME}_SOURCES
+ "${CMAKE_CURRENT_SOURCE_DIR}/adc-board.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/board.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/delay-board.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/eeprom-board.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/gpio-board.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/lpm-board.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/rtc-board.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/spi-board.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/sx1276-board.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/uart-board.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/sysIrqHandlers.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/utilities.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmsis/arm-gcc/startup_stm32l072xx.s"
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmsis/system_stm32l0xx.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_adc.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_adc_ex.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_cortex.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_dma.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_flash.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_flash_ex.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_gpio.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_i2c.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_i2c_ex.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_pwr.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_pwr_ex.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_rcc.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_rcc_ex.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_rtc.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_rtc_ex.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_spi.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_uart.c"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_uart_ex.c"
+)
+
+add_library(${PROJECT_NAME} OBJECT EXCLUDE_FROM_ALL ${${PROJECT_NAME}_SOURCES})
+
+target_compile_definitions(${PROJECT_NAME} PUBLIC -DUSE_HAL_DRIVER -DSTM32L072xx)
+
+# Add define if debbuger support is enabled
+target_compile_definitions(${PROJECT_NAME} PUBLIC $<$:USE_DEBUGGER>)
+
+# Add define if radio debug pins support is enabled
+target_compile_definitions(${PROJECT_NAME} PUBLIC $<$:USE_RADIO_DEBUG>)
+
+target_include_directories(${PROJECT_NAME} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmsis
+ ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32
+ ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/cmsis
+ ${CMAKE_CURRENT_SOURCE_DIR}/../mcu/stm32/STM32L0xx_HAL_Driver/Inc
+ $
+ $
+ $
+ $
+)
+
+set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11)
diff --git a/board/RHF76_STM32L072CBxx_Lora/Src/adc-board.c b/board/RHF76_STM32L072CBxx_Lora/Src/adc-board.c
index 85b72e59..73ec0e28 100644
--- a/board/RHF76_STM32L072CBxx_Lora/Src/adc-board.c
+++ b/board/RHF76_STM32L072CBxx_Lora/Src/adc-board.c
@@ -20,6 +20,8 @@
*
* \author Gregory Cristian ( Semtech )
*/
+#include
+#include
#include "stm32l0xx.h"
#include "board-config.h"
#include "adc-board.h"
@@ -70,6 +72,8 @@ uint16_t AdcMcuReadChannel( Adc_t *obj, uint32_t channel )
{
ADC_ChannelConfTypeDef adcConf = { 0 };
uint16_t adcData = 0;
+ uint32_t tickStart = 0;
+ bool isAdcReady = true;
// Enable HSI
__HAL_RCC_HSI_ENABLE( );
@@ -83,18 +87,31 @@ uint16_t AdcMcuReadChannel( Adc_t *obj, uint32_t channel )
adcConf.Channel = channel;
adcConf.Rank = ADC_RANK_CHANNEL_NUMBER;
-
HAL_ADC_ConfigChannel( &AdcHandle, &adcConf );
// Enable ADC1
__HAL_ADC_ENABLE( &AdcHandle );
- // Start ADC Software Conversion
- HAL_ADC_Start( &AdcHandle );
+ // Wait for ADC to effectively be enabled
+ tickStart = HAL_GetTick( );
+ while( __HAL_ADC_GET_FLAG( &AdcHandle, ADC_FLAG_RDY ) == RESET )
+ {
+ if( ( HAL_GetTick( ) - tickStart ) > ADC_ENABLE_TIMEOUT )
+ {
+ isAdcReady = false;
+ break;
+ }
+ }
- HAL_ADC_PollForConversion( &AdcHandle, HAL_MAX_DELAY );
+ if( isAdcReady != false )
+ {
+ // Start ADC Software Conversion
+ HAL_ADC_Start( &AdcHandle );
- adcData = HAL_ADC_GetValue( &AdcHandle );
+ HAL_ADC_PollForConversion( &AdcHandle, HAL_MAX_DELAY );
+
+ adcData = HAL_ADC_GetValue( &AdcHandle );
+ }
__HAL_ADC_DISABLE( &AdcHandle );
diff --git a/board/RHF76_STM32L072CBxx_Lora/Src/rtc-board.c b/board/RHF76_STM32L072CBxx_Lora/Src/rtc-board.c
index a7b8ea67..77a54071 100644
--- a/board/RHF76_STM32L072CBxx_Lora/Src/rtc-board.c
+++ b/board/RHF76_STM32L072CBxx_Lora/Src/rtc-board.c
@@ -185,8 +185,8 @@ void RtcInit( void )
time.Seconds = 0;
time.SubSeconds = 0;
time.TimeFormat = 0;
- time.StoreOperation = RTC_DAYLIGHTSAVING_NONE;
- time.DayLightSaving = RTC_STOREOPERATION_RESET;
+ time.StoreOperation = RTC_STOREOPERATION_RESET;
+ time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
HAL_RTC_SetTime( &RtcHandle, &time, RTC_FORMAT_BIN );
// Enable Direct Read of the calendar registers (not through Shadow registers)
@@ -469,7 +469,7 @@ void RtcSetMcuWakeUpTime( void )
mcuWakeUpTime = ( int16_t )( ( now - hit ) );
McuWakeUpTimeCal += mcuWakeUpTime;
- //PRINTF( 3, "Cal=%d, %d\n\r", McuWakeUpTimeCal, mcuWakeUpTime);
+ //PRINTF( 3, "Cal=%d, %d\n", McuWakeUpTimeCal, mcuWakeUpTime);
}
}
@@ -485,16 +485,13 @@ static uint64_t RtcGetCalendarValue( RTC_DateTypeDef* date, RTC_TimeTypeDef* tim
uint32_t correction;
uint32_t seconds;
- // Get Time and Date
- HAL_RTC_GetTime( &RtcHandle, time, RTC_FORMAT_BIN );
-
// Make sure it is correct due to asynchronus nature of RTC
do
{
- firstRead = time->SubSeconds;
+ firstRead = RTC->SSR;
HAL_RTC_GetDate( &RtcHandle, date, RTC_FORMAT_BIN );
HAL_RTC_GetTime( &RtcHandle, time, RTC_FORMAT_BIN );
- }while( firstRead != time->SubSeconds );
+ }while( firstRead != RTC->SSR );
// Calculte amount of elapsed days since 01/01/2000
seconds = DIVC( ( DAYS_IN_YEAR * 3 + DAYS_IN_LEAP_YEAR ) * date->Year , 4 );
@@ -525,7 +522,7 @@ uint32_t RtcGetCalendarTime( uint16_t *milliseconds )
uint64_t calendarValue = RtcGetCalendarValue( &date, &time );
- uint32_t seconds = ( uint32_t )calendarValue >> N_PREDIV_S;
+ uint32_t seconds = ( uint32_t )( calendarValue >> N_PREDIV_S );
ticks = ( uint32_t )calendarValue & PREDIV_S;
@@ -594,10 +591,10 @@ TimerTime_t RtcTempCompensation( TimerTime_t period, float temperature )
float kDev = RTC_TEMP_DEV_COEFFICIENT;
float t = RTC_TEMP_TURNOVER;
float tDev = RTC_TEMP_DEV_TURNOVER;
- float interim = 0.0;
- float ppm = 0.0;
+ float interim = 0.0f;
+ float ppm = 0.0f;
- if( k < 0.0 )
+ if( k < 0.0f )
{
ppm = ( k - kDev );
}
@@ -609,12 +606,12 @@ TimerTime_t RtcTempCompensation( TimerTime_t period, float temperature )
ppm *= interim * interim;
// Calculate the drift in time
- interim = ( ( float ) period * ppm ) / 1e6;
+ interim = ( ( float ) period * ppm ) / 1000000.0f;
// Calculate the resulting time period
interim += period;
interim = floor( interim );
- if( interim < 0.0 )
+ if( interim < 0.0f )
{
interim = ( float )period;
}
diff --git a/board/RHF76_STM32L072CBxx_Lora/Src/sx1276-board.c b/board/RHF76_STM32L072CBxx_Lora/Src/sx1276-board.c
index c365c33b..1e24096c 100644
--- a/board/RHF76_STM32L072CBxx_Lora/Src/sx1276-board.c
+++ b/board/RHF76_STM32L072CBxx_Lora/Src/sx1276-board.c
@@ -140,12 +140,24 @@ void SX1276IoDeInit( void )
GpioInit( &SX1276.DIO5, RADIO_DIO_5, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
}
+void SX1276IoDbgInit( void )
+{
+#if defined( USE_RADIO_DEBUG )
+ GpioInit( &DbgPinTx, RADIO_DBG_PIN_TX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
+ GpioInit( &DbgPinRx, RADIO_DBG_PIN_RX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
+#endif
+}
+
+void SX1276IoTcxoInit( void )
+{
+ GpioInit( &TcxoPower, RADIO_TCXO_POWER, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
+}
/*!
* \brief Enables/disables the TCXO if available on board design.
*
* \param [IN] state TCXO enabled when true and disabled when false.
*/
-static void SX1276SetBoardTcxo( uint8_t state )
+void SX1276SetBoardTcxo( uint8_t state )
{
if( state == true )
{
diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.c b/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.c
index 1140e924..5d214ac8 100644
--- a/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.c
+++ b/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.c
@@ -22,6 +22,7 @@ uint8_t NwkSEncKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0
uint8_t AppSKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
#endif
+
bool NextTx = true;
uint8_t IsTxConfirmed = false;
TimerEvent_t TxNextPacketTimer;
@@ -318,8 +319,6 @@ void LoRa_JoinNetwork(uint8_t jointype)
{
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_JOIN;
- mlmeReq.Req.Join.DevEui = DevEui;
- mlmeReq.Req.Join.JoinEui = JoinEui;
mlmeReq.Req.Join.Datarate = LORAWAN_DEFAULT_DATARATE;
LoRaMacMlmeRequest( &mlmeReq );
}
diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.h b/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.h
index 5d2cb283..f3db6d4a 100644
--- a/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.h
+++ b/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.h
@@ -9,6 +9,47 @@
#include "LoRaMac.h"
#include "NvmCtxMgmt.h"
+#define ACTIVE_REGION LORAMAC_REGION_CN470
+
+#ifndef ACTIVE_REGION
+
+#warning "No active region defined, LORAMAC_REGION_EU868 will be used as default."
+
+#define ACTIVE_REGION LORAMAC_REGION_EU868
+
+#endif
+
+/*!
+ * Defines the application data transmission duty cycle. 5s, value in [ms].
+ */
+#define APP_TX_DUTYCYCLE 5000
+
+/*!
+ * Defines a random delay for application data transmission duty cycle. 1s,
+ * value in [ms].
+ */
+#define APP_TX_DUTYCYCLE_RND 1000
+
+/*!
+ * Default datarate
+ */
+#define LORAWAN_DEFAULT_DATARATE DR_0
+
+/*!
+ * LoRaWAN confirmed messages
+ */
+#define LORAWAN_CONFIRMED_MSG_ON false
+
+/*!
+ * LoRaWAN Adaptive Data Rate
+ *
+ * \remark Please note that when ADR is enabled the end-device should be static
+ */
+#define LORAWAN_ADR_ON 1
+
+#define LORAWAN_DUTYCYCLE_ON false
+
+
#define OVER_THE_AIR_ACTIVATION 0
#define ABP_ACTIVATION_LRWAN_VERSION_V10x 0x01000300 // 1.0.3.0
@@ -19,16 +60,13 @@
#define LORAWAN_NETWORK_ID ( uint32_t )0
-#define ACTIVE_REGION LORAMAC_REGION_CN470
#define LORAWAN_APP_DATA_MAX_SIZE 64
-#define LORAWAN_DEFAULT_DATARATE DR_0
-#define LORAWAN_ADR_ON 1
-#define LORAWAN_DUTYCYCLE_ON false
+
extern bool NextTx;
diff --git a/components/connectivity/LoraWAN/boards_common/adc-board.h b/components/connectivity/LoraWAN/boards_common/adc-board.h
index ecc439a0..a142db1b 100644
--- a/components/connectivity/LoraWAN/boards_common/adc-board.h
+++ b/components/connectivity/LoraWAN/boards_common/adc-board.h
@@ -23,6 +23,11 @@
#ifndef __ADC_BOARD_H__
#define __ADC_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "adc.h"
/*!
@@ -46,4 +51,8 @@ void AdcMcuConfig( void );
*/
uint16_t AdcMcuReadChannel( Adc_t *obj, uint32_t channel );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __ADC_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/board.h b/components/connectivity/LoraWAN/boards_common/board.h
index de9cb520..e038993c 100644
--- a/components/connectivity/LoraWAN/boards_common/board.h
+++ b/components/connectivity/LoraWAN/boards_common/board.h
@@ -23,6 +23,11 @@
#ifndef __BOARD_H__
#define __BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include "utilities.h"
/*!
@@ -113,4 +118,8 @@ uint8_t GetBoardPowerSource( void );
*/
Version_t BoardGetVersion( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/delay-board.h b/components/connectivity/LoraWAN/boards_common/delay-board.h
index 8ac41ef5..d18794ea 100644
--- a/components/connectivity/LoraWAN/boards_common/delay-board.h
+++ b/components/connectivity/LoraWAN/boards_common/delay-board.h
@@ -25,6 +25,11 @@
#ifndef __DELAY_BOARD_H__
#define __DELAY_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
/*!
@@ -34,4 +39,8 @@
*/
void DelayMsMcu( uint32_t ms );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __DELAY_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/display-board.h b/components/connectivity/LoraWAN/boards_common/display-board.h
index a661a228..bced496f 100644
--- a/components/connectivity/LoraWAN/boards_common/display-board.h
+++ b/components/connectivity/LoraWAN/boards_common/display-board.h
@@ -28,6 +28,11 @@
#ifndef __DISPLAY_BOARD_H__
#define __DISPLAY_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
@@ -290,4 +295,8 @@ void DisplayPrint( const char *string );
*/
void DisplayPrintf( const char *format, ... );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __DISPLAY_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/eeprom-board.h b/components/connectivity/LoraWAN/boards_common/eeprom-board.h
index ce387078..673c866e 100644
--- a/components/connectivity/LoraWAN/boards_common/eeprom-board.h
+++ b/components/connectivity/LoraWAN/boards_common/eeprom-board.h
@@ -23,6 +23,11 @@
#ifndef __EEPROM_BOARD_H__
#define __EEPROM_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
/*!
@@ -31,7 +36,7 @@
* \param[IN] addr EEPROM address to write to
* \param[IN] buffer Pointer to the buffer to be written.
* \param[IN] size Size of the buffer to be written.
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t EepromMcuWriteBuffer( uint16_t addr, uint8_t *buffer, uint16_t size );
@@ -41,7 +46,7 @@ uint8_t EepromMcuWriteBuffer( uint16_t addr, uint8_t *buffer, uint16_t size );
* \param[IN] addr EEPROM address to read from
* \param[OUT] buffer Pointer to the buffer to be written with read data.
* \param[IN] size Size of the buffer to be read.
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t EepromMcuReadBuffer( uint16_t addr, uint8_t *buffer, uint16_t size );
@@ -63,4 +68,8 @@ void EepromMcuSetDeviceAddr( uint8_t addr );
*/
uint8_t EepromMcuGetDeviceAddr( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __EEPROM_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/gpio-board.h b/components/connectivity/LoraWAN/boards_common/gpio-board.h
index 84cb239d..b81e945a 100644
--- a/components/connectivity/LoraWAN/boards_common/gpio-board.h
+++ b/components/connectivity/LoraWAN/boards_common/gpio-board.h
@@ -23,6 +23,11 @@
#ifndef __GPIO_BOARD_H__
#define __GPIO_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "gpio.h"
/*!
@@ -89,4 +94,8 @@ void GpioMcuToggle( Gpio_t *obj );
*/
uint32_t GpioMcuRead( Gpio_t *obj );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __GPIO_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/gps-board.h b/components/connectivity/LoraWAN/boards_common/gps-board.h
index a76319cb..090dc3f4 100644
--- a/components/connectivity/LoraWAN/boards_common/gps-board.h
+++ b/components/connectivity/LoraWAN/boards_common/gps-board.h
@@ -23,6 +23,11 @@
#ifndef __GPS_BOARD_H__
#define __GPS_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "uart.h"
/*!
@@ -71,4 +76,8 @@ void GpsMcuProcess( void );
*/
void GpsMcuIrqNotify( UartNotifyId_t id );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __GPS_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/i2c-board.h b/components/connectivity/LoraWAN/boards_common/i2c-board.h
index 6f2abfaf..c8338d16 100644
--- a/components/connectivity/LoraWAN/boards_common/i2c-board.h
+++ b/components/connectivity/LoraWAN/boards_common/i2c-board.h
@@ -23,6 +23,11 @@
#ifndef __I2C_BOARD_H__
#define __I2C_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include "i2c.h"
@@ -137,4 +142,8 @@ uint8_t I2cMcuWaitStandbyState( I2c_t *obj, uint8_t deviceAddr );
*/
void I2cSetAddrSize( I2c_t *obj, I2cAddrSize addrSize );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __I2C_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/lpm-board.h b/components/connectivity/LoraWAN/boards_common/lpm-board.h
index b7eeef05..1d2e9602 100644
--- a/components/connectivity/LoraWAN/boards_common/lpm-board.h
+++ b/components/connectivity/LoraWAN/boards_common/lpm-board.h
@@ -25,8 +25,10 @@
#ifndef __LPM_BOARD_H__
#define __LPM_BOARD_H__
+
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "board-config.h"
diff --git a/components/connectivity/LoraWAN/boards_common/lr1110-board.h b/components/connectivity/LoraWAN/boards_common/lr1110-board.h
new file mode 100644
index 00000000..67f7c037
--- /dev/null
+++ b/components/connectivity/LoraWAN/boards_common/lr1110-board.h
@@ -0,0 +1,74 @@
+/*!
+ * \file lr1110-board.h
+ *
+ * \brief Target board LR1110 driver implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2013-2017 Semtech
+ *
+ * \endcode
+ *
+ * \author Miguel Luis ( Semtech )
+ *
+ * \author Gregory Cristian ( Semtech )
+ */
+#ifndef __LR1110_BOARD_H__
+#define __LR1110_BOARD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+#include "lr1110.h"
+
+/*!
+ * \brief Initializes the radio I/Os pins interface
+ */
+void lr1110_board_init_io( const void* context );
+
+/*!
+ * \brief De-initializes the radio I/Os pins interface.
+ *
+ * \remark Useful when going in MCU low power modes
+ */
+void lr1110_board_deinit_io( const void* context );
+
+/*!
+ * \brief Initializes the radio debug pins.
+ */
+void lr1110_board_init_dbg_io( const void* context );
+
+/*!
+ * \brief Sets the radio output power.
+ *
+ * \param [IN] power Sets the RF output power
+ */
+void lr1110_board_set_rf_tx_power( const void* context, int8_t power );
+
+/*!
+ * \brief Gets the Defines the time required for the TCXO to wakeup [ms].
+ *
+ * \retval time Board TCXO wakeup time in ms.
+ */
+uint32_t lr1110_board_get_tcxo_wakeup_time( const void* context );
+
+/*!
+ * \brief Initializes the radio driver
+ */
+void lr1110_board_init( const void* context, lr1110_dio_irq_handler dio_irq );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LR1110_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/pinName-board.h b/components/connectivity/LoraWAN/boards_common/pinName-board.h
index f2cf433a..91fc9886 100644
--- a/components/connectivity/LoraWAN/boards_common/pinName-board.h
+++ b/components/connectivity/LoraWAN/boards_common/pinName-board.h
@@ -23,6 +23,11 @@
#ifndef __PIN_NAME_BOARD_H__
#define __PIN_NAME_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
/*!
* STM32 Pin Names
*/
@@ -35,4 +40,8 @@
PF_0, PF_1, PF_2, PF_3, PF_4, PF_5, PF_6, PF_7, PF_8, PF_9, PF_10, PF_11, PF_12, PF_13, PF_14, PF_15, \
PH_0, PH_1, PH_2, PH_3, PH_4, PH_5, PH_6, PH_7, PH_8, PH_9, PH_10, PH_11, PH_12, PH_13, PH_14, PH_15
+#ifdef __cplusplus
+}
+#endif
+
#endif // __PIN_NAME_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/pinName-ioe.h b/components/connectivity/LoraWAN/boards_common/pinName-ioe.h
index b5847ef4..c84dd6e6 100644
--- a/components/connectivity/LoraWAN/boards_common/pinName-ioe.h
+++ b/components/connectivity/LoraWAN/boards_common/pinName-ioe.h
@@ -23,8 +23,18 @@
#ifndef __PIN_NAME_IOE_H__
#define __PIN_NAME_IOE_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
// SX1509 Pin Names
#define IOE_PINS \
IOE_0, IOE_1, IOE_2, IOE_3, IOE_4, IOE_5, IOE_6, IOE_7, \
IOE_8, IOE_9, IOE_10, IOE_11, IOE_12, IOE_13, IOE_14, IOE_15
+
+#ifdef __cplusplus
+}
+#endif
+
#endif // __PIN_NAME_IOE_H__
diff --git a/components/connectivity/LoraWAN/boards_common/rtc-board.h b/components/connectivity/LoraWAN/boards_common/rtc-board.h
index 73de8afd..8a6581bf 100644
--- a/components/connectivity/LoraWAN/boards_common/rtc-board.h
+++ b/components/connectivity/LoraWAN/boards_common/rtc-board.h
@@ -23,6 +23,11 @@
#ifndef __RTC_BOARD_H__
#define __RTC_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include "timer.h"
@@ -30,22 +35,22 @@
/*!
* \brief Temperature coefficient of the clock source
*/
-#define RTC_TEMP_COEFFICIENT ( -0.035 )
+#define RTC_TEMP_COEFFICIENT ( -0.035f )
/*!
* \brief Temperature coefficient deviation of the clock source
*/
-#define RTC_TEMP_DEV_COEFFICIENT ( 0.0035 )
+#define RTC_TEMP_DEV_COEFFICIENT ( 0.0035f )
/*!
* \brief Turnover temperature of the clock source
*/
-#define RTC_TEMP_TURNOVER ( 25.0 )
+#define RTC_TEMP_TURNOVER ( 25.0f )
/*!
* \brief Turnover temperature deviation of the clock source
*/
-#define RTC_TEMP_DEV_TURNOVER ( 5.0 )
+#define RTC_TEMP_DEV_TURNOVER ( 5.0f )
/*!
* \brief Initializes the RTC timer
@@ -189,4 +194,8 @@ void RtcProcess( void );
*/
TimerTime_t RtcTempCompensation( TimerTime_t period, float temperature );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __RTC_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/spi-board.h b/components/connectivity/LoraWAN/boards_common/spi-board.h
index 550f44e2..a2ccbbfa 100644
--- a/components/connectivity/LoraWAN/boards_common/spi-board.h
+++ b/components/connectivity/LoraWAN/boards_common/spi-board.h
@@ -23,8 +23,17 @@
#ifndef __SPI_BOARD_H__
#define __SPI_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "spi.h"
// An Spi.c file has to be implmented under system directory.
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SPI_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/sx126x-board.h b/components/connectivity/LoraWAN/boards_common/sx126x-board.h
index 528f9f20..c7f81d20 100644
--- a/components/connectivity/LoraWAN/boards_common/sx126x-board.h
+++ b/components/connectivity/LoraWAN/boards_common/sx126x-board.h
@@ -23,6 +23,11 @@
#ifndef __SX126x_BOARD_H__
#define __SX126x_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include "sx126x/sx126x.h"
@@ -46,6 +51,16 @@ void SX126xIoIrqInit( DioIrqHandler dioIrq );
*/
void SX126xIoDeInit( void );
+/*!
+ * \brief Initializes the TCXO power pin.
+ */
+void SX126xIoTcxoInit( void );
+
+/*!
+ * \brief Initializes the radio debug pins.
+ */
+void SX126xIoDbgInit( void );
+
/*!
* \brief HW Reset of the radio
*/
@@ -76,8 +91,10 @@ void SX126xWriteCommand( RadioCommands_t opcode, uint8_t *buffer, uint16_t size
* \param [in] opcode Opcode of the command
* \param [out] buffer Buffer holding data from the radio
* \param [in] size Size of the buffer
+ *
+ * \retval status Return command radio status
*/
-void SX126xReadCommand( RadioCommands_t opcode, uint8_t *buffer, uint16_t size );
+uint8_t SX126xReadCommand( RadioCommands_t opcode, uint8_t *buffer, uint16_t size );
/*!
* \brief Write a single byte of data to the radio memory
@@ -156,4 +173,8 @@ void SX126xDbgPinRxWrite( uint8_t state );
*/
extern SX126x_t SX126x;
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SX126x_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/sx1272-board.h b/components/connectivity/LoraWAN/boards_common/sx1272-board.h
index 83a8cf3c..0e30383f 100644
--- a/components/connectivity/LoraWAN/boards_common/sx1272-board.h
+++ b/components/connectivity/LoraWAN/boards_common/sx1272-board.h
@@ -23,6 +23,11 @@
#ifndef __SX1272_BOARD_H__
#define __SX1272_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include "sx1272/sx1272.h"
@@ -72,6 +77,16 @@ void SX1272IoIrqInit( DioIrqHandler **irqHandlers );
*/
void SX1272IoDeInit( void );
+/*!
+ * \brief Initializes the TCXO power pin.
+ */
+void SX1272IoTcxoInit( void );
+
+/*!
+ * \brief Initializes the radio debug pins.
+ */
+void SX1272IoDbgInit( void );
+
/*!
* \brief Resets the radio
*/
@@ -120,6 +135,13 @@ void SX1272SetAntSw( uint8_t opMode );
*/
bool SX1272CheckRfFrequency( uint32_t frequency );
+/*!
+ * \brief Enables/disables the TCXO if available on board design.
+ *
+ * \param [IN] state TCXO enabled when true and disabled when false.
+ */
+void SX1272SetBoardTcxo( uint8_t state );
+
/*!
* \brief Gets the Defines the time required for the TCXO to wakeup [ms].
*
@@ -146,4 +168,8 @@ void SX1272DbgPinRxWrite( uint8_t state );
*/
extern SX1272_t SX1272;
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SX1272_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/sx1276-board.h b/components/connectivity/LoraWAN/boards_common/sx1276-board.h
index 15544cdf..23867562 100644
--- a/components/connectivity/LoraWAN/boards_common/sx1276-board.h
+++ b/components/connectivity/LoraWAN/boards_common/sx1276-board.h
@@ -23,6 +23,11 @@
#ifndef __SX1276_BOARD_H__
#define __SX1276_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include "sx1276/sx1276.h"
@@ -73,6 +78,16 @@ void SX1276IoIrqInit( DioIrqHandler **irqHandlers );
*/
void SX1276IoDeInit( void );
+/*!
+ * \brief Initializes the TCXO power pin.
+ */
+void SX1276IoTcxoInit( void );
+
+/*!
+ * \brief Initializes the radio debug pins.
+ */
+void SX1276IoDbgInit( void );
+
/*!
* \brief Resets the radio
*/
@@ -121,6 +136,13 @@ void SX1276SetAntSw( uint8_t opMode );
*/
bool SX1276CheckRfFrequency( uint32_t frequency );
+/*!
+ * \brief Enables/disables the TCXO if available on board design.
+ *
+ * \param [IN] state TCXO enabled when true and disabled when false.
+ */
+void SX1276SetBoardTcxo( uint8_t state );
+
/*!
* \brief Gets the Defines the time required for the TCXO to wakeup [ms].
*
@@ -147,4 +169,8 @@ void SX1276DbgPinRxWrite( uint8_t state );
*/
extern SX1276_t SX1276;
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SX1276_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/uart-board.h b/components/connectivity/LoraWAN/boards_common/uart-board.h
index 81d5b04a..06e12818 100644
--- a/components/connectivity/LoraWAN/boards_common/uart-board.h
+++ b/components/connectivity/LoraWAN/boards_common/uart-board.h
@@ -23,6 +23,11 @@
#ifndef __UART_BOARD_H__
#define __UART_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include "uart.h"
@@ -96,4 +101,8 @@ uint8_t UartMcuGetChar( Uart_t *obj, uint8_t *data );
*/
uint8_t UartMcuGetBuffer( Uart_t *obj, uint8_t *buffer, uint16_t size, uint16_t *nbReadBytes );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __UART_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/uart-usb-board.h b/components/connectivity/LoraWAN/boards_common/uart-usb-board.h
index e9b81506..60d211d8 100644
--- a/components/connectivity/LoraWAN/boards_common/uart-usb-board.h
+++ b/components/connectivity/LoraWAN/boards_common/uart-usb-board.h
@@ -23,6 +23,11 @@
#ifndef __UART_USB_BOARD_H__
#define __UART_USB_BOARD_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include "uart.h"
@@ -90,4 +95,8 @@ uint8_t UartUsbPutChar( Uart_t *obj, uint8_t data );
*/
uint8_t UartUsbGetChar( Uart_t *obj, uint8_t *data );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __UART_USB_BOARD_H__
diff --git a/components/connectivity/LoraWAN/boards_common/utilities.h b/components/connectivity/LoraWAN/boards_common/utilities.h
index 87f20fbc..a3999a53 100644
--- a/components/connectivity/LoraWAN/boards_common/utilities.h
+++ b/components/connectivity/LoraWAN/boards_common/utilities.h
@@ -23,6 +23,11 @@
#ifndef __UTILITIES_H__
#define __UTILITIES_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
/*!
@@ -43,7 +48,9 @@
* \param [IN] b 2nd value
* \retval minValue Minimum value
*/
+#ifndef MIN
#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
+#endif
/*!
* \brief Returns the maximum value between a and b
@@ -52,7 +59,9 @@
* \param [IN] b 2nd value
* \retval maxValue Maximum value
*/
+#ifndef MAX
#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
+#endif
/*!
* \brief Returns 2 raised to the power of n
@@ -69,8 +78,8 @@ typedef union Version_u
{
struct Version_s
{
- uint8_t Rfu;
uint8_t Revision;
+ uint8_t Patch;
uint8_t Minor;
uint8_t Major;
}Fields;
@@ -162,4 +171,8 @@ void BoardCriticalSectionBegin( uint32_t *mask );
*/
void BoardCriticalSectionEnd( uint32_t *mask );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __UTILITIES_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMac.c b/components/connectivity/LoraWAN/mac/LoRaMac.c
index 26e83040..3544ae20 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMac.c
+++ b/components/connectivity/LoraWAN/mac/LoRaMac.c
@@ -41,12 +41,19 @@
#include "LoRaMacHeaderTypes.h"
#include "LoRaMacMessageTypes.h"
#include "LoRaMacParser.h"
-#include "LoRaMacFCntHandler.h"
#include "LoRaMacCommands.h"
#include "LoRaMacAdr.h"
+#include "LoRaMacSerializer.h"
#include "LoRaMac.h"
+#ifndef LORAMAC_VERSION
+/*!
+ * LORaWAN version definition.
+ */
+#define LORAMAC_VERSION 0x01000300
+#endif
+
/*!
* Maximum PHY layer payload size
*/
@@ -92,15 +99,6 @@ enum eLoRaMacState
LORAMAC_RX_ABORT = 0x00000080,
};
-/*
- * LoRa Mac boolean type
- */
-typedef enum eLoRaMacBoolean
-{
- LORAMAC_FALSE = 0,
- LORAMAC_TRUE = !LORAMAC_FALSE
-}LoRaMacBoolean_t;
-
/*
* Request permission state
*/
@@ -149,23 +147,11 @@ typedef struct sLoRaMacNvmCtx
* Counts the number of missed ADR acknowledgements
*/
uint32_t AdrAckCounter;
- /*
- * Limit of uplinks without any donwlink response before the ADRACKReq bit will be set.
- */
- uint16_t AdrAckLimit;
- /*
- * Limit of uplinks without any donwlink response after a the first frame with set ADRACKReq bit
- * before the trying to regain the connectivity.
- */
- uint16_t AdrAckDelay;
+
/*
* LoRaMac parameters
*/
LoRaMacParams_t MacParams;
- /*
- * Uplink messages repetitions counter
- */
- uint8_t ChannelsNbTransCounter;
/*
* Maximum duty cycle
* \remark Possibility to shutdown the device.
@@ -175,43 +161,10 @@ typedef struct sLoRaMacNvmCtx
* Enables/Disables duty cycle management (Test only)
*/
bool DutyCycleOn;
- /*
- * Current channel index
- */
- uint8_t Channel;
- /*
- * Current channel index
- */
- uint8_t LastTxChannel;
- /*
- * Holds the current rx window slot
- */
- bool RepeaterSupport;
/*
* Buffer containing the MAC layer commands
*/
uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH];
- /*
- * Buffer containing the MAC layer commands which must be repeated
- */
- uint8_t MacCommandsBufferToRepeat[LORA_MAC_COMMAND_MAX_LENGTH];
- /*
- * Number of trials to get a frame acknowledged
- */
- uint8_t AckTimeoutRetries;
- /*
- * Number of trials to get a frame acknowledged
- */
- uint8_t AckTimeoutRetriesCounter;
- /*
- * Indicates if the AckTimeout timer has expired or not
- */
- bool AckTimeoutRetry;
- /*
- * If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates
- * if the nodes needs to manage the server acknowledgement.
- */
- bool NodeAckRequested;
/*
* If the server has sent a FRAME_TYPE_DATA_CONFIRMED_DOWN this variable indicates
* if the ACK bit must be set for the next transmission
@@ -221,6 +174,17 @@ typedef struct sLoRaMacNvmCtx
* Aggregated duty cycle management
*/
uint16_t AggregatedDCycle;
+ /*
+ * Aggregated duty cycle management
+ */
+ TimerTime_t LastTxDoneTime;
+ TimerTime_t AggregatedTimeOff;
+ /*
+ * Stores the time at LoRaMac initialization.
+ *
+ * \remark Used for the BACKOFF_DC computation.
+ */
+ SysTime_t InitializationTime;
/*
* Current LoRaWAN Version
*/
@@ -237,14 +201,6 @@ typedef struct sLoRaMacNvmCtx
typedef struct sLoRaMacCtx
{
- /*
- * Device IEEE EUI
- */
- uint8_t* DevEui;
- /*
- * Join IEEE EUI
- */
- uint8_t* JoinEui;
/*
* Length of packet in PktBuffer
*/
@@ -269,17 +225,6 @@ typedef struct sLoRaMacCtx
* Buffer containing the upper layer data.
*/
uint8_t RxPayload[LORAMAC_PHY_MAXPAYLOAD];
- /*
- * Aggregated duty cycle management
- */
- TimerTime_t AggregatedLastTxDoneTime;
- TimerTime_t AggregatedTimeOff;
- /*
- * Stores the time at LoRaMac initialization.
- *
- * \remark Used for the BACKOFF_DC computation.
- */
- SysTime_t InitializationTime;
SysTime_t LastTxSysTime;
/*
* LoRaMac internal state
@@ -318,10 +263,45 @@ typedef struct sLoRaMacCtx
*/
RxConfigParams_t RxWindow1Config;
RxConfigParams_t RxWindow2Config;
+ RxConfigParams_t RxWindowCConfig;
+ /*
+ * Limit of uplinks without any donwlink response before the ADRACKReq bit will be set.
+ */
+ uint16_t AdrAckLimit;
+ /*
+ * Limit of uplinks without any donwlink response after a the first frame with set ADRACKReq bit
+ * before the trying to regain the connectivity.
+ */
+ uint16_t AdrAckDelay;
/*
* Acknowledge timeout timer. Used for packet retransmissions.
*/
TimerEvent_t AckTimeoutTimer;
+ /*
+ * Uplink messages repetitions counter
+ */
+ uint8_t ChannelsNbTransCounter;
+ /*
+ * Number of trials to get a frame acknowledged
+ */
+ uint8_t AckTimeoutRetries;
+ /*
+ * Number of trials to get a frame acknowledged
+ */
+ uint8_t AckTimeoutRetriesCounter;
+ /*
+ * Indicates if the AckTimeout timer has expired or not
+ */
+ bool AckTimeoutRetry;
+ /*
+ * If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates
+ * if the nodes needs to manage the server acknowledgement.
+ */
+ bool NodeAckRequested;
+ /*
+ * Current channel index
+ */
+ uint8_t Channel;
/*
* Last transmission time on air
*/
@@ -351,13 +331,17 @@ typedef struct sLoRaMacCtx
*/
LoRaMacFlags_t MacFlags;
/*
- * Data structure inidicating if a request is allowed or not.
+ * Data structure indicating if a request is allowed or not.
*/
LoRaMacRequestHandling_t AllowRequests;
/*
* Non-volatile module context structure
*/
LoRaMacNvmCtx_t* NvmCtx;
+ /*
+ * Duty cycle wait time
+ */
+ TimerTime_t DutyCycleWaitTime;
}LoRaMacCtx_t;
/*
@@ -444,35 +428,33 @@ static void OnRxWindow1TimerEvent( void* context );
*/
static void OnRxWindow2TimerEvent( void* context );
-/*!
- * \brief Check if the OnAckTimeoutTimer has do be disabled. If so, the
- * function disables it.
- *
- * \param [IN] nodeAckRequested Set to true, if the node has requested an ACK
- * \param [IN] class The device class
- * \param [IN] ackReceived Set to true, if the node has received an ACK
- */
-static void CheckToDisableAckTimeout( bool nodeAckRequested, DeviceClass_t devClass, bool ackReceived );
-
/*!
* \brief Function executed on AckTimeout timer event
*/
static void OnAckTimeoutTimerEvent( void* context );
-/*!
- * \brief Initializes and opens the reception window
- *
- * \param [IN] rxContinuous Set to true, if the RX is in continuous mode
- * \param [IN] maxRxWindow Maximum RX window timeout
- */
-static void RxWindowSetup( bool rxContinuous, uint32_t maxRxWindow );
-
/*!
* \brief Configures the events to trigger an MLME-Indication with
* a MLME type of MLME_SCHEDULE_UPLINK.
*/
static void SetMlmeScheduleUplinkIndication( void );
+/*!
+ * Computes next 32 bit downlink counter value and determines the frame counter ID.
+ *
+ * \param[IN] addrID - Address identifier
+ * \param[IN] fType - Frame type
+ * \param[IN] macMsg - Data message object, holding the current 16 bit transmitted frame counter
+ * \param[IN] lrWanVersion - LoRaWAN version
+ * \param[IN] maxFCntGap - Maximum allowed frame counter difference (only for 1.0.X necessary)
+ * \param[OUT] fCntID - Frame counter identifier
+ * \param[OUT] currentDown - Current downlink counter value
+ *
+ * \retval - Status of the operation
+ */
+static LoRaMacCryptoStatus_t GetFCntDown( AddressIdentifier_t addrID, FType_t fType, LoRaMacMessageData_t* macMsg, Version_t lrWanVersion,
+ uint16_t maxFCntGap, FCntIdentifier_t* fCntID, uint32_t* currentDown );
+
/*!
* \brief Switches the device class
*
@@ -569,11 +551,9 @@ static LoRaMacStatus_t ScheduleTx( bool allowDelayedTx );
static LoRaMacStatus_t SecureFrame( uint8_t txDr, uint8_t txCh );
/*
- * \brief Calculates the back-off time for the band of a channel.
- *
- * \param [IN] channel The last Tx channel index
+ * \brief Calculates the aggregated back off time.
*/
-static void CalculateBackOff( uint8_t channel );
+static void CalculateBackOff( void );
/*
* \brief Function to remove pending MAC commands
@@ -623,10 +603,18 @@ LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint
static void ResetMacParameters( void );
/*!
- * \brief Opens up a continuous RX 2 window. This is used for
+ * \brief Initializes and opens the reception window
+ *
+ * \param [IN] rxTimer Window timer to be topped.
+ * \param [IN] rxConfig Window parameters to be setup
+ */
+static void RxWindowSetup( TimerEvent_t* rxTimer, RxConfigParams_t* rxConfig );
+
+/*!
+ * \brief Opens up a continuous RX C window. This is used for
* class c devices.
*/
-static void OpenContinuousRx2Window( void );
+static void OpenContinuousRxCWindow( void );
/*!
* \brief Returns a pointer to the internal contexts structure.
@@ -737,11 +725,6 @@ static void EventClassBNvmCtxChanged( void );
*/
static void EventConfirmQueueNvmCtxChanged( void );
-/*!
- * \brief FCnt Handler module nvm context has been changed
- */
-static void EventFCntHandlerNvmCtxChanged( void );
-
/*!
* \brief Verifies if a request is pending currently
*
@@ -757,17 +740,10 @@ static uint8_t IsRequestPending( void );
static void LoRaMacEnableRequests( LoRaMacRequestHandling_t requestState );
/*!
- * \brief This function verifies if a RX abort occured
+ * \brief This function verifies if a RX abort occurred
*/
static void LoRaMacCheckForRxAbort( void );
-/*!
- * \brief This function verifies if a TX timeout occured
- *
- *\retval 1: TX timeout, 0: no TX timeout
- */
-static uint8_t LoRaMacCheckForTxTimeout( void );
-
/*!
* \brief This function verifies if a beacon acquisition MLME
* request was pending
@@ -779,7 +755,7 @@ static uint8_t LoRaMacCheckForBeaconAcquisition( void );
/*!
* \brief This function handles join request
*/
-static void LoRaMacHandleJoinRequest( void );
+static void LoRaMacHandleMlmeRequest( void );
/*!
* \brief This function handles mcps request
@@ -875,6 +851,18 @@ static void OnRadioRxTimeout( void )
}
}
+static void UpdateRxSlotIdleState( void )
+{
+ if( MacCtx.NvmCtx->DeviceClass != CLASS_C )
+ {
+ MacCtx.RxSlot = RX_SLOT_NONE;
+ }
+ else
+ {
+ MacCtx.RxSlot = RX_SLOT_WIN_CLASS_C;
+ }
+}
+
static void ProcessRadioTxDone( void )
{
GetPhyParams_t getPhy;
@@ -885,20 +873,13 @@ static void ProcessRadioTxDone( void )
{
Radio.Sleep( );
}
- else
- {
- OpenContinuousRx2Window( );
- }
-
// Setup timers
TimerSetValue( &MacCtx.RxWindowTimer1, MacCtx.RxWindow1Delay );
TimerStart( &MacCtx.RxWindowTimer1 );
- if( MacCtx.NvmCtx->DeviceClass != CLASS_C )
- {
- TimerSetValue( &MacCtx.RxWindowTimer2, MacCtx.RxWindow2Delay );
- TimerStart( &MacCtx.RxWindowTimer2 );
- }
- if( ( MacCtx.NvmCtx->DeviceClass == CLASS_C ) || ( MacCtx.NvmCtx->NodeAckRequested == true ) )
+ TimerSetValue( &MacCtx.RxWindowTimer2, MacCtx.RxWindow2Delay );
+ TimerStart( &MacCtx.RxWindowTimer2 );
+
+ if( ( MacCtx.NvmCtx->DeviceClass == CLASS_C ) || ( MacCtx.NodeAckRequested == true ) )
{
getPhy.Attribute = PHY_ACK_TIMEOUT;
phyParam = RegionGetPhyParam( MacCtx.NvmCtx->Region, &getPhy );
@@ -906,27 +887,25 @@ static void ProcessRadioTxDone( void )
TimerStart( &MacCtx.AckTimeoutTimer );
}
- // Store last Tx channel
- MacCtx.NvmCtx->LastTxChannel = MacCtx.NvmCtx->Channel;
+ // Update Aggregated last tx done time
+ MacCtx.NvmCtx->LastTxDoneTime = TxDoneParams.CurTime;
+
// Update last tx done time for the current channel
- txDone.Channel = MacCtx.NvmCtx->Channel;
+ txDone.Channel = MacCtx.Channel;
+ txDone.LastTxDoneTime = TxDoneParams.CurTime;
+ txDone.ElapsedTimeSinceStartUp = SysTimeSub( SysTimeGetMcuTime( ), MacCtx.NvmCtx->InitializationTime );
+ txDone.LastTxAirTime = MacCtx.TxTimeOnAir;
+ txDone.Joined = true;
if( MacCtx.NvmCtx->NetworkActivation == ACTIVATION_TYPE_NONE )
{
txDone.Joined = false;
}
- else
- {
- txDone.Joined = true;
- }
- txDone.LastTxDoneTime = TxDoneParams.CurTime;
- RegionSetBandTxDone( MacCtx.NvmCtx->Region, &txDone );
- // Update Aggregated last tx done time
- MacCtx.AggregatedLastTxDoneTime = TxDoneParams.CurTime;
- if( MacCtx.NvmCtx->NodeAckRequested == false )
+ RegionSetBandTxDone( MacCtx.NvmCtx->Region, &txDone );
+
+ if( MacCtx.NodeAckRequested == false )
{
MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
- MacCtx.NvmCtx->ChannelsNbTransCounter++;
}
}
@@ -934,13 +913,15 @@ static void PrepareRxDoneAbort( void )
{
MacCtx.MacState |= LORAMAC_RX_ABORT;
- if( MacCtx.NvmCtx->NodeAckRequested )
+ if( MacCtx.NodeAckRequested == true )
{
OnAckTimeoutTimerEvent( NULL );
}
MacCtx.MacFlags.Bits.McpsInd = 1;
MacCtx.MacFlags.Bits.MacDone = 1;
+
+ UpdateRxSlotIdleState( );
}
static void ProcessRadioRxDone( void )
@@ -964,7 +945,6 @@ static void ProcessRadioRxDone( void )
uint32_t address = MacCtx.NvmCtx->DevAddr;
uint8_t multicast = 0;
AddressIdentifier_t addrID = UNICAST_DEV_ADDR;
- LoRaMacFCntHandlerStatus_t fCntHandlerStatus;
FCntIdentifier_t fCntID;
MacCtx.McpsConfirm.AckReceived = false;
@@ -981,6 +961,7 @@ static void ProcessRadioRxDone( void )
MacCtx.McpsIndication.DownLinkCounter = 0;
MacCtx.McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
MacCtx.McpsIndication.DevAddress = 0;
+ MacCtx.McpsIndication.DeviceTimeAnsReceived = false;
Radio.Sleep( );
TimerStop( &MacCtx.RxWindowTimer2 );
@@ -999,13 +980,13 @@ static void ProcessRadioRxDone( void )
{
LoRaMacClassBSetPingSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
LoRaMacClassBPingSlotTimerEvent( NULL );
- MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_PING_SLOT;
+ MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_B_PING_SLOT;
}
else if( LoRaMacClassBIsMulticastExpected( ) == true )
{
LoRaMacClassBSetMulticastSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
LoRaMacClassBMulticastSlotTimerEvent( NULL );
- MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_MULTICAST_SLOT;
+ MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_B_MULTICAST_SLOT;
}
}
@@ -1014,6 +995,13 @@ static void ProcessRadioRxDone( void )
switch( macHdr.Bits.MType )
{
case FRAME_TYPE_JOIN_ACCEPT:
+ // Check if the received frame size is valid
+ if( size < LORAMAC_JOIN_ACCEPT_FRAME_MIN_SIZE )
+ {
+ MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+ PrepareRxDoneAbort( );
+ return;
+ }
macMsgJoinAccept.Buffer = payload;
macMsgJoinAccept.BufSize = size;
@@ -1024,7 +1012,7 @@ static void ProcessRadioRxDone( void )
PrepareRxDoneAbort( );
return;
}
- macCryptoStatus = LoRaMacCryptoHandleJoinAccept( JOIN_REQ, MacCtx.JoinEui, &macMsgJoinAccept );
+ macCryptoStatus = LoRaMacCryptoHandleJoinAccept( JOIN_REQ, SecureElementGetJoinEui( ), &macMsgJoinAccept );
if( LORAMAC_CRYPTO_SUCCESS == macCryptoStatus )
{
@@ -1039,6 +1027,7 @@ static void ProcessRadioRxDone( void )
// DLSettings
MacCtx.NvmCtx->MacParams.Rx1DrOffset = macMsgJoinAccept.DLSettings.Bits.RX1DRoffset;
MacCtx.NvmCtx->MacParams.Rx2Channel.Datarate = macMsgJoinAccept.DLSettings.Bits.RX2DataRate;
+ MacCtx.NvmCtx->MacParams.RxCChannel.Datarate = macMsgJoinAccept.DLSettings.Bits.RX2DataRate;
// RxDelay
MacCtx.NvmCtx->MacParams.ReceiveDelay1 = macMsgJoinAccept.RxDelay;
@@ -1083,14 +1072,9 @@ static void ProcessRadioRxDone( void )
getPhy.UplinkDwellTime = MacCtx.NvmCtx->MacParams.DownlinkDwellTime;
getPhy.Datarate = MacCtx.McpsIndication.RxDatarate;
getPhy.Attribute = PHY_MAX_PAYLOAD;
-
- // Get the maximum payload length
- if( MacCtx.NvmCtx->RepeaterSupport == true )
- {
- getPhy.Attribute = PHY_MAX_PAYLOAD_REPEATER;
- }
phyParam = RegionGetPhyParam( MacCtx.NvmCtx->Region, &getPhy );
- if( MAX( 0, ( int16_t )( ( int16_t ) size - ( int16_t ) LORA_MAC_FRMPAYLOAD_OVERHEAD ) ) > ( int16_t )phyParam.Value )
+ if( ( MAX( 0, ( int16_t )( ( int16_t ) size - ( int16_t ) LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE ) ) > ( int16_t )phyParam.Value ) ||
+ ( size < LORAMAC_FRAME_PAYLOAD_MIN_SIZE ) )
{
MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
PrepareRxDoneAbort( );
@@ -1124,26 +1108,40 @@ static void ProcessRadioRxDone( void )
downLinkCounter = 0;
for( uint8_t i = 0; i < LORAMAC_MAX_MC_CTX; i++ )
{
- if( ( MacCtx.NvmCtx->MulticastChannelList[i].Address == macMsgData.FHDR.DevAddr ) &&
- ( MacCtx.NvmCtx->MulticastChannelList[i].IsEnabled == true ) )
+ if( ( MacCtx.NvmCtx->MulticastChannelList[i].ChannelParams.Address == macMsgData.FHDR.DevAddr ) &&
+ ( MacCtx.NvmCtx->MulticastChannelList[i].ChannelParams.IsEnabled == true ) )
{
multicast = 1;
- addrID = MacCtx.NvmCtx->MulticastChannelList[i].AddrID;
+ addrID = MacCtx.NvmCtx->MulticastChannelList[i].ChannelParams.GroupID;
downLinkCounter = *( MacCtx.NvmCtx->MulticastChannelList[i].DownLinkCounter );
- address = MacCtx.NvmCtx->MulticastChannelList[i].Address;
+ address = MacCtx.NvmCtx->MulticastChannelList[i].ChannelParams.Address;
+ if( MacCtx.NvmCtx->DeviceClass == CLASS_C )
+ {
+ MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_C_MULTICAST;
+ }
break;
}
}
+ // Filter messages according to multicast downlink exceptions
+ if( ( multicast == 1 ) && ( ( fType != FRAME_TYPE_D ) ||
+ ( macMsgData.FHDR.FCtrl.Bits.Ack == true ) ||
+ ( macMsgData.FHDR.FCtrl.Bits.AdrAckReq == true ) ) )
+ {
+ MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+ PrepareRxDoneAbort( );
+ return;
+ }
+
// Get maximum allowed counter difference
getPhy.Attribute = PHY_MAX_FCNT_GAP;
phyParam = RegionGetPhyParam( MacCtx.NvmCtx->Region, &getPhy );
// Get downlink frame counter value
- fCntHandlerStatus = LoRaMacGetFCntDown( addrID, fType, &macMsgData, MacCtx.NvmCtx->Version, phyParam.Value, &fCntID, &downLinkCounter );
- if( fCntHandlerStatus != LORAMAC_FCNT_HANDLER_SUCCESS )
+ macCryptoStatus = GetFCntDown( addrID, fType, &macMsgData, MacCtx.NvmCtx->Version, phyParam.Value, &fCntID, &downLinkCounter );
+ if( macCryptoStatus != LORAMAC_CRYPTO_SUCCESS )
{
- if( fCntHandlerStatus == LORAMAC_FCNT_HANDLER_CHECK_FAIL )
+ if( macCryptoStatus == LORAMAC_CRYPTO_FAIL_FCNT_DUPLICATED )
{
// Catch the case of repeated downlink frame counter
MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
@@ -1152,7 +1150,7 @@ static void ProcessRadioRxDone( void )
MacCtx.NvmCtx->SrvAckRequested = true;
}
}
- else if( fCntHandlerStatus == LORAMAC_FCNT_HANDLER_MAX_GAP_FAIL )
+ else if( macCryptoStatus == LORAMAC_CRYPTO_FAIL_MAX_GAP_FCNT )
{
// Lost too many frames
MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS;
@@ -1174,19 +1172,13 @@ static void ProcessRadioRxDone( void )
{
// We are not the destination of this frame.
MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
-
- // Abort the reception, if we are not in RX_SLOT_WIN_CLASS_C
- if( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_CLASS_C )
- {
- PrepareRxDoneAbort( );
- }
}
else
{
// MIC calculation fail
MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
- PrepareRxDoneAbort( );
}
+ PrepareRxDoneAbort( );
return;
}
@@ -1202,7 +1194,12 @@ static void ProcessRadioRxDone( void )
MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
MacCtx.McpsConfirm.AckReceived = macMsgData.FHDR.FCtrl.Bits.Ack;
- MacCtx.NvmCtx->AdrAckCounter = 0;
+ // Reset ADR ACK Counter only, when RX1 or RX2 slot
+ if( ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_1 ) ||
+ ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_2 ) )
+ {
+ MacCtx.NvmCtx->AdrAckCounter = 0;
+ }
// MCPS Indication and ack requested handling
if( multicast == 1 )
@@ -1227,14 +1224,6 @@ static void ProcessRadioRxDone( void )
}
}
- // Update downlink counter in mac context / multicast context.
- if( LORAMAC_FCNT_HANDLER_SUCCESS != LoRaMacSetFCntDown( fCntID, downLinkCounter ) )
- {
- MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
- PrepareRxDoneAbort( );
- return;
- }
-
RemoveMacCommands( MacCtx.McpsIndication.RxSlot, macMsgData.FHDR.FCtrl, MacCtx.McpsConfirm.McpsRequest );
switch( fType )
@@ -1308,7 +1297,7 @@ static void ProcessRadioRxDone( void )
break;
case FRAME_TYPE_PROPRIETARY:
- memcpy1( MacCtx.RxPayload, &payload[pktHeaderLen], size );
+ memcpy1( MacCtx.RxPayload, &payload[pktHeaderLen], size - pktHeaderLen );
MacCtx.McpsIndication.McpsIndication = MCPS_PROPRIETARY;
MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
@@ -1324,12 +1313,23 @@ static void ProcessRadioRxDone( void )
}
// Verify if we need to disable the AckTimeoutTimer
- CheckToDisableAckTimeout( MacCtx.NvmCtx->NodeAckRequested, MacCtx.NvmCtx->DeviceClass, MacCtx.McpsConfirm.AckReceived );
-
- if( TimerIsStarted( &MacCtx.AckTimeoutTimer ) == false )
- { // Procedure is completed when the AckTimeoutTimer is not running anymore
- MacCtx.MacFlags.Bits.MacDone = 1;
+ if( MacCtx.NodeAckRequested == true )
+ {
+ if( MacCtx.McpsConfirm.AckReceived == true )
+ {
+ OnAckTimeoutTimerEvent( NULL );
+ }
}
+ else
+ {
+ if( MacCtx.NvmCtx->DeviceClass == CLASS_C )
+ {
+ OnAckTimeoutTimerEvent( NULL );
+ }
+ }
+ MacCtx.MacFlags.Bits.MacDone = 1;
+
+ UpdateRxSlotIdleState( );
}
static void ProcessRadioTxTimeout( void )
@@ -1338,13 +1338,14 @@ static void ProcessRadioTxTimeout( void )
{
Radio.Sleep( );
}
- else
- {
- OpenContinuousRx2Window( );
- }
+ UpdateRxSlotIdleState( );
MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
LoRaMacConfirmQueueSetStatusCmn( LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT );
+ if( MacCtx.NodeAckRequested == true )
+ {
+ MacCtx.AckTimeoutRetry = true;
+ }
MacCtx.MacFlags.Bits.MacDone = 1;
}
@@ -1383,24 +1384,21 @@ static void HandleRadioRxErrorTimeout( LoRaMacEventInfoStatus_t rx1EventInfoStat
{
if( MacCtx.RxSlot == RX_SLOT_WIN_1 )
{
- if( MacCtx.NvmCtx->NodeAckRequested == true )
+ if( MacCtx.NodeAckRequested == true )
{
MacCtx.McpsConfirm.Status = rx1EventInfoStatus;
}
LoRaMacConfirmQueueSetStatusCmn( rx1EventInfoStatus );
- if( MacCtx.NvmCtx->DeviceClass != CLASS_C )
+ if( TimerGetElapsedTime( MacCtx.NvmCtx->LastTxDoneTime ) >= MacCtx.RxWindow2Delay )
{
- if( TimerGetElapsedTime( MacCtx.AggregatedLastTxDoneTime ) >= MacCtx.RxWindow2Delay )
- {
- TimerStop( &MacCtx.RxWindowTimer2 );
- MacCtx.MacFlags.Bits.MacDone = 1;
- }
+ TimerStop( &MacCtx.RxWindowTimer2 );
+ MacCtx.MacFlags.Bits.MacDone = 1;
}
}
else
{
- if( MacCtx.NvmCtx->NodeAckRequested == true )
+ if( MacCtx.NodeAckRequested == true )
{
MacCtx.McpsConfirm.Status = rx2EventInfoStatus;
}
@@ -1413,10 +1411,7 @@ static void HandleRadioRxErrorTimeout( LoRaMacEventInfoStatus_t rx1EventInfoStat
}
}
- if( MacCtx.NvmCtx->DeviceClass == CLASS_C )
- {
- OpenContinuousRx2Window( );
- }
+ UpdateRxSlotIdleState( );
}
static void ProcessRadioRxError( void )
@@ -1463,14 +1458,14 @@ static void LoRaMacHandleIrqEvents( void )
}
}
-static LoRaMacBoolean_t LoRaMacIsBusy( void )
+bool LoRaMacIsBusy( void )
{
if( ( MacCtx.MacState == LORAMAC_IDLE ) &&
( MacCtx.AllowRequests == LORAMAC_REQUEST_HANDLING_ON ) )
{
- return LORAMAC_FALSE;
+ return false;
}
- return LORAMAC_TRUE;
+ return true;
}
@@ -1523,15 +1518,8 @@ static void LoRaMacHandleRequestEvents( void )
}
}
-static void LoRaMacHandleIndicationEvents( void )
+static void LoRaMacHandleScheduleUplinkEvent( void )
{
- // Handle MLME indication
- if( MacCtx.MacFlags.Bits.MlmeInd == 1 )
- {
- MacCtx.MacPrimitives->MacMlmeIndication( &MacCtx.MlmeIndication );
- MacCtx.MacFlags.Bits.MlmeInd = 0;
- }
-
// Handle events
if( MacCtx.MacState == LORAMAC_IDLE )
{
@@ -1541,21 +1529,33 @@ static void LoRaMacHandleIndicationEvents( void )
if( isStickyMacCommandPending == true )
{// Setup MLME indication
SetMlmeScheduleUplinkIndication( );
- MacCtx.MacPrimitives->MacMlmeIndication( &MacCtx.MlmeIndication );
}
}
+}
+
+static void LoRaMacHandleIndicationEvents( void )
+{
+ // Handle MLME indication
+ if( MacCtx.MacFlags.Bits.MlmeInd == 1 )
+ {
+ MacCtx.MacFlags.Bits.MlmeInd = 0;
+ MacCtx.MacPrimitives->MacMlmeIndication( &MacCtx.MlmeIndication );
+ }
+
+ if( MacCtx.MacFlags.Bits.MlmeSchedUplinkInd == 1 )
+ {
+ MlmeIndication_t schduleUplinkIndication;
+ schduleUplinkIndication.MlmeIndication = MLME_SCHEDULE_UPLINK;
+ schduleUplinkIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+
+ MacCtx.MacPrimitives->MacMlmeIndication( &schduleUplinkIndication );
+ MacCtx.MacFlags.Bits.MlmeSchedUplinkInd = 0;
+ }
// Handle MCPS indication
if( MacCtx.MacFlags.Bits.McpsInd == 1 )
{
MacCtx.MacFlags.Bits.McpsInd = 0;
- if( MacCtx.NvmCtx->DeviceClass == CLASS_C )
- {// Activate RX2 window for Class C
- if( MacCtx.MacState == LORAMAC_IDLE )
- {
- OpenContinuousRx2Window( );
- }
- }
MacCtx.MacPrimitives->MacMcpsIndication( &MacCtx.McpsIndication );
}
}
@@ -1575,7 +1575,7 @@ static void LoRaMacHandleMcpsRequest( void )
}
else if( MacCtx.McpsConfirm.McpsRequest == MCPS_CONFIRMED )
{
- if( MacCtx.NvmCtx->AckTimeoutRetry == true )
+ if( MacCtx.AckTimeoutRetry == true )
{
stopRetransmission = CheckRetransConfirmedUplink( );
@@ -1599,48 +1599,42 @@ static void LoRaMacHandleMcpsRequest( void )
if( stopRetransmission == true )
{// Stop retransmission
+ TimerStop( &MacCtx.TxDelayedTimer );
+ MacCtx.MacState &= ~LORAMAC_TX_DELAYED;
StopRetransmission( );
}
else if( waitForRetransmission == false )
{// Arrange further retransmission
MacCtx.MacFlags.Bits.MacDone = 0;
// Reset the state of the AckTimeout
- MacCtx.NvmCtx->AckTimeoutRetry = false;
+ MacCtx.AckTimeoutRetry = false;
// Sends the same frame again
OnTxDelayedTimerEvent( NULL );
}
}
}
-static void LoRaMacHandleJoinRequest( void )
+static void LoRaMacHandleMlmeRequest( void )
{
// Handle join request
- if( ( MacCtx.MacFlags.Bits.MlmeReq == 1 ) && ( LoRaMacConfirmQueueIsCmdActive( MLME_JOIN ) == true ) )
+ if( MacCtx.MacFlags.Bits.MlmeReq == 1 )
{
- if( LoRaMacConfirmQueueGetStatus( MLME_JOIN ) == LORAMAC_EVENT_INFO_STATUS_OK )
- {// Node joined successfully
- LoRaMacResetFCnts( );
- MacCtx.NvmCtx->ChannelsNbTransCounter = 0;
+ if( LoRaMacConfirmQueueIsCmdActive( MLME_JOIN ) == true )
+ {
+ if( LoRaMacConfirmQueueGetStatus( MLME_JOIN ) == LORAMAC_EVENT_INFO_STATUS_OK )
+ {// Node joined successfully
+ MacCtx.ChannelsNbTransCounter = 0;
+ }
+ MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
+ }
+ else if( ( LoRaMacConfirmQueueIsCmdActive( MLME_TXCW ) == true ) ||
+ ( LoRaMacConfirmQueueIsCmdActive( MLME_TXCW_1 ) == true ) )
+ {
+ MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
}
- MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
}
}
-static uint8_t LoRaMacCheckForTxTimeout( void )
-{
- if( ( LoRaMacConfirmQueueGetStatusCmn( ) == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) ||
- ( MacCtx.McpsConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) )
- {
- // Stop transmit cycle due to tx timeout
- MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
- MacCtx.McpsConfirm.NbRetries = MacCtx.NvmCtx->AckTimeoutRetriesCounter;
- MacCtx.McpsConfirm.AckReceived = false;
- MacCtx.McpsConfirm.TxTimeOnAir = 0;
- return 0x01;
- }
- return 0x00;
-}
-
static uint8_t LoRaMacCheckForBeaconAcquisition( void )
{
if( ( LoRaMacConfirmQueueIsCmdActive( MLME_BEACON_ACQUISITION ) == true ) &&
@@ -1682,19 +1676,23 @@ void LoRaMacProcess( void )
// An error occurs during transmitting
if( IsRequestPending( ) > 0 )
{
- noTx |= LoRaMacCheckForTxTimeout( );
noTx |= LoRaMacCheckForBeaconAcquisition( );
}
if( noTx == 0x00 )
{
- LoRaMacHandleJoinRequest( );
+ LoRaMacHandleMlmeRequest( );
LoRaMacHandleMcpsRequest( );
}
LoRaMacHandleRequestEvents( );
+ LoRaMacHandleScheduleUplinkEvent( );
LoRaMacEnableRequests( LORAMAC_REQUEST_HANDLING_ON );
}
LoRaMacHandleIndicationEvents( );
+ if( MacCtx.RxSlot == RX_SLOT_WIN_CLASS_C )
+ {
+ OpenContinuousRxCWindow( );
+ }
}
static void OnTxDelayedTimerEvent( void* context )
@@ -1714,7 +1712,7 @@ static void OnTxDelayedTimerEvent( void* context )
{
// Stop retransmission attempt
MacCtx.McpsConfirm.Datarate = MacCtx.NvmCtx->MacParams.ChannelsDatarate;
- MacCtx.McpsConfirm.NbRetries = MacCtx.NvmCtx->AckTimeoutRetriesCounter;
+ MacCtx.McpsConfirm.NbRetries = MacCtx.AckTimeoutRetriesCounter;
MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR;
LoRaMacConfirmQueueSetStatusCmn( LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR );
StopRetransmission( );
@@ -1725,99 +1723,96 @@ static void OnTxDelayedTimerEvent( void* context )
static void OnRxWindow1TimerEvent( void* context )
{
- TimerStop( &MacCtx.RxWindowTimer1 );
- MacCtx.RxSlot = RX_SLOT_WIN_1;
-
- MacCtx.RxWindow1Config.Channel = MacCtx.NvmCtx->Channel;
+ MacCtx.RxWindow1Config.Channel = MacCtx.Channel;
MacCtx.RxWindow1Config.DrOffset = MacCtx.NvmCtx->MacParams.Rx1DrOffset;
MacCtx.RxWindow1Config.DownlinkDwellTime = MacCtx.NvmCtx->MacParams.DownlinkDwellTime;
- MacCtx.RxWindow1Config.RepeaterSupport = MacCtx.NvmCtx->RepeaterSupport;
MacCtx.RxWindow1Config.RxContinuous = false;
- MacCtx.RxWindow1Config.RxSlot = MacCtx.RxSlot;
+ MacCtx.RxWindow1Config.RxSlot = RX_SLOT_WIN_1;
- if( MacCtx.NvmCtx->DeviceClass == CLASS_C )
- {
- Radio.Standby( );
- }
-
- RegionRxConfig( MacCtx.NvmCtx->Region, &MacCtx.RxWindow1Config, ( int8_t* ) &MacCtx.McpsIndication.RxDatarate );
- RxWindowSetup( MacCtx.RxWindow1Config.RxContinuous, MacCtx.NvmCtx->MacParams.MaxRxWindow );
+ RxWindowSetup( &MacCtx.RxWindowTimer1, &MacCtx.RxWindow1Config );
}
static void OnRxWindow2TimerEvent( void* context )
{
- TimerStop( &MacCtx.RxWindowTimer2 );
-
- MacCtx.RxWindow2Config.Channel = MacCtx.NvmCtx->Channel;
+ // Check if we are processing Rx1 window.
+ // If yes, we don't setup the Rx2 window.
+ if( MacCtx.RxSlot == RX_SLOT_WIN_1 )
+ {
+ return;
+ }
+ MacCtx.RxWindow2Config.Channel = MacCtx.Channel;
MacCtx.RxWindow2Config.Frequency = MacCtx.NvmCtx->MacParams.Rx2Channel.Frequency;
MacCtx.RxWindow2Config.DownlinkDwellTime = MacCtx.NvmCtx->MacParams.DownlinkDwellTime;
- MacCtx.RxWindow2Config.RepeaterSupport = MacCtx.NvmCtx->RepeaterSupport;
+ MacCtx.RxWindow2Config.RxContinuous = false;
MacCtx.RxWindow2Config.RxSlot = RX_SLOT_WIN_2;
- if( MacCtx.NvmCtx->DeviceClass != CLASS_C )
- {
- MacCtx.RxWindow2Config.RxContinuous = false;
- }
- else
- {
- // Setup continuous listening for class c
- MacCtx.RxWindow2Config.RxContinuous = true;
- }
-
- if( RegionRxConfig( MacCtx.NvmCtx->Region, &MacCtx.RxWindow2Config, ( int8_t* ) &MacCtx.McpsIndication.RxDatarate ) == true )
- {
- RxWindowSetup( MacCtx.RxWindow2Config.RxContinuous, MacCtx.NvmCtx->MacParams.MaxRxWindow );
- MacCtx.RxSlot = RX_SLOT_WIN_2;
- }
-}
-
-static void CheckToDisableAckTimeout( bool nodeAckRequested, DeviceClass_t devClass, bool ackReceived )
-{
- // There are three cases where we need to stop the AckTimeoutTimer:
- if( nodeAckRequested == false )
- {
- if( devClass == CLASS_C )
- {// FIRST CASE
- // We have performed an unconfirmed uplink in class c mode
- // and have received a downlink in RX1 or RX2.
- OnAckTimeoutTimerEvent( NULL );
- }
- }
- else
- {
- if( ackReceived == 1 )
- {// SECOND CASE
- // We have performed a confirmed uplink and have received a
- // downlink with a valid ACK.
- OnAckTimeoutTimerEvent( NULL );
- }
- }
+ RxWindowSetup( &MacCtx.RxWindowTimer2, &MacCtx.RxWindow2Config );
}
static void OnAckTimeoutTimerEvent( void* context )
{
TimerStop( &MacCtx.AckTimeoutTimer );
- if( MacCtx.NvmCtx->NodeAckRequested == true )
+ if( MacCtx.NodeAckRequested == true )
{
- MacCtx.NvmCtx->AckTimeoutRetry = true;
+ MacCtx.AckTimeoutRetry = true;
}
if( MacCtx.NvmCtx->DeviceClass == CLASS_C )
{
MacCtx.MacFlags.Bits.MacDone = 1;
}
+ if( ( MacCtx.MacCallbacks != NULL ) && ( MacCtx.MacCallbacks->MacProcessNotify != NULL ) )
+ {
+ MacCtx.MacCallbacks->MacProcessNotify( );
+ }
}
-static void RxWindowSetup( bool rxContinuous, uint32_t maxRxWindow )
+static LoRaMacCryptoStatus_t GetFCntDown( AddressIdentifier_t addrID, FType_t fType, LoRaMacMessageData_t* macMsg, Version_t lrWanVersion,
+ uint16_t maxFCntGap, FCntIdentifier_t* fCntID, uint32_t* currentDown )
{
- if( rxContinuous == false )
+ if( ( macMsg == NULL ) || ( fCntID == NULL ) ||
+ ( currentDown == NULL ) )
{
- Radio.Rx( maxRxWindow );
+ return LORAMAC_CRYPTO_ERROR_NPE;
}
- else
+
+ // Determine the frame counter identifier and choose counter from FCntList
+ switch( addrID )
{
- Radio.Rx( 0 ); // Continuous mode
+ case UNICAST_DEV_ADDR:
+ if( lrWanVersion.Fields.Minor == 1 )
+ {
+ if( ( fType == FRAME_TYPE_A ) || ( fType == FRAME_TYPE_D ) )
+ {
+ *fCntID = A_FCNT_DOWN;
+ }
+ else
+ {
+ *fCntID = N_FCNT_DOWN;
+ }
+ }
+ else
+ { // For LoRaWAN 1.0.X
+ *fCntID = FCNT_DOWN;
+ }
+ break;
+ case MULTICAST_0_ADDR:
+ *fCntID = MC_FCNT_DOWN_0;
+ break;
+ case MULTICAST_1_ADDR:
+ *fCntID = MC_FCNT_DOWN_1;
+ break;
+ case MULTICAST_2_ADDR:
+ *fCntID = MC_FCNT_DOWN_2;
+ break;
+ case MULTICAST_3_ADDR:
+ *fCntID = MC_FCNT_DOWN_3;
+ break;
+ default:
+ return LORAMAC_CRYPTO_FAIL_FCNT_ID;
}
+
+ return LoRaMacCryptoGetFCntDown( *fCntID, maxFCntGap, macMsg->FHDR.FCnt, currentDown );
}
static LoRaMacStatus_t SwitchClass( DeviceClass_t deviceClass )
@@ -1828,6 +1823,11 @@ static LoRaMacStatus_t SwitchClass( DeviceClass_t deviceClass )
{
case CLASS_A:
{
+ if( deviceClass == CLASS_A )
+ {
+ // Revert back RxC parameters
+ MacCtx.NvmCtx->MacParams.RxCChannel = MacCtx.NvmCtx->MacParams.Rx2Channel;
+ }
if( deviceClass == CLASS_B )
{
status = LoRaMacClassBSwitchClass( deviceClass );
@@ -1841,17 +1841,32 @@ static LoRaMacStatus_t SwitchClass( DeviceClass_t deviceClass )
{
MacCtx.NvmCtx->DeviceClass = deviceClass;
+ MacCtx.RxWindowCConfig = MacCtx.RxWindow2Config;
+ MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C;
+
+ for( int8_t i = 0; i < LORAMAC_MAX_MC_CTX; i++ )
+ {
+ if( MacCtx.NvmCtx->MulticastChannelList[i].ChannelParams.IsEnabled == true )
+ // TODO: Check multicast channel device class.
+ {
+ MacCtx.NvmCtx->MacParams.RxCChannel.Frequency = MacCtx.NvmCtx->MulticastChannelList[i].ChannelParams.RxParams.ClassC.Frequency;
+ MacCtx.NvmCtx->MacParams.RxCChannel.Datarate = MacCtx.NvmCtx->MulticastChannelList[i].ChannelParams.RxParams.ClassC.Datarate;
+
+ MacCtx.RxWindowCConfig.Channel = MacCtx.Channel;
+ MacCtx.RxWindowCConfig.Frequency = MacCtx.NvmCtx->MacParams.RxCChannel.Frequency;
+ MacCtx.RxWindowCConfig.DownlinkDwellTime = MacCtx.NvmCtx->MacParams.DownlinkDwellTime;
+ MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C_MULTICAST;
+ MacCtx.RxWindowCConfig.RxContinuous = true;
+ break;
+ }
+ }
+
// Set the NodeAckRequested indicator to default
- MacCtx.NvmCtx->NodeAckRequested = false;
+ MacCtx.NodeAckRequested = false;
// Set the radio into sleep mode in case we are still in RX mode
Radio.Sleep( );
- // Compute Rx2 windows parameters in case the RX2 datarate has changed
- RegionComputeRxWindowParameters( MacCtx.NvmCtx->Region,
- MacCtx.NvmCtx->MacParams.Rx2Channel.Datarate,
- MacCtx.NvmCtx->MacParams.MinRxSymbols,
- MacCtx.NvmCtx->MacParams.SystemMaxRxError,
- &MacCtx.RxWindow2Config );
- OpenContinuousRx2Window( );
+
+ OpenContinuousRxCWindow( );
status = LORAMAC_STATUS_OK;
}
@@ -1893,12 +1908,6 @@ static uint8_t GetMaxAppPayloadWithoutFOptsLength( int8_t datarate )
getPhy.UplinkDwellTime = MacCtx.NvmCtx->MacParams.UplinkDwellTime;
getPhy.Datarate = datarate;
getPhy.Attribute = PHY_MAX_PAYLOAD;
-
- // Get the maximum payload length
- if( MacCtx.NvmCtx->RepeaterSupport == true )
- {
- getPhy.Attribute = PHY_MAX_PAYLOAD_REPEATER;
- }
phyParam = RegionGetPhyParam( MacCtx.NvmCtx->Region, &getPhy );
return phyParam.Value;
@@ -1924,8 +1933,7 @@ static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsL
static void SetMlmeScheduleUplinkIndication( void )
{
- MacCtx.MlmeIndication.MlmeIndication = MLME_SCHEDULE_UPLINK;
- MacCtx.MacFlags.Bits.MlmeInd = 1;
+ MacCtx.MacFlags.Bits.MlmeSchedUplinkInd = 1;
}
static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, int8_t snr, LoRaMacRxSlot_t rxSlot )
@@ -1936,6 +1944,12 @@ static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t comm
while( macIndex < commandsSize )
{
+ // Make sure to parse only complete MAC commands
+ if( ( LoRaMacCommandsGetCmdSize( payload[macIndex] ) + macIndex ) > commandsSize )
+ {
+ return;
+ }
+
// Decode Frame MAC commands
switch( payload[macIndex++] )
{
@@ -2019,7 +2033,9 @@ static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t comm
if( ( status & 0x07 ) == 0x07 )
{
MacCtx.NvmCtx->MacParams.Rx2Channel.Datarate = rxParamSetupReq.Datarate;
+ MacCtx.NvmCtx->MacParams.RxCChannel.Datarate = rxParamSetupReq.Datarate;
MacCtx.NvmCtx->MacParams.Rx2Channel.Frequency = rxParamSetupReq.Frequency;
+ MacCtx.NvmCtx->MacParams.RxCChannel.Frequency = rxParamSetupReq.Frequency;
MacCtx.NvmCtx->MacParams.Rx1DrOffset = rxParamSetupReq.DrOffset;
}
macCmdPayload[0] = status;
@@ -2135,41 +2151,50 @@ static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t comm
}
case SRV_MAC_DEVICE_TIME_ANS:
{
- SysTime_t gpsEpochTime = { 0 };
- SysTime_t sysTime = { 0 };
- SysTime_t sysTimeCurrent = { 0 };
+ if( LoRaMacConfirmQueueIsCmdActive( MLME_DEVICE_TIME ) == true )
+ {
+ LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_DEVICE_TIME );
+ SysTime_t gpsEpochTime = { 0 };
+ SysTime_t sysTime = { 0 };
+ SysTime_t sysTimeCurrent = { 0 };
- gpsEpochTime.Seconds = ( uint32_t )payload[macIndex++];
- gpsEpochTime.Seconds |= ( uint32_t )payload[macIndex++] << 8;
- gpsEpochTime.Seconds |= ( uint32_t )payload[macIndex++] << 16;
- gpsEpochTime.Seconds |= ( uint32_t )payload[macIndex++] << 24;
- gpsEpochTime.SubSeconds = payload[macIndex++];
+ gpsEpochTime.Seconds = ( uint32_t )payload[macIndex++];
+ gpsEpochTime.Seconds |= ( uint32_t )payload[macIndex++] << 8;
+ gpsEpochTime.Seconds |= ( uint32_t )payload[macIndex++] << 16;
+ gpsEpochTime.Seconds |= ( uint32_t )payload[macIndex++] << 24;
+ gpsEpochTime.SubSeconds = payload[macIndex++];
- // Convert the fractional second received in ms
- // round( pow( 0.5, 8.0 ) * 1000 ) = 3.90625
- gpsEpochTime.SubSeconds = ( int16_t )( ( ( int32_t )gpsEpochTime.SubSeconds * 1000 ) >> 8 );
+ // Convert the fractional second received in ms
+ // round( pow( 0.5, 8.0 ) * 1000 ) = 3.90625
+ gpsEpochTime.SubSeconds = ( int16_t )( ( ( int32_t )gpsEpochTime.SubSeconds * 1000 ) >> 8 );
- // Copy received GPS Epoch time into system time
- sysTime = gpsEpochTime;
- // Add Unix to Gps epcoh offset. The system time is based on Unix time.
- sysTime.Seconds += UNIX_GPS_EPOCH_OFFSET;
+ // Copy received GPS Epoch time into system time
+ sysTime = gpsEpochTime;
+ // Add Unix to Gps epcoh offset. The system time is based on Unix time.
+ sysTime.Seconds += UNIX_GPS_EPOCH_OFFSET;
- // Compensate time difference between Tx Done time and now
- sysTimeCurrent = SysTimeGet( );
- sysTime = SysTimeAdd( sysTimeCurrent, SysTimeSub( sysTime, MacCtx.LastTxSysTime ) );
+ // Compensate time difference between Tx Done time and now
+ sysTimeCurrent = SysTimeGet( );
+ sysTime = SysTimeAdd( sysTimeCurrent, SysTimeSub( sysTime, MacCtx.LastTxSysTime ) );
- // Apply the new system time.
- SysTimeSet( sysTime );
- LoRaMacClassBDeviceTimeAns( );
+ // Apply the new system time.
+ SysTimeSet( sysTime );
+ LoRaMacClassBDeviceTimeAns( );
+ MacCtx.McpsIndication.DeviceTimeAnsReceived = true;
+ }
break;
}
case SRV_MAC_PING_SLOT_INFO_ANS:
{
- // According to the specification, it is not allowed to process this answer in
- // a ping or multicast slot
- if( ( MacCtx.RxSlot != RX_SLOT_WIN_PING_SLOT ) && ( MacCtx.RxSlot != RX_SLOT_WIN_MULTICAST_SLOT ) )
+ if( LoRaMacConfirmQueueIsCmdActive( MLME_PING_SLOT_INFO ) == true )
{
- LoRaMacClassBPingSlotInfoAns( );
+ LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_PING_SLOT_INFO );
+ // According to the specification, it is not allowed to process this answer in
+ // a ping or multicast slot
+ if( ( MacCtx.RxSlot != RX_SLOT_WIN_CLASS_B_PING_SLOT ) && ( MacCtx.RxSlot != RX_SLOT_WIN_CLASS_B_MULTICAST_SLOT ) )
+ {
+ LoRaMacClassBPingSlotInfoAns( );
+ }
}
break;
}
@@ -2192,14 +2217,18 @@ static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t comm
}
case SRV_MAC_BEACON_TIMING_ANS:
{
- uint16_t beaconTimingDelay = 0;
- uint8_t beaconTimingChannel = 0;
+ if( LoRaMacConfirmQueueIsCmdActive( MLME_BEACON_TIMING ) == true )
+ {
+ LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_BEACON_TIMING );
+ uint16_t beaconTimingDelay = 0;
+ uint8_t beaconTimingChannel = 0;
- beaconTimingDelay = ( uint16_t )payload[macIndex++];
- beaconTimingDelay |= ( uint16_t )payload[macIndex++] << 8;
- beaconTimingChannel = payload[macIndex++];
+ beaconTimingDelay = ( uint16_t )payload[macIndex++];
+ beaconTimingDelay |= ( uint16_t )payload[macIndex++] << 8;
+ beaconTimingChannel = payload[macIndex++];
- LoRaMacClassBBeaconTimingAns( beaconTimingDelay, beaconTimingChannel, RxDoneParams.LastRxDone );
+ LoRaMacClassBBeaconTimingAns( beaconTimingDelay, beaconTimingChannel, RxDoneParams.LastRxDone );
+ }
break;
}
case SRV_MAC_BEACON_FREQ_REQ:
@@ -2245,7 +2274,7 @@ LoRaMacStatus_t Send( LoRaMacHeader_t* macHdr, uint8_t fPort, void* fBuffer, uin
}
if( MacCtx.NvmCtx->MaxDCycle == 0 )
{
- MacCtx.AggregatedTimeOff = 0;
+ MacCtx.NvmCtx->AggregatedTimeOff = 0;
}
fCtrl.Value = 0;
@@ -2273,8 +2302,8 @@ LoRaMacStatus_t Send( LoRaMacHeader_t* macHdr, uint8_t fPort, void* fBuffer, uin
adrNext.UpdateChanMask = true;
adrNext.AdrEnabled = fCtrl.Bits.Adr;
adrNext.AdrAckCounter = MacCtx.NvmCtx->AdrAckCounter;
- adrNext.AdrAckLimit = MacCtx.NvmCtx->AdrAckLimit;
- adrNext.AdrAckDelay = MacCtx.NvmCtx->AdrAckDelay;
+ adrNext.AdrAckLimit = MacCtx.AdrAckLimit;
+ adrNext.AdrAckDelay = MacCtx.AdrAckDelay;
adrNext.Datarate = MacCtx.NvmCtx->MacParams.ChannelsDatarate;
adrNext.TxPower = MacCtx.NvmCtx->MacParams.ChannelsTxPower;
adrNext.UplinkDwellTime = MacCtx.NvmCtx->MacParams.UplinkDwellTime;
@@ -2327,6 +2356,8 @@ LoRaMacStatus_t SendReJoinReq( JoinReqIdentifier_t joinReqType )
{
case JOIN_REQ:
{
+ SwitchClass( CLASS_A );
+
MacCtx.TxMsg.Type = LORAMAC_MSG_TYPE_JOIN_REQUEST;
MacCtx.TxMsg.Message.JoinReq.Buffer = MacCtx.PktBuffer;
MacCtx.TxMsg.Message.JoinReq.BufSize = LORAMAC_PHY_MAXPAYLOAD;
@@ -2334,8 +2365,8 @@ LoRaMacStatus_t SendReJoinReq( JoinReqIdentifier_t joinReqType )
macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
MacCtx.TxMsg.Message.JoinReq.MHDR.Value = macHdr.Value;
- memcpy1( MacCtx.TxMsg.Message.JoinReq.JoinEUI, MacCtx.JoinEui, LORAMAC_JOIN_EUI_FIELD_SIZE );
- memcpy1( MacCtx.TxMsg.Message.JoinReq.DevEUI, MacCtx.DevEui, LORAMAC_DEV_EUI_FIELD_SIZE );
+ memcpy1( MacCtx.TxMsg.Message.JoinReq.JoinEUI, SecureElementGetJoinEui( ), LORAMAC_JOIN_EUI_FIELD_SIZE );
+ memcpy1( MacCtx.TxMsg.Message.JoinReq.DevEUI, SecureElementGetDevEui( ), LORAMAC_DEV_EUI_FIELD_SIZE );
allowDelayedTx = false;
@@ -2351,56 +2382,35 @@ LoRaMacStatus_t SendReJoinReq( JoinReqIdentifier_t joinReqType )
return status;
}
-static LoRaMacStatus_t ScheduleTx( bool allowDelayedTx )
+static LoRaMacStatus_t CheckForClassBCollision( void )
{
- LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
- TimerTime_t dutyCycleTimeOff = 0;
- NextChanParams_t nextChan;
- size_t macCmdsSize = 0;
-
- // Update back-off
- CalculateBackOff( MacCtx.NvmCtx->LastTxChannel );
-
- nextChan.AggrTimeOff = MacCtx.AggregatedTimeOff;
- nextChan.Datarate = MacCtx.NvmCtx->MacParams.ChannelsDatarate;
- nextChan.DutyCycleEnabled = MacCtx.NvmCtx->DutyCycleOn;
- if( MacCtx.NvmCtx->NetworkActivation == ACTIVATION_TYPE_NONE )
+ if( LoRaMacClassBIsBeaconExpected( ) == true )
{
- nextChan.Joined = false;
+ return LORAMAC_STATUS_BUSY_BEACON_RESERVED_TIME;
}
- else
- {
- nextChan.Joined = true;
- }
- nextChan.LastAggrTx = MacCtx.AggregatedLastTxDoneTime;
- // Select channel
- status = RegionNextChannel( MacCtx.NvmCtx->Region, &nextChan, &MacCtx.NvmCtx->Channel, &dutyCycleTimeOff, &MacCtx.AggregatedTimeOff );
-
- if( status != LORAMAC_STATUS_OK )
+ if( MacCtx.NvmCtx->DeviceClass == CLASS_B )
{
- if( ( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED ) &&
- ( allowDelayedTx == true ) )
+ if( LoRaMacClassBIsPingExpected( ) == true )
{
- // Allow delayed transmissions. We have to allow it in case
- // the MAC must retransmit a frame with the frame repetitions
- if( dutyCycleTimeOff != 0 )
- {// Send later - prepare timer
- MacCtx.MacState |= LORAMAC_TX_DELAYED;
- TimerSetValue( &MacCtx.TxDelayedTimer, dutyCycleTimeOff );
- TimerStart( &MacCtx.TxDelayedTimer );
- }
- return LORAMAC_STATUS_OK;
+ return LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME;
}
- else
- {// State where the MAC cannot send a frame
- return status;
+ else if( LoRaMacClassBIsMulticastExpected( ) == true )
+ {
+ return LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME;
}
}
+ return LORAMAC_STATUS_OK;
+}
+static void ComputeRxWindowParameters( void )
+{
// Compute Rx1 windows parameters
RegionComputeRxWindowParameters( MacCtx.NvmCtx->Region,
- RegionApplyDrOffset( MacCtx.NvmCtx->Region, MacCtx.NvmCtx->MacParams.DownlinkDwellTime, MacCtx.NvmCtx->MacParams.ChannelsDatarate, MacCtx.NvmCtx->MacParams.Rx1DrOffset ),
+ RegionApplyDrOffset( MacCtx.NvmCtx->Region,
+ MacCtx.NvmCtx->MacParams.DownlinkDwellTime,
+ MacCtx.NvmCtx->MacParams.ChannelsDatarate,
+ MacCtx.NvmCtx->MacParams.Rx1DrOffset ),
MacCtx.NvmCtx->MacParams.MinRxSymbols,
MacCtx.NvmCtx->MacParams.SystemMaxRxError,
&MacCtx.RxWindow1Config );
@@ -2411,12 +2421,22 @@ static LoRaMacStatus_t ScheduleTx( bool allowDelayedTx )
MacCtx.NvmCtx->MacParams.SystemMaxRxError,
&MacCtx.RxWindow2Config );
+ // Default setup, in case the device joined
+ MacCtx.RxWindow1Delay = MacCtx.NvmCtx->MacParams.ReceiveDelay1 + MacCtx.RxWindow1Config.WindowOffset;
+ MacCtx.RxWindow2Delay = MacCtx.NvmCtx->MacParams.ReceiveDelay2 + MacCtx.RxWindow2Config.WindowOffset;
+
if( MacCtx.NvmCtx->NetworkActivation == ACTIVATION_TYPE_NONE )
{
MacCtx.RxWindow1Delay = MacCtx.NvmCtx->MacParams.JoinAcceptDelay1 + MacCtx.RxWindow1Config.WindowOffset;
MacCtx.RxWindow2Delay = MacCtx.NvmCtx->MacParams.JoinAcceptDelay2 + MacCtx.RxWindow2Config.WindowOffset;
}
- else
+}
+
+static LoRaMacStatus_t VerifyTxFrame( void )
+{
+ size_t macCmdsSize = 0;
+
+ if( MacCtx.NvmCtx->NetworkActivation != ACTIVATION_TYPE_NONE )
{
if( LoRaMacCommandsGetSizeSerializedCmds( &macCmdsSize ) != LORAMAC_COMMANDS_SUCCESS )
{
@@ -2427,19 +2447,114 @@ static LoRaMacStatus_t ScheduleTx( bool allowDelayedTx )
{
return LORAMAC_STATUS_LENGTH_ERROR;
}
- MacCtx.RxWindow1Delay = MacCtx.NvmCtx->MacParams.ReceiveDelay1 + MacCtx.RxWindow1Config.WindowOffset;
- MacCtx.RxWindow2Delay = MacCtx.NvmCtx->MacParams.ReceiveDelay2 + MacCtx.RxWindow2Config.WindowOffset;
+ }
+ return LORAMAC_STATUS_OK;
+}
+
+static LoRaMacStatus_t SerializeTxFrame( void )
+{
+ LoRaMacSerializerStatus_t serializeStatus;
+
+ switch( MacCtx.TxMsg.Type )
+ {
+ case LORAMAC_MSG_TYPE_JOIN_REQUEST:
+ serializeStatus = LoRaMacSerializerJoinRequest( &MacCtx.TxMsg.Message.JoinReq );
+ if( LORAMAC_SERIALIZER_SUCCESS != serializeStatus )
+ {
+ return LORAMAC_STATUS_CRYPTO_ERROR;
+ }
+ MacCtx.PktBufferLen = MacCtx.TxMsg.Message.JoinReq.BufSize;
+ break;
+ case LORAMAC_MSG_TYPE_DATA:
+ serializeStatus = LoRaMacSerializerData( &MacCtx.TxMsg.Message.Data );
+ if( LORAMAC_SERIALIZER_SUCCESS != serializeStatus )
+ {
+ return LORAMAC_STATUS_CRYPTO_ERROR;
+ }
+ MacCtx.PktBufferLen = MacCtx.TxMsg.Message.Data.BufSize;
+ break;
+ case LORAMAC_MSG_TYPE_JOIN_ACCEPT:
+ case LORAMAC_MSG_TYPE_UNDEF:
+ default:
+ return LORAMAC_STATUS_PARAMETER_INVALID;
+ }
+ return LORAMAC_STATUS_OK;
+}
+
+static LoRaMacStatus_t ScheduleTx( bool allowDelayedTx )
+{
+ LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
+ NextChanParams_t nextChan;
+
+ // Check class b collisions
+ status = CheckForClassBCollision( );
+ if( status != LORAMAC_STATUS_OK )
+ {
+ return status;
}
- // Secure frame
- LoRaMacStatus_t retval = SecureFrame( MacCtx.NvmCtx->MacParams.ChannelsDatarate, MacCtx.NvmCtx->Channel );
- if( retval != LORAMAC_STATUS_OK )
+ // Update back-off
+ CalculateBackOff( );
+
+ // Serialize frame
+ status = SerializeTxFrame( );
+ if( status != LORAMAC_STATUS_OK )
{
- return retval;
+ return status;
+ }
+
+ nextChan.AggrTimeOff = MacCtx.NvmCtx->AggregatedTimeOff;
+ nextChan.Datarate = MacCtx.NvmCtx->MacParams.ChannelsDatarate;
+ nextChan.DutyCycleEnabled = MacCtx.NvmCtx->DutyCycleOn;
+ nextChan.ElapsedTimeSinceStartUp = SysTimeSub( SysTimeGetMcuTime( ), MacCtx.NvmCtx->InitializationTime );
+ nextChan.LastAggrTx = MacCtx.NvmCtx->LastTxDoneTime;
+ nextChan.LastTxIsJoinRequest = false;
+ nextChan.Joined = true;
+ nextChan.PktLen = MacCtx.PktBufferLen;
+
+ // Setup the parameters based on the join status
+ if( MacCtx.NvmCtx->NetworkActivation == ACTIVATION_TYPE_NONE )
+ {
+ nextChan.LastTxIsJoinRequest = true;
+ nextChan.Joined = false;
+ }
+
+ // Select channel
+ status = RegionNextChannel( MacCtx.NvmCtx->Region, &nextChan, &MacCtx.Channel, &MacCtx.DutyCycleWaitTime, &MacCtx.NvmCtx->AggregatedTimeOff );
+
+ if( status != LORAMAC_STATUS_OK )
+ {
+ if( ( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED ) &&
+ ( allowDelayedTx == true ) )
+ {
+ // Allow delayed transmissions. We have to allow it in case
+ // the MAC must retransmit a frame with the frame repetitions
+ if( MacCtx.DutyCycleWaitTime != 0 )
+ {// Send later - prepare timer
+ MacCtx.MacState |= LORAMAC_TX_DELAYED;
+ TimerSetValue( &MacCtx.TxDelayedTimer, MacCtx.DutyCycleWaitTime );
+ TimerStart( &MacCtx.TxDelayedTimer );
+ }
+ return LORAMAC_STATUS_OK;
+ }
+ else
+ {// State where the MAC cannot send a frame
+ return status;
+ }
+ }
+
+ // Compute window parameters, offsets, rx symbols, system errors etc.
+ ComputeRxWindowParameters( );
+
+ // Verify TX frame
+ status = VerifyTxFrame( );
+ if( status != LORAMAC_STATUS_OK )
+ {
+ return status;
}
// Try to send now
- return SendFrameOnChannel( MacCtx.NvmCtx->Channel );
+ return SendFrameOnChannel( MacCtx.Channel );
}
static LoRaMacStatus_t SecureFrame( uint8_t txDr, uint8_t txCh )
@@ -2459,11 +2574,16 @@ static LoRaMacStatus_t SecureFrame( uint8_t txDr, uint8_t txCh )
break;
case LORAMAC_MSG_TYPE_DATA:
- if( LORAMAC_FCNT_HANDLER_SUCCESS != LoRaMacGetFCntUp( &fCntUp ) )
+ if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoGetFCntUp( &fCntUp ) )
{
return LORAMAC_STATUS_FCNT_HANDLER_ERROR;
}
+ if( ( MacCtx.ChannelsNbTransCounter >= 1 ) || ( MacCtx.AckTimeoutRetriesCounter > 1 ) )
+ {
+ fCntUp -= 1;
+ }
+
macCryptoStatus = LoRaMacCryptoSecureMessage( fCntUp, txDr, txCh, &MacCtx.TxMsg.Message.Data );
if( LORAMAC_CRYPTO_SUCCESS != macCryptoStatus )
{
@@ -2479,34 +2599,16 @@ static LoRaMacStatus_t SecureFrame( uint8_t txDr, uint8_t txCh )
return LORAMAC_STATUS_OK;
}
-static void CalculateBackOff( uint8_t channel )
+static void CalculateBackOff( void )
{
- CalcBackOffParams_t calcBackOff;
-
- if( MacCtx.NvmCtx->NetworkActivation == ACTIVATION_TYPE_NONE )
+ // Make sure that the calculation of the backoff time for the aggregated time off will only be done in
+ // case the value is zero. It will be set to zero in the function RegionNextChannel.
+ if( MacCtx.NvmCtx->AggregatedTimeOff == 0 )
{
- calcBackOff.Joined = false;
+ // Update aggregated time-off. This must be an assignment and no incremental
+ // update as we do only calculate the time-off based on the last transmission
+ MacCtx.NvmCtx->AggregatedTimeOff = ( MacCtx.TxTimeOnAir * MacCtx.NvmCtx->AggregatedDCycle - MacCtx.TxTimeOnAir );
}
- else
- {
- calcBackOff.Joined = true;
- }
- calcBackOff.DutyCycleEnabled = MacCtx.NvmCtx->DutyCycleOn;
- calcBackOff.Channel = channel;
- calcBackOff.ElapsedTime = SysTimeSub( SysTimeGetMcuTime( ), MacCtx.InitializationTime );
- calcBackOff.TxTimeOnAir = MacCtx.TxTimeOnAir;
- calcBackOff.LastTxIsJoinRequest = false;
- if( ( MacCtx.MacFlags.Bits.MlmeReq == 1 ) && ( LoRaMacConfirmQueueIsCmdActive( MLME_JOIN ) == true ) )
- {
- calcBackOff.LastTxIsJoinRequest = true;
- }
-
- // Update regional back-off
- RegionCalcBackOff( MacCtx.NvmCtx->Region, &calcBackOff );
-
- // Update aggregated time-off. This must be an assignment and no incremental
- // update as we do only calculate the time-off based on the last transmission
- MacCtx.AggregatedTimeOff = ( MacCtx.TxTimeOnAir * MacCtx.NvmCtx->AggregatedDCycle - MacCtx.TxTimeOnAir );
}
static void RemoveMacCommands( LoRaMacRxSlot_t rxSlot, LoRaMacFrameCtrl_t fCtrl, Mcps_t request )
@@ -2537,13 +2639,10 @@ static void ResetMacParameters( void )
// ADR counter
MacCtx.NvmCtx->AdrAckCounter = 0;
- // Initialize the uplink and downlink counters default value
- LoRaMacResetFCnts( );
-
- MacCtx.NvmCtx->ChannelsNbTransCounter = 0;
- MacCtx.NvmCtx->AckTimeoutRetries = 1;
- MacCtx.NvmCtx->AckTimeoutRetriesCounter = 1;
- MacCtx.NvmCtx->AckTimeoutRetry = false;
+ MacCtx.ChannelsNbTransCounter = 0;
+ MacCtx.AckTimeoutRetries = 1;
+ MacCtx.AckTimeoutRetriesCounter = 1;
+ MacCtx.AckTimeoutRetry = false;
MacCtx.NvmCtx->MaxDCycle = 0;
MacCtx.NvmCtx->AggregatedDCycle = 1;
@@ -2552,35 +2651,84 @@ static void ResetMacParameters( void )
MacCtx.NvmCtx->MacParams.ChannelsDatarate = MacCtx.NvmCtx->MacParamsDefaults.ChannelsDatarate;
MacCtx.NvmCtx->MacParams.Rx1DrOffset = MacCtx.NvmCtx->MacParamsDefaults.Rx1DrOffset;
MacCtx.NvmCtx->MacParams.Rx2Channel = MacCtx.NvmCtx->MacParamsDefaults.Rx2Channel;
+ MacCtx.NvmCtx->MacParams.RxCChannel = MacCtx.NvmCtx->MacParamsDefaults.RxCChannel;
MacCtx.NvmCtx->MacParams.UplinkDwellTime = MacCtx.NvmCtx->MacParamsDefaults.UplinkDwellTime;
MacCtx.NvmCtx->MacParams.DownlinkDwellTime = MacCtx.NvmCtx->MacParamsDefaults.DownlinkDwellTime;
MacCtx.NvmCtx->MacParams.MaxEirp = MacCtx.NvmCtx->MacParamsDefaults.MaxEirp;
MacCtx.NvmCtx->MacParams.AntennaGain = MacCtx.NvmCtx->MacParamsDefaults.AntennaGain;
- MacCtx.NvmCtx->NodeAckRequested = false;
+ MacCtx.NodeAckRequested = false;
MacCtx.NvmCtx->SrvAckRequested = false;
// Reset to application defaults
InitDefaultsParams_t params;
- params.Type = INIT_TYPE_RESTORE_DEFAULT_CHANNELS;
+ params.Type = INIT_TYPE_INIT;
params.NvmCtx = NULL;
RegionInitDefaults( MacCtx.NvmCtx->Region, ¶ms );
// Initialize channel index.
- MacCtx.NvmCtx->Channel = 0;
- MacCtx.NvmCtx->LastTxChannel = MacCtx.NvmCtx->Channel;
+ MacCtx.Channel = 0;
+
+ // Initialize Rx2 config parameters.
+ MacCtx.RxWindow2Config.Channel = MacCtx.Channel;
+ MacCtx.RxWindow2Config.Frequency = MacCtx.NvmCtx->MacParams.Rx2Channel.Frequency;
+ MacCtx.RxWindow2Config.DownlinkDwellTime = MacCtx.NvmCtx->MacParams.DownlinkDwellTime;
+ MacCtx.RxWindow2Config.RxContinuous = false;
+ MacCtx.RxWindow2Config.RxSlot = RX_SLOT_WIN_2;
+
+ // Initialize RxC config parameters.
+ MacCtx.RxWindowCConfig = MacCtx.RxWindow2Config;
+ MacCtx.RxWindowCConfig.RxContinuous = true;
+ MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C;
+
}
-static void OpenContinuousRx2Window( void )
+/*!
+ * \brief Initializes and opens the reception window
+ *
+ * \param [IN] rxTimer Window timer to be topped.
+ * \param [IN] rxConfig Window parameters to be setup
+ */
+static void RxWindowSetup( TimerEvent_t* rxTimer, RxConfigParams_t* rxConfig )
{
- OnRxWindow2TimerEvent( NULL );
- MacCtx.RxSlot = RX_SLOT_WIN_CLASS_C;
+ TimerStop( rxTimer );
+
+ // Ensure the radio is Idle
+ Radio.Standby( );
+
+ if( RegionRxConfig( MacCtx.NvmCtx->Region, rxConfig, ( int8_t* )&MacCtx.McpsIndication.RxDatarate ) == true )
+ {
+ Radio.Rx( MacCtx.NvmCtx->MacParams.MaxRxWindow );
+ MacCtx.RxSlot = rxConfig->RxSlot;
+ }
+}
+
+static void OpenContinuousRxCWindow( void )
+{
+ // Compute RxC windows parameters
+ RegionComputeRxWindowParameters( MacCtx.NvmCtx->Region,
+ MacCtx.NvmCtx->MacParams.RxCChannel.Datarate,
+ MacCtx.NvmCtx->MacParams.MinRxSymbols,
+ MacCtx.NvmCtx->MacParams.SystemMaxRxError,
+ &MacCtx.RxWindowCConfig );
+
+ MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C;
+ // Setup continuous listening
+ MacCtx.RxWindowCConfig.RxContinuous = true;
+
+ // At this point the Radio should be idle.
+ // Thus, there is no need to set the radio in standby mode.
+ if( RegionRxConfig( MacCtx.NvmCtx->Region, &MacCtx.RxWindowCConfig, ( int8_t* )&MacCtx.McpsIndication.RxDatarate ) == true )
+ {
+ Radio.Rx( 0 ); // Continuous mode
+ MacCtx.RxSlot = MacCtx.RxWindowCConfig.RxSlot;
+ }
}
LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t* macHdr, LoRaMacFrameCtrl_t* fCtrl, uint8_t fPort, void* fBuffer, uint16_t fBufferSize )
{
MacCtx.PktBufferLen = 0;
- MacCtx.NvmCtx->NodeAckRequested = false;
+ MacCtx.NodeAckRequested = false;
uint32_t fCntUp = 0;
size_t macCmdsSize = 0;
uint8_t availableSize = 0;
@@ -2597,7 +2745,7 @@ LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t* macHdr, LoRaMacFrameCtrl_t* fCtrl
switch( macHdr->Bits.MType )
{
case FRAME_TYPE_DATA_CONFIRMED_UP:
- MacCtx.NvmCtx->NodeAckRequested = true;
+ MacCtx.NodeAckRequested = true;
// Intentional fall through
case FRAME_TYPE_DATA_UNCONFIRMED_UP:
MacCtx.TxMsg.Type = LORAMAC_MSG_TYPE_DATA;
@@ -2610,11 +2758,11 @@ LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t* macHdr, LoRaMacFrameCtrl_t* fCtrl
MacCtx.TxMsg.Message.Data.FRMPayloadSize = MacCtx.AppDataSize;
MacCtx.TxMsg.Message.Data.FRMPayload = MacCtx.AppData;
- if( LORAMAC_FCNT_HANDLER_SUCCESS != LoRaMacGetFCntUp( &fCntUp ) )
+ if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoGetFCntUp( &fCntUp ) )
{
return LORAMAC_STATUS_FCNT_HANDLER_ERROR;
}
- MacCtx.TxMsg.Message.Data.FHDR.FCnt = ( uint16_t ) fCntUp;
+ MacCtx.TxMsg.Message.Data.FHDR.FCnt = ( uint16_t )fCntUp;
// Reset confirm parameters
MacCtx.McpsConfirm.NbRetries = 0;
@@ -2684,6 +2832,7 @@ LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t* macHdr, LoRaMacFrameCtrl_t* fCtrl
LoRaMacStatus_t SendFrameOnChannel( uint8_t channel )
{
+ LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
TxConfigParams_t txConfig;
int8_t txPower = 0;
@@ -2694,27 +2843,6 @@ LoRaMacStatus_t SendFrameOnChannel( uint8_t channel )
txConfig.AntennaGain = MacCtx.NvmCtx->MacParams.AntennaGain;
txConfig.PktLen = MacCtx.PktBufferLen;
-
- if( LoRaMacClassBIsBeaconExpected( ) == true )
- {
- return LORAMAC_STATUS_BUSY_BEACON_RESERVED_TIME;
- }
-
- if( MacCtx.NvmCtx->DeviceClass == CLASS_B )
- {
- if( LoRaMacClassBIsPingExpected( ) == true )
- {
- return LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME;
- }
- else if( LoRaMacClassBIsMulticastExpected( ) == true )
- {
- return LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME;
- }
- else
- {
- LoRaMacClassBStopRxSlots( );
- }
- }
RegionTxConfig( MacCtx.NvmCtx->Region, &txConfig, &txPower, &MacCtx.TxTimeOnAir );
MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
@@ -2738,9 +2866,26 @@ LoRaMacStatus_t SendFrameOnChannel( uint8_t channel )
}
}
+ if( MacCtx.NvmCtx->DeviceClass == CLASS_B )
+ {
+ // Stop slots for class b
+ LoRaMacClassBStopRxSlots( );
+ }
+
LoRaMacClassBHaltBeaconing( );
+ // Secure frame
+ status = SecureFrame( MacCtx.NvmCtx->MacParams.ChannelsDatarate, MacCtx.Channel );
+ if( status != LORAMAC_STATUS_OK )
+ {
+ return status;
+ }
+
MacCtx.MacState |= LORAMAC_TX_RUNNING;
+ if( MacCtx.NodeAckRequested == false )
+ {
+ MacCtx.ChannelsNbTransCounter++;
+ }
// Send now
Radio.Send( MacCtx.PktBuffer, MacCtx.PktBufferLen );
@@ -2752,7 +2897,7 @@ LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout )
{
ContinuousWaveParams_t continuousWave;
- continuousWave.Channel = MacCtx.NvmCtx->Channel;
+ continuousWave.Channel = MacCtx.Channel;
continuousWave.Datarate = MacCtx.NvmCtx->MacParams.ChannelsDatarate;
continuousWave.TxPower = MacCtx.NvmCtx->MacParams.ChannelsTxPower;
continuousWave.MaxEirp = MacCtx.NvmCtx->MacParams.MaxEirp;
@@ -2787,7 +2932,6 @@ LoRaMacCtxs_t* GetCtxs( void )
Contexts.CommandsNvmCtx = LoRaMacCommandsGetNvmCtx( &Contexts.CommandsNvmCtxSize );
Contexts.ClassBNvmCtx = LoRaMacClassBGetNvmCtx( &Contexts.ClassBNvmCtxSize );
Contexts.ConfirmQueueNvmCtx = LoRaMacConfirmQueueGetNvmCtx( &Contexts.ConfirmQueueNvmCtxSize );
- Contexts.FCntHandlerNvmCtx = LoRaMacFCntHandlerGetNvmCtx( &Contexts.FCntHandlerNvmCtxSize );
return &Contexts;
}
@@ -2812,6 +2956,13 @@ LoRaMacStatus_t RestoreCtxs( LoRaMacCtxs_t* contexts )
params.NvmCtx = contexts->RegionNvmCtx;
RegionInitDefaults( MacCtx.NvmCtx->Region, ¶ms );
+ // Initialize RxC config parameters.
+ MacCtx.RxWindowCConfig.Channel = MacCtx.Channel;
+ MacCtx.RxWindowCConfig.Frequency = MacCtx.NvmCtx->MacParams.RxCChannel.Frequency;
+ MacCtx.RxWindowCConfig.DownlinkDwellTime = MacCtx.NvmCtx->MacParams.DownlinkDwellTime;
+ MacCtx.RxWindowCConfig.RxContinuous = true;
+ MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C;
+
if( SecureElementRestoreNvmCtx( contexts->SecureElementNvmCtx ) != SECURE_ELEMENT_SUCCESS )
{
return LORAMAC_STATUS_CRYPTO_ERROR;
@@ -2822,11 +2973,6 @@ LoRaMacStatus_t RestoreCtxs( LoRaMacCtxs_t* contexts )
return LORAMAC_STATUS_CRYPTO_ERROR;
}
- if( LoRaMacFCntHandlerRestoreNvmCtx( contexts->FCntHandlerNvmCtx ) != LORAMAC_FCNT_HANDLER_SUCCESS )
- {
- return LORAMAC_STATUS_FCNT_HANDLER_ERROR;
- }
-
if( LoRaMacCommandsRestoreNvmCtx( contexts->CommandsNvmCtx ) != LORAMAC_COMMANDS_SUCCESS )
{
return LORAMAC_STATUS_MAC_COMMAD_ERROR;
@@ -2900,7 +3046,7 @@ LoRaMacStatus_t DetermineFrameType( LoRaMacMessageData_t* macMsg, FType_t* fType
static bool CheckRetransUnconfirmedUplink( void )
{
// Unconfirmed uplink, when all retransmissions are done.
- if( MacCtx.NvmCtx->ChannelsNbTransCounter >=
+ if( MacCtx.ChannelsNbTransCounter >=
MacCtx.NvmCtx->MacParams.ChannelsNbTrans )
{
return true;
@@ -2914,7 +3060,7 @@ static bool CheckRetransUnconfirmedUplink( void )
}
else
{// For Class B & C stop only if the frame was received in RX1 window
- if( MacCtx.RxSlot == RX_SLOT_WIN_1 )
+ if( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_1 )
{
return true;
}
@@ -2926,8 +3072,8 @@ static bool CheckRetransUnconfirmedUplink( void )
static bool CheckRetransConfirmedUplink( void )
{
// Confirmed uplink, when all retransmissions ( tries to get a ack ) are done.
- if( MacCtx.NvmCtx->AckTimeoutRetriesCounter >=
- MacCtx.NvmCtx->AckTimeoutRetries )
+ if( MacCtx.AckTimeoutRetriesCounter >=
+ MacCtx.AckTimeoutRetries )
{
return true;
}
@@ -2941,21 +3087,11 @@ static bool CheckRetransConfirmedUplink( void )
return false;
}
-
static bool StopRetransmission( void )
{
- // Increase the current value by 1
- uint32_t fCntUp = 0;
- if( LORAMAC_FCNT_HANDLER_SUCCESS != LoRaMacGetFCntUp( &fCntUp ) )
- {
- return false;
- }
- if( LORAMAC_FCNT_HANDLER_SUCCESS != LoRaMacSetFCntUp( ( fCntUp ) ) )
- {
- return false;
- }
-
- if( MacCtx.MacFlags.Bits.McpsInd == 0 )
+ if( ( MacCtx.MacFlags.Bits.McpsInd == 0 ) ||
+ ( ( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_1 ) &&
+ ( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_2 ) ) )
{ // Maximum repetitions without downlink. Increase ADR Ack counter.
// Only process the case when the MAC did not receive a downlink.
if( MacCtx.NvmCtx->AdrCtrlOn == true )
@@ -2964,9 +3100,9 @@ static bool StopRetransmission( void )
}
}
- MacCtx.NvmCtx->ChannelsNbTransCounter = 0;
- MacCtx.NvmCtx->NodeAckRequested = false;
- MacCtx.NvmCtx->AckTimeoutRetry = false;
+ MacCtx.ChannelsNbTransCounter = 0;
+ MacCtx.NodeAckRequested = false;
+ MacCtx.AckTimeoutRetry = false;
MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
return true;
@@ -2974,10 +3110,10 @@ static bool StopRetransmission( void )
static void AckTimeoutRetriesProcess( void )
{
- if( ( MacCtx.NvmCtx->AckTimeoutRetriesCounter < MacCtx.NvmCtx->AckTimeoutRetries ) && ( MacCtx.NvmCtx->AckTimeoutRetriesCounter <= MAX_ACK_RETRIES ) )
+ if( MacCtx.AckTimeoutRetriesCounter < MacCtx.AckTimeoutRetries )
{
- MacCtx.NvmCtx->AckTimeoutRetriesCounter++;
- if( ( MacCtx.NvmCtx->AckTimeoutRetriesCounter % 2 ) == 1 )
+ MacCtx.AckTimeoutRetriesCounter++;
+ if( ( MacCtx.AckTimeoutRetriesCounter % 2 ) == 1 )
{
GetPhyParams_t getPhy;
PhyParam_t phyParam;
@@ -3000,10 +3136,10 @@ static void AckTimeoutRetriesFinalize( void )
params.NvmCtx = Contexts.RegionNvmCtx;
RegionInitDefaults( MacCtx.NvmCtx->Region, ¶ms );
- MacCtx.NvmCtx->NodeAckRequested = false;
+ MacCtx.NodeAckRequested = false;
MacCtx.McpsConfirm.AckReceived = false;
}
- MacCtx.McpsConfirm.NbRetries = MacCtx.NvmCtx->AckTimeoutRetriesCounter;
+ MacCtx.McpsConfirm.NbRetries = MacCtx.AckTimeoutRetriesCounter;
}
static void CallNvmCtxCallback( LoRaMacNvmCtxModule_t module )
@@ -3049,11 +3185,6 @@ static void EventConfirmQueueNvmCtxChanged( void )
CallNvmCtxCallback( LORAMAC_NVMCTXMODULE_CONFIRM_QUEUE );
}
-static void EventFCntHandlerNvmCtxChanged( void )
-{
- CallNvmCtxCallback( LORAMAC_NVMCTXMODULE_FCNT_HANDLER );
-}
-
static uint8_t IsRequestPending( void )
{
if( ( MacCtx.MacFlags.Bits.MlmeReq == 1 ) ||
@@ -3100,18 +3231,13 @@ LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t* primitives, LoRaMacC
MacCtx.NvmCtx = &NvmMacCtx;
// Set non zero variables to its default value
- MacCtx.NvmCtx->AckTimeoutRetriesCounter = 1;
- MacCtx.NvmCtx->AckTimeoutRetries = 1;
+ MacCtx.AckTimeoutRetriesCounter = 1;
+ MacCtx.AckTimeoutRetries = 1;
MacCtx.NvmCtx->Region = region;
MacCtx.NvmCtx->DeviceClass = CLASS_A;
- MacCtx.NvmCtx->RepeaterSupport = false;
- Version_t lrWanVersion;
- lrWanVersion.Fields.Major = 1;
- lrWanVersion.Fields.Minor = 0;
- lrWanVersion.Fields.Revision = 3;
- lrWanVersion.Fields.Rfu = 0;
- MacCtx.NvmCtx->Version = lrWanVersion;
+ // Setup version
+ MacCtx.NvmCtx->Version.Value = LORAMAC_VERSION;
// Reset to defaults
getPhy.Attribute = PHY_DUTY_CYCLE;
@@ -3153,10 +3279,12 @@ LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t* primitives, LoRaMacC
getPhy.Attribute = PHY_DEF_RX2_FREQUENCY;
phyParam = RegionGetPhyParam( MacCtx.NvmCtx->Region, &getPhy );
MacCtx.NvmCtx->MacParamsDefaults.Rx2Channel.Frequency = phyParam.Value;
+ MacCtx.NvmCtx->MacParamsDefaults.RxCChannel.Frequency = phyParam.Value;
getPhy.Attribute = PHY_DEF_RX2_DR;
phyParam = RegionGetPhyParam( MacCtx.NvmCtx->Region, &getPhy );
MacCtx.NvmCtx->MacParamsDefaults.Rx2Channel.Datarate = phyParam.Value;
+ MacCtx.NvmCtx->MacParamsDefaults.RxCChannel.Datarate = phyParam.Value;
getPhy.Attribute = PHY_DEF_UPLINK_DWELL_TIME;
phyParam = RegionGetPhyParam( MacCtx.NvmCtx->Region, &getPhy );
@@ -3176,11 +3304,11 @@ LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t* primitives, LoRaMacC
getPhy.Attribute = PHY_DEF_ADR_ACK_LIMIT;
phyParam = RegionGetPhyParam( MacCtx.NvmCtx->Region, &getPhy );
- MacCtx.NvmCtx->AdrAckLimit = phyParam.Value;
+ MacCtx.AdrAckLimit = phyParam.Value;
getPhy.Attribute = PHY_DEF_ADR_ACK_DELAY;
phyParam = RegionGetPhyParam( MacCtx.NvmCtx->Region, &getPhy );
- MacCtx.NvmCtx->AdrAckDelay = phyParam.Value;
+ MacCtx.AdrAckDelay = phyParam.Value;
// Init parameters which are not set in function ResetMacParameters
MacCtx.NvmCtx->MacParamsDefaults.ChannelsNbTrans = 1;
@@ -3196,6 +3324,11 @@ LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t* primitives, LoRaMacC
MacCtx.NvmCtx->MacParams.JoinAcceptDelay2 = MacCtx.NvmCtx->MacParamsDefaults.JoinAcceptDelay2;
MacCtx.NvmCtx->MacParams.ChannelsNbTrans = MacCtx.NvmCtx->MacParamsDefaults.ChannelsNbTrans;
+ InitDefaultsParams_t params;
+ params.Type = INIT_TYPE_BANDS;
+ params.NvmCtx = NULL;
+ RegionInitDefaults( MacCtx.NvmCtx->Region, ¶ms );
+
ResetMacParameters( );
MacCtx.NvmCtx->PublicNetwork = true;
@@ -3206,8 +3339,8 @@ LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t* primitives, LoRaMacC
MacCtx.MacState = LORAMAC_STOPPED;
// Reset duty cycle times
- MacCtx.AggregatedLastTxDoneTime = 0;
- MacCtx.AggregatedTimeOff = 0;
+ MacCtx.NvmCtx->LastTxDoneTime = 0;
+ MacCtx.NvmCtx->AggregatedTimeOff = 0;
// Initialize timers
TimerInit( &MacCtx.TxDelayedTimer, OnTxDelayedTimerEvent );
@@ -3216,7 +3349,7 @@ LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t* primitives, LoRaMacC
TimerInit( &MacCtx.AckTimeoutTimer, OnAckTimeoutTimerEvent );
// Store the current initialization time
- MacCtx.InitializationTime = SysTimeGetMcuTime( );
+ MacCtx.NvmCtx->InitializationTime = SysTimeGetMcuTime( );
// Initialize Radio driver
MacCtx.RadioEvents.TxDone = OnRadioTxDone;
@@ -3226,11 +3359,6 @@ LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t* primitives, LoRaMacC
MacCtx.RadioEvents.RxTimeout = OnRadioRxTimeout;
Radio.Init( &MacCtx.RadioEvents );
- InitDefaultsParams_t params;
- params.Type = INIT_TYPE_INIT;
- params.NvmCtx = NULL;
- RegionInitDefaults( MacCtx.NvmCtx->Region, ¶ms );
-
// Initialize the Secure Element driver
if( SecureElementInit( EventSecureElementNvmCtxChanged ) != SECURE_ELEMENT_SUCCESS )
{
@@ -3249,14 +3377,11 @@ LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t* primitives, LoRaMacC
return LORAMAC_STATUS_MAC_COMMAD_ERROR;
}
- // Initialize FCnt Handler module
- if( LoRaMacFCntHandlerInit( EventFCntHandlerNvmCtxChanged ) != LORAMAC_FCNT_HANDLER_SUCCESS )
- {
- return LORAMAC_STATUS_FCNT_HANDLER_ERROR;
- }
-
// Set multicast downlink counter reference
- LoRaMacFCntHandlerSetMulticastReference( MacCtx.NvmCtx->MulticastChannelList );
+ if( LoRaMacCryptoSetMulticastReference( MacCtx.NvmCtx->MulticastChannelList ) != LORAMAC_CRYPTO_SUCCESS )
+ {
+ return LORAMAC_STATUS_CRYPTO_ERROR;
+ }
// Random seed initialization
srand1( Radio.Random( ) );
@@ -3299,7 +3424,7 @@ LoRaMacStatus_t LoRaMacStart( void )
LoRaMacStatus_t LoRaMacStop( void )
{
- if( LoRaMacIsBusy( ) == LORAMAC_FALSE )
+ if( LoRaMacIsBusy( ) == false )
{
MacCtx.MacState = LORAMAC_STOPPED;
return LORAMAC_STATUS_OK;
@@ -3329,8 +3454,8 @@ LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo )
adrNext.UpdateChanMask = false;
adrNext.AdrEnabled = MacCtx.NvmCtx->AdrCtrlOn;
adrNext.AdrAckCounter = MacCtx.NvmCtx->AdrAckCounter;
- adrNext.AdrAckLimit = MacCtx.NvmCtx->AdrAckLimit;
- adrNext.AdrAckDelay = MacCtx.NvmCtx->AdrAckDelay;
+ adrNext.AdrAckLimit = MacCtx.AdrAckLimit;
+ adrNext.AdrAckDelay = MacCtx.AdrAckDelay;
adrNext.Datarate = MacCtx.NvmCtx->MacParams.ChannelsDatarate;
adrNext.TxPower = MacCtx.NvmCtx->MacParams.ChannelsTxPower;
adrNext.UplinkDwellTime = MacCtx.NvmCtx->MacParams.UplinkDwellTime;
@@ -3392,6 +3517,21 @@ LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t* mibGet )
mibGet->Param.NetworkActivation = MacCtx.NvmCtx->NetworkActivation;
break;
}
+ case MIB_DEV_EUI:
+ {
+ mibGet->Param.DevEui = SecureElementGetDevEui( );
+ break;
+ }
+ case MIB_JOIN_EUI:
+ {
+ mibGet->Param.JoinEui = SecureElementGetJoinEui( );
+ break;
+ }
+ case MIB_SE_PIN:
+ {
+ mibGet->Param.JoinEui = SecureElementGetPin( );
+ break;
+ }
case MIB_ADR:
{
mibGet->Param.AdrEnable = MacCtx.NvmCtx->AdrCtrlOn;
@@ -3412,11 +3552,6 @@ LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t* mibGet )
mibGet->Param.EnablePublicNetwork = MacCtx.NvmCtx->PublicNetwork;
break;
}
- case MIB_REPEATER_SUPPORT:
- {
- mibGet->Param.EnableRepeaterSupport = MacCtx.NvmCtx->RepeaterSupport;
- break;
- }
case MIB_CHANNELS:
{
getPhy.Attribute = PHY_CHANNELS;
@@ -3435,6 +3570,16 @@ LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t* mibGet )
mibGet->Param.Rx2Channel = MacCtx.NvmCtx->MacParamsDefaults.Rx2Channel;
break;
}
+ case MIB_RXC_CHANNEL:
+ {
+ mibGet->Param.RxCChannel = MacCtx.NvmCtx->MacParams.RxCChannel;
+ break;
+ }
+ case MIB_RXC_DEFAULT_CHANNEL:
+ {
+ mibGet->Param.RxCChannel = MacCtx.NvmCtx->MacParamsDefaults.RxCChannel;
+ break;
+ }
case MIB_CHANNELS_DEFAULT_MASK:
{
getPhy.Attribute = PHY_CHANNELS_DEFAULT_MASK;
@@ -3526,6 +3671,12 @@ LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t* mibGet )
mibGet->Param.DefaultAntennaGain = MacCtx.NvmCtx->MacParamsDefaults.AntennaGain;
break;
}
+ case MIB_LORAWAN_VERSION:
+ {
+ mibGet->Param.LrWanVersion.LoRaWan = MacCtx.NvmCtx->Version;
+ mibGet->Param.LrWanVersion.LoRaWanRegion = RegionGetVersion( );
+ break;
+ }
default:
{
status = LoRaMacClassBMibGetRequestConfirm( mibGet );
@@ -3569,6 +3720,30 @@ LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t* mibSet )
}
break;
}
+ case MIB_DEV_EUI:
+ {
+ if( SecureElementSetDevEui( mibSet->Param.DevEui ) != SECURE_ELEMENT_SUCCESS )
+ {
+ status = LORAMAC_STATUS_PARAMETER_INVALID;
+ }
+ break;
+ }
+ case MIB_JOIN_EUI:
+ {
+ if( SecureElementSetJoinEui( mibSet->Param.JoinEui ) != SECURE_ELEMENT_SUCCESS )
+ {
+ status = LORAMAC_STATUS_PARAMETER_INVALID;
+ }
+ break;
+ }
+ case MIB_SE_PIN:
+ {
+ if( SecureElementSetPin( mibSet->Param.SePin ) != SECURE_ELEMENT_SUCCESS )
+ {
+ status = LORAMAC_STATUS_PARAMETER_INVALID;
+ }
+ break;
+ }
case MIB_ADR:
{
MacCtx.NvmCtx->AdrCtrlOn = mibSet->Param.AdrEnable;
@@ -3905,11 +4080,6 @@ LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t* mibSet )
Radio.SetPublicNetwork( MacCtx.NvmCtx->PublicNetwork );
break;
}
- case MIB_REPEATER_SUPPORT:
- {
- MacCtx.NvmCtx->RepeaterSupport = mibSet->Param.EnableRepeaterSupport;
- break;
- }
case MIB_RX2_CHANNEL:
{
verify.DatarateParams.Datarate = mibSet->Param.Rx2Channel.Datarate;
@@ -3918,22 +4088,6 @@ LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t* mibSet )
if( RegionVerify( MacCtx.NvmCtx->Region, &verify, PHY_RX_DR ) == true )
{
MacCtx.NvmCtx->MacParams.Rx2Channel = mibSet->Param.Rx2Channel;
-
- if( ( MacCtx.NvmCtx->DeviceClass == CLASS_C ) && ( MacCtx.NvmCtx->NetworkActivation != ACTIVATION_TYPE_NONE ) )
- {
- // We can only compute the RX window parameters directly, if we are already
- // in class c mode and joined. We cannot setup an RX window in case of any other
- // class type.
- // Set the radio into sleep mode in case we are still in RX mode
- Radio.Sleep( );
- // Compute Rx2 windows parameters
- RegionComputeRxWindowParameters( MacCtx.NvmCtx->Region,
- MacCtx.NvmCtx->MacParams.Rx2Channel.Datarate,
- MacCtx.NvmCtx->MacParams.MinRxSymbols,
- MacCtx.NvmCtx->MacParams.SystemMaxRxError,
- &MacCtx.RxWindow2Config );
- OpenContinuousRx2Window( );
- }
}
else
{
@@ -3956,9 +4110,50 @@ LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t* mibSet )
}
break;
}
+ case MIB_RXC_CHANNEL:
+ {
+ verify.DatarateParams.Datarate = mibSet->Param.RxCChannel.Datarate;
+ verify.DatarateParams.DownlinkDwellTime = MacCtx.NvmCtx->MacParams.DownlinkDwellTime;
+
+ if( RegionVerify( MacCtx.NvmCtx->Region, &verify, PHY_RX_DR ) == true )
+ {
+ MacCtx.NvmCtx->MacParams.RxCChannel = mibSet->Param.RxCChannel;
+
+ if( ( MacCtx.NvmCtx->DeviceClass == CLASS_C ) && ( MacCtx.NvmCtx->NetworkActivation != ACTIVATION_TYPE_NONE ) )
+ {
+ // We can only compute the RX window parameters directly, if we are already
+ // in class c mode and joined. We cannot setup an RX window in case of any other
+ // class type.
+ // Set the radio into sleep mode in case we are still in RX mode
+ Radio.Sleep( );
+
+ OpenContinuousRxCWindow( );
+ }
+ }
+ else
+ {
+ status = LORAMAC_STATUS_PARAMETER_INVALID;
+ }
+ break;
+ }
+ case MIB_RXC_DEFAULT_CHANNEL:
+ {
+ verify.DatarateParams.Datarate = mibSet->Param.RxCChannel.Datarate;
+ verify.DatarateParams.DownlinkDwellTime = MacCtx.NvmCtx->MacParams.DownlinkDwellTime;
+
+ if( RegionVerify( MacCtx.NvmCtx->Region, &verify, PHY_RX_DR ) == true )
+ {
+ MacCtx.NvmCtx->MacParamsDefaults.RxCChannel = mibSet->Param.RxCDefaultChannel;
+ }
+ else
+ {
+ status = LORAMAC_STATUS_PARAMETER_INVALID;
+ }
+ break;
+ }
case MIB_CHANNELS_DEFAULT_MASK:
{
- chanMaskSet.ChannelsMaskIn = mibSet->Param.ChannelsMask;
+ chanMaskSet.ChannelsMaskIn = mibSet->Param.ChannelsDefaultMask;
chanMaskSet.ChannelsMaskType = CHANNELS_DEFAULT_MASK;
if( RegionChanMaskSet( MacCtx.NvmCtx->Region, &chanMaskSet ) == false )
@@ -4176,21 +4371,156 @@ LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id )
return LORAMAC_STATUS_OK;
}
-LoRaMacStatus_t LoRaMacMulticastChannelSet( MulticastChannel_t channel )
+LoRaMacStatus_t LoRaMacMcChannelSetup( McChannelParams_t *channel )
{
if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
{
return LORAMAC_STATUS_BUSY;
}
- MacCtx.NvmCtx->MulticastChannelList[channel.AddrID].Address = channel.Address;
- MacCtx.NvmCtx->MulticastChannelList[channel.AddrID].IsEnabled = channel.IsEnabled;
- MacCtx.NvmCtx->MulticastChannelList[channel.AddrID].Frequency = channel.Frequency;
- MacCtx.NvmCtx->MulticastChannelList[channel.AddrID].Datarate = channel.Datarate;
- MacCtx.NvmCtx->MulticastChannelList[channel.AddrID].Periodicity = channel.Periodicity;
+ if( channel->GroupID >= LORAMAC_MAX_MC_CTX )
+ {
+ return LORAMAC_STATUS_MC_GROUP_UNDEFINED;
+ }
- // Calculate class b parameters
- LoRaMacClassBSetMulticastPeriodicity( &MacCtx.NvmCtx->MulticastChannelList[channel.AddrID] );
+ MacCtx.NvmCtx->MulticastChannelList[channel->GroupID].ChannelParams = *channel;
+
+ if( channel->IsRemotelySetup == true )
+ {
+ const KeyIdentifier_t mcKeys[LORAMAC_MAX_MC_CTX] = { MC_KEY_0, MC_KEY_1, MC_KEY_2, MC_KEY_3 };
+ if( LoRaMacCryptoSetKey( mcKeys[channel->GroupID], channel->McKeys.McKeyE ) != LORAMAC_CRYPTO_SUCCESS )
+ {
+ return LORAMAC_STATUS_CRYPTO_ERROR;
+ }
+
+ if( LoRaMacCryptoDeriveMcSessionKeyPair( channel->GroupID, channel->Address ) != LORAMAC_CRYPTO_SUCCESS )
+ {
+ return LORAMAC_STATUS_CRYPTO_ERROR;
+ }
+ }
+ else
+ {
+ const KeyIdentifier_t mcAppSKeys[LORAMAC_MAX_MC_CTX] = { MC_APP_S_KEY_0, MC_APP_S_KEY_1, MC_APP_S_KEY_2, MC_APP_S_KEY_3 };
+ const KeyIdentifier_t mcNwkSKeys[LORAMAC_MAX_MC_CTX] = { MC_NWK_S_KEY_0, MC_NWK_S_KEY_1, MC_NWK_S_KEY_2, MC_NWK_S_KEY_3 };
+ if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( mcAppSKeys[channel->GroupID], channel->McKeys.Session.McAppSKey ) )
+ {
+ return LORAMAC_STATUS_CRYPTO_ERROR;
+ }
+ if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( mcNwkSKeys[channel->GroupID], channel->McKeys.Session.McNwkSKey ) )
+ {
+ return LORAMAC_STATUS_CRYPTO_ERROR;
+ }
+ }
+
+ if( channel->Class == CLASS_B )
+ {
+ // Calculate class b parameters
+ LoRaMacClassBSetMulticastPeriodicity( &MacCtx.NvmCtx->MulticastChannelList[channel->GroupID] );
+ }
+
+ // Reset multicast channel downlink counter to initial value.
+ *MacCtx.NvmCtx->MulticastChannelList[channel->GroupID].DownLinkCounter = FCNT_DOWN_INITAL_VALUE;
+
+ EventMacNvmCtxChanged( );
+ EventRegionNvmCtxChanged( );
+ return LORAMAC_STATUS_OK;
+}
+
+LoRaMacStatus_t LoRaMacMcChannelDelete( AddressIdentifier_t groupID )
+{
+ if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
+ {
+ return LORAMAC_STATUS_BUSY;
+ }
+
+ if( ( groupID >= LORAMAC_MAX_MC_CTX ) ||
+ ( MacCtx.NvmCtx->MulticastChannelList[groupID].ChannelParams.IsEnabled == false ) )
+ {
+ return LORAMAC_STATUS_MC_GROUP_UNDEFINED;
+ }
+
+ McChannelParams_t channel;
+
+ // Set all channel fields with 0
+ memset1( ( uint8_t* )&channel, 0, sizeof( McChannelParams_t ) );
+
+ MacCtx.NvmCtx->MulticastChannelList[groupID].ChannelParams = channel;
+
+ EventMacNvmCtxChanged( );
+ EventRegionNvmCtxChanged( );
+ return LORAMAC_STATUS_OK;
+}
+
+uint8_t LoRaMacMcChannelGetGroupId( uint32_t mcAddress )
+{
+ for( uint8_t i = 0; i < LORAMAC_MAX_MC_CTX; i++ )
+ {
+ if( mcAddress == MacCtx.NvmCtx->MulticastChannelList[i].ChannelParams.Address )
+ {
+ return i;
+ }
+ }
+ return 0xFF;
+}
+
+LoRaMacStatus_t LoRaMacMcChannelSetupRxParams( AddressIdentifier_t groupID, McRxParams_t *rxParams, uint8_t *status )
+{
+ *status = 0x1C + ( groupID & 0x03 );
+
+ if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
+ {
+ return LORAMAC_STATUS_BUSY;
+ }
+
+ DeviceClass_t devClass = MacCtx.NvmCtx->MulticastChannelList[groupID].ChannelParams.Class;
+ if( ( devClass == CLASS_A ) || ( devClass > CLASS_C ) )
+ {
+ return LORAMAC_STATUS_PARAMETER_INVALID;
+ }
+
+ if( ( groupID >= LORAMAC_MAX_MC_CTX ) ||
+ ( MacCtx.NvmCtx->MulticastChannelList[groupID].ChannelParams.IsEnabled == false ) )
+ {
+ return LORAMAC_STATUS_MC_GROUP_UNDEFINED;
+ }
+ *status &= 0x0F; // groupID OK
+
+ VerifyParams_t verify;
+ // Check datarate
+ if( devClass == CLASS_B )
+ {
+ verify.DatarateParams.Datarate = rxParams->ClassB.Datarate;
+ }
+ else
+ {
+ verify.DatarateParams.Datarate = rxParams->ClassC.Datarate;
+ }
+ verify.DatarateParams.DownlinkDwellTime = MacCtx.NvmCtx->MacParams.DownlinkDwellTime;
+
+ if( RegionVerify( MacCtx.NvmCtx->Region, &verify, PHY_RX_DR ) == true )
+ {
+ *status &= 0xFB; // datarate OK
+ }
+
+ // Check frequency
+ if( devClass == CLASS_B )
+ {
+ verify.Frequency = rxParams->ClassB.Frequency;
+ }
+ else
+ {
+ verify.Frequency = rxParams->ClassC.Frequency;
+ }
+ if( RegionVerify( MacCtx.NvmCtx->Region, &verify, PHY_FREQUENCY ) == true )
+ {
+ *status &= 0xF7; // frequency OK
+ }
+
+ if( *status == ( groupID & 0x03 ) )
+ {
+ // Apply parameters
+ MacCtx.NvmCtx->MulticastChannelList[groupID].ChannelParams.RxParams = *rxParams;
+ }
EventMacNvmCtxChanged( );
EventRegionNvmCtxChanged( );
@@ -4207,7 +4537,7 @@ LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t* mlmeRequest )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
- if( LoRaMacIsBusy( ) == LORAMAC_TRUE )
+ if( LoRaMacIsBusy( ) == true )
{
return LORAMAC_STATUS_BUSY;
}
@@ -4236,19 +4566,8 @@ LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t* mlmeRequest )
return LORAMAC_STATUS_BUSY;
}
- if( ( mlmeRequest->Req.Join.DevEui == NULL ) ||
- ( mlmeRequest->Req.Join.JoinEui == NULL ) )
- {
- return LORAMAC_STATUS_PARAMETER_INVALID;
- }
-
- MacCtx.NvmCtx->NetworkActivation = ACTIVATION_TYPE_NONE;
-
ResetMacParameters( );
- MacCtx.DevEui = mlmeRequest->Req.Join.DevEui;
- MacCtx.JoinEui = mlmeRequest->Req.Join.JoinEui;
-
MacCtx.NvmCtx->MacParams.ChannelsDatarate = RegionAlternateDr( MacCtx.NvmCtx->Region, mlmeRequest->Req.Join.Datarate, ALTERNATE_DR );
queueElement.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
@@ -4295,15 +4614,18 @@ LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t* mlmeRequest )
}
case MLME_PING_SLOT_INFO:
{
- uint8_t value = mlmeRequest->Req.PingSlotInfo.PingSlot.Value;
-
- // LoRaMac will send this command piggy-pack
- LoRaMacClassBSetPingSlotInfo( mlmeRequest->Req.PingSlotInfo.PingSlot.Fields.Periodicity );
- macCmdPayload[0] = value;
- status = LORAMAC_STATUS_OK;
- if( LoRaMacCommandsAddCmd( MOTE_MAC_PING_SLOT_INFO_REQ, macCmdPayload, 1 ) != LORAMAC_COMMANDS_SUCCESS )
+ if( MacCtx.NvmCtx->DeviceClass == CLASS_A )
{
- status = LORAMAC_STATUS_MAC_COMMAD_ERROR;
+ uint8_t value = mlmeRequest->Req.PingSlotInfo.PingSlot.Value;
+
+ // LoRaMac will send this command piggy-pack
+ LoRaMacClassBSetPingSlotInfo( mlmeRequest->Req.PingSlotInfo.PingSlot.Fields.Periodicity );
+ macCmdPayload[0] = value;
+ status = LORAMAC_STATUS_OK;
+ if( LoRaMacCommandsAddCmd( MOTE_MAC_PING_SLOT_INFO_REQ, macCmdPayload, 1 ) != LORAMAC_COMMANDS_SUCCESS )
+ {
+ status = LORAMAC_STATUS_MAC_COMMAD_ERROR;
+ }
}
break;
}
@@ -4340,11 +4662,14 @@ LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t* mlmeRequest )
break;
}
+ // Fill return structure
+ mlmeRequest->ReqReturn.DutyCycleWaitTime = MacCtx.DutyCycleWaitTime;
+
if( status != LORAMAC_STATUS_OK )
{
if( LoRaMacConfirmQueueGetCnt( ) == 0 )
{
- MacCtx.NvmCtx->NodeAckRequested = false;
+ MacCtx.NodeAckRequested = false;
MacCtx.MacFlags.Bits.MlmeReq = 0;
}
}
@@ -4373,7 +4698,7 @@ LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t* mcpsRequest )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
- if( LoRaMacIsBusy( ) == LORAMAC_TRUE )
+ if( LoRaMacIsBusy( ) == true )
{
return LORAMAC_STATUS_BUSY;
}
@@ -4383,14 +4708,14 @@ LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t* mcpsRequest )
MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
// AckTimeoutRetriesCounter must be reset every time a new request (unconfirmed or confirmed) is performed.
- MacCtx.NvmCtx->AckTimeoutRetriesCounter = 1;
+ MacCtx.AckTimeoutRetriesCounter = 1;
switch( mcpsRequest->Type )
{
case MCPS_UNCONFIRMED:
{
readyToSend = true;
- MacCtx.NvmCtx->AckTimeoutRetries = 1;
+ MacCtx.AckTimeoutRetries = 1;
macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
fPort = mcpsRequest->Req.Unconfirmed.fPort;
@@ -4402,7 +4727,7 @@ LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t* mcpsRequest )
case MCPS_CONFIRMED:
{
readyToSend = true;
- MacCtx.NvmCtx->AckTimeoutRetries = mcpsRequest->Req.Confirmed.NbTrials;
+ MacCtx.AckTimeoutRetries = MIN( mcpsRequest->Req.Confirmed.NbTrials, MAX_ACK_RETRIES );
macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
fPort = mcpsRequest->Req.Confirmed.fPort;
@@ -4414,7 +4739,7 @@ LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t* mcpsRequest )
case MCPS_PROPRIETARY:
{
readyToSend = true;
- MacCtx.NvmCtx->AckTimeoutRetries = 1;
+ MacCtx.AckTimeoutRetries = 1;
macHdr.Bits.MType = FRAME_TYPE_PROPRIETARY;
fBuffer = mcpsRequest->Req.Proprietary.fBuffer;
@@ -4456,14 +4781,17 @@ LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t* mcpsRequest )
{
MacCtx.McpsConfirm.McpsRequest = mcpsRequest->Type;
MacCtx.MacFlags.Bits.McpsReq = 1;
+ EventMacNvmCtxChanged( );
}
else
{
- MacCtx.NvmCtx->NodeAckRequested = false;
+ MacCtx.NodeAckRequested = false;
}
}
- EventMacNvmCtxChanged( );
+ // Fill return structure
+ mcpsRequest->ReqReturn.DutyCycleWaitTime = MacCtx.DutyCycleWaitTime;
+
return status;
}
@@ -4478,3 +4806,32 @@ void LoRaMacTestSetDutyCycleOn( bool enable )
MacCtx.NvmCtx->DutyCycleOn = enable;
}
}
+
+LoRaMacStatus_t LoRaMacDeInitialization( void )
+{
+ // Check the current state of the LoRaMac
+ if ( LoRaMacStop( ) == LORAMAC_STATUS_OK )
+ {
+ // Stop Timers
+ TimerStop( &MacCtx.TxDelayedTimer );
+ TimerStop( &MacCtx.RxWindowTimer1 );
+ TimerStop( &MacCtx.RxWindowTimer2 );
+ TimerStop( &MacCtx.AckTimeoutTimer );
+
+ // Take care about class B
+ LoRaMacClassBHaltBeaconing( );
+
+ // Reset Mac parameters
+ ResetMacParameters( );
+
+ // Switch off Radio
+ Radio.Sleep( );
+
+ // Return success
+ return LORAMAC_STATUS_OK;
+ }
+ else
+ {
+ return LORAMAC_STATUS_BUSY;
+ }
+}
diff --git a/components/connectivity/LoraWAN/mac/LoRaMac.h b/components/connectivity/LoraWAN/mac/LoRaMac.h
index 879e298b..d9ccc468 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMac.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMac.h
@@ -36,6 +36,15 @@
* layer and the supported features.
* \{
*
+ * \example classA/B-L072Z-LRWAN1/main.c
+ * LoRaWAN class A application example for the B-L072Z-LRWAN1.
+ *
+ * \example classB/B-L072Z-LRWAN1/main.c
+ * LoRaWAN class B application example for the B-L072Z-LRWAN1.
+ *
+ * \example classC/B-L072Z-LRWAN1/main.c
+ * LoRaWAN class C application example for the B-L072Z-LRWAN1.
+ *
* \example classA/NAMote72/main.c
* LoRaWAN class A application example for the NAMote72.
*
@@ -63,10 +72,60 @@
* \example classC/NucleoL152/main.c
* LoRaWAN class C application example for the NucleoL152.
*
+ * \example classA/NucleoL476/main.c
+ * LoRaWAN class A application example for the NucleoL476.
+ *
+ * \example classB/NucleoL476/main.c
+ * LoRaWAN class B application example for the NucleoL476.
+ *
+ * \example classC/NucleoL476/main.c
+ * LoRaWAN class C application example for the NucleoL476.
+ *
+ * \example classA/SAMR34/main.c
+ * LoRaWAN class A application example for the SAMR34.
+ *
+ * \example classB/SAMR34/main.c
+ * LoRaWAN class B application example for the SAMR34.
+ *
+ * \example classC/SAMR34/main.c
+ * LoRaWAN class C application example for the SAMR34.
+ *
+ * \example classA/SKiM880B/main.c
+ * LoRaWAN class A application example for the SKiM880B.
+ *
+ * \example classB/SKiM880B/main.c
+ * LoRaWAN class B application example for the SKiM880B.
+ *
+ * \example classC/SKiM880B/main.c
+ * LoRaWAN class C application example for the SKiM880B.
+ *
+ * \example classA/SKiM881AXL/main.c
+ * LoRaWAN class A application example for the SKiM881AXL.
+ *
+ * \example classB/SKiM881AXL/main.c
+ * LoRaWAN class B application example for the SKiM881AXL.
+ *
+ * \example classC/SKiM881AXL/main.c
+ * LoRaWAN class C application example for the SKiM881AXL.
+ *
+ * \example classA/SKiM980A/main.c
+ * LoRaWAN class A application example for the SKiM980A.
+ *
+ * \example classB/SKiM980A/main.c
+ * LoRaWAN class B application example for the SKiM980A.
+ *
+ * \example classC/SKiM980A/main.c
+ * LoRaWAN class C application example for the SKiM980A.
+ *
*/
#ifndef __LORAMAC_H__
#define __LORAMAC_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include "utilities.h"
@@ -90,24 +149,11 @@
*/
#define DOWN_LINK 1
-/*!
- * Sets the length of the LoRaMAC footer field.
- * Mainly indicates the MIC field length
- */
-#define LORAMAC_MFR_LEN 4
-
/*!
* LoRaMac MLME-Confirm queue length
*/
#define LORA_MAC_MLME_CONFIRM_QUEUE_LEN 5
-/*!
- * FRMPayload overhead to be used when setting the Radio.SetMaxPayloadLength
- * in RxWindowSetup function.
- * Maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + LORA_MAC_FRMPAYLOAD_OVERHEAD
- */
-#define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4)
-
/*!
* Maximum number of multicast context
*/
@@ -116,34 +162,7 @@
/*!
* Start value for multicast keys enumeration
*/
-#define LORAMAC_CRYPTO_MULITCAST_KEYS 127
-
-/*!
- * LoRaWAN devices classes definition
- *
- * LoRaWAN Specification V1.0.2, chapter 2.1
- */
-typedef enum eDeviceClass
-{
- /*!
- * LoRaWAN device class A
- *
- * LoRaWAN Specification V1.0.2, chapter 3
- */
- CLASS_A = 0x00,
- /*!
- * LoRaWAN device class B
- *
- * LoRaWAN Specification V1.0.2, chapter 8
- */
- CLASS_B = 0x01,
- /*!
- * LoRaWAN device class C
- *
- * LoRaWAN Specification V1.0.2, chapter 17
- */
- CLASS_C = 0x02,
-}DeviceClass_t;
+#define LORAMAC_CRYPTO_MULTICAST_KEYS 127
/*!
* End-Device activation type
@@ -164,7 +183,6 @@ typedef enum eActivationType
ACTIVATION_TYPE_OTAA = 2,
}ActivationType_t;
-
/*!
* LoRaMAC channels parameters definition
*/
@@ -222,9 +240,9 @@ typedef struct sChannelParams
}ChannelParams_t;
/*!
- * LoRaMAC receive window 2 channel parameters
+ * LoRaMAC receive window channel parameters
*/
-typedef struct sRx2ChannelParams
+typedef struct sRxChannelParams
{
/*!
* Frequency in Hz
@@ -238,7 +256,7 @@ typedef struct sRx2ChannelParams
* The allowed ranges are region specific. Please refer to \ref DR_0 to \ref DR_15 for details.
*/
uint8_t Datarate;
-}Rx2ChannelParams_t;
+}RxChannelParams_t;
/*!
* LoRaMAC receive window enumeration
@@ -257,14 +275,22 @@ typedef enum eLoRaMacRxSlot
* LoRaMAC receive window 2 for class c - continuous listening
*/
RX_SLOT_WIN_CLASS_C,
+ /*!
+ * LoRaMAC class c multicast downlink
+ */
+ RX_SLOT_WIN_CLASS_C_MULTICAST,
/*!
* LoRaMAC class b ping slot window
*/
- RX_SLOT_WIN_PING_SLOT,
+ RX_SLOT_WIN_CLASS_B_PING_SLOT,
/*!
* LoRaMAC class b multicast slot window
*/
- RX_SLOT_WIN_MULTICAST_SLOT,
+ RX_SLOT_WIN_CLASS_B_MULTICAST_SLOT,
+ /*!
+ * LoRaMAC no active receive window
+ */
+ RX_SLOT_NONE,
}LoRaMacRxSlot_t;
/*!
@@ -328,14 +354,6 @@ typedef struct sLoRaMacCtxs
* \brief Size of MLME Confirm queue module context
*/
size_t ConfirmQueueNvmCtxSize;
- /*!
- * \brief Pointer to FCnt handler module context
- */
- void* FCntHandlerNvmCtx;
- /*!
- * \brief Size of FCnt handler module context
- */
- size_t FCntHandlerNvmCtxSize;
}LoRaMacCtxs_t;
/*!
@@ -393,7 +411,11 @@ typedef struct sLoRaMacParams
/*!
* LoRaMAC 2nd reception window settings
*/
- Rx2ChannelParams_t Rx2Channel;
+ RxChannelParams_t Rx2Channel;
+ /*!
+ * LoRaMAC continuous reception window settings
+ */
+ RxChannelParams_t RxCChannel;
/*!
* Uplink dwell time configuration. 0: No limit, 1: 400ms
*/
@@ -410,44 +432,8 @@ typedef struct sLoRaMacParams
* Antenna gain of the node
*/
float AntennaGain;
- /*!
- * Indicates if the node supports repeaters
- */
- bool RepeaterSupport;
}LoRaMacParams_t;
-/*!
- * Multicast channel
- */
-typedef struct sMulticastChannel
-{
- /*
- * Address identifier
- */
- AddressIdentifier_t AddrID;
- /*!
- * Address
- */
- uint32_t Address;
- /*!
- * True if the entry is active
- */
- bool IsEnabled;
- /*!
- * Reception frequency of the ping slot windows
- */
- uint32_t Frequency;
- /*!
- * Datarate of the ping slot
- */
- int8_t Datarate;
- /*!
- * This parameter is necessary for class b operation. It defines the
- * periodicity of the multicast downlink slots
- */
- uint16_t Periodicity;
-}MulticastChannel_t;
-
/*!
* LoRaMAC data structure for a PingSlotInfoReq \ref MLME_PING_SLOT_INFO
*
@@ -487,7 +473,7 @@ typedef struct sBeaconInfo
* Timestamp in seconds since 00:00:00, Sunday 6th of January 1980
* (start of the GPS epoch) modulo 2^32
*/
- uint32_t Time;
+ SysTime_t Time;
/*!
* Frequency
*/
@@ -616,23 +602,27 @@ typedef union eLoRaMacFlags_t
/*!
* MCPS-Req pending
*/
- uint8_t McpsReq : 1;
+ uint8_t McpsReq : 1;
/*!
* MCPS-Ind pending
*/
- uint8_t McpsInd : 1;
+ uint8_t McpsInd : 1;
/*!
* MLME-Req pending
*/
- uint8_t MlmeReq : 1;
+ uint8_t MlmeReq : 1;
/*!
* MLME-Ind pending
*/
- uint8_t MlmeInd : 1;
+ uint8_t MlmeInd : 1;
+ /*!
+ * MLME-Ind to schedule an uplink pending
+ */
+ uint8_t MlmeSchedUplinkInd : 1;
/*!
* MAC cycle done
*/
- uint8_t MacDone : 1;
+ uint8_t MacDone : 1;
}Bits;
}LoRaMacFlags_t;
@@ -679,6 +669,19 @@ typedef enum eMcps
MCPS_PROPRIETARY,
}Mcps_t;
+/*!
+ * Structure which defines return parameters for requests.
+ */
+typedef struct sRequestReturnParam
+{
+ /*!
+ * This value reports the time in milliseconds which
+ * an application must wait before its possible to send
+ * the next uplink.
+ */
+ TimerTime_t DutyCycleWaitTime;
+}RequestReturnParam_t;
+
/*!
* LoRaMAC MCPS-Request for an unconfirmed frame
*/
@@ -799,6 +802,11 @@ typedef struct sMcpsReq
*/
McpsReqProprietary_t Proprietary;
}Req;
+
+ /*!
+ * MCPS-Request return parameters
+ */
+ RequestReturnParam_t ReqReturn;
}McpsReq_t;
/*!
@@ -909,6 +917,10 @@ typedef struct sMcpsIndication
* The device address of the frame
*/
uint32_t DevAddress;
+ /*!
+ * Set if a DeviceTimeAns MAC command was received.
+ */
+ bool DeviceTimeAnsReceived;
}McpsIndication_t;
/*!
@@ -937,6 +949,10 @@ typedef struct sMcpsIndication
*/
typedef enum eMlme
{
+ /*!
+ * An unknown MLME service
+ */
+ MLME_UNKNOWN,
/*!
* Initiates the Over-the-Air activation
*
@@ -1033,18 +1049,6 @@ typedef enum eMlme
*/
typedef struct sMlmeReqJoin
{
- /*!
- * Globally unique end-device identifier
- *
- * LoRaWAN Specification V1.1.0, chapter 6.1.1.2
- */
- uint8_t* DevEui;
- /*!
- * Join Sever identifier
- *
- * LoRaWAN Specification V1.1.0, chapter 6.1.1.1
- */
- uint8_t* JoinEui;
/*!
* Datarate used for join request.
*/
@@ -1105,7 +1109,7 @@ typedef struct sMlmeReqDeriveMcSessionKeyPair
/*!
* Address identifier to select the multicast group
*/
- AddressIdentifier_t AddrID;
+ AddressIdentifier_t GroupID;
}MlmeReqDeriveMcSessionKeyPair_t;
/*!
@@ -1144,6 +1148,11 @@ typedef struct sMlmeReq
*/
MlmeReqDeriveMcSessionKeyPair_t DeriveMcSessionKeyPair;
}Req;
+
+ /*!
+ * MLME-Request return parameters
+ */
+ RequestReturnParam_t ReqReturn;
}MlmeReq_t;
/*!
@@ -1216,6 +1225,9 @@ typedef struct sMlmeIndication
* ----------------------------------------------| :-: | :-:
* \ref MIB_DEVICE_CLASS | YES | YES
* \ref MIB_NETWORK_ACTIVATION | YES | YES
+ * \ref MIB_DEV_EUI | YES | YES
+ * \ref MIB_JOIN_EUI | YES | YES
+ * \ref MIB_SE_PIN | YES | YES
* \ref MIB_ADR | YES | YES
* \ref MIB_NET_ID | YES | YES
* \ref MIB_DEV_ADDR | YES | YES
@@ -1241,9 +1253,11 @@ typedef struct sMlmeIndication
* \ref MIB_MC_APP_S_KEY_3 | NO | YES
* \ref MIB_MC_NWK_S_KEY_3 | NO | YES
* \ref MIB_PUBLIC_NETWORK | YES | YES
- * \ref MIB_REPEATER_SUPPORT | YES | YES
* \ref MIB_CHANNELS | YES | NO
* \ref MIB_RX2_CHANNEL | YES | YES
+ * \ref MIB_RX2_DFAULT_CHANNEL | YES | YES
+ * \ref MIB_RXC_CHANNEL | YES | YES
+ * \ref MIB_RXC_DFAULT_CHANNEL | YES | YES
* \ref MIB_CHANNELS_MASK | YES | YES
* \ref MIB_CHANNELS_DEFAULT_MASK | YES | YES
* \ref MIB_CHANNELS_NB_TRANS | YES | YES
@@ -1273,7 +1287,8 @@ typedef struct sMlmeIndication
* \ref MIB_ANTENNA_GAIN | YES | YES
* \ref MIB_DEFAULT_ANTENNA_GAIN | YES | YES
* \ref MIB_NVM_CTXS | YES | YES
- * \ref MIB_ABP_LORAWAN_VERSION | YES | YES
+ * \ref MIB_ABP_LORAWAN_VERSION | NO | YES
+ * \ref MIB_LORAWAN_VERSION | YES | NO
*
* The following table provides links to the function implementations of the
* related MIB primitives:
@@ -1297,6 +1312,22 @@ typedef enum eMib
* LoRaWAN Specification V1.0.2
*/
MIB_NETWORK_ACTIVATION,
+ /*!
+ * LoRaWAN device EUI
+ *
+ * LoRaWAN Specification V1.0.2
+ */
+ MIB_DEV_EUI,
+ /*!
+ * LoRaWAN join EUI
+ *
+ * LoRaWAN Specification V1.0.2
+ */
+ MIB_JOIN_EUI,
+ /*!
+ * Secure-element pin
+ */
+ MIB_SE_PIN,
/*!
* Adaptive data rate
*
@@ -1451,14 +1482,6 @@ typedef enum eMib
* [true: public network, false: private network]
*/
MIB_PUBLIC_NETWORK,
- /*!
- * Support the operation with repeaters
- *
- * LoRaWAN Regional Parameters V1.0.2rB
- *
- * [true: repeater support enabled, false: repeater support disabled]
- */
- MIB_REPEATER_SUPPORT,
/*!
* Communication channels. A get request will return a
* pointer which references the first entry of the channel list. The
@@ -1479,6 +1502,18 @@ typedef enum eMib
* LoRaWAN Specification V1.0.2, chapter 3.3.2
*/
MIB_RX2_DEFAULT_CHANNEL,
+ /*!
+ * Set receive window C channel
+ *
+ * LoRaWAN Specification V1.0.2, chapter 3.3.1
+ */
+ MIB_RXC_CHANNEL,
+ /*!
+ * Set receive window C channel
+ *
+ * LoRaWAN Specification V1.0.2, chapter 3.3.2
+ */
+ MIB_RXC_DEFAULT_CHANNEL,
/*!
* LoRaWAN channels mask
*
@@ -1575,7 +1610,7 @@ typedef enum eMib
* The antenna gain is used to calculate the TX power of the node.
* The formula is:
* radioTxPower = ( int8_t )floor( maxEirp - antennaGain )
- *
+ *
* \remark The antenna gain value is referenced to the isotropic antenna.
* The value is in dBi.
* MIB_ANTENNA_GAIN[dBi] = measuredAntennaGain[dBd] + 2.15
@@ -1586,7 +1621,7 @@ typedef enum eMib
* The antenna gain is used to calculate the TX power of the node.
* The formula is:
* radioTxPower = ( int8_t )floor( maxEirp - antennaGain )
- *
+ *
* \remark The antenna gain value is referenced to the isotropic antenna.
* The value is in dBi.
* MIB_DEFAULT_ANTENNA_GAIN[dBi] = measuredAntennaGain[dBd] + 2.15
@@ -1600,6 +1635,10 @@ typedef enum eMib
* LoRaWAN MAC layer operating version when activated by ABP.
*/
MIB_ABP_LORAWAN_VERSION,
+ /*!
+ * LoRaWAN MAC and regional parameter version.
+ */
+ MIB_LORAWAN_VERSION,
/*!
* Beacon interval in ms
*/
@@ -1677,6 +1716,24 @@ typedef union uMibParam
* Related MIB type: \ref MIB_NETWORK_ACTIVATION
*/
ActivationType_t NetworkActivation;
+ /*!
+ * LoRaWAN device EUI
+ *
+ * Related MIB type: \ref MIB_DEV_EUI
+ */
+ uint8_t* DevEui;
+ /*!
+ * LoRaWAN Join server EUI
+ *
+ * Related MIB type: \ref MIB_JOIN_EUI
+ */
+ uint8_t* JoinEui;
+ /*!
+ * Secure-element pin
+ *
+ * Related MIB type: \ref MIB_SE_PIN
+ */
+ uint8_t* SePin;
/*!
* Activation state of ADR
*
@@ -1827,12 +1884,6 @@ typedef union uMibParam
* Related MIB type: \ref MIB_PUBLIC_NETWORK
*/
bool EnablePublicNetwork;
- /*!
- * Enable or disable repeater support
- *
- * Related MIB type: \ref MIB_REPEATER_SUPPORT
- */
- bool EnableRepeaterSupport;
/*!
* LoRaWAN Channel
*
@@ -1844,13 +1895,25 @@ typedef union uMibParam
*
* Related MIB type: \ref MIB_RX2_CHANNEL
*/
- Rx2ChannelParams_t Rx2Channel;
+ RxChannelParams_t Rx2Channel;
/*!
* Channel for the receive window 2
*
* Related MIB type: \ref MIB_RX2_DEFAULT_CHANNEL
*/
- Rx2ChannelParams_t Rx2DefaultChannel;
+ RxChannelParams_t Rx2DefaultChannel;
+ /*!
+ * Channel for the receive window C
+ *
+ * Related MIB type: \ref MIB_RXC_CHANNEL
+ */
+ RxChannelParams_t RxCChannel;
+ /*!
+ * Channel for the receive window C
+ *
+ * Related MIB type: \ref MIB_RXC_DEFAULT_CHANNEL
+ */
+ RxChannelParams_t RxCDefaultChannel;
/*!
* Channel mask
*
@@ -1928,7 +1991,7 @@ typedef union uMibParam
*
* Related MIB type: \ref MIB_MULTICAST_CHANNEL
*/
- MulticastChannel_t MulticastChannel;
+ McChannelParams_t MulticastChannel;
/*!
* System overall timing error in milliseconds.
*
@@ -1965,6 +2028,16 @@ typedef union uMibParam
* Related MIB type: \ref MIB_ABP_LORAWAN_VERSION
*/
Version_t AbpLrWanVersion;
+ /*
+ * LoRaWAN MAC regional parameter version.
+ *
+ * Related MIB type: \ref MIB_LORAWAN_VERSION
+ */
+ struct sLrWanVersion
+ {
+ Version_t LoRaWan;
+ Version_t LoRaWanRegion;
+ }LrWanVersion;
/*!
* Beacon interval in ms
*
@@ -2131,7 +2204,17 @@ typedef enum eLoRaMacStatus
*/
LORAMAC_STATUS_SKIPPED_APP_DATA,
/*!
- * ToDo
+ * An MCPS or MLME request can return this status. In this case,
+ * the MAC cannot send the frame, as the duty cycle limits all
+ * available bands. When a request returns this value, the
+ * variable "DutyCycleWaitTime" in "ReqReturn" of the input
+ * parameters contains the remaining time to wait. If the
+ * value is constant and does not change, the expected time
+ * on air for this frame is exceeding the maximum permitted
+ * time according to the duty cycle time period, defined
+ * in Region.h, DUTY_CYCLE_TIME_PERIOD. By default this time
+ * is 1 hour, and a band with 1% duty cycle is then allowed
+ * to use an air time of 36 seconds.
*/
LORAMAC_STATUS_DUTYCYCLE_RESTRICTED,
/*!
@@ -2175,7 +2258,11 @@ typedef enum eLoRaMacStatus
*/
LORAMAC_STATUS_CONFIRM_QUEUE_ERROR,
/*!
- * Undefined error occured
+ * The multicast group doesn't exist
+ */
+ LORAMAC_STATUS_MC_GROUP_UNDEFINED,
+ /*!
+ * Undefined error occurred
*/
LORAMAC_STATUS_ERROR
}LoRaMacStatus_t;
@@ -2260,10 +2347,6 @@ typedef enum LoRaMacNvmCtxModule_e
* Context for the confirm queue
*/
LORAMAC_NVMCTXMODULE_CONFIRM_QUEUE,
- /*!
- * Context for the frame count handler
- */
- LORAMAC_NVMCTXMODULE_FCNT_HANDLER
}LoRaMacNvmCtxModule_t;
@@ -2328,7 +2411,7 @@ typedef struct sLoRaMacCallback
/*!
*\brief Will be called each time a Radio IRQ is handled by the MAC
* layer.
- *
+ *
*\warning Runs in a IRQ context. Should only change variables state.
*/
void ( *MacProcessNotify )( void );
@@ -2382,6 +2465,13 @@ LoRaMacStatus_t LoRaMacStart( void );
*/
LoRaMacStatus_t LoRaMacStop( void );
+/*!
+ * \brief Returns a value indicating if the MAC layer is busy or not.
+ *
+ * \retval isBusy Mac layer is busy.
+ */
+bool LoRaMacIsBusy( void );
+
/*!
* Processes the LoRaMac events.
*
@@ -2449,18 +2539,60 @@ LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params );
LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id );
/*!
- * \brief LoRaMAC multicast channel setting service
+ * \brief LoRaMAC multicast channel setup service
*
- * \details Sets a multicast channel.
+ * \details Sets up a multicast channel.
*
* \param [IN] channel - Multicast channel to set.
*
* \retval LoRaMacStatus_t Status of the operation. Possible returns are:
* \ref LORAMAC_STATUS_OK,
* \ref LORAMAC_STATUS_BUSY,
- * \ref LORAMAC_STATUS_PARAMETER_INVALID.
+ * \ref LORAMAC_STATUS_PARAMETER_INVALID,
+ * \ref LORAMAC_STATUS_MC_GROUP_UNDEFINED.
*/
-LoRaMacStatus_t LoRaMacMulticastChannelSet( MulticastChannel_t channel );
+LoRaMacStatus_t LoRaMacMcChannelSetup( McChannelParams_t *channel );
+
+/*!
+ * \brief LoRaMAC multicast channel removal service
+ *
+ * \details Removes/Disables a multicast channel.
+ *
+ * \param [IN] groupID - Multicast channel ID to be removed/disabled
+ *
+ * \retval LoRaMacStatus_t Status of the operation. Possible returns are:
+ * \ref LORAMAC_STATUS_OK,
+ * \ref LORAMAC_STATUS_BUSY,
+ * \ref LORAMAC_STATUS_MC_GROUP_UNDEFINED.
+ */
+LoRaMacStatus_t LoRaMacMcChannelDelete( AddressIdentifier_t groupID );
+
+/*!
+ * \brief LoRaMAC multicast channel get groupId from MC address.
+ *
+ * \param [IN] mcAddress - Multicast address to be checked
+ *
+ * \retval groupID Multicast channel ID associated to the address.
+ * Returns 0xFF if the address isn't found.
+ */
+uint8_t LoRaMacMcChannelGetGroupId( uint32_t mcAddress );
+
+/*!
+ * \brief LoRaMAC multicast channel Rx parameters setup service
+ *
+ * \details Sets up a multicast channel reception parameters.
+ *
+ * \param [IN] groupID - Multicast channel ID
+ * \param [IN] rxParams - Reception parameters
+ * \param [OUT] status - Status mask [UNDEF_ID | FREQ_ERR | DR_ERR | GROUP_ID]
+ *
+ * \retval LoRaMacStatus_t Status of the operation. Possible returns are:
+ * \ref LORAMAC_STATUS_OK,
+ * \ref LORAMAC_STATUS_BUSY,
+ * \ref LORAMAC_STATUS_PARAMETER_INVALID,
+ * \ref LORAMAC_STATUS_MC_GROUP_UNDEFINED.
+ */
+LoRaMacStatus_t LoRaMacMcChannelSetupRxParams( AddressIdentifier_t groupID, McRxParams_t *rxParams, uint8_t *status );
/*!
* \brief LoRaMAC MIB-Get
@@ -2526,32 +2658,15 @@ LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t* mibSet );
*
* \details The Mac layer management entity handles management services. The
* following code-snippet shows how to use the API to perform a
- * network join request.
+ * network join request. Please note that for a join request, the
+ * DevEUI and the JoinEUI must be set previously via the MIB. Please
+ * also refer to the sample implementations.
*
* \code
- * static uint8_t DevEui[] =
- * {
- * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- * };
- * static uint8_t JoinEui[] =
- * {
- * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- * };
- * static uint8_t NwkKey[] =
- * {
- * 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
- * 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
- * };
- * static uint8_t AppKey[] =
- * {
- * 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
- * 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
- * };
*
* MlmeReq_t mlmeReq;
* mlmeReq.Type = MLME_JOIN;
- * mlmeReq.Req.Join.DevEui = DevEui;
- * mlmeReq.Req.Join.JoinEui = JoinEui;
+ * mlmeReq.Req.Join.Datarate = LORAWAN_DEFAULT_DATARATE;
*
* if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK )
* {
@@ -2605,6 +2720,18 @@ LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t* mlmeRequest );
*/
LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t* mcpsRequest );
+/*!
+ * \brief LoRaMAC deinitialization
+ *
+ * \details This function stops the timers, re-initializes MAC & regional parameters to default
+ * and sets radio into sleep state.
+ *
+ * \retval LoRaMacStatus_t Status of the operation. Possible returns are:
+ * \ref LORAMAC_STATUS_OK,
+ * \ref LORAMAC_STATUS_BUSY
+ */
+LoRaMacStatus_t LoRaMacDeInitialization( void );
+
/*!
* Automatically add the Region.h file at the end of LoRaMac.h file.
* This is required because Region.h uses definitions from LoRaMac.h
@@ -2613,4 +2740,8 @@ LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t* mcpsRequest );
/*! \} defgroup LORAMAC */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMAC_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacAdr.c b/components/connectivity/LoraWAN/mac/LoRaMacAdr.c
index c1cfc396..5d0a3e01 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacAdr.c
+++ b/components/connectivity/LoraWAN/mac/LoRaMacAdr.c
@@ -65,10 +65,6 @@ static bool CalcNextV10X( CalcNextAdrParams_t* adrNext, int8_t* drOut, int8_t* t
if( adrNext->AdrAckCounter >= adrNext->AdrAckLimit )
{
adrAckReq = true;
- // Set TX Power to maximum
- getPhy.Attribute = PHY_MAX_TX_POWER;
- phyParam = RegionGetPhyParam( adrNext->Region, &getPhy );
- txPower = phyParam.Value;
}
else
{
@@ -76,6 +72,11 @@ static bool CalcNextV10X( CalcNextAdrParams_t* adrNext, int8_t* drOut, int8_t* t
}
if( adrNext->AdrAckCounter >= ( adrNext->AdrAckLimit + adrNext->AdrAckDelay ) )
{
+ // Set TX Power to maximum
+ getPhy.Attribute = PHY_MAX_TX_POWER;
+ phyParam = RegionGetPhyParam( adrNext->Region, &getPhy );
+ txPower = phyParam.Value;
+
if( ( adrNext->AdrAckCounter % adrNext->AdrAckDelay ) == 1 )
{
// Decrease the datarate
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacAdr.h b/components/connectivity/LoraWAN/mac/LoRaMacAdr.h
index 228df763..4e0ea87f 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacAdr.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMacAdr.h
@@ -37,6 +37,11 @@
#ifndef __LORAMACADR_H__
#define __LORAMACADR_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
/*! \} defgroup LORAMACADR */
/*
@@ -101,4 +106,8 @@ typedef struct sCalcNextAdrParams
*/
bool LoRaMacAdrCalcNext( CalcNextAdrParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMACADR_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacClassB.c b/components/connectivity/LoraWAN/mac/LoRaMacClassB.c
index 49989c51..ba9f9dea 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacClassB.c
+++ b/components/connectivity/LoraWAN/mac/LoRaMacClassB.c
@@ -28,11 +28,89 @@ Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jae
#ifdef LORAMAC_CLASSB_ENABLED
+
+/*
+ * LoRaMac Class B Context structure for NVM parameters
+ * related to ping slots
+ */
+typedef struct sLoRaMacClassBPingSlotNvmCtx
+{
+ struct sPingSlotCtrlNvm
+ {
+ /*!
+ * Set when the server assigned a ping slot to the node
+ */
+ uint8_t Assigned : 1;
+ /*!
+ * Set when a custom frequency is used
+ */
+ uint8_t CustomFreq : 1;
+ }Ctrl;
+ /*!
+ * Number of ping slots
+ */
+ uint8_t PingNb;
+ /*!
+ * Period of the ping slots
+ */
+ uint16_t PingPeriod;
+ /*!
+ * Reception frequency of the ping slot windows
+ */
+ uint32_t Frequency;
+ /*!
+ * Datarate of the ping slot
+ */
+ int8_t Datarate;
+} LoRaMacClassBPingSlotNvmCtx_t;
+
+/*
+ * LoRaMac Class B Context structure for NVM parameters
+ * related to beaconing
+ */
+typedef struct sLoRaMacClassBBeaconNvmCtx
+{
+ struct sBeaconCtrlNvm
+ {
+ /*!
+ * Set if the node has a custom frequency for beaconing and ping slots
+ */
+ uint8_t CustomFreq : 1;
+ }Ctrl;
+ /*!
+ * Beacon reception frequency
+ */
+ uint32_t Frequency;
+} LoRaMacClassBBeaconNvmCtx_t;
+
/*
* LoRaMac Class B Context structure
*/
typedef struct sLoRaMacClassBNvmCtx
{
+ /*!
+ * Class B ping slot context
+ */
+ LoRaMacClassBPingSlotNvmCtx_t PingSlotCtx;
+ /*!
+ * Class B beacon context
+ */
+ LoRaMacClassBBeaconNvmCtx_t BeaconCtx;
+} LoRaMacClassBNvmCtx_t;
+
+/*
+ * LoRaMac Class B Context structure
+ */
+typedef struct sLoRaMacClassBCtx
+{
+ /*!
+ * Class B ping slot context
+ */
+ PingSlotContext_t PingSlotCtx;
+ /*!
+ * Class B beacon context
+ */
+ BeaconContext_t BeaconCtx;
/*!
* State of the beaconing mechanism
*/
@@ -45,21 +123,6 @@ typedef struct sLoRaMacClassBNvmCtx
* State of the multicast slot mechanism
*/
PingSlotState_t MulticastSlotState;
- /*!
- * Class B ping slot context
- */
- PingSlotContext_t PingSlotCtx;
- /*!
- * Class B beacon context
- */
- BeaconContext_t BeaconCtx;
-} LoRaMacClassBNvmCtx_t;
-
-/*
- * LoRaMac Class B Context structure
- */
-typedef struct sLoRaMacClassBCtx
-{
/*!
* Timer for CLASS B beacon acquisition and tracking.
*/
@@ -84,7 +147,7 @@ typedef struct sLoRaMacClassBCtx
/*
* Callback function to notify the upper layer about context change
*/
- EventNvmCtxChanged EventNvmCtxChanged;
+ LoRaMacClassBNvmEvent LoRaMacClassBNvmEvent;
/*!
* Non-volatile module context.
*/
@@ -127,7 +190,6 @@ static LoRaMacClassBCtx_t Ctx;
*/
static void ComputePingOffset( uint64_t beaconTime, uint32_t address, uint16_t pingPeriod, uint16_t *pingOffset )
{
- uint8_t zeroKey[16];
uint8_t buffer[16];
uint8_t cipher[16];
uint32_t result = 0;
@@ -136,7 +198,6 @@ static void ComputePingOffset( uint64_t beaconTime, uint32_t address, uint16_t p
*/
uint32_t time = ( beaconTime % ( ( ( uint64_t ) 1 ) << 32 ) );
- memset1( zeroKey, 0, 16 );
memset1( buffer, 0, 16 );
memset1( cipher, 0, 16 );
@@ -150,8 +211,6 @@ static void ComputePingOffset( uint64_t beaconTime, uint32_t address, uint16_t p
buffer[6] = ( address >> 16 ) & 0xFF;
buffer[7] = ( address >> 24 ) & 0xFF;
- SecureElementSetKey( SLOT_RAND_ZERO_KEY, zeroKey );
-
SecureElementAesEncrypt( buffer, 16, SLOT_RAND_ZERO_KEY, cipher );
result = ( ( ( uint32_t ) cipher[0] ) + ( ( ( uint32_t ) cipher[1] ) * 256 ) );
@@ -164,51 +223,64 @@ static void ComputePingOffset( uint64_t beaconTime, uint32_t address, uint16_t p
*
* \param [IN] channel The channel according to the channel plan.
*
+ * \param [IN] isBeacon Set to true, if the function shall
+ * calculate the frequency for a beacon.
+ *
* \retval The downlink frequency
*/
-static uint32_t CalcDownlinkFrequency( uint8_t channel )
+static uint32_t CalcDownlinkFrequency( uint8_t channel, bool isBeacon )
{
GetPhyParams_t getPhy;
PhyParam_t phyParam;
- uint32_t frequency = 0;
- uint32_t stepwidth = 0;
- getPhy.Attribute = PHY_BEACON_CHANNEL_FREQ;
+ getPhy.Attribute = PHY_PING_SLOT_CHANNEL_FREQ;
+
+ if( isBeacon == true )
+ {
+ getPhy.Attribute = PHY_BEACON_CHANNEL_FREQ;
+ }
+ getPhy.Channel = channel;
phyParam = RegionGetPhyParam( *Ctx.LoRaMacClassBParams.LoRaMacRegion, &getPhy );
- frequency = phyParam.Value;
- getPhy.Attribute = PHY_BEACON_CHANNEL_STEPWIDTH;
- phyParam = RegionGetPhyParam( *Ctx.LoRaMacClassBParams.LoRaMacRegion, &getPhy );
- stepwidth = phyParam.Value;
-
- // Calculate the frequency
- return frequency + ( channel * stepwidth );
+ return phyParam.Value;
}
/*!
* \brief Calculates the downlink channel for the beacon and for
* ping slot downlinks.
*
- * \param [IN] devAddr The address of the device
+ * \param [IN] devAddr The address of the device. Assign 0 if its a beacon.
*
* \param [IN] beaconTime The beacon time of the beacon.
*
- * \param [IN] beaconInterval The beacon interval
+ * \param [IN] beaconInterval The beacon interval.
+ *
+ * \param [IN] isBeacon Set to true, if the function shall
+ * calculate the frequency for a beacon.
*
* \retval The downlink channel
*/
-static uint32_t CalcDownlinkChannelAndFrequency( uint32_t devAddr, TimerTime_t beaconTime, TimerTime_t beaconInterval )
+static uint32_t CalcDownlinkChannelAndFrequency( uint32_t devAddr, TimerTime_t beaconTime,
+ TimerTime_t beaconInterval, bool isBeacon )
{
GetPhyParams_t getPhy;
PhyParam_t phyParam;
uint32_t channel = 0;
uint8_t nbChannels = 0;
- uint32_t frequency = 0;
- getPhy.Attribute = PHY_BEACON_NB_CHANNELS;
+ // Default initialization - ping slot channels
+ getPhy.Attribute = PHY_PING_SLOT_NB_CHANNELS;
+
+ if( isBeacon == true )
+ {
+ // Beacon channels
+ getPhy.Attribute = PHY_BEACON_NB_CHANNELS;
+ }
phyParam = RegionGetPhyParam( *Ctx.LoRaMacClassBParams.LoRaMacRegion, &getPhy );
- nbChannels = (uint8_t) phyParam.Value;
+ nbChannels = ( uint8_t ) phyParam.Value;
+ // nbChannels is > 1, when the channel plan requires more than one possible channel
+ // defined by the calculation below.
if( nbChannels > 1 )
{
// Calculate the channel for the next downlink
@@ -216,11 +288,9 @@ static uint32_t CalcDownlinkChannelAndFrequency( uint32_t devAddr, TimerTime_t b
channel = channel % nbChannels;
}
- // Calculate the frequency for the next downlink
- frequency = CalcDownlinkFrequency( channel );
-
- // Calculate the frequency for the next downlink
- return frequency;
+ // Calculate the frequency for the next downlink. This holds
+ // for beacons and ping slots.
+ return CalcDownlinkFrequency( channel, isBeacon );
}
/*!
@@ -237,19 +307,19 @@ static void RxBeaconSetup( TimerTime_t rxTime, bool activateDefaultChannel )
RxConfigParams_t beaconRxConfig;
GetPhyParams_t getPhy;
PhyParam_t phyParam;
- uint16_t windowTimeout = Ctx.NvmCtx->BeaconCtx.SymbolTimeout;
+ uint16_t windowTimeout = Ctx.BeaconCtx.SymbolTimeout;
if( activateDefaultChannel == true )
{
// This is the default frequency in case we don't know when the next
// beacon will be transmitted. We select channel 0 as default.
- frequency = CalcDownlinkFrequency( 0 );
+ frequency = CalcDownlinkFrequency( 0, true );
}
else
{
// This is the frequency according to the channel plan
- frequency = CalcDownlinkChannelAndFrequency( 0, Ctx.NvmCtx->BeaconCtx.BeaconTime + ( CLASSB_BEACON_INTERVAL / 1000 ),
- CLASSB_BEACON_INTERVAL );
+ frequency = CalcDownlinkChannelAndFrequency( 0, Ctx.BeaconCtx.BeaconTime.Seconds + ( CLASSB_BEACON_INTERVAL / 1000 ),
+ CLASSB_BEACON_INTERVAL, true );
}
if( Ctx.NvmCtx->BeaconCtx.Ctrl.CustomFreq == 1 )
@@ -258,14 +328,14 @@ static void RxBeaconSetup( TimerTime_t rxTime, bool activateDefaultChannel )
frequency = Ctx.NvmCtx->BeaconCtx.Frequency;
}
- if( Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconChannelSet == 1 )
+ if( Ctx.BeaconCtx.Ctrl.BeaconChannelSet == 1 )
{
// Set the frequency which was provided by BeaconTimingAns MAC command
- Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconChannelSet = 0;
- frequency = CalcDownlinkFrequency( Ctx.NvmCtx->BeaconCtx.BeaconTimingChannel );
+ Ctx.BeaconCtx.Ctrl.BeaconChannelSet = 0;
+ frequency = CalcDownlinkFrequency( Ctx.BeaconCtx.BeaconTimingChannel, true );
}
- if( ( Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconAcquired == 1 ) || ( Ctx.NvmCtx->BeaconCtx.Ctrl.AcquisitionPending == 1 ) )
+ if( ( Ctx.BeaconCtx.Ctrl.BeaconAcquired == 1 ) || ( Ctx.BeaconCtx.Ctrl.AcquisitionPending == 1 ) )
{
// Apply the symbol timeout only if we have acquired the beacon
// Otherwise, take the window enlargement into account
@@ -308,7 +378,7 @@ static bool CalcNextSlotTime( uint16_t slotOffset, uint16_t pingPeriod, uint16_t
TimerTime_t currentTime = TimerGetCurrentTime( );
// Calculate the point in time of the last beacon even if we missed it
- slotTime = ( ( currentTime - Ctx.NvmCtx->BeaconCtx.LastBeaconRx ) % CLASSB_BEACON_INTERVAL );
+ slotTime = ( ( currentTime - SysTimeToMs( Ctx.BeaconCtx.LastBeaconRx ) ) % CLASSB_BEACON_INTERVAL );
slotTime = currentTime - slotTime;
// Add the reserved time and the ping offset
@@ -325,12 +395,12 @@ static bool CalcNextSlotTime( uint16_t slotOffset, uint16_t pingPeriod, uint16_t
if( currentPingSlot < pingNb )
{
- if( slotTime <= ( Ctx.NvmCtx->BeaconCtx.NextBeaconRx - CLASSB_BEACON_GUARD - CLASSB_PING_SLOT_WINDOW ) )
+ if( slotTime <= ( SysTimeToMs( Ctx.BeaconCtx.NextBeaconRx ) - CLASSB_BEACON_GUARD - CLASSB_PING_SLOT_WINDOW ) )
{
// Calculate the relative ping slot time
slotTime -= currentTime;
slotTime -= Radio.GetWakeupTime( );
- slotTime = TimerTempCompensation( slotTime, Ctx.NvmCtx->BeaconCtx.Temperature );
+ slotTime = TimerTempCompensation( slotTime, Ctx.BeaconCtx.Temperature );
*timeOffset = slotTime;
return true;
}
@@ -379,7 +449,7 @@ static void GetTemperatureLevel( LoRaMacClassBCallback_t *callbacks, BeaconConte
}
}
-static void InitClassBDefaults( void )
+static void InitClassB( void )
{
GetPhyParams_t getPhy;
PhyParam_t phyParam;
@@ -388,12 +458,13 @@ static void InitClassBDefaults( void )
LoRaMacClassBEvents.Value = 0;
// Init variables to default
- memset1( ( uint8_t* ) &Ctx.NvmCtx->BeaconCtx, 0, sizeof( BeaconContext_t ) );
- memset1( ( uint8_t* ) &Ctx.NvmCtx->PingSlotCtx, 0, sizeof( PingSlotContext_t ) );
+ memset1( ( uint8_t* ) &NvmCtx, 0, sizeof( LoRaMacClassBNvmCtx_t ) );
+ memset1( ( uint8_t* ) &Ctx.PingSlotCtx, 0, sizeof( PingSlotContext_t ) );
+ memset1( ( uint8_t* ) &Ctx.BeaconCtx, 0, sizeof( BeaconContext_t ) );
// Setup default temperature
- Ctx.NvmCtx->BeaconCtx.Temperature = 25.0;
- GetTemperatureLevel( &Ctx.LoRaMacClassBCallbacks, &Ctx.NvmCtx->BeaconCtx );
+ Ctx.BeaconCtx.Temperature = 25.0;
+ GetTemperatureLevel( &Ctx.LoRaMacClassBCallbacks, &Ctx.BeaconCtx );
// Setup default ping slot datarate
getPhy.Attribute = PHY_PING_SLOT_CHANNEL_DR;
@@ -401,37 +472,56 @@ static void InitClassBDefaults( void )
Ctx.NvmCtx->PingSlotCtx.Datarate = (int8_t)( phyParam.Value );
// Setup default states
- Ctx.NvmCtx->BeaconState = BEACON_STATE_ACQUISITION;
- Ctx.NvmCtx->PingSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
- Ctx.NvmCtx->MulticastSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
+ Ctx.BeaconState = BEACON_STATE_ACQUISITION;
+ Ctx.PingSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
+ Ctx.MulticastSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
+}
+
+static void InitClassBDefaults( void )
+{
+ // This function shall reset the Class B settings to default,
+ // but should keep important configurations
+ LoRaMacClassBBeaconNvmCtx_t beaconCtx = Ctx.NvmCtx->BeaconCtx;
+ LoRaMacClassBPingSlotNvmCtx_t pingSlotCtx = Ctx.NvmCtx->PingSlotCtx;
+
+ InitClassB( );
+
+ // Parameters from BeaconFreqReq
+ Ctx.NvmCtx->BeaconCtx.Frequency = beaconCtx.Frequency;
+ Ctx.NvmCtx->BeaconCtx.Ctrl.CustomFreq = beaconCtx.Ctrl.CustomFreq;
+
+ // Parameters from PingSlotChannelReq
+ Ctx.NvmCtx->PingSlotCtx.Ctrl.CustomFreq = pingSlotCtx.Ctrl.CustomFreq;
+ Ctx.NvmCtx->PingSlotCtx.Frequency = pingSlotCtx.Frequency;
+ Ctx.NvmCtx->PingSlotCtx.Datarate = pingSlotCtx.Datarate;
}
static void EnlargeWindowTimeout( void )
{
// Update beacon movement
- Ctx.NvmCtx->BeaconCtx.BeaconWindowMovement *= CLASSB_WINDOW_MOVE_EXPANSION_FACTOR;
- if( Ctx.NvmCtx->BeaconCtx.BeaconWindowMovement > CLASSB_WINDOW_MOVE_EXPANSION_MAX )
+ Ctx.BeaconCtx.BeaconWindowMovement *= CLASSB_WINDOW_MOVE_EXPANSION_FACTOR;
+ if( Ctx.BeaconCtx.BeaconWindowMovement > CLASSB_WINDOW_MOVE_EXPANSION_MAX )
{
- Ctx.NvmCtx->BeaconCtx.BeaconWindowMovement = CLASSB_WINDOW_MOVE_EXPANSION_MAX;
+ Ctx.BeaconCtx.BeaconWindowMovement = CLASSB_WINDOW_MOVE_EXPANSION_MAX;
}
// Update symbol timeout
- Ctx.NvmCtx->BeaconCtx.SymbolTimeout *= CLASSB_BEACON_SYMBOL_TO_EXPANSION_FACTOR;
- if( Ctx.NvmCtx->BeaconCtx.SymbolTimeout > CLASSB_BEACON_SYMBOL_TO_EXPANSION_MAX )
+ Ctx.BeaconCtx.SymbolTimeout *= CLASSB_BEACON_SYMBOL_TO_EXPANSION_FACTOR;
+ if( Ctx.BeaconCtx.SymbolTimeout > CLASSB_BEACON_SYMBOL_TO_EXPANSION_MAX )
{
- Ctx.NvmCtx->BeaconCtx.SymbolTimeout = CLASSB_BEACON_SYMBOL_TO_EXPANSION_MAX;
+ Ctx.BeaconCtx.SymbolTimeout = CLASSB_BEACON_SYMBOL_TO_EXPANSION_MAX;
}
- Ctx.NvmCtx->PingSlotCtx.SymbolTimeout *= CLASSB_BEACON_SYMBOL_TO_EXPANSION_FACTOR;
- if( Ctx.NvmCtx->PingSlotCtx.SymbolTimeout > CLASSB_PING_SLOT_SYMBOL_TO_EXPANSION_MAX )
+ Ctx.PingSlotCtx.SymbolTimeout *= CLASSB_BEACON_SYMBOL_TO_EXPANSION_FACTOR;
+ if( Ctx.PingSlotCtx.SymbolTimeout > CLASSB_PING_SLOT_SYMBOL_TO_EXPANSION_MAX )
{
- Ctx.NvmCtx->PingSlotCtx.SymbolTimeout = CLASSB_PING_SLOT_SYMBOL_TO_EXPANSION_MAX;
+ Ctx.PingSlotCtx.SymbolTimeout = CLASSB_PING_SLOT_SYMBOL_TO_EXPANSION_MAX;
}
}
static void ResetWindowTimeout( void )
{
- Ctx.NvmCtx->BeaconCtx.SymbolTimeout = CLASSB_BEACON_SYMBOL_TO_DEFAULT;
- Ctx.NvmCtx->PingSlotCtx.SymbolTimeout = CLASSB_BEACON_SYMBOL_TO_DEFAULT;
- Ctx.NvmCtx->BeaconCtx.BeaconWindowMovement = CLASSB_WINDOW_MOVE_DEFAULT;
+ Ctx.BeaconCtx.SymbolTimeout = CLASSB_BEACON_SYMBOL_TO_DEFAULT;
+ Ctx.PingSlotCtx.SymbolTimeout = CLASSB_BEACON_SYMBOL_TO_DEFAULT;
+ Ctx.BeaconCtx.BeaconWindowMovement = CLASSB_WINDOW_MOVE_DEFAULT;
}
static TimerTime_t CalcDelayForNextBeacon( TimerTime_t currentTime, TimerTime_t lastBeaconRx )
@@ -445,7 +535,7 @@ static TimerTime_t CalcDelayForNextBeacon( TimerTime_t currentTime, TimerTime_t
static void IndicateBeaconStatus( LoRaMacEventInfoStatus_t status )
{
- if( Ctx.NvmCtx->BeaconCtx.Ctrl.ResumeBeaconing == 0 )
+ if( Ctx.BeaconCtx.Ctrl.ResumeBeaconing == 0 )
{
Ctx.LoRaMacClassBParams.MlmeIndication->MlmeIndication = MLME_BEACON;
Ctx.LoRaMacClassBParams.MlmeIndication->Status = status;
@@ -453,7 +543,7 @@ static void IndicateBeaconStatus( LoRaMacEventInfoStatus_t status )
Ctx.LoRaMacClassBParams.LoRaMacFlags->Bits.MacDone = 1;
}
- Ctx.NvmCtx->BeaconCtx.Ctrl.ResumeBeaconing = 0;
+ Ctx.BeaconCtx.Ctrl.ResumeBeaconing = 0;
}
static TimerTime_t ApplyGuardTime( TimerTime_t beaconEventTime )
@@ -474,18 +564,18 @@ static TimerTime_t UpdateBeaconState( LoRaMacEventInfoStatus_t status,
TimerTime_t beaconEventTime = 0;
// Calculate the next beacon RX time
- beaconEventTime = CalcDelayForNextBeacon( currentTime, Ctx.NvmCtx->BeaconCtx.LastBeaconRx );
- Ctx.NvmCtx->BeaconCtx.NextBeaconRx = currentTime + beaconEventTime;
+ beaconEventTime = CalcDelayForNextBeacon( currentTime, SysTimeToMs( Ctx.BeaconCtx.LastBeaconRx ) );
+ Ctx.BeaconCtx.NextBeaconRx = SysTimeFromMs( currentTime + beaconEventTime );
// Take temperature compensation into account
- beaconEventTime = TimerTempCompensation( beaconEventTime, Ctx.NvmCtx->BeaconCtx.Temperature );
+ beaconEventTime = TimerTempCompensation( beaconEventTime, Ctx.BeaconCtx.Temperature );
// Move the window
if( beaconEventTime > windowMovement )
{
beaconEventTime -= windowMovement;
}
- Ctx.NvmCtx->BeaconCtx.NextBeaconRxAdjusted = currentTime + beaconEventTime;
+ Ctx.BeaconCtx.NextBeaconRxAdjusted = currentTime + beaconEventTime;
// Start the RX slot state machine for ping and multicast slots
LoRaMacClassBStartRxSlots( );
@@ -512,15 +602,15 @@ static uint16_t CalcPingPeriod( uint8_t pingNb )
*/
static void NvmContextChange( void )
{
- if( Ctx.EventNvmCtxChanged != NULL )
+ if( Ctx.LoRaMacClassBNvmEvent != NULL )
{
- Ctx.EventNvmCtxChanged( );
+ Ctx.LoRaMacClassBNvmEvent( );
}
}
#endif // LORAMAC_CLASSB_ENABLED
-void LoRaMacClassBInit( LoRaMacClassBParams_t *classBParams, LoRaMacClassBCallback_t *callbacks, EventNvmCtxChanged classBNvmCtxChanged )
+void LoRaMacClassBInit( LoRaMacClassBParams_t *classBParams, LoRaMacClassBCallback_t *callbacks, LoRaMacClassBNvmEvent classBNvmCtxChanged )
{
#ifdef LORAMAC_CLASSB_ENABLED
// Store callbacks
@@ -533,14 +623,14 @@ void LoRaMacClassBInit( LoRaMacClassBParams_t *classBParams, LoRaMacClassBCallba
Ctx.NvmCtx = &NvmCtx;
// Assign callback
- Ctx.EventNvmCtxChanged = classBNvmCtxChanged;
+ Ctx.LoRaMacClassBNvmEvent = classBNvmCtxChanged;
// Initialize timers
TimerInit( &Ctx.BeaconTimer, LoRaMacClassBBeaconTimerEvent );
TimerInit( &Ctx.PingSlotTimer, LoRaMacClassBPingSlotTimerEvent );
TimerInit( &Ctx.MulticastSlotTimer, LoRaMacClassBMulticastSlotTimerEvent );
- InitClassBDefaults( );
+ InitClassB( );
#endif // LORAMAC_CLASSB_ENABLED
}
@@ -580,50 +670,45 @@ void LoRaMacClassBSetBeaconState( BeaconState_t beaconState )
{
// If the MAC has received a time reference for the beacon,
// apply the state BEACON_STATE_ACQUISITION_BY_TIME.
- if( ( Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconDelaySet == 1 ) &&
+ if( ( Ctx.BeaconCtx.Ctrl.BeaconDelaySet == 1 ) &&
( LoRaMacClassBIsAcquisitionPending( ) == false ) )
{
- Ctx.NvmCtx->BeaconState = BEACON_STATE_ACQUISITION_BY_TIME;
+ Ctx.BeaconState = BEACON_STATE_ACQUISITION_BY_TIME;
}
else
{
- Ctx.NvmCtx->BeaconState = beaconState;
+ Ctx.BeaconState = beaconState;
}
}
else
{
- if( ( Ctx.NvmCtx->BeaconState != BEACON_STATE_ACQUISITION ) &&
- ( Ctx.NvmCtx->BeaconState != BEACON_STATE_ACQUISITION_BY_TIME ) )
+ if( ( Ctx.BeaconState != BEACON_STATE_ACQUISITION ) &&
+ ( Ctx.BeaconState != BEACON_STATE_ACQUISITION_BY_TIME ) )
{
- Ctx.NvmCtx->BeaconState = beaconState;
+ Ctx.BeaconState = beaconState;
}
}
-
- NvmContextChange( );
-
#endif // LORAMAC_CLASSB_ENABLED
}
void LoRaMacClassBSetPingSlotState( PingSlotState_t pingSlotState )
{
#ifdef LORAMAC_CLASSB_ENABLED
- Ctx.NvmCtx->PingSlotState = pingSlotState;
- NvmContextChange( );
+ Ctx.PingSlotState = pingSlotState;
#endif // LORAMAC_CLASSB_ENABLED
}
void LoRaMacClassBSetMulticastSlotState( PingSlotState_t multicastSlotState )
{
#ifdef LORAMAC_CLASSB_ENABLED
- Ctx.NvmCtx->MulticastSlotState = multicastSlotState;
- NvmContextChange( );
+ Ctx.MulticastSlotState = multicastSlotState;
#endif // LORAMAC_CLASSB_ENABLED
}
bool LoRaMacClassBIsAcquisitionInProgress( void )
{
#ifdef LORAMAC_CLASSB_ENABLED
- if( Ctx.NvmCtx->BeaconState == BEACON_STATE_ACQUISITION_BY_TIME )
+ if( Ctx.BeaconState == BEACON_STATE_ACQUISITION_BY_TIME )
{
// In this case the acquisition is in progress, as the MAC has
// a time reference for the next beacon RX.
@@ -644,7 +729,7 @@ bool LoRaMacClassBIsAcquisitionInProgress( void )
void LoRaMacClassBBeaconTimerEvent( void* context )
{
#ifdef LORAMAC_CLASSB_ENABLED
- Ctx.NvmCtx->BeaconCtx.TimeStamp = TimerGetCurrentTime( );
+ Ctx.BeaconCtx.TimeStamp = TimerGetCurrentTime( );
TimerStop( &Ctx.BeaconTimer );
LoRaMacClassBEvents.Events.Beacon = 1;
@@ -660,50 +745,50 @@ static void LoRaMacClassBProcessBeacon( void )
{
bool activateTimer = false;
TimerTime_t beaconEventTime = 1;
- TimerTime_t currentTime = Ctx.NvmCtx->BeaconCtx.TimeStamp;
+ TimerTime_t currentTime = Ctx.BeaconCtx.TimeStamp;
// Beacon state machine
- switch( Ctx.NvmCtx->BeaconState )
+ switch( Ctx.BeaconState )
{
case BEACON_STATE_ACQUISITION_BY_TIME:
{
activateTimer = true;
- if( Ctx.NvmCtx->BeaconCtx.Ctrl.AcquisitionPending == 1 )
+ if( Ctx.BeaconCtx.Ctrl.AcquisitionPending == 1 )
{
Radio.Sleep();
- Ctx.NvmCtx->BeaconState = BEACON_STATE_LOST;
+ Ctx.BeaconState = BEACON_STATE_LOST;
}
else
{
// Default symbol timeouts
ResetWindowTimeout( );
- if( Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconDelaySet == 1 )
+ if( Ctx.BeaconCtx.Ctrl.BeaconDelaySet == 1 )
{
- if( Ctx.NvmCtx->BeaconCtx.BeaconTimingDelay > 0 )
+ if( Ctx.BeaconCtx.BeaconTimingDelay > 0 )
{
- if( Ctx.NvmCtx->BeaconCtx.NextBeaconRx > currentTime )
+ if( SysTimeToMs( Ctx.BeaconCtx.NextBeaconRx ) > currentTime )
{
- beaconEventTime = TimerTempCompensation( Ctx.NvmCtx->BeaconCtx.NextBeaconRx - currentTime, Ctx.NvmCtx->BeaconCtx.Temperature );
+ beaconEventTime = TimerTempCompensation( SysTimeToMs( Ctx.BeaconCtx.NextBeaconRx ) - currentTime, Ctx.BeaconCtx.Temperature );
}
else
{
// Reset status provides by BeaconTimingAns
- Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconDelaySet = 0;
- Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconChannelSet = 0;
- Ctx.NvmCtx->BeaconState = BEACON_STATE_ACQUISITION;
+ Ctx.BeaconCtx.Ctrl.BeaconDelaySet = 0;
+ Ctx.BeaconCtx.Ctrl.BeaconChannelSet = 0;
+ Ctx.BeaconState = BEACON_STATE_ACQUISITION;
}
- Ctx.NvmCtx->BeaconCtx.BeaconTimingDelay = 0;
+ Ctx.BeaconCtx.BeaconTimingDelay = 0;
}
else
{
activateTimer = false;
// Reset status provides by BeaconTimingAns
- Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconDelaySet = 0;
+ Ctx.BeaconCtx.Ctrl.BeaconDelaySet = 0;
// Set the node into acquisition mode
- Ctx.NvmCtx->BeaconCtx.Ctrl.AcquisitionPending = 1;
+ Ctx.BeaconCtx.Ctrl.AcquisitionPending = 1;
// Don't use the default channel. We know on which
// channel the next beacon will be transmitted
@@ -712,10 +797,11 @@ static void LoRaMacClassBProcessBeacon( void )
}
else
{
- Ctx.NvmCtx->BeaconCtx.NextBeaconRx = 0;
- Ctx.NvmCtx->BeaconCtx.BeaconTimingDelay = 0;
+ Ctx.BeaconCtx.NextBeaconRx.Seconds = 0;
+ Ctx.BeaconCtx.NextBeaconRx.SubSeconds = 0;
+ Ctx.BeaconCtx.BeaconTimingDelay = 0;
- Ctx.NvmCtx->BeaconState = BEACON_STATE_ACQUISITION;
+ Ctx.BeaconState = BEACON_STATE_ACQUISITION;
}
}
break;
@@ -724,17 +810,17 @@ static void LoRaMacClassBProcessBeacon( void )
{
activateTimer = true;
- if( Ctx.NvmCtx->BeaconCtx.Ctrl.AcquisitionPending == 1 )
+ if( Ctx.BeaconCtx.Ctrl.AcquisitionPending == 1 )
{
Radio.Sleep();
- Ctx.NvmCtx->BeaconState = BEACON_STATE_LOST;
+ Ctx.BeaconState = BEACON_STATE_LOST;
}
else
{
// Default symbol timeouts
ResetWindowTimeout( );
- Ctx.NvmCtx->BeaconCtx.Ctrl.AcquisitionPending = 1;
+ Ctx.BeaconCtx.Ctrl.AcquisitionPending = 1;
beaconEventTime = CLASSB_BEACON_INTERVAL;
// Start the beacon acquisition. When the MAC has received a beacon in function
@@ -749,13 +835,14 @@ static void LoRaMacClassBProcessBeacon( void )
case BEACON_STATE_TIMEOUT:
{
// We have to update the beacon time, since we missed a beacon
- Ctx.NvmCtx->BeaconCtx.BeaconTime += ( CLASSB_BEACON_INTERVAL / 1000 );
+ Ctx.BeaconCtx.BeaconTime.Seconds += ( CLASSB_BEACON_INTERVAL / 1000 );
+ Ctx.BeaconCtx.BeaconTime.SubSeconds = 0;
// Enlarge window timeouts to increase the chance to receive the next beacon
EnlargeWindowTimeout( );
// Setup next state
- Ctx.NvmCtx->BeaconState = BEACON_STATE_REACQUISITION;
+ Ctx.BeaconState = BEACON_STATE_REACQUISITION;
}
// Intentional fall through
case BEACON_STATE_REACQUISITION:
@@ -763,21 +850,21 @@ static void LoRaMacClassBProcessBeacon( void )
activateTimer = true;
// The beacon is no longer acquired
- Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconAcquired = 0;
+ Ctx.BeaconCtx.Ctrl.BeaconAcquired = 0;
// Verify if the maximum beacon less period has been elapsed
- if( ( currentTime - Ctx.NvmCtx->BeaconCtx.LastBeaconRx ) > CLASSB_MAX_BEACON_LESS_PERIOD )
+ if( ( currentTime - SysTimeToMs( Ctx.BeaconCtx.LastBeaconRx ) ) > CLASSB_MAX_BEACON_LESS_PERIOD )
{
- Ctx.NvmCtx->BeaconState = BEACON_STATE_LOST;
+ Ctx.BeaconState = BEACON_STATE_LOST;
}
else
{
// Handle beacon miss
beaconEventTime = UpdateBeaconState( LORAMAC_EVENT_INFO_STATUS_BEACON_LOST,
- Ctx.NvmCtx->BeaconCtx.BeaconWindowMovement, currentTime );
+ Ctx.BeaconCtx.BeaconWindowMovement, currentTime );
// Setup next state
- Ctx.NvmCtx->BeaconState = BEACON_STATE_IDLE;
+ Ctx.BeaconState = BEACON_STATE_IDLE;
}
break;
}
@@ -786,7 +873,7 @@ static void LoRaMacClassBProcessBeacon( void )
activateTimer = true;
// We have received a beacon. Acquisition is no longer pending.
- Ctx.NvmCtx->BeaconCtx.Ctrl.AcquisitionPending = 0;
+ Ctx.BeaconCtx.Ctrl.AcquisitionPending = 0;
// Handle beacon reception
beaconEventTime = UpdateBeaconState( LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED,
@@ -803,32 +890,32 @@ static void LoRaMacClassBProcessBeacon( void )
}
// Setup next state
- Ctx.NvmCtx->BeaconState = BEACON_STATE_IDLE;
+ Ctx.BeaconState = BEACON_STATE_IDLE;
break;
}
case BEACON_STATE_IDLE:
{
activateTimer = true;
- GetTemperatureLevel( &Ctx.LoRaMacClassBCallbacks, &Ctx.NvmCtx->BeaconCtx );
- beaconEventTime = Ctx.NvmCtx->BeaconCtx.NextBeaconRxAdjusted - Radio.GetWakeupTime( );
+ GetTemperatureLevel( &Ctx.LoRaMacClassBCallbacks, &Ctx.BeaconCtx );
+ beaconEventTime = Ctx.BeaconCtx.NextBeaconRxAdjusted - Radio.GetWakeupTime( );
currentTime = TimerGetCurrentTime( );
if( beaconEventTime > currentTime )
{
- Ctx.NvmCtx->BeaconState = BEACON_STATE_GUARD;
+ Ctx.BeaconState = BEACON_STATE_GUARD;
beaconEventTime -= currentTime;
- beaconEventTime = TimerTempCompensation( beaconEventTime, Ctx.NvmCtx->BeaconCtx.Temperature );
+ beaconEventTime = TimerTempCompensation( beaconEventTime, Ctx.BeaconCtx.Temperature );
}
else
{
- Ctx.NvmCtx->BeaconState = BEACON_STATE_REACQUISITION;
+ Ctx.BeaconState = BEACON_STATE_REACQUISITION;
beaconEventTime = 1;
}
break;
}
case BEACON_STATE_GUARD:
{
- Ctx.NvmCtx->BeaconState = BEACON_STATE_RX;
+ Ctx.BeaconState = BEACON_STATE_RX;
// Stop slot timers
LoRaMacClassBStopRxSlots( );
@@ -867,7 +954,7 @@ static void LoRaMacClassBProcessBeacon( void )
}
default:
{
- Ctx.NvmCtx->BeaconState = BEACON_STATE_ACQUISITION;
+ Ctx.BeaconState = BEACON_STATE_ACQUISITION;
break;
}
}
@@ -877,8 +964,6 @@ static void LoRaMacClassBProcessBeacon( void )
TimerSetValue( &Ctx.BeaconTimer, beaconEventTime );
TimerStart( &Ctx.BeaconTimer );
}
-
- NvmContextChange( );
}
#endif // LORAMAC_CLASSB_ENABLED
@@ -900,22 +985,22 @@ static void LoRaMacClassBProcessPingSlot( void )
static RxConfigParams_t pingSlotRxConfig;
TimerTime_t pingSlotTime = 0;
- switch( Ctx.NvmCtx->PingSlotState )
+ switch( Ctx.PingSlotState )
{
case PINGSLOT_STATE_CALC_PING_OFFSET:
{
- ComputePingOffset( Ctx.NvmCtx->BeaconCtx.BeaconTime,
- *Ctx.LoRaMacClassBParams.LoRaMacDevAddr,
- Ctx.NvmCtx->PingSlotCtx.PingPeriod,
- &( Ctx.NvmCtx->PingSlotCtx.PingOffset ) );
- Ctx.NvmCtx->PingSlotState = PINGSLOT_STATE_SET_TIMER;
+ ComputePingOffset( Ctx.BeaconCtx.BeaconTime.Seconds,
+ *Ctx.LoRaMacClassBParams.LoRaMacDevAddr,
+ Ctx.NvmCtx->PingSlotCtx.PingPeriod,
+ &( Ctx.PingSlotCtx.PingOffset ) );
+ Ctx.PingSlotState = PINGSLOT_STATE_SET_TIMER;
}
// Intentional fall through
case PINGSLOT_STATE_SET_TIMER:
{
- if( CalcNextSlotTime( Ctx.NvmCtx->PingSlotCtx.PingOffset, Ctx.NvmCtx->PingSlotCtx.PingPeriod, Ctx.NvmCtx->PingSlotCtx.PingNb, &pingSlotTime ) == true )
+ if( CalcNextSlotTime( Ctx.PingSlotCtx.PingOffset, Ctx.NvmCtx->PingSlotCtx.PingPeriod, Ctx.NvmCtx->PingSlotCtx.PingNb, &pingSlotTime ) == true )
{
- if( Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconAcquired == 1 )
+ if( Ctx.BeaconCtx.Ctrl.BeaconAcquired == 1 )
{
// Compute the symbol timeout. Apply it only, if the beacon is acquired
// Otherwise, take the enlargement of the symbols into account.
@@ -924,7 +1009,7 @@ static void LoRaMacClassBProcessPingSlot( void )
Ctx.LoRaMacClassBParams.LoRaMacParams->MinRxSymbols,
Ctx.LoRaMacClassBParams.LoRaMacParams->SystemMaxRxError,
&pingSlotRxConfig );
- Ctx.NvmCtx->PingSlotCtx.SymbolTimeout = pingSlotRxConfig.WindowTimeout;
+ Ctx.PingSlotCtx.SymbolTimeout = pingSlotRxConfig.WindowTimeout;
if( ( int32_t )pingSlotTime > pingSlotRxConfig.WindowOffset )
{// Apply the window offset
@@ -933,7 +1018,7 @@ static void LoRaMacClassBProcessPingSlot( void )
}
// Start the timer if the ping slot time is in range
- Ctx.NvmCtx->PingSlotState = PINGSLOT_STATE_IDLE;
+ Ctx.PingSlotState = PINGSLOT_STATE_IDLE;
TimerSetValue( &Ctx.PingSlotTimer, pingSlotTime );
TimerStart( &Ctx.PingSlotTimer );
}
@@ -947,21 +1032,21 @@ static void LoRaMacClassBProcessPingSlot( void )
if( Ctx.NvmCtx->PingSlotCtx.Ctrl.CustomFreq == 0 )
{
// Restore floor plan
- frequency = CalcDownlinkChannelAndFrequency( *Ctx.LoRaMacClassBParams.LoRaMacDevAddr, Ctx.NvmCtx->BeaconCtx.BeaconTime, CLASSB_BEACON_INTERVAL );
+ frequency = CalcDownlinkChannelAndFrequency( *Ctx.LoRaMacClassBParams.LoRaMacDevAddr, Ctx.BeaconCtx.BeaconTime.Seconds,
+ CLASSB_BEACON_INTERVAL, false );
}
// Open the ping slot window only, if there is no multicast ping slot
// open. Multicast ping slots have always priority
- if( Ctx.NvmCtx->MulticastSlotState != PINGSLOT_STATE_RX )
+ if( Ctx.MulticastSlotState != PINGSLOT_STATE_RX )
{
- Ctx.NvmCtx->PingSlotState = PINGSLOT_STATE_RX;
+ Ctx.PingSlotState = PINGSLOT_STATE_RX;
pingSlotRxConfig.Datarate = Ctx.NvmCtx->PingSlotCtx.Datarate;
pingSlotRxConfig.DownlinkDwellTime = Ctx.LoRaMacClassBParams.LoRaMacParams->DownlinkDwellTime;
- pingSlotRxConfig.RepeaterSupport = Ctx.LoRaMacClassBParams.LoRaMacParams->RepeaterSupport;
pingSlotRxConfig.Frequency = frequency;
pingSlotRxConfig.RxContinuous = false;
- pingSlotRxConfig.RxSlot = RX_SLOT_WIN_PING_SLOT;
+ pingSlotRxConfig.RxSlot = RX_SLOT_WIN_CLASS_B_PING_SLOT;
RegionRxConfig( *Ctx.LoRaMacClassBParams.LoRaMacRegion, &pingSlotRxConfig, ( int8_t* )&Ctx.LoRaMacClassBParams.McpsIndication->RxDatarate );
@@ -977,7 +1062,7 @@ static void LoRaMacClassBProcessPingSlot( void )
else
{
// Multicast slots have priority. Skip Rx
- Ctx.NvmCtx->PingSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
+ Ctx.PingSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
TimerSetValue( &Ctx.PingSlotTimer, CLASSB_PING_SLOT_WINDOW );
TimerStart( &Ctx.PingSlotTimer );
}
@@ -985,12 +1070,10 @@ static void LoRaMacClassBProcessPingSlot( void )
}
default:
{
- Ctx.NvmCtx->PingSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
+ Ctx.PingSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
break;
}
}
-
- NvmContextChange( );
}
#endif // LORAMAC_CLASSB_ENABLED
@@ -1020,32 +1103,32 @@ static void LoRaMacClassBProcessMulticastSlot( void )
return;
}
- if( Ctx.NvmCtx->MulticastSlotState == PINGSLOT_STATE_RX )
+ if( Ctx.MulticastSlotState == PINGSLOT_STATE_RX )
{
// A multicast slot is already open
return;
}
- switch( Ctx.NvmCtx->MulticastSlotState )
+ switch( Ctx.MulticastSlotState )
{
case PINGSLOT_STATE_CALC_PING_OFFSET:
{
// Compute all offsets for every multicast slots
for( uint8_t i = 0; i < 4; i++ )
{
- ComputePingOffset( Ctx.NvmCtx->BeaconCtx.BeaconTime,
- cur->Address,
- cur->PingPeriod,
- &( cur->PingOffset ) );
+ ComputePingOffset( Ctx.BeaconCtx.BeaconTime.Seconds,
+ cur->ChannelParams.Address,
+ cur->PingPeriod,
+ &( cur->PingOffset ) );
cur++;
}
- Ctx.NvmCtx->MulticastSlotState = PINGSLOT_STATE_SET_TIMER;
+ Ctx.MulticastSlotState = PINGSLOT_STATE_SET_TIMER;
}
// Intentional fall through
case PINGSLOT_STATE_SET_TIMER:
{
cur = Ctx.LoRaMacClassBParams.MulticastChannels;
- Ctx.NvmCtx->PingSlotCtx.NextMulticastChannel = NULL;
+ Ctx.PingSlotCtx.NextMulticastChannel = NULL;
for( uint8_t i = 0; i < 4; i++ )
{
@@ -1056,23 +1139,23 @@ static void LoRaMacClassBProcessMulticastSlot( void )
{
// Update the slot time and the next multicast channel
multicastSlotTime = slotTime;
- Ctx.NvmCtx->PingSlotCtx.NextMulticastChannel = cur;
+ Ctx.PingSlotCtx.NextMulticastChannel = cur;
}
}
cur++;
}
// Schedule the next multicast slot
- if( Ctx.NvmCtx->PingSlotCtx.NextMulticastChannel != NULL )
+ if( Ctx.PingSlotCtx.NextMulticastChannel != NULL )
{
- if( Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconAcquired == 1 )
+ if( Ctx.BeaconCtx.Ctrl.BeaconAcquired == 1 )
{
RegionComputeRxWindowParameters( *Ctx.LoRaMacClassBParams.LoRaMacRegion,
Ctx.NvmCtx->PingSlotCtx.Datarate,
Ctx.LoRaMacClassBParams.LoRaMacParams->MinRxSymbols,
Ctx.LoRaMacClassBParams.LoRaMacParams->SystemMaxRxError,
&multicastSlotRxConfig );
- Ctx.NvmCtx->PingSlotCtx.SymbolTimeout = multicastSlotRxConfig.WindowTimeout;
+ Ctx.PingSlotCtx.SymbolTimeout = multicastSlotRxConfig.WindowTimeout;
}
if( ( int32_t )multicastSlotTime > multicastSlotRxConfig.WindowOffset )
@@ -1081,7 +1164,7 @@ static void LoRaMacClassBProcessMulticastSlot( void )
}
// Start the timer if the ping slot time is in range
- Ctx.NvmCtx->MulticastSlotState = PINGSLOT_STATE_IDLE;
+ Ctx.MulticastSlotState = PINGSLOT_STATE_IDLE;
TimerSetValue( &Ctx.MulticastSlotTimer, multicastSlotTime );
TimerStart( &Ctx.MulticastSlotTimer );
}
@@ -1092,40 +1175,40 @@ static void LoRaMacClassBProcessMulticastSlot( void )
uint32_t frequency = 0;
// Verify if the multicast channel is valid
- if( Ctx.NvmCtx->PingSlotCtx.NextMulticastChannel == NULL )
+ if( Ctx.PingSlotCtx.NextMulticastChannel == NULL )
{
- Ctx.NvmCtx->MulticastSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
+ Ctx.MulticastSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
TimerSetValue( &Ctx.MulticastSlotTimer, 1 );
TimerStart( &Ctx.MulticastSlotTimer );
break;
}
// Apply frequency
- frequency = Ctx.NvmCtx->PingSlotCtx.NextMulticastChannel->Frequency;
+ frequency = Ctx.PingSlotCtx.NextMulticastChannel->ChannelParams.RxParams.ClassB.Frequency;
// Restore the floor plan frequency if there is no individual frequency assigned
if( frequency == 0 )
{
// Restore floor plan
- frequency = CalcDownlinkChannelAndFrequency( Ctx.NvmCtx->PingSlotCtx.NextMulticastChannel->Address, Ctx.NvmCtx->BeaconCtx.BeaconTime, CLASSB_BEACON_INTERVAL );
+ frequency = CalcDownlinkChannelAndFrequency( Ctx.PingSlotCtx.NextMulticastChannel->ChannelParams.Address,
+ Ctx.BeaconCtx.BeaconTime.Seconds, CLASSB_BEACON_INTERVAL, false );
}
- Ctx.NvmCtx->MulticastSlotState = PINGSLOT_STATE_RX;
+ Ctx.MulticastSlotState = PINGSLOT_STATE_RX;
- multicastSlotRxConfig.Datarate = Ctx.NvmCtx->PingSlotCtx.NextMulticastChannel->Datarate;
+ multicastSlotRxConfig.Datarate = Ctx.PingSlotCtx.NextMulticastChannel->ChannelParams.RxParams.ClassB.Datarate;
multicastSlotRxConfig.DownlinkDwellTime = Ctx.LoRaMacClassBParams.LoRaMacParams->DownlinkDwellTime;
- multicastSlotRxConfig.RepeaterSupport = Ctx.LoRaMacClassBParams.LoRaMacParams->RepeaterSupport;
multicastSlotRxConfig.Frequency = frequency;
multicastSlotRxConfig.RxContinuous = false;
- multicastSlotRxConfig.RxSlot = RX_SLOT_WIN_MULTICAST_SLOT;
+ multicastSlotRxConfig.RxSlot = RX_SLOT_WIN_CLASS_B_MULTICAST_SLOT;
RegionRxConfig( *Ctx.LoRaMacClassBParams.LoRaMacRegion, &multicastSlotRxConfig, ( int8_t* )&Ctx.LoRaMacClassBParams.McpsIndication->RxDatarate );
- if( Ctx.NvmCtx->PingSlotState == PINGSLOT_STATE_RX )
+ if( Ctx.PingSlotState == PINGSLOT_STATE_RX )
{
// Close ping slot window, if necessary. Multicast slots have priority
Radio.Standby( );
- Ctx.NvmCtx->PingSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
+ Ctx.PingSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
TimerSetValue( &Ctx.PingSlotTimer, CLASSB_PING_SLOT_WINDOW );
TimerStart( &Ctx.PingSlotTimer );
}
@@ -1142,12 +1225,10 @@ static void LoRaMacClassBProcessMulticastSlot( void )
}
default:
{
- Ctx.NvmCtx->MulticastSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
+ Ctx.MulticastSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
break;
}
}
-
- NvmContextChange( );
}
#endif // LORAMAC_CLASSB_ENABLED
@@ -1166,7 +1247,7 @@ bool LoRaMacClassBRxBeacon( uint8_t *payload, uint16_t size )
phyParam = RegionGetPhyParam( *Ctx.LoRaMacClassBParams.LoRaMacRegion, &getPhy );
// Verify if we are in the state where we expect a beacon
- if( ( Ctx.NvmCtx->BeaconState == BEACON_STATE_RX ) || ( Ctx.NvmCtx->BeaconCtx.Ctrl.AcquisitionPending == 1 ) )
+ if( ( Ctx.BeaconState == BEACON_STATE_RX ) || ( Ctx.BeaconCtx.Ctrl.AcquisitionPending == 1 ) )
{
if( size == phyParam.BeaconFormat.BeaconSize )
{
@@ -1186,11 +1267,12 @@ bool LoRaMacClassBRxBeacon( uint8_t *payload, uint16_t size )
if( crc0 == beaconCrc0 )
{
// Read Time field from the frame
- Ctx.NvmCtx->BeaconCtx.BeaconTime = ( ( uint32_t )payload[phyParam.BeaconFormat.Rfu1Size] ) & 0x000000FF;
- Ctx.NvmCtx->BeaconCtx.BeaconTime |= ( ( uint32_t )( payload[phyParam.BeaconFormat.Rfu1Size + 1] << 8 ) ) & 0x0000FF00;
- Ctx.NvmCtx->BeaconCtx.BeaconTime |= ( ( uint32_t )( payload[phyParam.BeaconFormat.Rfu1Size + 2] << 16 ) ) & 0x00FF0000;
- Ctx.NvmCtx->BeaconCtx.BeaconTime |= ( ( uint32_t )( payload[phyParam.BeaconFormat.Rfu1Size + 3] << 24 ) ) & 0xFF000000;
- Ctx.LoRaMacClassBParams.MlmeIndication->BeaconInfo.Time = Ctx.NvmCtx->BeaconCtx.BeaconTime;
+ Ctx.BeaconCtx.BeaconTime.Seconds = ( ( uint32_t )payload[phyParam.BeaconFormat.Rfu1Size] ) & 0x000000FF;
+ Ctx.BeaconCtx.BeaconTime.Seconds |= ( ( uint32_t )( payload[phyParam.BeaconFormat.Rfu1Size + 1] << 8 ) ) & 0x0000FF00;
+ Ctx.BeaconCtx.BeaconTime.Seconds |= ( ( uint32_t )( payload[phyParam.BeaconFormat.Rfu1Size + 2] << 16 ) ) & 0x00FF0000;
+ Ctx.BeaconCtx.BeaconTime.Seconds |= ( ( uint32_t )( payload[phyParam.BeaconFormat.Rfu1Size + 3] << 24 ) ) & 0xFF000000;
+ Ctx.BeaconCtx.BeaconTime.SubSeconds = 0;
+ Ctx.LoRaMacClassBParams.MlmeIndication->BeaconInfo.Time = Ctx.BeaconCtx.BeaconTime;
beaconProcessed = true;
}
@@ -1211,19 +1293,44 @@ bool LoRaMacClassBRxBeacon( uint8_t *payload, uint16_t size )
// Reset beacon variables, if one of the crc is valid
if( beaconProcessed == true )
{
- Ctx.NvmCtx->BeaconCtx.LastBeaconRx = TimerGetCurrentTime( ) - Radio.TimeOnAir( MODEM_LORA, size );
- Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconAcquired = 1;
- Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconMode = 1;
+ uint32_t spreadingFactor = 0;
+ uint32_t bandwith = 0;
+
+ getPhy.Attribute = PHY_BEACON_CHANNEL_DR;
+ phyParam = RegionGetPhyParam( *Ctx.LoRaMacClassBParams.LoRaMacRegion, &getPhy );
+
+ getPhy.Attribute = PHY_SF_FROM_DR;
+ getPhy.Datarate = phyParam.Value;
+ phyParam = RegionGetPhyParam( *Ctx.LoRaMacClassBParams.LoRaMacRegion, &getPhy );
+ spreadingFactor = phyParam.Value;
+
+ getPhy.Attribute = PHY_BW_FROM_DR;
+ phyParam = RegionGetPhyParam( *Ctx.LoRaMacClassBParams.LoRaMacRegion, &getPhy );
+ bandwith = phyParam.Value;
+
+ TimerTime_t time = Radio.TimeOnAir( MODEM_LORA, bandwith, spreadingFactor, 1, 10, true, size, false );
+ SysTime_t timeOnAir;
+ timeOnAir.Seconds = time / 1000;
+ timeOnAir.SubSeconds = time - timeOnAir.Seconds * 1000;
+
+ Ctx.BeaconCtx.LastBeaconRx = Ctx.BeaconCtx.BeaconTime;
+ Ctx.BeaconCtx.LastBeaconRx.Seconds += UNIX_GPS_EPOCH_OFFSET;
+
+ // Update system time.
+ SysTimeSet( SysTimeAdd( Ctx.BeaconCtx.LastBeaconRx, timeOnAir ) );
+
+ Ctx.BeaconCtx.Ctrl.BeaconAcquired = 1;
+ Ctx.BeaconCtx.Ctrl.BeaconMode = 1;
ResetWindowTimeout( );
- Ctx.NvmCtx->BeaconState = BEACON_STATE_LOCKED;
+ Ctx.BeaconState = BEACON_STATE_LOCKED;
LoRaMacClassBBeaconTimerEvent( NULL );
}
}
- if( Ctx.NvmCtx->BeaconState == BEACON_STATE_RX )
+ if( Ctx.BeaconState == BEACON_STATE_RX )
{
- Ctx.NvmCtx->BeaconState = BEACON_STATE_TIMEOUT;
+ Ctx.BeaconState = BEACON_STATE_TIMEOUT;
LoRaMacClassBBeaconTimerEvent( NULL );
}
// When the MAC listens for a beacon, it is not allowed to process any other
@@ -1235,9 +1342,6 @@ bool LoRaMacClassBRxBeacon( uint8_t *payload, uint16_t size )
// valid beacon has been received.
beaconProcessed = true;
}
-
- NvmContextChange( );
-
return beaconProcessed;
#else
return false;
@@ -1247,8 +1351,8 @@ bool LoRaMacClassBRxBeacon( uint8_t *payload, uint16_t size )
bool LoRaMacClassBIsBeaconExpected( void )
{
#ifdef LORAMAC_CLASSB_ENABLED
- if( ( Ctx.NvmCtx->BeaconCtx.Ctrl.AcquisitionPending == 1 ) ||
- ( Ctx.NvmCtx->BeaconState == BEACON_STATE_RX ) )
+ if( ( Ctx.BeaconCtx.Ctrl.AcquisitionPending == 1 ) ||
+ ( Ctx.BeaconState == BEACON_STATE_RX ) )
{
return true;
}
@@ -1261,7 +1365,7 @@ bool LoRaMacClassBIsBeaconExpected( void )
bool LoRaMacClassBIsPingExpected( void )
{
#ifdef LORAMAC_CLASSB_ENABLED
- if( Ctx.NvmCtx->PingSlotState == PINGSLOT_STATE_RX )
+ if( Ctx.PingSlotState == PINGSLOT_STATE_RX )
{
return true;
}
@@ -1274,7 +1378,7 @@ bool LoRaMacClassBIsPingExpected( void )
bool LoRaMacClassBIsMulticastExpected( void )
{
#ifdef LORAMAC_CLASSB_ENABLED
- if( Ctx.NvmCtx->MulticastSlotState == PINGSLOT_STATE_RX )
+ if( Ctx.MulticastSlotState == PINGSLOT_STATE_RX )
{
return true;
}
@@ -1287,7 +1391,7 @@ bool LoRaMacClassBIsMulticastExpected( void )
bool LoRaMacClassBIsAcquisitionPending( void )
{
#ifdef LORAMAC_CLASSB_ENABLED
- if( Ctx.NvmCtx->BeaconCtx.Ctrl.AcquisitionPending == 1 )
+ if( Ctx.BeaconCtx.Ctrl.AcquisitionPending == 1 )
{
return true;
}
@@ -1300,8 +1404,8 @@ bool LoRaMacClassBIsAcquisitionPending( void )
bool LoRaMacClassBIsBeaconModeActive( void )
{
#ifdef LORAMAC_CLASSB_ENABLED
- if( ( Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconMode == 1 ) ||
- ( Ctx.NvmCtx->BeaconState == BEACON_STATE_ACQUISITION_BY_TIME ) )
+ if( ( Ctx.BeaconCtx.Ctrl.BeaconMode == 1 ) ||
+ ( Ctx.BeaconState == BEACON_STATE_ACQUISITION_BY_TIME ) )
{
return true;
}
@@ -1323,10 +1427,10 @@ void LoRaMacClassBSetPingSlotInfo( uint8_t periodicity )
void LoRaMacClassBHaltBeaconing( void )
{
#ifdef LORAMAC_CLASSB_ENABLED
- if( Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconMode == 1 )
+ if( Ctx.BeaconCtx.Ctrl.BeaconMode == 1 )
{
- if( ( Ctx.NvmCtx->BeaconState == BEACON_STATE_TIMEOUT ) ||
- ( Ctx.NvmCtx->BeaconState == BEACON_STATE_LOST ) )
+ if( ( Ctx.BeaconState == BEACON_STATE_TIMEOUT ) ||
+ ( Ctx.BeaconState == BEACON_STATE_LOST ) )
{
// Update the state machine before halt
LoRaMacClassBBeaconTimerEvent( NULL );
@@ -1340,12 +1444,10 @@ void LoRaMacClassBHaltBeaconing( void )
TimerStop( &Ctx.BeaconTimer );
// Halt beacon state machine
- Ctx.NvmCtx->BeaconState = BEACON_STATE_HALT;
+ Ctx.BeaconState = BEACON_STATE_HALT;
// Halt ping and multicast slot state machines
LoRaMacClassBStopRxSlots( );
-
- NvmContextChange( );
}
#endif // LORAMAC_CLASSB_ENABLED
}
@@ -1353,21 +1455,20 @@ void LoRaMacClassBHaltBeaconing( void )
void LoRaMacClassBResumeBeaconing( void )
{
#ifdef LORAMAC_CLASSB_ENABLED
- if( Ctx.NvmCtx->BeaconState == BEACON_STATE_HALT )
+ if( Ctx.BeaconState == BEACON_STATE_HALT )
{
- Ctx.NvmCtx->BeaconCtx.Ctrl.ResumeBeaconing = 1;
+ Ctx.BeaconCtx.Ctrl.ResumeBeaconing = 1;
// Set default state
- Ctx.NvmCtx->BeaconState = BEACON_STATE_LOCKED;
+ Ctx.BeaconState = BEACON_STATE_LOCKED;
- if( Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconAcquired == 0 )
+ if( Ctx.BeaconCtx.Ctrl.BeaconAcquired == 0 )
{
// Set the default state for beacon less operation
- Ctx.NvmCtx->BeaconState = BEACON_STATE_REACQUISITION;
+ Ctx.BeaconState = BEACON_STATE_REACQUISITION;
}
LoRaMacClassBBeaconTimerEvent( NULL );
- NvmContextChange( );
}
#endif // LORAMAC_CLASSB_ENABLED
}
@@ -1377,7 +1478,7 @@ LoRaMacStatus_t LoRaMacClassBSwitchClass( DeviceClass_t nextClass )
#ifdef LORAMAC_CLASSB_ENABLED
if( nextClass == CLASS_B )
{// Switch to from class a to class b
- if( ( Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconMode == 1 ) && ( Ctx.NvmCtx->PingSlotCtx.Ctrl.Assigned == 1 ) )
+ if( ( Ctx.BeaconCtx.Ctrl.BeaconMode == 1 ) && ( Ctx.NvmCtx->PingSlotCtx.Ctrl.Assigned == 1 ) )
{
return LORAMAC_STATUS_OK;
}
@@ -1431,6 +1532,7 @@ LoRaMacStatus_t LoRaMacMibClassBSetRequestConfirm( MibRequestConfirm_t *mibSet )
case MIB_PING_SLOT_DATARATE:
{
Ctx.NvmCtx->PingSlotCtx.Datarate = mibSet->Param.PingSlotDatarate;
+ NvmContextChange( );
break;
}
default:
@@ -1439,7 +1541,6 @@ LoRaMacStatus_t LoRaMacMibClassBSetRequestConfirm( MibRequestConfirm_t *mibSet )
break;
}
}
- NvmContextChange( );
return status;
#else
return LORAMAC_STATUS_SERVICE_UNKNOWN;
@@ -1453,6 +1554,7 @@ void LoRaMacClassBPingSlotInfoAns( void )
{
LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_PING_SLOT_INFO );
Ctx.NvmCtx->PingSlotCtx.Ctrl.Assigned = 1;
+ NvmContextChange( );
}
#endif // LORAMAC_CLASSB_ENABLED
}
@@ -1467,7 +1569,8 @@ uint8_t LoRaMacClassBPingSlotChannelReq( uint8_t datarate, uint32_t frequency )
if( frequency != 0 )
{
isCustomFreq = true;
- if( Radio.CheckRfFrequency( frequency ) == false )
+ verify.Frequency = frequency;
+ if( RegionVerify( *Ctx.LoRaMacClassBParams.LoRaMacRegion, &verify, PHY_FREQUENCY ) == false )
{
status &= 0xFE; // Channel frequency KO
}
@@ -1506,30 +1609,29 @@ uint8_t LoRaMacClassBPingSlotChannelReq( uint8_t datarate, uint32_t frequency )
void LoRaMacClassBBeaconTimingAns( uint16_t beaconTimingDelay, uint8_t beaconTimingChannel, TimerTime_t lastRxDone )
{
#ifdef LORAMAC_CLASSB_ENABLED
- Ctx.NvmCtx->BeaconCtx.BeaconTimingDelay = ( CLASSB_BEACON_DELAY_BEACON_TIMING_ANS * beaconTimingDelay );
- Ctx.NvmCtx->BeaconCtx.BeaconTimingChannel = beaconTimingChannel;
+ Ctx.BeaconCtx.BeaconTimingDelay = ( CLASSB_BEACON_DELAY_BEACON_TIMING_ANS * beaconTimingDelay );
+ Ctx.BeaconCtx.BeaconTimingChannel = beaconTimingChannel;
if( LoRaMacConfirmQueueIsCmdActive( MLME_BEACON_TIMING ) == true )
{
- if( Ctx.NvmCtx->BeaconCtx.BeaconTimingDelay > CLASSB_BEACON_INTERVAL )
+ if( Ctx.BeaconCtx.BeaconTimingDelay > CLASSB_BEACON_INTERVAL )
{
// We missed the beacon already
- Ctx.NvmCtx->BeaconCtx.BeaconTimingDelay = 0;
- Ctx.NvmCtx->BeaconCtx.BeaconTimingChannel = 0;
+ Ctx.BeaconCtx.BeaconTimingDelay = 0;
+ Ctx.BeaconCtx.BeaconTimingChannel = 0;
LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND, MLME_BEACON_TIMING );
}
else
{
- Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconDelaySet = 1;
- Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconChannelSet = 1;
- Ctx.NvmCtx->BeaconCtx.NextBeaconRx = lastRxDone + Ctx.NvmCtx->BeaconCtx.BeaconTimingDelay;
+ Ctx.BeaconCtx.Ctrl.BeaconDelaySet = 1;
+ Ctx.BeaconCtx.Ctrl.BeaconChannelSet = 1;
+ Ctx.BeaconCtx.NextBeaconRx = SysTimeFromMs( lastRxDone + Ctx.BeaconCtx.BeaconTimingDelay );
LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_BEACON_TIMING );
}
- Ctx.LoRaMacClassBParams.MlmeConfirm->BeaconTimingDelay = Ctx.NvmCtx->BeaconCtx.BeaconTimingDelay;
- Ctx.LoRaMacClassBParams.MlmeConfirm->BeaconTimingChannel = Ctx.NvmCtx->BeaconCtx.BeaconTimingChannel;
+ Ctx.LoRaMacClassBParams.MlmeConfirm->BeaconTimingDelay = Ctx.BeaconCtx.BeaconTimingDelay;
+ Ctx.LoRaMacClassBParams.MlmeConfirm->BeaconTimingChannel = Ctx.BeaconCtx.BeaconTimingChannel;
}
- NvmContextChange( );
#endif // LORAMAC_CLASSB_ENABLED
}
@@ -1538,60 +1640,60 @@ void LoRaMacClassBDeviceTimeAns( void )
#ifdef LORAMAC_CLASSB_ENABLED
SysTime_t nextBeacon = SysTimeGet( );
- uint32_t currentTimeMs = SysTime2Ms( nextBeacon );
+ uint32_t currentTimeMs = SysTimeToMs( nextBeacon );
nextBeacon.Seconds = nextBeacon.Seconds + ( 128 - ( nextBeacon.Seconds % 128 ) );
+ nextBeacon.SubSeconds = 0;
- Ctx.NvmCtx->BeaconCtx.NextBeaconRx = SysTime2Ms( nextBeacon );
- if( Ctx.NvmCtx->BeaconCtx.NextBeaconRx > CLASSB_BEACON_INTERVAL )
- {
- Ctx.NvmCtx->BeaconCtx.LastBeaconRx = Ctx.NvmCtx->BeaconCtx.NextBeaconRx - CLASSB_BEACON_INTERVAL;
- }
- else
- {
- Ctx.NvmCtx->BeaconCtx.LastBeaconRx = 0;
- }
+ Ctx.BeaconCtx.NextBeaconRx = nextBeacon;
+ Ctx.BeaconCtx.LastBeaconRx = SysTimeSub( Ctx.BeaconCtx.NextBeaconRx, ( SysTime_t ){ .Seconds = CLASSB_BEACON_INTERVAL / 1000, .SubSeconds = 0 } );
if( LoRaMacConfirmQueueIsCmdActive( MLME_DEVICE_TIME ) == true )
{
- if( currentTimeMs > Ctx.NvmCtx->BeaconCtx.NextBeaconRx )
+ if( currentTimeMs > SysTimeToMs( Ctx.BeaconCtx.NextBeaconRx ) )
{
// We missed the beacon already
- Ctx.NvmCtx->BeaconCtx.LastBeaconRx = 0;
- Ctx.NvmCtx->BeaconCtx.NextBeaconRx = 0;
+ Ctx.BeaconCtx.LastBeaconRx.Seconds = 0;
+ Ctx.BeaconCtx.LastBeaconRx.SubSeconds = 0;
+ Ctx.BeaconCtx.NextBeaconRx.Seconds = 0;
+ Ctx.BeaconCtx.NextBeaconRx.SubSeconds = 0;
LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND, MLME_DEVICE_TIME );
}
else
{
- Ctx.NvmCtx->BeaconCtx.Ctrl.BeaconDelaySet = 1;
- Ctx.NvmCtx->BeaconCtx.BeaconTimingDelay = Ctx.NvmCtx->BeaconCtx.NextBeaconRx - currentTimeMs;
- Ctx.NvmCtx->BeaconCtx.BeaconTime = nextBeacon.Seconds - UNIX_GPS_EPOCH_OFFSET - 128;
+ Ctx.BeaconCtx.Ctrl.BeaconDelaySet = 1;
+ Ctx.BeaconCtx.BeaconTimingDelay = SysTimeToMs( Ctx.BeaconCtx.NextBeaconRx ) - currentTimeMs;
+ Ctx.BeaconCtx.BeaconTime.Seconds = nextBeacon.Seconds - UNIX_GPS_EPOCH_OFFSET - 128;
+ Ctx.BeaconCtx.BeaconTime.SubSeconds = 0;
LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_DEVICE_TIME );
}
}
-
- NvmContextChange( );
#endif // LORAMAC_CLASSB_ENABLED
}
bool LoRaMacClassBBeaconFreqReq( uint32_t frequency )
{
#ifdef LORAMAC_CLASSB_ENABLED
+ VerifyParams_t verify;
+
if( frequency != 0 )
{
- if( Radio.CheckRfFrequency( frequency ) == true )
+ verify.Frequency = frequency;
+
+ if( RegionVerify( *Ctx.LoRaMacClassBParams.LoRaMacRegion, &verify, PHY_FREQUENCY ) == true )
{
Ctx.NvmCtx->BeaconCtx.Ctrl.CustomFreq = 1;
Ctx.NvmCtx->BeaconCtx.Frequency = frequency;
+ NvmContextChange( );
return true;
}
}
else
{
Ctx.NvmCtx->BeaconCtx.Ctrl.CustomFreq = 0;
+ NvmContextChange( );
return true;
}
- NvmContextChange( );
return false;
#else
return false;
@@ -1603,15 +1705,16 @@ TimerTime_t LoRaMacClassBIsUplinkCollision( TimerTime_t txTimeOnAir )
#ifdef LORAMAC_CLASSB_ENABLED
TimerTime_t currentTime = TimerGetCurrentTime( );
TimerTime_t beaconReserved = 0;
+ TimerTime_t nextBeacon = SysTimeToMs( Ctx.BeaconCtx.NextBeaconRx );
- beaconReserved = Ctx.NvmCtx->BeaconCtx.NextBeaconRx -
+ beaconReserved = nextBeacon -
CLASSB_BEACON_GUARD -
Ctx.LoRaMacClassBParams.LoRaMacParams->ReceiveDelay1 -
Ctx.LoRaMacClassBParams.LoRaMacParams->ReceiveDelay2 -
txTimeOnAir;
// Check if the next beacon will be received during the next uplink.
- if( ( currentTime >= beaconReserved ) && ( currentTime < ( Ctx.NvmCtx->BeaconCtx.NextBeaconRx + CLASSB_BEACON_RESERVED ) ) )
+ if( ( currentTime >= beaconReserved ) && ( currentTime < ( nextBeacon + CLASSB_BEACON_RESERVED ) ) )
{// Next beacon will be sent during the next uplink.
return CLASSB_BEACON_RESERVED;
}
@@ -1639,15 +1742,13 @@ void LoRaMacClassBStartRxSlots( void )
#ifdef LORAMAC_CLASSB_ENABLED
if( Ctx.NvmCtx->PingSlotCtx.Ctrl.Assigned == 1 )
{
- Ctx.NvmCtx->PingSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
+ Ctx.PingSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
TimerSetValue( &Ctx.PingSlotTimer, 1 );
TimerStart( &Ctx.PingSlotTimer );
- Ctx.NvmCtx->MulticastSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
+ Ctx.MulticastSlotState = PINGSLOT_STATE_CALC_PING_OFFSET;
TimerSetValue( &Ctx.MulticastSlotTimer, 1 );
TimerStart( &Ctx.MulticastSlotTimer );
-
- NvmContextChange( );
}
#endif // LORAMAC_CLASSB_ENABLED
}
@@ -1657,7 +1758,7 @@ void LoRaMacClassBSetMulticastPeriodicity( MulticastCtx_t* multicastChannel )
#ifdef LORAMAC_CLASSB_ENABLED
if( multicastChannel != NULL )
{
- multicastChannel->PingNb = CalcPingNb( multicastChannel->Periodicity );
+ multicastChannel->PingNb = CalcPingNb( multicastChannel->ChannelParams.RxParams.ClassB.Periodicity );
multicastChannel->PingPeriod = CalcPingPeriod( multicastChannel->PingNb );
}
#endif // LORAMAC_CLASSB_ENABLED
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacClassB.h b/components/connectivity/LoraWAN/mac/LoRaMacClassB.h
index 14a3039e..f8b74f26 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacClassB.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMacClassB.h
@@ -37,6 +37,11 @@
#ifndef __LORAMACCLASSB_H__
#define __LORAMACCLASSB_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "systime.h"
#include "LoRaMacTypes.h"
@@ -121,42 +126,15 @@ typedef enum ePingSlotState
*/
typedef struct sPingSlotContext
{
- struct sPingSlotCtrl
- {
- /*!
- * Set when the server assigned a ping slot to the node
- */
- uint8_t Assigned : 1;
- /*!
- * Set when a custom frequency is used
- */
- uint8_t CustomFreq : 1;
- }Ctrl;
/*!
* Ping slot length time in ms
*/
uint32_t PingSlotWindow;
- /*!
- * Number of ping slots
- */
- uint8_t PingNb;
- /*!
- * Period of the ping slots
- */
- uint16_t PingPeriod;
/*!
* Ping offset
*/
uint16_t PingOffset;
- /*!
- * Reception frequency of the ping slot windows
- */
- uint32_t Frequency;
- /*!
- * Datarate of the ping slot
- */
- int8_t Datarate;
/*!
* Current symbol timeout. The node enlarges this variable in case of beacon
* loss.
@@ -184,10 +162,6 @@ typedef struct sBeaconContext
* Set if the node has acquired the beacon
*/
uint8_t BeaconAcquired : 1;
- /*!
- * Set if the node has a custom frequency for beaconing and ping slots
- */
- uint8_t CustomFreq : 1;
/*!
* Set if a beacon delay was set for the beacon acquisition
*/
@@ -205,10 +179,7 @@ typedef struct sBeaconContext
*/
uint8_t ResumeBeaconing : 1;
}Ctrl;
- /*!
- * Beacon reception frequency
- */
- uint32_t Frequency;
+
/*!
* Current temperature
*/
@@ -216,15 +187,15 @@ typedef struct sBeaconContext
/*!
* Beacon time received with the beacon frame
*/
- TimerTime_t BeaconTime;
+ SysTime_t BeaconTime;
/*!
* Time when the last beacon was received
*/
- TimerTime_t LastBeaconRx;
+ SysTime_t LastBeaconRx;
/*!
* Time when the next beacon will be received
*/
- TimerTime_t NextBeaconRx;
+ SysTime_t NextBeaconRx;
/*!
* This is the time where the RX window will be opened.
* Its base is NextBeaconRx with temperature compensations
@@ -265,7 +236,7 @@ typedef struct sLoRaMacClassBCallback
/*!
*\brief Will be called each time a Radio IRQ is handled by the MAC
* layer.
- *
+ *
*\warning Runs in a IRQ context. Should only change variables state.
*/
void ( *MacProcessNotify )( void );
@@ -314,7 +285,7 @@ typedef struct sLoRaMacClassBParams
* Signature of callback function to be called by this module when the
* non-volatile needs to be saved.
*/
-typedef void ( *EventNvmCtxChanged )( void );
+typedef void ( *LoRaMacClassBNvmEvent )( void );
/*!
* \brief Initialize LoRaWAN Class B
@@ -323,7 +294,7 @@ typedef void ( *EventNvmCtxChanged )( void );
* \param [IN] callbacks Contains the callback which the Class B implementation needs
* \param [IN] callback function which will be called when the non-volatile context needs to be saved.
*/
-void LoRaMacClassBInit( LoRaMacClassBParams_t *classBParams, LoRaMacClassBCallback_t *callbacks, EventNvmCtxChanged classBNvmCtxChanged );
+void LoRaMacClassBInit( LoRaMacClassBParams_t *classBParams, LoRaMacClassBCallback_t *callbacks, LoRaMacClassBNvmEvent classBNvmCtxChanged );
/*!
* Restores the internal non-volatile context from passed pointer.
@@ -561,4 +532,8 @@ void LoRaMacClassBSetMulticastPeriodicity( MulticastCtx_t* multicastChannel );
void LoRaMacClassBProcess( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMACCLASSB_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacClassBConfig.h b/components/connectivity/LoraWAN/mac/LoRaMacClassBConfig.h
index b1b089c6..3c231aff 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacClassBConfig.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMacClassBConfig.h
@@ -36,6 +36,11 @@
#ifndef __LORAMACCLASSBCONFIG_H__
#define __LORAMACCLASSBCONFIG_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
/*!
* Defines the beacon interval in ms
*/
@@ -112,4 +117,8 @@
*/
#define CLASSB_WINDOW_MOVE_EXPANSION_FACTOR 2
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMACCLASSBCONFIG_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacCommands.c b/components/connectivity/LoraWAN/mac/LoRaMacCommands.c
index 74eecf95..7c3f5ba4 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacCommands.c
+++ b/components/connectivity/LoraWAN/mac/LoRaMacCommands.c
@@ -17,27 +17,23 @@ License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Daniel Jaeckle ( STACKFORCE ), Johannes Bruder ( STACKFORCE )
*/
+#include
#include "utilities.h"
#include "LoRaMacCommands.h"
#include "LoRaMacConfirmQueue.h"
-/*
+/*!
* Number of MAC Command slots
*/
#define NUM_OF_MAC_COMMANDS 15
-/*
+/*!
* Size of the CID field of MAC commands
*/
-#define CID_FIELD_SIZE 1
+#define CID_FIELD_SIZE 1
-/*
- * List of all stick MAC command answers which will be deleted after a receiving downlink
- */
-const uint8_t CIDsStickyAnsCmds[] = { MOTE_MAC_DL_CHANNEL_ANS, MOTE_MAC_RX_PARAM_SETUP_ANS, MOTE_MAC_RX_TIMING_SETUP_ANS };
-
-/*
+/*!
* Mac Commands list structure
*/
typedef struct sMacCommandsList
@@ -52,7 +48,7 @@ typedef struct sMacCommandsList
MacCommand_t* Last;
} MacCommandsList_t;
-/*
+/*!
* LoRaMac Commands Context structure
*/
typedef struct sLoRaMacCommandsCtx
@@ -71,27 +67,27 @@ typedef struct sLoRaMacCommandsCtx
size_t SerializedCmdsSize;
} LoRaMacCommandsCtx_t;
-/*
+/*!
* Callback function to notify the upper layer about context change
*/
-static EventNvmCtxChanged CommandsNvmCtxChanged;
+static LoRaMacCommandsNvmEvent CommandsNvmCtxChanged;
-/*
+/*!
* Non-volatile module context.
*/
static LoRaMacCommandsCtx_t NvmCtx;
/* Memory management functions */
-/*
+/*!
* \brief Determines if a MAC command slot is free
*
* \param[IN] slot - Slot to check
* \retval - Status of the operation
*/
-bool isSlotFree( const MacCommand_t* slot )
+static bool IsSlotFree( const MacCommand_t* slot )
{
- uint8_t* mem = (uint8_t*) slot;
+ uint8_t* mem = ( uint8_t* )slot;
for( uint16_t size = 0; size < sizeof( MacCommand_t ); size++ )
{
@@ -103,114 +99,112 @@ bool isSlotFree( const MacCommand_t* slot )
return true;
}
-/*
+/*!
* \brief Allocates a new MAC command memory slot
*
* \retval - Pointer to slot
*/
-MacCommand_t* mallocNewMacCommandSlot( )
+static MacCommand_t* MallocNewMacCommandSlot( void )
{
uint8_t itr = 0;
- while( isSlotFree( ( const MacCommand_t* ) &NvmCtx.MacCommandSlots[itr]) == false )
+ while( IsSlotFree( ( const MacCommand_t* )&NvmCtx.MacCommandSlots[itr] ) == false )
{
itr++;
if( itr == NUM_OF_MAC_COMMANDS )
{
- return 0;
+ return NULL;
}
}
return &NvmCtx.MacCommandSlots[itr];
}
-
-/*
+/*!
* \brief Free memory slot
*
* \param[IN] slot - Slot to free
*
* \retval - Status of the operation
*/
-bool freeMacCommandSlot( MacCommand_t* slot )
+static bool FreeMacCommandSlot( MacCommand_t* slot )
{
- if( slot == 0 )
+ if( slot == NULL )
{
return false;
}
- memset1( (uint8_t*) slot, 0x00, sizeof( MacCommand_t ));
+ memset1( ( uint8_t* )slot, 0x00, sizeof( MacCommand_t ) );
return true;
}
-
/* Linked list functions */
-/*
+/*!
* \brief Initialize list
*
* \param[IN] list - List that shall be initialized
* \retval - Status of the operation
*/
-static bool linkedListInit( MacCommandsList_t* list )
+static bool LinkedListInit( MacCommandsList_t* list )
{
- if( list == 0 )
+ if( list == NULL )
{
return false;
}
- list->First = 0;
- list->Last = 0;
+ list->First = NULL;
+ list->Last = NULL;
return true;
}
-/*
+/*!
* \brief Add an element to the list
*
* \param[IN] list - List where the element shall be added.
* \param[IN] element - Element to add
* \retval - Status of the operation
*/
-static bool linkedListAdd( MacCommandsList_t* list, MacCommand_t* element )
+static bool LinkedListAdd( MacCommandsList_t* list, MacCommand_t* element )
{
- if( ( list == 0 ) && ( element == 0 ) )
+ if( ( list == NULL ) || ( element == NULL ) )
{
return false;
}
- /* Check if this is the first entry to enter the list. */
- if( list->First == 0 )
+ // Check if this is the first entry to enter the list.
+ if( list->First == NULL )
{
list->First = element;
}
- /* Check if the last entry exists and update its next point. */
+ // Check if the last entry exists and update its next point.
if( list->Last )
{
list->Last->Next = element;
}
- /* Update the next point of this entry. */
- element->Next = 0;
+ // Update the next point of this entry.
+ element->Next = NULL;
- /* Update the last entry of the list. */
+ // Update the last entry of the list.
list->Last = element;
return true;
}
-/*
+/*!
* \brief Return the previous element in the list.
*
* \param[IN] list - List
* \param[IN] element - Element where the previous element shall be searched
* \retval - Status of the operation
*/
-static MacCommand_t* linkedListGetPrevious( MacCommandsList_t* list, MacCommand_t* element )
+static MacCommand_t* LinkedListGetPrevious( MacCommandsList_t* list, MacCommand_t* element )
{
- if( ( list == 0 ) && ( element == 0 ) )
+ if( ( list == NULL ) || ( element == NULL ) )
{
return NULL;
}
@@ -220,14 +214,11 @@ static MacCommand_t* linkedListGetPrevious( MacCommandsList_t* list, MacCommand_
// Start at the head of the list
curElement = list->First;
- /*
- * When current element is the first of the list, there's no previous element so we can return NULL immediately.
- */
- if( element != curElement)
+ // When current element is the first of the list, there's no previous element so we can return NULL immediately.
+ if( element != curElement )
{
-
// Loop through all elements until the end is reached or the next of current is the current element.
- while(curElement && (curElement->Next != element))
+ while( ( curElement != NULL ) && ( curElement->Next != element ) )
{
curElement = curElement->Next;
}
@@ -240,21 +231,21 @@ static MacCommand_t* linkedListGetPrevious( MacCommandsList_t* list, MacCommand_
return curElement;
}
-/*
+/*!
* \brief Remove an element from the list
*
* \param[IN] list - List where the element shall be removed from.
* \param[IN] element - Element to remove
* \retval - Status of the operation
*/
-static bool linkedListRemove( MacCommandsList_t* list, MacCommand_t* element )
+static bool LinkedListRemove( MacCommandsList_t* list, MacCommand_t* element )
{
- if( ( list == 0 ) && ( element == 0 ) )
+ if( ( list == NULL ) || ( element == NULL ) )
{
return false;
}
- MacCommand_t* PrevElement = linkedListGetPrevious( list, element );
+ MacCommand_t* PrevElement = LinkedListGetPrevious( list, element );
if( list->First == element )
{
@@ -266,12 +257,12 @@ static bool linkedListRemove( MacCommandsList_t* list, MacCommand_t* element )
list->Last = PrevElement;
}
- if( PrevElement )
+ if( PrevElement != NULL )
{
PrevElement->Next = element->Next;
}
- element->Next = 0;
+ element->Next = NULL;
return true;
}
@@ -290,6 +281,7 @@ static bool IsSticky( uint8_t cid )
case MOTE_MAC_DL_CHANNEL_ANS:
case MOTE_MAC_RX_PARAM_SETUP_ANS:
case MOTE_MAC_RX_TIMING_SETUP_ANS:
+ case MOTE_MAC_TX_PARAM_SETUP_ANS:
return true;
default:
return false;
@@ -307,13 +299,12 @@ static void NvmCtxCallback( void )
}
}
-LoRaMacCommandStatus_t LoRaMacCommandsInit( EventNvmCtxChanged commandsNvmCtxChanged )
+LoRaMacCommandStatus_t LoRaMacCommandsInit( LoRaMacCommandsNvmEvent commandsNvmCtxChanged )
{
-
// Initialize with default
- memset1( (uint8_t*)&NvmCtx, 0, sizeof( NvmCtx ) );
+ memset1( ( uint8_t* )&NvmCtx, 0, sizeof( NvmCtx ) );
- linkedListInit( &NvmCtx.MacCommandList );
+ LinkedListInit( &NvmCtx.MacCommandList );
// Assign callback
CommandsNvmCtxChanged = commandsNvmCtxChanged;
@@ -326,7 +317,7 @@ LoRaMacCommandStatus_t LoRaMacCommandsRestoreNvmCtx( void* commandsNvmCtx )
// Restore module context
if( commandsNvmCtx != NULL )
{
- memcpy1( ( uint8_t* ) &NvmCtx, ( uint8_t* ) commandsNvmCtx, sizeof( NvmCtx ) );
+ memcpy1( ( uint8_t* )&NvmCtx, ( uint8_t* )commandsNvmCtx, sizeof( NvmCtx ) );
return LORAMAC_COMMANDS_SUCCESS;
}
else
@@ -341,24 +332,24 @@ void* LoRaMacCommandsGetNvmCtx( size_t* commandsNvmCtxSize )
return &NvmCtx;
}
-LoRaMacCommandStatus_t LoRaMacCommandsAddCmd( uint8_t cid, uint8_t* payload, size_t payloadSize )
+LoRaMacCommandStatus_t LoRaMacCommandsAddCmd( uint8_t cid, uint8_t* payload, size_t payloadSize )
{
- if( payload == 0 )
+ if( payload == NULL )
{
return LORAMAC_COMMANDS_ERROR_NPE;
}
MacCommand_t* newCmd;
// Allocate a memory slot
- newCmd = mallocNewMacCommandSlot( );
+ newCmd = MallocNewMacCommandSlot( );
- if( newCmd == 0 )
+ if( newCmd == NULL )
{
return LORAMAC_COMMANDS_ERROR_MEMORY;
}
// Add it to the list of Mac commands
- if( linkedListAdd( &NvmCtx.MacCommandList, newCmd ) == false )
+ if( LinkedListAdd( &NvmCtx.MacCommandList, newCmd ) == false )
{
return LORAMAC_COMMANDS_ERROR;
}
@@ -366,7 +357,7 @@ LoRaMacCommandStatus_t LoRaMacCommandsAddCmd( uint8_t cid, uint8_t* payload, si
// Set Values
newCmd->CID = cid;
newCmd->PayloadSize = payloadSize;
- memcpy1( ( uint8_t* ) newCmd->Payload, payload, payloadSize );
+ memcpy1( ( uint8_t* )newCmd->Payload, payload, payloadSize );
newCmd->IsSticky = IsSticky( cid );
NvmCtx.SerializedCmdsSize += ( CID_FIELD_SIZE + payloadSize );
@@ -384,7 +375,7 @@ LoRaMacCommandStatus_t LoRaMacCommandsRemoveCmd( MacCommand_t* macCmd )
}
// Remove the Mac command element from MacCommandList
- if( linkedListRemove( &NvmCtx.MacCommandList, macCmd ) == false )
+ if( LinkedListRemove( &NvmCtx.MacCommandList, macCmd ) == false )
{
return LORAMAC_COMMANDS_ERROR_CMD_NOT_FOUND;
}
@@ -392,7 +383,7 @@ LoRaMacCommandStatus_t LoRaMacCommandsRemoveCmd( MacCommand_t* macCmd )
NvmCtx.SerializedCmdsSize -= ( CID_FIELD_SIZE + macCmd->PayloadSize );
// Free the MacCommand Slot
- if( freeMacCommandSlot( macCmd ) == false )
+ if( FreeMacCommandSlot( macCmd ) == false )
{
return LORAMAC_COMMANDS_ERROR;
}
@@ -410,19 +401,19 @@ LoRaMacCommandStatus_t LoRaMacCommandsGetCmd( uint8_t cid, MacCommand_t** macCmd
curElement = NvmCtx.MacCommandList.First;
// Loop through all elements until we find the element with the given CID
- while(curElement && ( curElement->CID != cid ) )
+ while( ( curElement != NULL ) && ( curElement->CID != cid ) )
{
curElement = curElement->Next;
}
+ // Update the pointer anyway
+ *macCmd = curElement;
+
// Handle error in case if we reached the end without finding it.
if( curElement == NULL )
{
return LORAMAC_COMMANDS_ERROR_CMD_NOT_FOUND;
}
-
- *macCmd = curElement;
-
return LORAMAC_COMMANDS_SUCCESS;
}
@@ -435,7 +426,7 @@ LoRaMacCommandStatus_t LoRaMacCommandsRemoveNoneStickyCmds( void )
curElement = NvmCtx.MacCommandList.First;
// Loop through all elements
- while( curElement )
+ while( curElement != NULL )
{
if( curElement->IsSticky == false )
{
@@ -466,16 +457,9 @@ LoRaMacCommandStatus_t LoRaMacCommandsRemoveStickyAnsCmds( void )
while( curElement != NULL )
{
nexElement = curElement->Next;
- if( curElement->IsSticky == true )
+ if( IsSticky( curElement->CID ) == true )
{
- for( uint8_t i = 0; i < sizeof( CIDsStickyAnsCmds ); i++)
- {
- if( curElement->CID == CIDsStickyAnsCmds[i] )
- {
- LoRaMacCommandsRemoveCmd( curElement );
- break;
- }
- }
+ LoRaMacCommandsRemoveCmd( curElement );
}
curElement = nexElement;
}
@@ -493,28 +477,28 @@ LoRaMacCommandStatus_t LoRaMacCommandsGetSizeSerializedCmds( size_t* size )
}
*size = NvmCtx.SerializedCmdsSize;
return LORAMAC_COMMANDS_SUCCESS;
-
}
-LoRaMacCommandStatus_t LoRaMacCommandsSerializeCmds( size_t availableSize, size_t* effectiveSize, uint8_t* buffer )
+LoRaMacCommandStatus_t LoRaMacCommandsSerializeCmds( size_t availableSize, size_t* effectiveSize, uint8_t* buffer )
{
+ MacCommand_t* curElement = NvmCtx.MacCommandList.First;
+ MacCommand_t* nextElement;
+ uint8_t itr = 0;
+
if( ( buffer == NULL ) || ( effectiveSize == NULL ) )
{
return LORAMAC_COMMANDS_ERROR_NPE;
}
- MacCommand_t* curElement;
- curElement = NvmCtx.MacCommandList.First;
- uint8_t itr = 0;
- // Loop through all elements
- while( curElement )
+ // Loop through all elements which fits into the buffer
+ while( curElement != NULL )
{
// If the next MAC command still fits into the buffer, add it.
if( ( availableSize - itr ) >= ( CID_FIELD_SIZE + curElement->PayloadSize ) )
{
buffer[itr++] = curElement->CID;
memcpy1( &buffer[itr], curElement->Payload, curElement->PayloadSize );
- itr = itr + curElement->PayloadSize;
+ itr += curElement->PayloadSize;
}
else
{
@@ -523,6 +507,18 @@ LoRaMacCommandStatus_t LoRaMacCommandsSerializeCmds( size_t availableSize, size_
curElement = curElement->Next;
}
+ // Remove all commands which do not fit into the buffer
+ while( curElement != NULL )
+ {
+ // Store the next element before removing the current one
+ nextElement = curElement->Next;
+ LoRaMacCommandsRemoveCmd( curElement );
+ curElement = nextElement;
+ }
+
+ // Fetch the effective size of the mac commands
+ LoRaMacCommandsGetSizeSerializedCmds( effectiveSize );
+
return LORAMAC_COMMANDS_SUCCESS;
}
@@ -538,7 +534,7 @@ LoRaMacCommandStatus_t LoRaMacCommandsStickyCmdsPending( bool* cmdsPending )
*cmdsPending = false;
// Loop through all elements
- while( curElement )
+ while( curElement != NULL )
{
if( curElement->IsSticky == true )
{
@@ -551,3 +547,103 @@ LoRaMacCommandStatus_t LoRaMacCommandsStickyCmdsPending( bool* cmdsPending )
return LORAMAC_COMMANDS_SUCCESS;
}
+
+uint8_t LoRaMacCommandsGetCmdSize( uint8_t cid )
+{
+ uint8_t cidSize = 0;
+
+ // Decode Frame MAC commands
+ switch( cid )
+ {
+ case SRV_MAC_LINK_CHECK_ANS:
+ {
+ // cid + Margin + GwCnt
+ cidSize = 3;
+ break;
+ }
+ case SRV_MAC_LINK_ADR_REQ:
+ {
+ // cid + DataRate_TXPower + ChMask (2) + Redundancy
+ cidSize = 5;
+ break;
+ }
+ case SRV_MAC_DUTY_CYCLE_REQ:
+ {
+ // cid + DutyCyclePL
+ cidSize = 2;
+ break;
+ }
+ case SRV_MAC_RX_PARAM_SETUP_REQ:
+ {
+ // cid + DLsettings + Frequency (3)
+ cidSize = 5;
+ break;
+ }
+ case SRV_MAC_DEV_STATUS_REQ:
+ {
+ // cid
+ cidSize = 1;
+ break;
+ }
+ case SRV_MAC_NEW_CHANNEL_REQ:
+ {
+ // cid + ChIndex + Frequency (3) + DrRange
+ cidSize = 6;
+ break;
+ }
+ case SRV_MAC_RX_TIMING_SETUP_REQ:
+ {
+ // cid + Settings
+ cidSize = 2;
+ break;
+ }
+ case SRV_MAC_TX_PARAM_SETUP_REQ:
+ {
+ // cid + EIRP_DwellTime
+ cidSize = 2;
+ break;
+ }
+ case SRV_MAC_DL_CHANNEL_REQ:
+ {
+ // cid + ChIndex + Frequency (3)
+ cidSize = 5;
+ break;
+ }
+ case SRV_MAC_DEVICE_TIME_ANS:
+ {
+ // cid + Seconds (4) + Fractional seconds (1)
+ cidSize = 6;
+ break;
+ }
+ case SRV_MAC_PING_SLOT_INFO_ANS:
+ {
+ // cid
+ cidSize = 1;
+ break;
+ }
+ case SRV_MAC_PING_SLOT_CHANNEL_REQ:
+ {
+ // cid + Frequency (3) + DR
+ cidSize = 5;
+ break;
+ }
+ case SRV_MAC_BEACON_TIMING_ANS:
+ {
+ // cid + TimingDelay (2) + Channel
+ cidSize = 4;
+ break;
+ }
+ case SRV_MAC_BEACON_FREQ_REQ:
+ {
+ // cid + Frequency (3)
+ cidSize = 4;
+ break;
+ }
+ default:
+ {
+ // Unknown command. ABORT MAC commands processing
+ break;
+ }
+ }
+ return cidSize;
+}
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacCommands.h b/components/connectivity/LoraWAN/mac/LoRaMacCommands.h
index 03ef1bf1..2452efe7 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacCommands.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMacCommands.h
@@ -35,6 +35,11 @@
#ifndef __LORAMAC_COMMANDS_H__
#define __LORAMAC_COMMANDS_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include "LoRaMacTypes.h"
@@ -109,7 +114,7 @@ typedef enum eLoRaMacCommandsStatus
* Signature of callback function to be called by this module when the
* non-volatile needs to be saved.
*/
-typedef void ( *EventNvmCtxChanged )( void );
+typedef void ( *LoRaMacCommandsNvmEvent )( void );
/*!
* \brief Initialization of LoRaMac MAC commands module
@@ -119,7 +124,7 @@ typedef void ( *EventNvmCtxChanged )( void );
*
* \retval - Status of the operation
*/
-LoRaMacCommandStatus_t LoRaMacCommandsInit( EventNvmCtxChanged commandsNvmCtxChanged );
+LoRaMacCommandStatus_t LoRaMacCommandsInit( LoRaMacCommandsNvmEvent commandsNvmCtxChanged );
/*!
* Restores the internal non-volatile context from passed pointer.
@@ -212,7 +217,20 @@ LoRaMacCommandStatus_t LoRaMacCommandsSerializeCmds( size_t availableSize, size_
*/
LoRaMacCommandStatus_t LoRaMacCommandsStickyCmdsPending( bool* cmdsPending );
+/*!
+ * \brief Get the MAC command size with corresponding CID.
+ *
+ * \param[IN] cid - MAC command identifier
+ *
+ * \retval Size of the command.
+ */
+uint8_t LoRaMacCommandsGetCmdSize( uint8_t cid );
+
/*! \} addtogroup LORAMAC */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMAC_COMMANDS_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacConfirmQueue.c b/components/connectivity/LoraWAN/mac/LoRaMacConfirmQueue.c
index 9f7000b1..390192dd 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacConfirmQueue.c
+++ b/components/connectivity/LoraWAN/mac/LoRaMacConfirmQueue.c
@@ -66,7 +66,7 @@ typedef struct sLoRaMacConfirmQueueCtx
/*
* Callback function to notify the upper layer about context change
*/
- EventNvmCtxChanged EventNvmCtxChanged;
+ LoRaMacConfirmQueueNvmEvent LoRaMacConfirmQueueNvmEvent;
/*!
* Non-volatile module context.
*/
@@ -112,26 +112,47 @@ static MlmeConfirmQueue_t* DecreaseBufferPointer( MlmeConfirmQueue_t* bufferPoin
return bufferPointer;
}
+static bool IsListEmpty( uint8_t count )
+{
+ if( count == 0 )
+ {
+ return true;
+ }
+ return false;
+}
+
+static bool IsListFull( uint8_t count )
+{
+ if( count >= LORA_MAC_MLME_CONFIRM_QUEUE_LEN )
+ {
+ return true;
+ }
+ return false;
+}
+
static MlmeConfirmQueue_t* GetElement( Mlme_t request, MlmeConfirmQueue_t* bufferStart, MlmeConfirmQueue_t* bufferEnd )
{
MlmeConfirmQueue_t* element = bufferStart;
- while( element != bufferEnd )
+ if( IsListEmpty( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt ) == true )
+ {
+ return NULL;
+ }
+
+ for( uint8_t elementCnt = 0; elementCnt < ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt; elementCnt++ )
{
if( element->Request == request )
{
// We have found the element
return element;
}
- else
- {
- element = IncreaseBufferPointer( element );
- }
+ element = IncreaseBufferPointer( element );
}
+
return NULL;
}
-void LoRaMacConfirmQueueInit( LoRaMacPrimitives_t* primitives, EventNvmCtxChanged confirmQueueNvmCtxChanged )
+void LoRaMacConfirmQueueInit( LoRaMacPrimitives_t* primitives, LoRaMacConfirmQueueNvmEvent confirmQueueNvmCtxChanged )
{
ConfirmQueueCtx.Primitives = primitives;
@@ -151,7 +172,7 @@ void LoRaMacConfirmQueueInit( LoRaMacPrimitives_t* primitives, EventNvmCtxChange
ConfirmQueueCtx.ConfirmQueueNvmCtx->CommonStatus = LORAMAC_EVENT_INFO_STATUS_ERROR;
// Assign callback
- ConfirmQueueCtx.EventNvmCtxChanged = confirmQueueNvmCtxChanged;
+ ConfirmQueueCtx.LoRaMacConfirmQueueNvmEvent = confirmQueueNvmCtxChanged;
}
bool LoRaMacConfirmQueueRestoreNvmCtx( void* confirmQueueNvmCtx )
@@ -176,7 +197,7 @@ void* LoRaMacConfirmQueueGetNvmCtx( size_t* confirmQueueNvmCtxSize )
bool LoRaMacConfirmQueueAdd( MlmeConfirmQueue_t* mlmeConfirm )
{
- if( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt >= LORA_MAC_MLME_CONFIRM_QUEUE_LEN )
+ if( IsListFull( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt ) == true )
{
// Protect the buffer against overwrites
return false;
@@ -197,7 +218,7 @@ bool LoRaMacConfirmQueueAdd( MlmeConfirmQueue_t* mlmeConfirm )
bool LoRaMacConfirmQueueRemoveLast( void )
{
- if( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt == 0 )
+ if( IsListEmpty( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt ) == true )
{
return false;
}
@@ -212,7 +233,7 @@ bool LoRaMacConfirmQueueRemoveLast( void )
bool LoRaMacConfirmQueueRemoveFirst( void )
{
- if( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt == 0 )
+ if( IsListEmpty( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt ) == true )
{
return false;
}
@@ -229,7 +250,7 @@ void LoRaMacConfirmQueueSetStatus( LoRaMacEventInfoStatus_t status, Mlme_t reque
{
MlmeConfirmQueue_t* element = NULL;
- if( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt > 0 )
+ if( IsListEmpty( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt ) == false )
{
element = GetElement( request, ConfirmQueueCtx.BufferStart, ConfirmQueueCtx.BufferEnd );
if( element != NULL )
@@ -244,7 +265,7 @@ LoRaMacEventInfoStatus_t LoRaMacConfirmQueueGetStatus( Mlme_t request )
{
MlmeConfirmQueue_t* element = NULL;
- if( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt > 0 )
+ if( IsListEmpty( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt ) == false )
{
element = GetElement( request, ConfirmQueueCtx.BufferStart, ConfirmQueueCtx.BufferEnd );
if( element != NULL )
@@ -261,7 +282,7 @@ void LoRaMacConfirmQueueSetStatusCmn( LoRaMacEventInfoStatus_t status )
ConfirmQueueCtx.ConfirmQueueNvmCtx->CommonStatus = status;
- if( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt > 0 )
+ if( IsListEmpty( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt ) == false )
{
do
{
@@ -333,7 +354,7 @@ uint8_t LoRaMacConfirmQueueGetCnt( void )
bool LoRaMacConfirmQueueIsFull( void )
{
- if( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt >= LORA_MAC_MLME_CONFIRM_QUEUE_LEN )
+ if( IsListFull( ConfirmQueueCtx.ConfirmQueueNvmCtx->MlmeConfirmQueueCnt ) == true )
{
return true;
}
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacConfirmQueue.h b/components/connectivity/LoraWAN/mac/LoRaMacConfirmQueue.h
index 462b0e43..b572be4f 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacConfirmQueue.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMacConfirmQueue.h
@@ -39,6 +39,11 @@
#ifndef __LORAMAC_CONFIRMQUEUE_H__
#define __LORAMAC_CONFIRMQUEUE_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
@@ -77,7 +82,7 @@ typedef struct sMlmeConfirmQueue
* Signature of callback function to be called by this module when the
* non-volatile needs to be saved.
*/
-typedef void ( *EventNvmCtxChanged )( void );
+typedef void ( *LoRaMacConfirmQueueNvmEvent )( void );
/*!
* \brief Initializes the confirm queue
@@ -87,7 +92,7 @@ typedef void ( *EventNvmCtxChanged )( void );
* \param [IN] confirmQueueNvmCtxChanged - Callback function which will be called when the
* non-volatile context needs to be saved.
*/
-void LoRaMacConfirmQueueInit( LoRaMacPrimitives_t* primitives, EventNvmCtxChanged confirmQueueNvmCtxChanged );
+void LoRaMacConfirmQueueInit( LoRaMacPrimitives_t* primitives, LoRaMacConfirmQueueNvmEvent confirmQueueNvmCtxChanged );
/*!
* Restores the internal non-volatile context from passed pointer.
@@ -192,4 +197,8 @@ uint8_t LoRaMacConfirmQueueGetCnt( void );
*/
bool LoRaMacConfirmQueueIsFull( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMAC_CONFIRMQUEUE_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacCrypto.c b/components/connectivity/LoraWAN/mac/LoRaMacCrypto.c
index 91e0b8b6..cfebcbb7 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacCrypto.c
+++ b/components/connectivity/LoraWAN/mac/LoRaMacCrypto.c
@@ -41,11 +41,6 @@
#include "LoRaMacSerializer.h"
#include "LoRaMacCrypto.h"
-/*
- * Initial value of the frame counters
- */
-#define FCNT_DOWN_INITAL_VALUE 0xFFFFFFFF
-
/*
* Frame direction definition for uplink communications
*/
@@ -61,16 +56,6 @@
*/
#define MIC_BLOCK_BX_SIZE 16
-/*
- * Size of JoinReqType is field for integrity check
- */
-#define JOIN_REQ_TYPE_SIZE 1
-
-/*
- * Size of DevNonce is field for integrity check
- */
-#define DEV_NONCE_SIZE 2
-
/*
* Number of security context entries
*/
@@ -96,40 +81,28 @@
*/
#define CRYPTO_BUFFER_SIZE CRYPTO_MAXMESSAGE_SIZE + MIC_BLOCK_BX_SIZE
-/*
- * MIC computaion offset
+/*!
+ * LoRaWAN Frame counter list.
*/
-#define CRYPTO_MIC_COMPUTATION_OFFSET JOIN_REQ_TYPE_SIZE + LORAMAC_JOIN_EUI_FIELD_SIZE + DEV_NONCE_SIZE + LORAMAC_MHDR_FIELD_SIZE
-
-/*
- * LoRaMac Crypto Non Volatile Context structure
- */
-typedef struct sLoRaMacCryptoNvmCtx
+typedef struct sFCntList
{
- /*
- * Device nonce is a counter starting at 0 when the device is initially
- * powered up and incremented with every JoinRequest.
- */
- uint16_t DevNonce;
- /*
- * JoinNonce is a device specific counter value (that never repeats itself)
- * provided by the join server and incremented with every JoinAccept message.
- */
- uint32_t JoinNonce;
- /*
- * Uplink frame counter.
+ /*!
+ * Uplink frame counter which is incremented with each uplink.
*/
uint32_t FCntUp;
- /*
- * Network downlink frame counter.
+ /*!
+ * Network downlink frame counter which is incremented with each downlink on FPort 0
+ * or when the FPort field is missing.
*/
uint32_t NFCntDown;
- /*
- * Application downlink frame counter.
+ /*!
+ * Application downlink frame counter which is incremented with each downlink
+ * on a port different than 0.
*/
uint32_t AFCntDown;
- /*
- * Downlink frame counter for LoRaWAN 1.0 Server
+ /*!
+ * In case if the device is connected to a LoRaWAN 1.0 Server,
+ * this counter is used for every kind of downlink frame.
*/
uint32_t FCntDown;
/*!
@@ -148,10 +121,38 @@ typedef struct sLoRaMacCryptoNvmCtx
* Multicast downlink counter for index 3
*/
uint32_t McFCntDown3;
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
/*
* RJcount1 is a counter incremented with every Rejoin request Type 1 frame transmitted.
*/
uint16_t RJcount1;
+#endif
+}FCntList_t;
+
+/*
+ * LoRaMac Crypto Non Volatile Context structure
+ */
+typedef struct sLoRaMacCryptoNvmCtx
+{
+ /*
+ * Stores the information if the device is connected to a LoRaWAN network
+ * server with prior to 1.1.0 implementation.
+ */
+ Version_t LrWanVersion;
+ /*
+ * Device nonce is a counter starting at 0 when the device is initially
+ * powered up and incremented with every JoinRequest.
+ */
+ uint16_t DevNonce;
+ /*
+ * JoinNonce is a device specific counter value (that never repeats itself)
+ * provided by the join server and incremented with every JoinAccept message.
+ */
+ uint32_t JoinNonce;
+ /*
+ * Frame counter list
+ */
+ FCntList_t FCntList;
/*
* LastDownFCnt stores the information which frame counter was used to unsecure the last frame.
* This information is needed to compute ConfFCnt in B1 block for the MIC.
@@ -164,15 +165,12 @@ typedef struct sLoRaMacCryptoNvmCtx
*/
typedef struct sLoRaMacCryptoCtx
{
- /*
- * Stores the information if the device is connected to a LoRaWAN network
- * server with prior to 1.1.0 implementation.
- */
- Version_t LrWanVersion;
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
/*
* RJcount0 is a counter incremented with every Type 0 or 2 Rejoin frame transmitted.
*/
uint16_t RJcount0;
+#endif
/*
* Non volatile module context structure
*/
@@ -180,7 +178,7 @@ typedef struct sLoRaMacCryptoCtx
/*
* Callback function to notify the upper layer about context change
*/
- EventNvmCtxChanged EventCryptoNvmCtxChanged;
+ LoRaMacCryptoNvmEvent EventCryptoNvmCtxChanged;
}LoRaMacCryptoCtx_t;
/*
@@ -225,7 +223,7 @@ static KeyAddr_t KeyAddrList[NUM_OF_SEC_CTX] =
{ MULTICAST_1_ADDR, MC_APP_S_KEY_1, MC_NWK_S_KEY_1, MC_KEY_1 },
{ MULTICAST_2_ADDR, MC_APP_S_KEY_2, MC_NWK_S_KEY_2, MC_KEY_2 },
{ MULTICAST_3_ADDR, MC_APP_S_KEY_3, MC_NWK_S_KEY_3, MC_KEY_3 },
- { UNICAST_DEV_ADDR, APP_S_KEY, NWK_S_ENC_KEY, NO_KEY }
+ { UNICAST_DEV_ADDR, APP_S_KEY, S_NWK_S_INT_KEY, NO_KEY }
};
/*
@@ -243,7 +241,7 @@ static KeyAddr_t KeyAddrList[NUM_OF_SEC_CTX] =
* \param[IN/OUT] buffer - Data buffer
* \retval - Status of the operation
*/
-static LoRaMacCryptoStatus_t PayloadEncrypt( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID, uint32_t address, uint8_t dir, uint32_t frameCounter )
+static LoRaMacCryptoStatus_t PayloadEncrypt( uint8_t* buffer, int16_t size, KeyIdentifier_t keyID, uint32_t address, uint8_t dir, uint32_t frameCounter )
{
if( buffer == 0 )
{
@@ -269,7 +267,7 @@ static LoRaMacCryptoStatus_t PayloadEncrypt( uint8_t* buffer, uint16_t size, Key
aBlock[12] = ( frameCounter >> 16 ) & 0xFF;
aBlock[13] = ( frameCounter >> 24 ) & 0xFF;
- while( size >= 16 )
+ while( size > 0 )
{
aBlock[15] = ctr & 0xFF;
ctr++;
@@ -278,7 +276,7 @@ static LoRaMacCryptoStatus_t PayloadEncrypt( uint8_t* buffer, uint16_t size, Key
return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
- for( uint8_t i = 0; i < 16; i++ )
+ for( uint8_t i = 0; i < ( ( size > 16 ) ? 16 : size ); i++ )
{
buffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i];
}
@@ -286,22 +284,10 @@ static LoRaMacCryptoStatus_t PayloadEncrypt( uint8_t* buffer, uint16_t size, Key
bufferIndex += 16;
}
- if( size > 0 )
- {
- aBlock[15] = ctr & 0xFF;
- if( SecureElementAesEncrypt( aBlock, 16, keyID, sBlock ) != SECURE_ELEMENT_SUCCESS )
- {
- return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
- }
- for( uint8_t i = 0; i < size; i++ )
- {
- buffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i];
- }
- }
-
return LORAMAC_CRYPTO_SUCCESS;
}
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
/*
* Encrypts the FOpts
*
@@ -326,25 +312,29 @@ static LoRaMacCryptoStatus_t FOptsEncrypt( uint16_t size, uint32_t address, uint
aBlock[0] = 0x01;
- switch( fCntID )
+ if( CryptoCtx.NvmCtx->LrWanVersion.Value > 0x01010000 )
{
- case FCNT_UP:
+ // Introduced in LoRaWAN 1.1.1 specification
+ switch( fCntID )
{
- aBlock[4] = 0x01;
- break;
+ case FCNT_UP:
+ {
+ aBlock[4] = 0x01;
+ break;
+ }
+ case N_FCNT_DOWN:
+ {
+ aBlock[4] = 0x01;
+ break;
+ }
+ case A_FCNT_DOWN:
+ {
+ aBlock[4] = 0x02;
+ break;
+ }
+ default:
+ return LORAMAC_CRYPTO_FAIL_PARAM;
}
- case N_FCNT_DOWN:
- {
- aBlock[4] = 0x01;
- break;
- }
- case A_FCNT_DOWN:
- {
- aBlock[4] = 0x02;
- break;
- }
- default:
- return LORAMAC_CRYPTO_FAIL_PARAM;
}
aBlock[5] = dir;
@@ -359,7 +349,11 @@ static LoRaMacCryptoStatus_t FOptsEncrypt( uint16_t size, uint32_t address, uint
aBlock[12] = ( frameCounter >> 16 ) & 0xFF;
aBlock[13] = ( frameCounter >> 24 ) & 0xFF;
- aBlock[15] = 0x01;
+ if( CryptoCtx.NvmCtx->LrWanVersion.Value > 0x01010000 )
+ {
+ // Introduced in LoRaWAN 1.1.1 specification
+ aBlock[15] = 0x01;
+ }
if( size > 0 )
{
@@ -375,46 +369,7 @@ static LoRaMacCryptoStatus_t FOptsEncrypt( uint16_t size, uint32_t address, uint
return LORAMAC_CRYPTO_SUCCESS;
}
-
-/*
- * Computes cmac.
- *
- * cmac = aes128_cmac(keyID, msg)
- *
- * \param[IN] msg - Message to compute the integrity code
- * \param[IN] len - Length of message
- * \param[IN] keyID - Key identifier
- * \param[OUT] cmac - Computed cmac
- * \retval - Status of the operation
- */
-static LoRaMacCryptoStatus_t ComputeCmac( uint8_t* msg, uint16_t len, KeyIdentifier_t keyID, uint32_t* cmac )
-{
- if( SecureElementComputeAesCmac( msg, len, keyID, cmac ) != SECURE_ELEMENT_SUCCESS )
- {
- return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
- }
-
- return LORAMAC_CRYPTO_SUCCESS;
-}
-
-/*!
- * Verifies cmac
- *
- * \param[IN] msg - Message to compute the integrity code
- * \param[IN] len - Length of message
- * \param[in] expectedCmac - Expected cmac
- * \param[IN] keyID - Key identifier to determine the AES key to be used
- * \retval - Status of the operation
- */
-static LoRaMacCryptoStatus_t VerifyCmac( uint8_t* msg, uint16_t len, KeyIdentifier_t keyID, uint32_t expectedcmac )
-{
- if( SecureElementVerifyAesCmac( msg, len, expectedcmac, keyID ) != SECURE_ELEMENT_SUCCESS )
- {
- return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
- }
-
- return LORAMAC_CRYPTO_SUCCESS;
-}
+#endif
/*
* Prepares B0 block for cmac computation.
@@ -437,18 +392,12 @@ static LoRaMacCryptoStatus_t PrepareB0( uint16_t msgLen, KeyIdentifier_t keyID,
b0[0] = 0x49;
- if( isAck == true )
+ if( ( isAck == true ) && ( dir == DOWNLINK ) )
{
// confFCnt contains the frame counter value modulo 2^16 of the "confirmed" uplink or downlink frame that is being acknowledged
uint16_t confFCnt = 0;
- if( dir == UPLINK )
- {
- confFCnt = ( uint16_t )( CryptoCtx.NvmCtx->FCntDown % 65536 );
- }
- else
- {
- confFCnt = ( uint16_t )( CryptoCtx.NvmCtx->FCntUp % 65536 );
- }
+
+ confFCnt = ( uint16_t )( CryptoCtx.NvmCtx->FCntList.FCntUp % 65536 );
b0[1] = confFCnt & 0xFF;
b0[2] = ( confFCnt >> 8 ) & 0xFF;
@@ -507,20 +456,15 @@ static LoRaMacCryptoStatus_t ComputeCmacB0( uint8_t* msg, uint16_t len, KeyIdent
return LORAMAC_CRYPTO_ERROR_BUF_SIZE;
}
- uint8_t micBuff[CRYPTO_BUFFER_SIZE];
- memset1( micBuff, 0, CRYPTO_BUFFER_SIZE );
+ uint8_t micBuff[MIC_BLOCK_BX_SIZE];
// Initialize the first Block
PrepareB0( len, keyID, isAck, dir, devAddr, fCnt, micBuff );
- // Copy the given data to the mic computation buffer
- memcpy1( ( micBuff + MIC_BLOCK_BX_SIZE ), msg, len );
-
- if( SecureElementComputeAesCmac( micBuff, ( len + MIC_BLOCK_BX_SIZE ), keyID, cmac ) != SECURE_ELEMENT_SUCCESS )
+ if( SecureElementComputeAesCmac( micBuff, msg, len, keyID, cmac ) != SECURE_ELEMENT_SUCCESS )
{
return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
-
return LORAMAC_CRYPTO_SUCCESS;
}
@@ -572,6 +516,7 @@ static LoRaMacCryptoStatus_t VerifyCmacB0( uint8_t* msg, uint16_t len, KeyIdenti
return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
/*
* Prpares B1 block for cmac computation.
*
@@ -655,28 +600,22 @@ static LoRaMacCryptoStatus_t ComputeCmacB1( uint8_t* msg, uint16_t len, KeyIdent
return LORAMAC_CRYPTO_ERROR_BUF_SIZE;
}
- uint8_t micBuff[CRYPTO_BUFFER_SIZE];
- memset1( micBuff, 0, CRYPTO_BUFFER_SIZE );
+ uint8_t micBuff[MIC_BLOCK_BX_SIZE];
// Initialize the first Block
PrepareB1( len, keyID, isAck, txDr, txCh, devAddr, fCntUp, micBuff );
- // Copy the given data to the mic computation buffer
- memcpy1( ( micBuff + MIC_BLOCK_BX_SIZE ), msg, len );
-
- if( SecureElementComputeAesCmac( micBuff, ( len + MIC_BLOCK_BX_SIZE ), keyID, cmac ) != SECURE_ELEMENT_SUCCESS )
+ if( SecureElementComputeAesCmac( micBuff, msg, len, keyID, cmac ) != SECURE_ELEMENT_SUCCESS )
{
return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
-
return LORAMAC_CRYPTO_SUCCESS;
}
+#endif
/*
* Gets security item from list.
*
- * cmac = aes128_cmac(keyID, B0 | msg)
- *
* \param[IN] addrID - Address identifier
* \param[OUT] keyItem - Key item reference
* \retval - Status of the operation
@@ -730,7 +669,7 @@ static LoRaMacCryptoStatus_t DeriveSessionKey10x( KeyIdentifier_t keyID, uint8_t
memcpy1( compBase + 4, netID, 3 );
memcpy1( compBase + 7, devNonce, 2 );
- if( SecureElementDeriveAndStoreKey( CryptoCtx.LrWanVersion, compBase, NWK_KEY, keyID ) != SECURE_ELEMENT_SUCCESS )
+ if( SecureElementDeriveAndStoreKey( CryptoCtx.NvmCtx->LrWanVersion, compBase, NWK_KEY, keyID ) != SECURE_ELEMENT_SUCCESS )
{
return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
@@ -738,6 +677,7 @@ static LoRaMacCryptoStatus_t DeriveSessionKey10x( KeyIdentifier_t keyID, uint8_t
return LORAMAC_CRYPTO_SUCCESS;
}
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
/*
* Derives a session key as of LoRaWAN 1.1.0
*
@@ -780,7 +720,7 @@ static LoRaMacCryptoStatus_t DeriveSessionKey11x( KeyIdentifier_t keyID, uint8_t
memcpyr( compBase + 4, joinEUI, 8 );
memcpy1( compBase + 12, devNonce, 2 );
- if( SecureElementDeriveAndStoreKey( CryptoCtx.LrWanVersion, compBase, rootKeyId, keyID ) != SECURE_ELEMENT_SUCCESS )
+ if( SecureElementDeriveAndStoreKey( CryptoCtx.NvmCtx->LrWanVersion, compBase, rootKeyId, keyID ) != SECURE_ELEMENT_SUCCESS )
{
return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
@@ -818,13 +758,60 @@ static LoRaMacCryptoStatus_t DeriveLifeTimeSessionKey( KeyIdentifier_t keyID, ui
memcpyr( compBase + 1, devEUI, 8 );
- if( SecureElementDeriveAndStoreKey( CryptoCtx.LrWanVersion, compBase, NWK_KEY, keyID ) != SECURE_ELEMENT_SUCCESS )
+ if( SecureElementDeriveAndStoreKey( CryptoCtx.NvmCtx->LrWanVersion, compBase, NWK_KEY, keyID ) != SECURE_ELEMENT_SUCCESS )
{
return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
return LORAMAC_CRYPTO_SUCCESS;
}
+#endif
+
+/*
+ * Gets the last received frame counter
+ *
+ * \param[IN] fCntID - Frame counter identifier
+ * \param[IN] lastDown - Last downlink counter value
+ *
+ * \retval - Status of the operation
+ */
+static LoRaMacCryptoStatus_t GetLastFcntDown( FCntIdentifier_t fCntID, uint32_t* lastDown )
+{
+ if( lastDown == NULL )
+ {
+ return LORAMAC_CRYPTO_ERROR_NPE;
+ }
+ switch( fCntID )
+ {
+ case N_FCNT_DOWN:
+ *lastDown = CryptoCtx.NvmCtx->FCntList.NFCntDown;
+ CryptoCtx.NvmCtx->LastDownFCnt = &CryptoCtx.NvmCtx->FCntList.NFCntDown;
+ break;
+ case A_FCNT_DOWN:
+ *lastDown = CryptoCtx.NvmCtx->FCntList.AFCntDown;
+ CryptoCtx.NvmCtx->LastDownFCnt = &CryptoCtx.NvmCtx->FCntList.AFCntDown;
+ break;
+ case FCNT_DOWN:
+ *lastDown = CryptoCtx.NvmCtx->FCntList.FCntDown;
+ CryptoCtx.NvmCtx->LastDownFCnt = &CryptoCtx.NvmCtx->FCntList.FCntDown;
+ break;
+ case MC_FCNT_DOWN_0:
+ *lastDown = CryptoCtx.NvmCtx->FCntList.McFCntDown0;
+ break;
+ case MC_FCNT_DOWN_1:
+ *lastDown = CryptoCtx.NvmCtx->FCntList.McFCntDown1;
+ break;
+ case MC_FCNT_DOWN_2:
+ *lastDown = CryptoCtx.NvmCtx->FCntList.McFCntDown2;
+ break;
+ case MC_FCNT_DOWN_3:
+ *lastDown = CryptoCtx.NvmCtx->FCntList.McFCntDown3;
+ break;
+ default:
+ return LORAMAC_CRYPTO_FAIL_FCNT_ID;
+ }
+ return LORAMAC_CRYPTO_SUCCESS;
+}
/*
* Checks the downlink counter value
@@ -837,36 +824,9 @@ static LoRaMacCryptoStatus_t DeriveLifeTimeSessionKey( KeyIdentifier_t keyID, ui
static bool CheckFCntDown( FCntIdentifier_t fCntID, uint32_t currentDown )
{
uint32_t lastDown = 0;
- switch( fCntID )
+ if( GetLastFcntDown( fCntID, &lastDown ) != LORAMAC_CRYPTO_SUCCESS )
{
- case FCNT_UP:
- return false;
- case N_FCNT_DOWN:
- lastDown = CryptoCtx.NvmCtx->NFCntDown;
- CryptoCtx.NvmCtx->LastDownFCnt = &CryptoCtx.NvmCtx->NFCntDown;
- break;
- case A_FCNT_DOWN:
- lastDown = CryptoCtx.NvmCtx->AFCntDown;
- CryptoCtx.NvmCtx->LastDownFCnt = &CryptoCtx.NvmCtx->AFCntDown;
- break;
- case FCNT_DOWN:
- lastDown = CryptoCtx.NvmCtx->FCntDown;
- CryptoCtx.NvmCtx->LastDownFCnt = &CryptoCtx.NvmCtx->FCntDown;
- break;
- case MC_FCNT_DOWN_0:
- lastDown = CryptoCtx.NvmCtx->McFCntDown0;
- break;
- case MC_FCNT_DOWN_1:
- lastDown = CryptoCtx.NvmCtx->McFCntDown1;
- break;
- case MC_FCNT_DOWN_2:
- lastDown = CryptoCtx.NvmCtx->McFCntDown2;
- break;
- case MC_FCNT_DOWN_3:
- lastDown = CryptoCtx.NvmCtx->McFCntDown3;
- break;
- default:
- return false;
+ return false;
}
if( ( currentDown > lastDown ) ||
// For LoRaWAN 1.0.X only. Allow downlink frames of 0
@@ -893,25 +853,25 @@ static void UpdateFCntDown( FCntIdentifier_t fCntID, uint32_t currentDown )
switch( fCntID )
{
case N_FCNT_DOWN:
- CryptoCtx.NvmCtx->NFCntDown = currentDown;
+ CryptoCtx.NvmCtx->FCntList.NFCntDown = currentDown;
break;
case A_FCNT_DOWN:
- CryptoCtx.NvmCtx->AFCntDown = currentDown;
+ CryptoCtx.NvmCtx->FCntList.AFCntDown = currentDown;
break;
case FCNT_DOWN:
- CryptoCtx.NvmCtx->FCntDown = currentDown;
+ CryptoCtx.NvmCtx->FCntList.FCntDown = currentDown;
break;
case MC_FCNT_DOWN_0:
- CryptoCtx.NvmCtx->McFCntDown0 = currentDown;
+ CryptoCtx.NvmCtx->FCntList.McFCntDown0 = currentDown;
break;
case MC_FCNT_DOWN_1:
- CryptoCtx.NvmCtx->McFCntDown1 = currentDown;
+ CryptoCtx.NvmCtx->FCntList.McFCntDown1 = currentDown;
break;
case MC_FCNT_DOWN_2:
- CryptoCtx.NvmCtx->McFCntDown2 = currentDown;
+ CryptoCtx.NvmCtx->FCntList.McFCntDown2 = currentDown;
break;
case MC_FCNT_DOWN_3:
- CryptoCtx.NvmCtx->McFCntDown3 = currentDown;
+ CryptoCtx.NvmCtx->FCntList.McFCntDown3 = currentDown;
break;
default:
break;
@@ -922,18 +882,19 @@ static void UpdateFCntDown( FCntIdentifier_t fCntID, uint32_t currentDown )
/*!
* Resets the frame counters
*/
-void ResetFCnts( void )
+static void ResetFCnts( void )
{
- CryptoCtx.NvmCtx->FCntUp = 0;
- CryptoCtx.NvmCtx->NFCntDown = FCNT_DOWN_INITAL_VALUE;
- CryptoCtx.NvmCtx->AFCntDown = FCNT_DOWN_INITAL_VALUE;
- CryptoCtx.NvmCtx->FCntDown = FCNT_DOWN_INITAL_VALUE;
+ CryptoCtx.NvmCtx->FCntList.FCntUp = 0;
+ CryptoCtx.NvmCtx->FCntList.NFCntDown = FCNT_DOWN_INITAL_VALUE;
+ CryptoCtx.NvmCtx->FCntList.AFCntDown = FCNT_DOWN_INITAL_VALUE;
+ CryptoCtx.NvmCtx->FCntList.FCntDown = FCNT_DOWN_INITAL_VALUE;
+ CryptoCtx.NvmCtx->LastDownFCnt = &CryptoCtx.NvmCtx->FCntList.FCntDown;
- CryptoCtx.NvmCtx->McFCntDown0 = FCNT_DOWN_INITAL_VALUE;
- CryptoCtx.NvmCtx->McFCntDown1 = FCNT_DOWN_INITAL_VALUE;
- CryptoCtx.NvmCtx->McFCntDown2 = FCNT_DOWN_INITAL_VALUE;
- CryptoCtx.NvmCtx->McFCntDown3 = FCNT_DOWN_INITAL_VALUE;
+ CryptoCtx.NvmCtx->FCntList.McFCntDown0 = FCNT_DOWN_INITAL_VALUE;
+ CryptoCtx.NvmCtx->FCntList.McFCntDown1 = FCNT_DOWN_INITAL_VALUE;
+ CryptoCtx.NvmCtx->FCntList.McFCntDown2 = FCNT_DOWN_INITAL_VALUE;
+ CryptoCtx.NvmCtx->FCntList.McFCntDown3 = FCNT_DOWN_INITAL_VALUE;
CryptoCtx.EventCryptoNvmCtxChanged( );
}
@@ -950,15 +911,8 @@ static void DummyCB( void )
* API functions
*/
-LoRaMacCryptoStatus_t LoRaMacCryptoInit( EventNvmCtxChanged cryptoNvmCtxChanged )
+LoRaMacCryptoStatus_t LoRaMacCryptoInit( LoRaMacCryptoNvmEvent cryptoNvmCtxChanged )
{
- // Initialize volatile variables
- CryptoCtx.LrWanVersion.Fields.Major = 1;
- CryptoCtx.LrWanVersion.Fields.Minor = 1;
- CryptoCtx.LrWanVersion.Fields.Revision = 0;
- CryptoCtx.LrWanVersion.Fields.Rfu = 0;
- CryptoCtx.RJcount0 = 0;
-
// Assign non volatile context
CryptoCtx.NvmCtx = &NvmCryptoCtx;
@@ -973,17 +927,15 @@ LoRaMacCryptoStatus_t LoRaMacCryptoInit( EventNvmCtxChanged cryptoNvmCtxChanged
}
// Initialize with default
- memset1( (uint8_t*) CryptoCtx.NvmCtx, 0, sizeof( LoRaMacCryptoNvmCtx_t ) );
+ memset1( ( uint8_t* )CryptoCtx.NvmCtx, 0, sizeof( LoRaMacCryptoNvmCtx_t ) );
+
+ // Set default LoRaWAN version
+ CryptoCtx.NvmCtx->LrWanVersion.Fields.Major = 1;
+ CryptoCtx.NvmCtx->LrWanVersion.Fields.Minor = 1;
+ CryptoCtx.NvmCtx->LrWanVersion.Fields.Patch = 1;
+ CryptoCtx.NvmCtx->LrWanVersion.Fields.Revision = 0;
// Reset frame counters
- CryptoCtx.RJcount0 = 0;
- CryptoCtx.NvmCtx->FCntUp = 0;
- CryptoCtx.NvmCtx->FCntDown = FCNT_DOWN_INITAL_VALUE;
- CryptoCtx.NvmCtx->NFCntDown = FCNT_DOWN_INITAL_VALUE;
- CryptoCtx.NvmCtx->AFCntDown = FCNT_DOWN_INITAL_VALUE;
-
- // Set non zero values
- CryptoCtx.NvmCtx->LastDownFCnt = &CryptoCtx.NvmCtx->FCntDown;
ResetFCnts( );
return LORAMAC_CRYPTO_SUCCESS;
@@ -991,7 +943,7 @@ LoRaMacCryptoStatus_t LoRaMacCryptoInit( EventNvmCtxChanged cryptoNvmCtxChanged
LoRaMacCryptoStatus_t LoRaMacCryptoSetLrWanVersion( Version_t version )
{
- CryptoCtx.LrWanVersion = version;
+ CryptoCtx.NvmCtx->LrWanVersion = version;
return LORAMAC_CRYPTO_SUCCESS;
}
@@ -1000,7 +952,7 @@ LoRaMacCryptoStatus_t LoRaMacCryptoRestoreNvmCtx( void* cryptoNvmCtx )
// Restore module context
if( cryptoNvmCtx != 0 )
{
- memcpy1( ( uint8_t* ) &NvmCryptoCtx, ( uint8_t* ) cryptoNvmCtx, CRYPTO_NVM_CTX_SIZE );
+ memcpy1( ( uint8_t* )&NvmCryptoCtx, ( uint8_t* )cryptoNvmCtx, CRYPTO_NVM_CTX_SIZE );
return LORAMAC_CRYPTO_SUCCESS;
}
else
@@ -1015,12 +967,127 @@ void* LoRaMacCryptoGetNvmCtx( size_t* cryptoNvmCtxSize )
return &NvmCryptoCtx;
}
+LoRaMacCryptoStatus_t LoRaMacCryptoGetFCntUp( uint32_t* currentUp )
+{
+ if( currentUp == NULL )
+ {
+ return LORAMAC_CRYPTO_ERROR_NPE;
+ }
+
+ *currentUp = CryptoCtx.NvmCtx->FCntList.FCntUp + 1;
+
+ return LORAMAC_CRYPTO_SUCCESS;
+}
+
+LoRaMacCryptoStatus_t LoRaMacCryptoGetFCntDown( FCntIdentifier_t fCntID, uint16_t maxFCntGap, uint32_t frameFcnt, uint32_t* currentDown )
+{
+ uint32_t lastDown = 0;
+ int32_t fCntDiff = 0;
+ LoRaMacCryptoStatus_t cryptoStatus = LORAMAC_CRYPTO_ERROR;
+
+ if( currentDown == NULL )
+ {
+ return LORAMAC_CRYPTO_ERROR_NPE;
+ }
+
+ cryptoStatus = GetLastFcntDown( fCntID, &lastDown );
+ if( cryptoStatus != LORAMAC_CRYPTO_SUCCESS )
+ {
+ return cryptoStatus;
+ }
+
+ // For LoRaWAN 1.0.X only, allow downlink frames of 0
+ if( lastDown == FCNT_DOWN_INITAL_VALUE )
+ {
+ *currentDown = frameFcnt;
+ }
+ else
+ {
+ // Add difference, consider roll-over
+ fCntDiff = ( int32_t )( ( int64_t )frameFcnt - ( int64_t )( lastDown & 0x0000FFFF ) );
+
+ if( fCntDiff > 0 )
+ { // Positive difference
+ *currentDown = lastDown + fCntDiff;
+ }
+ else if( fCntDiff == 0 )
+ { // Duplicate FCnt value, keep the current value.
+ *currentDown = lastDown;
+ return LORAMAC_CRYPTO_FAIL_FCNT_DUPLICATED;
+ }
+ else
+ { // Negative difference, assume a roll-over of one uint16_t
+ *currentDown = ( lastDown & 0xFFFF0000 ) + 0x10000 + frameFcnt;
+ }
+ }
+
+ // For LoRaWAN 1.0.X only, check maxFCntGap
+ if( CryptoCtx.NvmCtx->LrWanVersion.Fields.Minor == 0 )
+ {
+ if( ( ( int64_t )*currentDown - ( int64_t )lastDown ) >= maxFCntGap )
+ {
+ return LORAMAC_CRYPTO_FAIL_MAX_GAP_FCNT;
+ }
+ }
+
+ return LORAMAC_CRYPTO_SUCCESS;
+}
+
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
+LoRaMacCryptoStatus_t LoRaMacCryptoGetRJcount( FCntIdentifier_t fCntID, uint16_t* rJcount )
+{
+ if( rJcount == 0 )
+ {
+ return LORAMAC_CRYPTO_ERROR_NPE;
+ }
+ switch( fCntID )
+ {
+ case RJ_COUNT_0:
+ *rJcount = CryptoCtx.RJcount0 + 1;
+ break;
+ case RJ_COUNT_1:
+ *rJcount = CryptoCtx.NvmCtx->FCntList.RJcount1 + 1;
+ break;
+ default:
+ return LORAMAC_CRYPTO_FAIL_FCNT_ID;
+ }
+ return LORAMAC_CRYPTO_SUCCESS;
+}
+#endif
+
+LoRaMacCryptoStatus_t LoRaMacCryptoSetMulticastReference( MulticastCtx_t* multicastList )
+{
+ if( multicastList == NULL )
+ {
+ return LORAMAC_CRYPTO_ERROR_NPE;
+ }
+
+ multicastList[0].DownLinkCounter = &CryptoCtx.NvmCtx->FCntList.McFCntDown0;
+ multicastList[1].DownLinkCounter = &CryptoCtx.NvmCtx->FCntList.McFCntDown1;
+ multicastList[2].DownLinkCounter = &CryptoCtx.NvmCtx->FCntList.McFCntDown2;
+ multicastList[3].DownLinkCounter = &CryptoCtx.NvmCtx->FCntList.McFCntDown3;
+
+ return LORAMAC_CRYPTO_SUCCESS;
+}
+
LoRaMacCryptoStatus_t LoRaMacCryptoSetKey( KeyIdentifier_t keyID, uint8_t* key )
{
if( SecureElementSetKey( keyID, key ) != SECURE_ELEMENT_SUCCESS )
{
return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
+ if( keyID == APP_KEY )
+ {
+ // Derive lifetime keys
+ if( LoRaMacCryptoDeriveMcRootKey( keyID ) != LORAMAC_CRYPTO_SUCCESS )
+ {
+ return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
+ }
+ if( LoRaMacCryptoDeriveMcKEKey( MC_ROOT_KEY ) != LORAMAC_CRYPTO_SUCCESS )
+ {
+ return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
+ }
+ }
return LORAMAC_CRYPTO_SUCCESS;
}
@@ -1031,24 +1098,29 @@ LoRaMacCryptoStatus_t LoRaMacCryptoPrepareJoinRequest( LoRaMacMessageJoinRequest
return LORAMAC_CRYPTO_ERROR_NPE;
}
KeyIdentifier_t micComputationKeyID = NWK_KEY;
- LoRaMacCryptoStatus_t retval = LORAMAC_CRYPTO_ERROR;
// Add device nonce
+#if ( USE_RANDOM_DEV_NONCE == 1 )
+ uint32_t devNonce = 0;
+ SecureElementRandomNumber( &devNonce );
+ CryptoCtx.NvmCtx->DevNonce = devNonce;
+#else
CryptoCtx.NvmCtx->DevNonce++;
+#endif
CryptoCtx.EventCryptoNvmCtxChanged( );
macMsg->DevNonce = CryptoCtx.NvmCtx->DevNonce;
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
// Derive lifetime session keys
- retval = DeriveLifeTimeSessionKey( J_S_INT_KEY, macMsg->DevEUI );
- if( retval != LORAMAC_CRYPTO_SUCCESS )
+ if( DeriveLifeTimeSessionKey( J_S_INT_KEY, macMsg->DevEUI ) != LORAMAC_CRYPTO_SUCCESS )
{
- return retval;
+ return LORAMAC_CRYPTO_ERROR;
}
- retval = DeriveLifeTimeSessionKey( J_S_ENC_KEY, macMsg->DevEUI );
- if( retval != LORAMAC_CRYPTO_SUCCESS )
+ if( DeriveLifeTimeSessionKey( J_S_ENC_KEY, macMsg->DevEUI ) != LORAMAC_CRYPTO_SUCCESS )
{
- return retval;
+ return LORAMAC_CRYPTO_ERROR;
}
+#endif
// Serialize message
if( LoRaMacSerializerJoinRequest( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
@@ -1057,10 +1129,9 @@ LoRaMacCryptoStatus_t LoRaMacCryptoPrepareJoinRequest( LoRaMacMessageJoinRequest
}
// Compute mic
- retval = ComputeCmac( macMsg->Buffer, ( LORAMAC_JOIN_REQ_MSG_SIZE - LORAMAC_MIC_FIELD_SIZE ), micComputationKeyID, &macMsg->MIC );
- if( retval != LORAMAC_CRYPTO_SUCCESS )
+ if( SecureElementComputeAesCmac( NULL, macMsg->Buffer, ( LORAMAC_JOIN_REQ_MSG_SIZE - LORAMAC_MIC_FIELD_SIZE ), micComputationKeyID, &macMsg->MIC ) != SECURE_ELEMENT_SUCCESS )
{
- return retval;
+ return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
// Reserialize message to add the MIC
@@ -1072,6 +1143,7 @@ LoRaMacCryptoStatus_t LoRaMacCryptoPrepareJoinRequest( LoRaMacMessageJoinRequest
return LORAMAC_CRYPTO_SUCCESS;
}
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
LoRaMacCryptoStatus_t LoRaMacCryptoPrepareReJoinType1( LoRaMacMessageReJoinType1_t* macMsg )
{
if( macMsg == 0 )
@@ -1080,7 +1152,7 @@ LoRaMacCryptoStatus_t LoRaMacCryptoPrepareReJoinType1( LoRaMacMessageReJoinType1
}
// Check for RJcount1 overflow
- if( CryptoCtx.NvmCtx->RJcount1 == 65535 )
+ if( CryptoCtx.NvmCtx->FCntList.RJcount1 == 65535 )
{
return LORAMAC_CRYPTO_ERROR_RJCOUNT1_OVERFLOW;
}
@@ -1093,10 +1165,9 @@ LoRaMacCryptoStatus_t LoRaMacCryptoPrepareReJoinType1( LoRaMacMessageReJoinType1
// Compute mic
// cmac = aes128_cmac(JSIntKey, MHDR | RejoinType | JoinEUI| DevEUI | RJcount1)
- LoRaMacCryptoStatus_t retval = ComputeCmac( macMsg->Buffer, ( LORAMAC_RE_JOIN_1_MSG_SIZE - LORAMAC_MIC_FIELD_SIZE ), J_S_INT_KEY, &macMsg->MIC );
- if( retval != LORAMAC_CRYPTO_SUCCESS )
+ if( SecureElementComputeAesCmac( NULL, macMsg->Buffer, ( LORAMAC_RE_JOIN_1_MSG_SIZE - LORAMAC_MIC_FIELD_SIZE ), J_S_INT_KEY, &macMsg->MIC ) != SECURE_ELEMENT_SUCCESS )
{
- return retval;
+ return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
// Reserialize message to add the MIC
@@ -1106,7 +1177,7 @@ LoRaMacCryptoStatus_t LoRaMacCryptoPrepareReJoinType1( LoRaMacMessageReJoinType1
}
// Increment RJcount1
- CryptoCtx.NvmCtx->RJcount1++;
+ CryptoCtx.NvmCtx->FCntList.RJcount1++;
CryptoCtx.EventCryptoNvmCtxChanged( );
return LORAMAC_CRYPTO_SUCCESS;
@@ -1133,13 +1204,12 @@ LoRaMacCryptoStatus_t LoRaMacCryptoPrepareReJoinType0or2( LoRaMacMessageReJoinTy
// Compute mic
// cmac = aes128_cmac(SNwkSIntKey, MHDR | Rejoin Type | NetID | DevEUI | RJcount0)
- LoRaMacCryptoStatus_t retval = ComputeCmac( macMsg->Buffer, ( LORAMAC_RE_JOIN_0_2_MSG_SIZE - LORAMAC_MIC_FIELD_SIZE ), S_NWK_S_INT_KEY, &macMsg->MIC );
- if( retval != LORAMAC_CRYPTO_SUCCESS )
+ if( SecureElementComputeAesCmac( NULL, macMsg->Buffer, ( LORAMAC_RE_JOIN_0_2_MSG_SIZE - LORAMAC_MIC_FIELD_SIZE ), S_NWK_S_INT_KEY, &macMsg->MIC ) != SECURE_ELEMENT_SUCCESS )
{
- return retval;
+ return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
- // Reserialize message to add the MIC
+ // Re-serialize message to add the MIC
if( LoRaMacSerializerReJoinType0or2( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
{
return LORAMAC_CRYPTO_ERROR_SERIALIZER;
@@ -1150,6 +1220,7 @@ LoRaMacCryptoStatus_t LoRaMacCryptoPrepareReJoinType0or2( LoRaMacMessageReJoinTy
return LORAMAC_CRYPTO_SUCCESS;
}
+#endif
LoRaMacCryptoStatus_t LoRaMacCryptoHandleJoinAccept( JoinReqIdentifier_t joinReqType, uint8_t* joinEUI, LoRaMacMessageJoinAccept_t* macMsg )
{
@@ -1159,42 +1230,17 @@ LoRaMacCryptoStatus_t LoRaMacCryptoHandleJoinAccept( JoinReqIdentifier_t joinReq
}
LoRaMacCryptoStatus_t retval = LORAMAC_CRYPTO_ERROR;
- KeyIdentifier_t micComputationKeyID;
- KeyIdentifier_t encryptionKeyID;
- uint8_t micComputationOffset = 0;
- uint8_t* devNonceForKeyDerivation = ( uint8_t* ) &CryptoCtx.NvmCtx->DevNonce;
+ uint8_t decJoinAccept[33] = { 0 };
+ uint8_t versionMinor = 0;
- // Determine decryption key and DevNonce for key derivation
- if( joinReqType == JOIN_REQ )
- {
- encryptionKeyID = NWK_KEY;
- micComputationOffset = CRYPTO_MIC_COMPUTATION_OFFSET;
- }
- else
- {
- encryptionKeyID = J_S_ENC_KEY;
-
- // If Join-accept is a reply to a rejoin, the RJcount(0 or 1) replaces DevNonce in the key derivation process.
- if( ( joinReqType == REJOIN_REQ_0 ) || ( joinReqType == REJOIN_REQ_2 ) )
- {
- devNonceForKeyDerivation = ( uint8_t* ) &CryptoCtx.RJcount0;
- }
- else
- {
- devNonceForKeyDerivation = ( uint8_t* ) &CryptoCtx.NvmCtx->RJcount1;
- }
- }
-
- // Decrypt header, skip MHDR
- uint8_t procBuffer[CRYPTO_MAXMESSAGE_SIZE + CRYPTO_MIC_COMPUTATION_OFFSET];
- memset1( procBuffer, 0, ( macMsg->BufSize + micComputationOffset ) );
-
- if( SecureElementAesEncrypt( macMsg->Buffer + LORAMAC_MHDR_FIELD_SIZE, ( macMsg->BufSize - LORAMAC_MHDR_FIELD_SIZE ), encryptionKeyID, ( procBuffer + micComputationOffset ) ) != SECURE_ELEMENT_SUCCESS )
+ if( SecureElementProcessJoinAccept( joinReqType, joinEUI, CryptoCtx.NvmCtx->DevNonce, macMsg->Buffer,
+ macMsg->BufSize, decJoinAccept,
+ &versionMinor ) != SECURE_ELEMENT_SUCCESS )
{
return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
- // Copy the result to an offset location to keep space for additional information which have to be added in case of 1.1 and later
- memcpy1( macMsg->Buffer + LORAMAC_MHDR_FIELD_SIZE, ( procBuffer + micComputationOffset ), ( macMsg->BufSize - LORAMAC_MHDR_FIELD_SIZE ) );
+
+ memcpy1( macMsg->Buffer, decJoinAccept, macMsg->BufSize );
// Parse the message
if( LoRaMacParserJoinAccept( macMsg ) != LORAMAC_PARSER_SUCCESS )
@@ -1202,72 +1248,65 @@ LoRaMacCryptoStatus_t LoRaMacCryptoHandleJoinAccept( JoinReqIdentifier_t joinReq
return LORAMAC_CRYPTO_ERROR_PARSER;
}
- // Is it a LoRaWAN 1.1.0 or later ?
- if( macMsg->DLSettings.Bits.OptNeg == 1 )
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 ) || ( USE_JOIN_NONCE_COUNTER_CHECK == 1 )
+ // Check if the JoinNonce is greater as the previous one
+ uint32_t currentJoinNonce = 0;
+
+ currentJoinNonce = ( uint32_t )macMsg->JoinNonce[0];
+ currentJoinNonce |= ( ( uint32_t )macMsg->JoinNonce[1] << 8 );
+ currentJoinNonce |= ( ( uint32_t )macMsg->JoinNonce[2] << 16 );
+
+ if( currentJoinNonce > CryptoCtx.NvmCtx->JoinNonce )
{
- CryptoCtx.LrWanVersion.Fields.Minor = 1;
- micComputationKeyID = J_S_INT_KEY;
+ CryptoCtx.NvmCtx->JoinNonce = currentJoinNonce;
+ CryptoCtx.EventCryptoNvmCtxChanged( );
}
else
{
- CryptoCtx.LrWanVersion.Fields.Minor = 0;
- micComputationKeyID = NWK_KEY;
+ return LORAMAC_CRYPTO_FAIL_JOIN_NONCE;
}
+#endif
- // Verify mic
- if( CryptoCtx.LrWanVersion.Fields.Minor == 0 )
+ // Derive session keys
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
+ uint8_t* devNonceForKeyDerivation = ( uint8_t* )&CryptoCtx.NvmCtx->DevNonce;
+#endif
+
+ // Determine decryption key and DevNonce for key derivation
+ if( joinReqType == JOIN_REQ )
{
- // For legacy mode :
- // cmac = aes128_cmac(NwkKey, MHDR | JoinNonce | NetID | DevAddr | DLSettings | RxDelay | CFList | CFListType)
- retval = VerifyCmac( macMsg->Buffer, ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE ), micComputationKeyID, macMsg->MIC );
- if( retval != LORAMAC_CRYPTO_SUCCESS )
- {
- return retval;
- }
+ // Nothing to be done
}
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
else
{
- // For 1.1 and later:
- // cmac = aes128_cmac(JSIntKey, JoinReqType | JoinEUI | DevNonce | MHDR | JoinNonce | NetID | DevAddr | DLSettings | RxDelay | CFList | CFListType)
-
- // Prepare the msg for integrity check (adding JoinReqType, JoinEUI and DevNonce)
- uint16_t bufItr = 0;
- procBuffer[bufItr++] = ( uint8_t ) joinReqType;
-
- memcpyr( &procBuffer[bufItr], joinEUI, LORAMAC_JOIN_EUI_FIELD_SIZE );
- bufItr += LORAMAC_JOIN_EUI_FIELD_SIZE;
-
- procBuffer[bufItr++] = CryptoCtx.NvmCtx->DevNonce & 0xFF;
- procBuffer[bufItr++] = ( CryptoCtx.NvmCtx->DevNonce >> 8 ) & 0xFF;
-
- procBuffer[bufItr++] = macMsg->MHDR.Value;
-
- retval = VerifyCmac( procBuffer, ( macMsg->BufSize + micComputationOffset - LORAMAC_MHDR_FIELD_SIZE - LORAMAC_MIC_FIELD_SIZE ), micComputationKeyID, macMsg->MIC );
- if( retval != LORAMAC_CRYPTO_SUCCESS )
+ // If Join-accept is a reply to a rejoin, the RJcount(0 or 1) replaces DevNonce in the key derivation process.
+ if( ( joinReqType == REJOIN_REQ_0 ) || ( joinReqType == REJOIN_REQ_2 ) )
{
- return retval;
- }
-
- // Check if the JoinNonce is greater as the previous one
- uint32_t currentJoinNonce = 0;
- currentJoinNonce = ( uint32_t ) macMsg->JoinNonce[0];
- currentJoinNonce |= ( ( uint32_t ) macMsg->JoinNonce[1] << 8 );
- currentJoinNonce |= ( ( uint32_t ) macMsg->JoinNonce[2] << 16 );
-
- if( currentJoinNonce > CryptoCtx.NvmCtx->JoinNonce )
- {
- CryptoCtx.NvmCtx->JoinNonce = currentJoinNonce;
- CryptoCtx.EventCryptoNvmCtxChanged( );
+ devNonceForKeyDerivation = ( uint8_t* )&CryptoCtx.RJcount0;
}
else
{
- return LORAMAC_CRYPTO_FAIL_JOIN_NONCE;
+ devNonceForKeyDerivation = ( uint8_t* )&CryptoCtx.NvmCtx->FCntList.RJcount1;
}
}
- // Derive session keys
- if( CryptoCtx.LrWanVersion.Fields.Minor == 1 )
+ if( versionMinor == 1 )
{
+ // Operating in LoRaWAN 1.1.x mode
+ // Derive lifetime keys
+ retval = LoRaMacCryptoDeriveMcRootKey( APP_KEY );
+ if( retval != LORAMAC_CRYPTO_SUCCESS )
+ {
+ return retval;
+ }
+
+ retval = LoRaMacCryptoDeriveMcKEKey( MC_ROOT_KEY );
+ if( retval != LORAMAC_CRYPTO_SUCCESS )
+ {
+ return retval;
+ }
+
retval = DeriveSessionKey11x( F_NWK_S_INT_KEY, macMsg->JoinNonce, joinEUI, devNonceForKeyDerivation );
if( retval != LORAMAC_CRYPTO_SUCCESS )
{
@@ -1293,40 +1332,59 @@ LoRaMacCryptoStatus_t LoRaMacCryptoHandleJoinAccept( JoinReqIdentifier_t joinReq
}
}
else
+#endif
{
- // prior LoRaWAN 1.1.0
-
- retval = DeriveSessionKey10x( APP_S_KEY, macMsg->JoinNonce, macMsg->NetID, ( uint8_t* ) &CryptoCtx.NvmCtx->DevNonce );
+ // Operating in LoRaWAN 1.0.x mode
+ retval = LoRaMacCryptoDeriveMcRootKey( APP_KEY );
if( retval != LORAMAC_CRYPTO_SUCCESS )
{
return retval;
}
- retval = DeriveSessionKey10x( NWK_S_ENC_KEY, macMsg->JoinNonce, macMsg->NetID, ( uint8_t* ) &CryptoCtx.NvmCtx->DevNonce );
+ retval = LoRaMacCryptoDeriveMcKEKey( MC_ROOT_KEY );
if( retval != LORAMAC_CRYPTO_SUCCESS )
{
return retval;
}
- retval = DeriveSessionKey10x( F_NWK_S_INT_KEY, macMsg->JoinNonce, macMsg->NetID, ( uint8_t* ) &CryptoCtx.NvmCtx->DevNonce );
+ retval = DeriveSessionKey10x( APP_S_KEY, macMsg->JoinNonce, macMsg->NetID, ( uint8_t* )&CryptoCtx.NvmCtx->DevNonce );
if( retval != LORAMAC_CRYPTO_SUCCESS )
{
return retval;
}
- retval = DeriveSessionKey10x( S_NWK_S_INT_KEY, macMsg->JoinNonce, macMsg->NetID, ( uint8_t* ) &CryptoCtx.NvmCtx->DevNonce );
+ retval = DeriveSessionKey10x( NWK_S_ENC_KEY, macMsg->JoinNonce, macMsg->NetID, ( uint8_t* )&CryptoCtx.NvmCtx->DevNonce );
+ if( retval != LORAMAC_CRYPTO_SUCCESS )
+ {
+ return retval;
+ }
+
+ retval = DeriveSessionKey10x( F_NWK_S_INT_KEY, macMsg->JoinNonce, macMsg->NetID, ( uint8_t* )&CryptoCtx.NvmCtx->DevNonce );
+ if( retval != LORAMAC_CRYPTO_SUCCESS )
+ {
+ return retval;
+ }
+
+ retval = DeriveSessionKey10x( S_NWK_S_INT_KEY, macMsg->JoinNonce, macMsg->NetID, ( uint8_t* )&CryptoCtx.NvmCtx->DevNonce );
if( retval != LORAMAC_CRYPTO_SUCCESS )
{
return retval;
}
}
- // Join-Accept is successfully processed, reset frame counters
+ // Join-Accept is successfully processed
+ // Save LoRaWAN specification version
+ CryptoCtx.NvmCtx->LrWanVersion.Fields.Minor = versionMinor;
+
+ // Reset frame counters
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
CryptoCtx.RJcount0 = 0;
- CryptoCtx.NvmCtx->FCntUp = 0;
- CryptoCtx.NvmCtx->FCntDown = FCNT_DOWN_INITAL_VALUE;
- CryptoCtx.NvmCtx->NFCntDown = FCNT_DOWN_INITAL_VALUE;
- CryptoCtx.NvmCtx->AFCntDown = FCNT_DOWN_INITAL_VALUE;
+#endif
+ CryptoCtx.NvmCtx->FCntList.FCntUp = 0;
+ CryptoCtx.NvmCtx->FCntList.FCntDown = FCNT_DOWN_INITAL_VALUE;
+ CryptoCtx.NvmCtx->FCntList.NFCntDown = FCNT_DOWN_INITAL_VALUE;
+ CryptoCtx.NvmCtx->FCntList.AFCntDown = FCNT_DOWN_INITAL_VALUE;
+
CryptoCtx.EventCryptoNvmCtxChanged( );
return LORAMAC_CRYPTO_SUCCESS;
@@ -1335,45 +1393,45 @@ LoRaMacCryptoStatus_t LoRaMacCryptoHandleJoinAccept( JoinReqIdentifier_t joinReq
LoRaMacCryptoStatus_t LoRaMacCryptoSecureMessage( uint32_t fCntUp, uint8_t txDr, uint8_t txCh, LoRaMacMessageData_t* macMsg )
{
LoRaMacCryptoStatus_t retval = LORAMAC_CRYPTO_ERROR;
- KeyIdentifier_t FRMPayloadDecryptionKeyID = APP_S_KEY;
+ KeyIdentifier_t payloadDecryptionKeyID = APP_S_KEY;
if( macMsg == NULL )
{
return LORAMAC_CRYPTO_ERROR_NPE;
}
- if( fCntUp < CryptoCtx.NvmCtx->FCntUp )
+ if( fCntUp < CryptoCtx.NvmCtx->FCntList.FCntUp )
{
- return LORAMAC_CRYPTO_FAIL_FCNT;
+ return LORAMAC_CRYPTO_FAIL_FCNT_SMALLER;
}
// Encrypt payload
if( macMsg->FPort == 0 )
{
// Use network session key
- FRMPayloadDecryptionKeyID = NWK_S_ENC_KEY;
+ payloadDecryptionKeyID = NWK_S_ENC_KEY;
}
- if( fCntUp > CryptoCtx.NvmCtx->FCntUp )
+ if( fCntUp > CryptoCtx.NvmCtx->FCntList.FCntUp )
{
- retval = PayloadEncrypt( macMsg->FRMPayload, macMsg->FRMPayloadSize, FRMPayloadDecryptionKeyID, macMsg->FHDR.DevAddr, UPLINK, fCntUp );
+ retval = PayloadEncrypt( macMsg->FRMPayload, macMsg->FRMPayloadSize, payloadDecryptionKeyID, macMsg->FHDR.DevAddr, UPLINK, fCntUp );
if( retval != LORAMAC_CRYPTO_SUCCESS )
{
return retval;
}
- if( CryptoCtx.LrWanVersion.Fields.Minor == 1 )
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
+ if( CryptoCtx.NvmCtx->LrWanVersion.Fields.Minor == 1 )
{
// Encrypt FOpts
- retval = FOptsEncrypt( macMsg->FHDR.FCtrl.Bits.FOptsLen, macMsg->FHDR.DevAddr, UPLINK, FCNT_UP, fCntUp, macMsg->FHDR.FOpts );
+ retval = FOptsEncrypt( macMsg->FHDR.FCtrl.Bits.FOptsLen, macMsg->FHDR.DevAddr, UPLINK, FCNT_UP, fCntUp, macMsg->FHDR.FOpts );
if( retval != LORAMAC_CRYPTO_SUCCESS )
{
return retval;
}
}
+#endif
}
- CryptoCtx.NvmCtx->FCntUp = fCntUp;
- CryptoCtx.EventCryptoNvmCtxChanged( );
// Serialize message
if( LoRaMacSerializerData( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
@@ -1382,19 +1440,20 @@ LoRaMacCryptoStatus_t LoRaMacCryptoSecureMessage( uint32_t fCntUp, uint8_t txDr,
}
// Compute mic
- if( CryptoCtx.LrWanVersion.Fields.Minor == 1 )
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
+ if( CryptoCtx.NvmCtx->LrWanVersion.Fields.Minor == 1 )
{
uint32_t cmacS = 0;
uint32_t cmacF = 0;
// cmacS = aes128_cmac(SNwkSIntKey, B1 | msg)
- retval = ComputeCmacB1( macMsg->Buffer, ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE ), S_NWK_S_INT_KEY, macMsg->FHDR.FCtrl.Bits.Ack, txDr, txCh, macMsg->FHDR.DevAddr, macMsg->FHDR.FCnt, &cmacS );
+ retval = ComputeCmacB1( macMsg->Buffer, ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE ), S_NWK_S_INT_KEY, macMsg->FHDR.FCtrl.Bits.Ack, txDr, txCh, macMsg->FHDR.DevAddr, fCntUp, &cmacS );
if( retval != LORAMAC_CRYPTO_SUCCESS )
{
return retval;
}
//cmacF = aes128_cmac(FNwkSIntKey, B0 | msg)
- retval = ComputeCmacB0( macMsg->Buffer, ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE ), F_NWK_S_INT_KEY, macMsg->FHDR.FCtrl.Bits.Ack, UPLINK, macMsg->FHDR.DevAddr, macMsg->FHDR.FCnt, &cmacF );
+ retval = ComputeCmacB0( macMsg->Buffer, ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE ), F_NWK_S_INT_KEY, macMsg->FHDR.FCtrl.Bits.Ack, UPLINK, macMsg->FHDR.DevAddr, fCntUp, &cmacF );
if( retval != LORAMAC_CRYPTO_SUCCESS )
{
return retval;
@@ -1403,10 +1462,11 @@ LoRaMacCryptoStatus_t LoRaMacCryptoSecureMessage( uint32_t fCntUp, uint8_t txDr,
macMsg->MIC = ( ( cmacF << 16 ) & 0xFFFF0000 ) | ( cmacS & 0x0000FFFF );
}
else
+#endif
{
// MIC = cmacF[0..3]
// The IsAck parameter is every time false since the ConfFCnt field is not used in legacy mode.
- retval = ComputeCmacB0( macMsg->Buffer, ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE ), NWK_S_ENC_KEY, false, UPLINK, macMsg->FHDR.DevAddr, macMsg->FHDR.FCnt, &macMsg->MIC );
+ retval = ComputeCmacB0( macMsg->Buffer, ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE ), NWK_S_ENC_KEY, false, UPLINK, macMsg->FHDR.DevAddr, fCntUp, &macMsg->MIC );
if( retval != LORAMAC_CRYPTO_SUCCESS )
{
return retval;
@@ -1419,6 +1479,9 @@ LoRaMacCryptoStatus_t LoRaMacCryptoSecureMessage( uint32_t fCntUp, uint8_t txDr,
return LORAMAC_CRYPTO_ERROR_SERIALIZER;
}
+ CryptoCtx.NvmCtx->FCntList.FCntUp = fCntUp;
+ CryptoCtx.EventCryptoNvmCtxChanged( );
+
return LORAMAC_CRYPTO_SUCCESS;
}
@@ -1431,11 +1494,11 @@ LoRaMacCryptoStatus_t LoRaMacCryptoUnsecureMessage( AddressIdentifier_t addrID,
if( CheckFCntDown( fCntID, fCntDown ) == false )
{
- return LORAMAC_CRYPTO_FAIL_FCNT;
+ return LORAMAC_CRYPTO_FAIL_FCNT_SMALLER;
}
LoRaMacCryptoStatus_t retval = LORAMAC_CRYPTO_ERROR;
- KeyIdentifier_t FRMPayloadDecryptionKeyID = APP_S_KEY;
+ KeyIdentifier_t payloadDecryptionKeyID = APP_S_KEY;
KeyIdentifier_t micComputationKeyID = S_NWK_S_INT_KEY;
KeyAddr_t* curItem;
@@ -1451,7 +1514,9 @@ LoRaMacCryptoStatus_t LoRaMacCryptoUnsecureMessage( AddressIdentifier_t addrID,
{
return retval;
}
- FRMPayloadDecryptionKeyID = curItem->AppSkey;
+
+ payloadDecryptionKeyID = curItem->AppSkey;
+ micComputationKeyID = curItem->NwkSkey;
// Check if it is our address
if( address != macMsg->FHDR.DevAddr )
@@ -1461,7 +1526,7 @@ LoRaMacCryptoStatus_t LoRaMacCryptoUnsecureMessage( AddressIdentifier_t addrID,
// Compute mic
bool isAck = macMsg->FHDR.FCtrl.Bits.Ack;
- if( CryptoCtx.LrWanVersion.Fields.Minor == 0 )
+ if( CryptoCtx.NvmCtx->LrWanVersion.Fields.Minor == 0 )
{
// In legacy mode the IsAck parameter is forced to be false since the ConfFCnt field is not used.
isAck = false;
@@ -1478,54 +1543,65 @@ LoRaMacCryptoStatus_t LoRaMacCryptoUnsecureMessage( AddressIdentifier_t addrID,
if( macMsg->FPort == 0 )
{
// Use network session encryption key
- FRMPayloadDecryptionKeyID = NWK_S_ENC_KEY;
+ payloadDecryptionKeyID = NWK_S_ENC_KEY;
}
- retval = PayloadEncrypt( macMsg->FRMPayload, macMsg->FRMPayloadSize, FRMPayloadDecryptionKeyID, address, DOWNLINK, fCntDown );
+ retval = PayloadEncrypt( macMsg->FRMPayload, macMsg->FRMPayloadSize, payloadDecryptionKeyID, address, DOWNLINK, fCntDown );
if( retval != LORAMAC_CRYPTO_SUCCESS )
{
return retval;
}
- if( CryptoCtx.LrWanVersion.Fields.Minor == 1 )
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
+ if( CryptoCtx.NvmCtx->LrWanVersion.Fields.Minor == 1 )
{
- // Decrypt FOpts
- retval = FOptsEncrypt( macMsg->FHDR.FCtrl.Bits.FOptsLen, address, DOWNLINK, fCntID, fCntDown, macMsg->FHDR.FOpts );
- if( retval != LORAMAC_CRYPTO_SUCCESS )
+ if( addrID == UNICAST_DEV_ADDR )
{
- return retval;
- }
+ // Decrypt FOpts
+ retval = FOptsEncrypt( macMsg->FHDR.FCtrl.Bits.FOptsLen, address, DOWNLINK, fCntID, fCntDown, macMsg->FHDR.FOpts );
+ if( retval != LORAMAC_CRYPTO_SUCCESS )
+ {
+ return retval;
+ }
+ }
}
+#endif
UpdateFCntDown( fCntID, fCntDown );
return LORAMAC_CRYPTO_SUCCESS;
}
-LoRaMacCryptoStatus_t LoRaMacCryptoDeriveMcKEKey( KeyIdentifier_t keyID, uint16_t nonce, uint8_t* devEUI )
+LoRaMacCryptoStatus_t LoRaMacCryptoDeriveMcRootKey( KeyIdentifier_t keyID )
{
- if( devEUI == 0 )
- {
- return LORAMAC_CRYPTO_ERROR_NPE;
- }
-
- // Nonce SHALL be greater than 15
- if( nonce < 16 )
- {
- return LORAMAC_CRYPTO_FAIL_PARAM;
- }
-
- // Prevent other keys than NwkKey or AppKey for LoRaWAN 1.1 or later
- if( ( ( keyID == APP_KEY ) && ( CryptoCtx.LrWanVersion.Fields.Minor == 0 ) ) || ( keyID == NWK_KEY ) )
+ // Prevent other keys than AppKey
+ if( keyID != APP_KEY )
{
return LORAMAC_CRYPTO_ERROR_INVALID_KEY_ID;
}
uint8_t compBase[16] = { 0 };
- compBase[0] = nonce & 0xFF;
- compBase[1] = ( nonce >> 8 ) & 0xFF;
- memcpyr( compBase + 2, devEUI, 8 );
+ if( CryptoCtx.NvmCtx->LrWanVersion.Fields.Minor == 1 )
+ {
+ compBase[0] = 0x20;
+ }
+ if( SecureElementDeriveAndStoreKey( CryptoCtx.NvmCtx->LrWanVersion, compBase, keyID, MC_ROOT_KEY ) != SECURE_ELEMENT_SUCCESS )
+ {
+ return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
+ }
- if( SecureElementDeriveAndStoreKey( CryptoCtx.LrWanVersion, compBase, keyID, MC_KE_KEY ) != SECURE_ELEMENT_SUCCESS )
+ return LORAMAC_CRYPTO_SUCCESS;
+}
+
+LoRaMacCryptoStatus_t LoRaMacCryptoDeriveMcKEKey( KeyIdentifier_t keyID )
+{
+ // Prevent other keys than McRootKey
+ if( keyID != MC_ROOT_KEY )
+ {
+ return LORAMAC_CRYPTO_ERROR_INVALID_KEY_ID;
+ }
+ uint8_t compBase[16] = { 0 };
+
+ if( SecureElementDeriveAndStoreKey( CryptoCtx.NvmCtx->LrWanVersion, compBase, keyID, MC_KE_KEY ) != SECURE_ELEMENT_SUCCESS )
{
return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
@@ -1550,31 +1626,30 @@ LoRaMacCryptoStatus_t LoRaMacCryptoDeriveMcSessionKeyPair( AddressIdentifier_t a
return retval;
}
- //McAppSKey = aes128_encrypt(McKey, 0x01 | McAddr | pad16)
- //McNwkSKey = aes128_encrypt(McKey, 0x02 | McAddr | pad16)
+ // McAppSKey = aes128_encrypt(McKey, 0x01 | McAddr | pad16)
+ // McNwkSKey = aes128_encrypt(McKey, 0x02 | McAddr | pad16)
uint8_t compBaseAppS[16] = { 0 };
uint8_t compBaseNwkS[16] = { 0 };
compBaseAppS[0] = 0x01;
- compBaseNwkS[0] = 0x02;
-
compBaseAppS[1] = mcAddr & 0xFF;
compBaseAppS[2] = ( mcAddr >> 8 ) & 0xFF;
compBaseAppS[3] = ( mcAddr >> 16 ) & 0xFF;
compBaseAppS[4] = ( mcAddr >> 24 ) & 0xFF;
+ compBaseNwkS[0] = 0x02;
compBaseNwkS[1] = mcAddr & 0xFF;
compBaseNwkS[2] = ( mcAddr >> 8 ) & 0xFF;
compBaseNwkS[3] = ( mcAddr >> 16 ) & 0xFF;
compBaseNwkS[4] = ( mcAddr >> 24 ) & 0xFF;
- if( SecureElementDeriveAndStoreKey( CryptoCtx.LrWanVersion, compBaseAppS, curItem->RootKey, curItem->AppSkey ) != SECURE_ELEMENT_SUCCESS )
+ if( SecureElementDeriveAndStoreKey( CryptoCtx.NvmCtx->LrWanVersion, compBaseAppS, curItem->RootKey, curItem->AppSkey ) != SECURE_ELEMENT_SUCCESS )
{
return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
- if( SecureElementDeriveAndStoreKey( CryptoCtx.LrWanVersion, compBaseNwkS, curItem->RootKey, curItem->NwkSkey ) != SECURE_ELEMENT_SUCCESS )
+ if( SecureElementDeriveAndStoreKey( CryptoCtx.NvmCtx->LrWanVersion, compBaseNwkS, curItem->RootKey, curItem->NwkSkey ) != SECURE_ELEMENT_SUCCESS )
{
return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
}
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacCrypto.h b/components/connectivity/LoraWAN/mac/LoRaMacCrypto.h
index fa8f75a8..63ba64f8 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacCrypto.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMacCrypto.h
@@ -37,6 +37,11 @@
#ifndef __LORAMAC_CRYPTO_H__
#define __LORAMAC_CRYPTO_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include
@@ -44,6 +49,26 @@
#include "LoRaMacTypes.h"
#include "LoRaMacMessageTypes.h"
+/*!
+ * Indicates if LoRaWAN 1.1.x crypto scheme is enabled
+ */
+#define USE_LRWAN_1_1_X_CRYPTO 0
+
+/*!
+ * Indicates if a random devnonce must be used or not
+ */
+#define USE_RANDOM_DEV_NONCE 1
+
+/*!
+ * Indicates if JoinNonce is counter based and requires to be checked
+ */
+#define USE_JOIN_NONCE_COUNTER_CHECK 0
+
+/*!
+ * Initial value of the frame counters
+ */
+#define FCNT_DOWN_INITAL_VALUE 0xFFFFFFFF
+
/*!
* LoRaMac Cryto Status
*/
@@ -70,9 +95,21 @@ typedef enum eLoRaMacCryptoStatus
*/
LORAMAC_CRYPTO_FAIL_RJCOUNT0_OVERFLOW,
/*!
- * FCntUp/Down check failed
+ * FCNT_ID is not supported
*/
- LORAMAC_CRYPTO_FAIL_FCNT,
+ LORAMAC_CRYPTO_FAIL_FCNT_ID,
+ /*!
+ * FCntUp/Down check failed (new FCnt is smaller than previous one)
+ */
+ LORAMAC_CRYPTO_FAIL_FCNT_SMALLER,
+ /*!
+ * FCntUp/Down check failed (duplicated)
+ */
+ LORAMAC_CRYPTO_FAIL_FCNT_DUPLICATED,
+ /*!
+ * MAX_GAP_FCNT check failed
+ */
+ LORAMAC_CRYPTO_FAIL_MAX_GAP_FCNT,
/*!
* Not allowed parameter value
*/
@@ -125,7 +162,7 @@ typedef enum eLoRaMacCryptoStatus
* crypto module context.
*
*/
-typedef void ( *EventNvmCtxChanged )( void );
+typedef void ( *LoRaMacCryptoNvmEvent )( void );
/*!
* Initialization of LoRaMac Crypto module
@@ -135,11 +172,11 @@ typedef void ( *EventNvmCtxChanged )( void );
* non-volatile context have to be stored.
* \retval - Status of the operation
*/
-LoRaMacCryptoStatus_t LoRaMacCryptoInit( EventNvmCtxChanged cryptoNvmCtxChanged );
+LoRaMacCryptoStatus_t LoRaMacCryptoInit( LoRaMacCryptoNvmEvent cryptoNvmCtxChanged );
/*!
* Sets the LoRaWAN specification version to be used.
- *
+ *
* \warning This function should be used for ABP only. In case of OTA the version will be set automatically.
*
* \param[IN] version - LoRaWAN specification version to be used.
@@ -164,6 +201,34 @@ LoRaMacCryptoStatus_t LoRaMacCryptoRestoreNvmCtx( void* cryptoNvmCtx );
*/
void* LoRaMacCryptoGetNvmCtx( size_t* cryptoNvmCtxSize );
+/*!
+ * Returns updated fCntID downlink counter value.
+ *
+ * \param[IN] fCntID - Frame counter identifier
+ * \param[IN] maxFcntGap - Maximum allowed frame counter difference (only necessary for L2 LW1.0.x)
+ * \param[IN] frameFcnt - Received frame counter (used to update current counter value)
+ * \param[OUT] currentDown - Current downlink counter value
+ * \retval - Status of the operation
+ */
+LoRaMacCryptoStatus_t LoRaMacCryptoGetFCntDown( FCntIdentifier_t fCntID, uint16_t maxFCntGap, uint32_t frameFcnt, uint32_t* currentDown );
+
+/*!
+ * Returns updated fCntUp uplink counter value.
+ *
+ * \param[IN] currentUp - Uplink counter value
+ * \retval - Status of the operation
+ */
+LoRaMacCryptoStatus_t LoRaMacCryptoGetFCntUp( uint32_t* currentUp );
+
+/*!
+ * Provides multicast context.
+ *
+ * \param[IN] multicastList - Pointer to the multicast context list
+ *
+ * \retval - Status of the operation
+ */
+LoRaMacCryptoStatus_t LoRaMacCryptoSetMulticastReference( MulticastCtx_t* multicastList );
+
/*!
* Sets a key
*
@@ -235,16 +300,28 @@ LoRaMacCryptoStatus_t LoRaMacCryptoSecureMessage( uint32_t fCntUp, uint8_t txDr,
LoRaMacCryptoStatus_t LoRaMacCryptoUnsecureMessage( AddressIdentifier_t addrID, uint32_t address, FCntIdentifier_t fCntID, uint32_t fCntDown, LoRaMacMessageData_t* macMsg );
/*!
- * Derives the McKEKey from the AppKey or NwkKey.
+ * Derives the McRootKey from the AppKey.
*
- * McKEKey = aes128_encrypt(NwkKey or AppKey , nonce | DevEUI | pad16)
+ * 1.0.x
+ * McRootKey = aes128_encrypt(AppKey, 0x00 | pad16)
*
- * \param[IN] keyID - Key identifier of the root key to use to perform the derivation ( NwkKey or AppKey )
- * \param[IN] nonce - Nonce value ( nonce <= 15)
- * \param[IN] devEUI - DevEUI Value
+ * 1.1.x
+ * McRootKey = aes128_encrypt(AppKey, 0x20 | pad16)
+ *
+ * \param[IN] keyID - Key identifier of the root key to use to perform the derivation ( AppKey )
* \retval - Status of the operation
*/
-LoRaMacCryptoStatus_t LoRaMacCryptoDeriveMcKEKey( KeyIdentifier_t keyID, uint16_t nonce, uint8_t* devEUI );
+LoRaMacCryptoStatus_t LoRaMacCryptoDeriveMcRootKey( KeyIdentifier_t keyID );
+
+/*!
+ * Derives the McKEKey from the McRootKey.
+ *
+ * McKEKey = aes128_encrypt(McRootKey , 0x00 | pad16)
+ *
+ * \param[IN] keyID - Key identifier of the root key to use to perform the derivation ( McRootKey )
+ * \retval - Status of the operation
+ */
+LoRaMacCryptoStatus_t LoRaMacCryptoDeriveMcKEKey( KeyIdentifier_t keyID );
/*!
* Derives a Multicast group key pair ( McAppSKey, McNwkSKey ) from McKey
@@ -260,4 +337,8 @@ LoRaMacCryptoStatus_t LoRaMacCryptoDeriveMcSessionKeyPair( AddressIdentifier_t a
/*! \} addtogroup LORAMAC */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMAC_CRYPTO_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacFCntHandler.c b/components/connectivity/LoraWAN/mac/LoRaMacFCntHandler.c
deleted file mode 100644
index 9972bf27..00000000
--- a/components/connectivity/LoraWAN/mac/LoRaMacFCntHandler.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- / _____) _ | |
-( (____ _____ ____ _| |_ _____ ____| |__
- \____ \| ___ | (_ _) ___ |/ ___) _ \
- _____) ) ____| | | || |_| ____( (___| | | |
-(______/|_____)_|_|_| \__)_____)\____)_| |_|
- (C)2013 Semtech
- ___ _____ _ ___ _ _____ ___ ___ ___ ___
-/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
-\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
-|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
-embedded.connectivity.solutions===============
-
-Description: LoRa MAC layer frame counter handling implementation
-
-License: Revised BSD License, see LICENSE.TXT file include in the project
-
-Maintainer: Miguel Luis ( Semtech ), Daniel Jaeckle ( STACKFORCE ), Johannes Bruder ( STACKFORCE )
-*/
-
-#include
-#include "utilities.h"
-#include "LoRaMacFCntHandler.h"
-
-/*
- * Initial value of the frame counters
- */
-#define FCNT_DOWN_INITAL_VALUE 0xFFFFFFFF
-
-
-/*!
- * LoRaWAN Frame counter list.
- */
-typedef struct sFCntList
-{
- /*
- * Uplink frame counter which is incremented with each uplink.
- */
- uint32_t FCntUp;
- /*
- * Network downlink frame counter which is incremented with each downlink on FPort 0
- * or when the FPort field is missing.
- */
- uint32_t NFCntDown;
- /*
- * Application downlink frame counter which is incremented with each downlink
- * on a port different than 0.
- */
- uint32_t AFCntDown;
- /*
- * In case if the device is connected to a LoRaWAN 1.0 Server,
- * this counter is used for every kind of downlink frame.
- */
- uint32_t FCntDown;
- /*!
- * Multicast downlink counter for index 0
- */
- uint32_t McFCntDown0;
- /*!
- * Multicast downlink counter for index 1
- */
- uint32_t McFCntDown1;
- /*!
- * Multicast downlink counter for index 2
- */
- uint32_t McFCntDown2;
- /*!
- * Multicast downlink counter for index 3
- */
- uint32_t McFCntDown3;
-}FCntList_t;
-
-
-/*
- * LoRaMac Commands Context structure
- */
-typedef struct sLoRaMacFCntHandlerNvmCtx
-{
- /*
- * Frame counter list
- */
- FCntList_t FCntList;
-} LoRaMacFCntHandlerNvmCtx_t;
-
-/*
- * Non-volatile module context.
- */
-static LoRaMacFCntHandlerNvmCtx_t FCntHandlerNvmCtx;
-
-/*
- * Callback function to notify the upper layer about context change
- */
-static EventNvmCtxChanged FCntHandlerNvmCtxChanged;
-
-/*
- * \brief Wrapper function for the NvmCtx
- */
-static void NvmCtxChanged( void )
-{
- if( FCntHandlerNvmCtxChanged != NULL )
- {
- FCntHandlerNvmCtxChanged( );
- }
-}
-
-
-LoRaMacFCntHandlerStatus_t LoRaMacFCntHandlerInit( EventNvmCtxChanged fCntHandlerNvmCtxChanged )
-{
- // Initialize with default
- LoRaMacResetFCnts( );
-
- // Assign callback
- FCntHandlerNvmCtxChanged = fCntHandlerNvmCtxChanged;
-
- return LORAMAC_FCNT_HANDLER_SUCCESS;
-}
-
-LoRaMacFCntHandlerStatus_t LoRaMacFCntHandlerRestoreNvmCtx( void* fCntHandlerNvmCtx )
-{
- // Restore module context
- if( fCntHandlerNvmCtx != NULL )
- {
- memcpy1( ( uint8_t* ) &FCntHandlerNvmCtx, ( uint8_t* ) fCntHandlerNvmCtx, sizeof( FCntHandlerNvmCtx ) );
- return LORAMAC_FCNT_HANDLER_SUCCESS;
- }
- else
- {
- return LORAMAC_FCNT_HANDLER_ERROR_NPE;
- }
-}
-
-void* LoRaMacFCntHandlerGetNvmCtx( size_t* fCntHandlerNvmCtxSize )
-{
- *fCntHandlerNvmCtxSize = sizeof( FCntHandlerNvmCtx );
- return &FCntHandlerNvmCtx;
-}
-
-LoRaMacFCntHandlerStatus_t LoRaMacGetFCntDown( AddressIdentifier_t addrID, FType_t fType, LoRaMacMessageData_t* macMsg, Version_t lrWanVersion,
- uint16_t maxFCntGap, FCntIdentifier_t* fCntID, uint32_t* currentDown )
-{
- uint32_t previousDown = 0;
- int32_t fCntDiff = 0;
-
- if( ( macMsg == NULL ) || ( fCntID == NULL ) ||
- ( currentDown == NULL ) )
- {
- return LORAMAC_FCNT_HANDLER_ERROR_NPE;
- }
-
- // Determine the frame counter identifier and choose counter from FCntList
- switch( addrID )
- {
- case UNICAST_DEV_ADDR:
- if( lrWanVersion.Fields.Minor == 1 )
- {
- if( ( fType == FRAME_TYPE_A ) || ( fType == FRAME_TYPE_D ) )
- {
- *fCntID = A_FCNT_DOWN;
- previousDown = FCntHandlerNvmCtx.FCntList.AFCntDown;
- }
- else
- {
- *fCntID = N_FCNT_DOWN;
- previousDown = FCntHandlerNvmCtx.FCntList.NFCntDown;
- }
- }
- else
- { // For LoRaWAN 1.0.X
- *fCntID = FCNT_DOWN;
- previousDown = FCntHandlerNvmCtx.FCntList.FCntDown;
- }
- break;
- case MULTICAST_0_ADDR:
- *fCntID = MC_FCNT_DOWN_0;
- previousDown = FCntHandlerNvmCtx.FCntList.McFCntDown0;
- break;
- case MULTICAST_1_ADDR:
- *fCntID = MC_FCNT_DOWN_1;
- previousDown = FCntHandlerNvmCtx.FCntList.McFCntDown1;
- break;
- case MULTICAST_2_ADDR:
- *fCntID = MC_FCNT_DOWN_2;
- previousDown = FCntHandlerNvmCtx.FCntList.McFCntDown3;
- break;
- case MULTICAST_3_ADDR:
- *fCntID = MC_FCNT_DOWN_3;
- previousDown = FCntHandlerNvmCtx.FCntList.McFCntDown3;
- break;
- default:
- return LORAMAC_FCNT_HANDLER_ERROR;
- }
-
- // For LoRaWAN 1.0.X only, allow downlink frames of 0
- if( previousDown == FCNT_DOWN_INITAL_VALUE )
- {
- *currentDown = macMsg->FHDR.FCnt;
- }
- else
- {
- // Add difference, consider roll-over
- fCntDiff = ( int32_t )macMsg->FHDR.FCnt - ( int32_t )( previousDown & 0x0000FFFF );
-
- if( fCntDiff > 0 )
- { // Positive difference
- *currentDown = previousDown + fCntDiff;
- }
- else if( fCntDiff == 0 )
- { // Duplicate FCnt value, keep the current value.
- *currentDown = previousDown;
- return LORAMAC_FCNT_HANDLER_CHECK_FAIL;
- }
- else
- { // Negative difference, assume a roll-over of one uint16_t
- *currentDown = ( previousDown & 0xFFFF0000 ) + 0x10000 + macMsg->FHDR.FCnt;
- }
- }
-
-
- // For LoRaWAN 1.0.X only, check maxFCntGap
- if( lrWanVersion.Fields.Minor == 0 )
- {
- if( ( ( int32_t )*currentDown - ( int32_t )previousDown ) >= maxFCntGap )
- {
- return LORAMAC_FCNT_HANDLER_MAX_GAP_FAIL;
- }
- }
-
- return LORAMAC_FCNT_HANDLER_SUCCESS;
-}
-
-LoRaMacFCntHandlerStatus_t LoRaMacSetFCntDown( FCntIdentifier_t fCntID, uint32_t currentDown )
-{
- switch( fCntID )
- {
- case FCNT_UP:
- return LORAMAC_FCNT_HANDLER_ERROR_INVALID_FCNT_ID;
- case N_FCNT_DOWN:
- FCntHandlerNvmCtx.FCntList.NFCntDown = currentDown;
- break;
- case A_FCNT_DOWN:
- FCntHandlerNvmCtx.FCntList.AFCntDown = currentDown;
- break;
- case FCNT_DOWN:
- FCntHandlerNvmCtx.FCntList.FCntDown = currentDown;
- break;
- case MC_FCNT_DOWN_0:
- FCntHandlerNvmCtx.FCntList.McFCntDown0 = currentDown;
- break;
- case MC_FCNT_DOWN_1:
- FCntHandlerNvmCtx.FCntList.McFCntDown1 = currentDown;
- break;
- case MC_FCNT_DOWN_2:
- FCntHandlerNvmCtx.FCntList.McFCntDown2 = currentDown;
- break;
- case MC_FCNT_DOWN_3:
- FCntHandlerNvmCtx.FCntList.McFCntDown3 = currentDown;
- break;
- default:
- return LORAMAC_FCNT_HANDLER_ERROR;
- }
-
- NvmCtxChanged( );
-
- return LORAMAC_FCNT_HANDLER_SUCCESS;
-}
-
-LoRaMacFCntHandlerStatus_t LoRaMacGetFCntUp( uint32_t* currentUp )
-{
- if( currentUp == NULL )
- {
- return LORAMAC_FCNT_HANDLER_ERROR_NPE;
- }
-
- *currentUp = FCntHandlerNvmCtx.FCntList.FCntUp + 1;
-
- return LORAMAC_FCNT_HANDLER_SUCCESS;
-}
-
-LoRaMacFCntHandlerStatus_t LoRaMacSetFCntUp( uint32_t currentUp )
-{
- FCntHandlerNvmCtx.FCntList.FCntUp = currentUp;
-
- NvmCtxChanged( );
-
- return LORAMAC_FCNT_HANDLER_SUCCESS;
-}
-
-LoRaMacFCntHandlerStatus_t LoRaMacResetFCnts( void )
-{
-
- FCntHandlerNvmCtx.FCntList.FCntUp = 0;
- FCntHandlerNvmCtx.FCntList.NFCntDown = FCNT_DOWN_INITAL_VALUE;
- FCntHandlerNvmCtx.FCntList.AFCntDown = FCNT_DOWN_INITAL_VALUE;
- FCntHandlerNvmCtx.FCntList.FCntDown = FCNT_DOWN_INITAL_VALUE;
-
- FCntHandlerNvmCtx.FCntList.McFCntDown0 = FCNT_DOWN_INITAL_VALUE;
- FCntHandlerNvmCtx.FCntList.McFCntDown1 = FCNT_DOWN_INITAL_VALUE;
- FCntHandlerNvmCtx.FCntList.McFCntDown2 = FCNT_DOWN_INITAL_VALUE;
- FCntHandlerNvmCtx.FCntList.McFCntDown3 = FCNT_DOWN_INITAL_VALUE;
-
- NvmCtxChanged( );
-
- return LORAMAC_FCNT_HANDLER_SUCCESS;
-}
-
-LoRaMacFCntHandlerStatus_t LoRaMacFCntHandlerSetMulticastReference( MulticastCtx_t* multicastList )
-{
- if( multicastList == NULL )
- {
- return LORAMAC_FCNT_HANDLER_ERROR_NPE;
- }
-
- multicastList[0].DownLinkCounter = &FCntHandlerNvmCtx.FCntList.McFCntDown0;
- multicastList[1].DownLinkCounter = &FCntHandlerNvmCtx.FCntList.McFCntDown1;
- multicastList[2].DownLinkCounter = &FCntHandlerNvmCtx.FCntList.McFCntDown2;
- multicastList[3].DownLinkCounter = &FCntHandlerNvmCtx.FCntList.McFCntDown3;
-
- return LORAMAC_FCNT_HANDLER_SUCCESS;
-}
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacFCntHandler.h b/components/connectivity/LoraWAN/mac/LoRaMacFCntHandler.h
deleted file mode 100644
index df766251..00000000
--- a/components/connectivity/LoraWAN/mac/LoRaMacFCntHandler.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*!
- * \file LoRaMacFCntHandler.h
- *
- * \brief LoRa MAC layer frame counter handling
- *
- * \copyright Revised BSD License, see section \ref LICENSE.
- *
- * \code
- * ______ _
- * / _____) _ | |
- * ( (____ _____ ____ _| |_ _____ ____| |__
- * \____ \| ___ | (_ _) ___ |/ ___) _ \
- * _____) ) ____| | | || |_| ____( (___| | | |
- * (______/|_____)_|_|_| \__)_____)\____)_| |_|
- * (C)2013 Semtech
- *
- * ___ _____ _ ___ _ _____ ___ ___ ___ ___
- * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
- * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
- * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
- * embedded.connectivity.solutions===============
- *
- * \endcode
- *
- * \author Miguel Luis ( Semtech )
- *
- * \author Daniel Jaeckle ( STACKFORCE )
- *
- * \author Johannes Bruder ( STACKFORCE )
- *
- * addtogroup LORAMAC
- * \{
- *
- */
-#ifndef __LORAMAC_FCNT_HANDLER_H__
-#define __LORAMAC_FCNT_HANDLER_H__
-
-#include
-#include "LoRaMacTypes.h"
-#include "LoRaMacMessageTypes.h"
-
-/*!
- * LoRaMac FCnt Handler Status
- */
-typedef enum eLoRaMacFCntHandlerStatus
-{
- /*!
- * No error occurred
- */
- LORAMAC_FCNT_HANDLER_SUCCESS = 0,
- /*!
- * FCntUp/Down check failed
- */
- LORAMAC_FCNT_HANDLER_CHECK_FAIL,
- /*!
- * The status idicates that the node has lost MAX_FCNT_GAP or more frames
- */
- LORAMAC_FCNT_HANDLER_MAX_GAP_FAIL,
- /*!
- * Invalid frame counter identifier exception
- */
- LORAMAC_FCNT_HANDLER_ERROR_INVALID_FCNT_ID,
- /*!
- * Null pointer exception
- */
- LORAMAC_FCNT_HANDLER_ERROR_NPE,
- /*!
- * Undefined Error occurred
- */
- LORAMAC_FCNT_HANDLER_ERROR,
-}LoRaMacFCntHandlerStatus_t;
-
-/*!
- * Signature of callback function to be called by this module when the
- * non-volatile needs to be saved.
- */
-typedef void ( *EventNvmCtxChanged )( void );
-
-/*!
- * \brief Initialization of LoRaMac FCnt Handler module
- *
- * \param[IN] fCntHandlerNvmCtxChanged - Callback function which will be called when the
- * non-volatile context needs to be saved.
- *
- * \retval - Status of the operation
- */
-LoRaMacFCntHandlerStatus_t LoRaMacFCntHandlerInit( EventNvmCtxChanged fCntHandlerNvmCtxChanged );
-
-/*!
- * Restores the internal non-volatile context from passed pointer.
- *
- * \param[IN] fCntHandlerNvmCtx - Pointer to non-volatile FCnt handler module context to be restored.
- *
- * \retval - Status of the operation
- */
-LoRaMacFCntHandlerStatus_t LoRaMacFCntHandlerRestoreNvmCtx( void* fCntHandlerNvmCtx );
-
-/*!
- * Returns a pointer to the internal non-volatile context.
- *
- * \param[IN] fCntHandlerNvmCtxSize - Size of the module non-volatile context
- *
- * \retval - Points to a structure where the module store its non-volatile context
- */
-void* LoRaMacFCntHandlerGetNvmCtx( size_t* fCntHandlerNvmCtxSize );
-
-/*!
- * Computes next 32 bit downlink counter value and determines the frame counter ID.
- *
- * \param[IN] addrID - Address identifier
- * \param[IN] fType - Frame type
- * \param[IN] macMsg - Data message object, holding the current 16 bit transmitted frame counter
- * \param[IN] lrWanVersion - LoRaWAN version
- * \param[IN] maxFCntGap - Maximum allowed frame counter difference (only for 1.0.X necessary)
- * \param[OUT] fCntID - Frame counter identifier
- * \param[OUT] currentDown - Current downlink counter value
- *
- * \retval - Status of the operation
- */
-LoRaMacFCntHandlerStatus_t LoRaMacGetFCntDown( AddressIdentifier_t addrID, FType_t fType, LoRaMacMessageData_t* macMsg, Version_t lrWanVersion,
- uint16_t maxFCntGap, FCntIdentifier_t* fCntID, uint32_t* currentDown );
-
-/*!
- * Sets the downlink counter value according to the counter ID.
- *
- * \param[IN] fCntID - Frame counter identifier
- * \param[IN] currentDown - Current downlink counter value
- *
- * \retval - Status of the operation
- */
-LoRaMacFCntHandlerStatus_t LoRaMacSetFCntDown( FCntIdentifier_t fCntID, uint32_t currentDown );
-
-/*!
- * Computes next uplink counter value.
- *
- * \param[OUT] currentUp - Current uplink counter value
- *
- * \retval - Status of the operation
- */
-LoRaMacFCntHandlerStatus_t LoRaMacGetFCntUp( uint32_t* currentUp );
-
-/*!
- * Sets the uplink counter value according to the counter ID.
- *
- * \param[IN] currentUp - Current uplink counter value
- *
- * \retval - Status of the operation
- */
-LoRaMacFCntHandlerStatus_t LoRaMacSetFCntUp( uint32_t currentUp );
-
-/*!
- * Resets the value of FCntUp, NFCntDown, AFCntDown and FCntDown to zero
- *
- * \retval - Status of the operation
- */
-LoRaMacFCntHandlerStatus_t LoRaMacResetFCnts( void );
-
-/*!
- * Sets the reference to the multicast downlink counter
- *
- * \param[IN] multicastList Pointer to the multicast list
- *
- * \retval - Status of the operation
- */
-LoRaMacFCntHandlerStatus_t LoRaMacFCntHandlerSetMulticastReference( MulticastCtx_t* multicastList );
-
-/*! \} addtogroup LORAMAC */
-
-#endif // __LORAMAC_FCNT_HANDLER_H__
-
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacHeaderTypes.h b/components/connectivity/LoraWAN/mac/LoRaMacHeaderTypes.h
index 61c43c06..6a865c03 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacHeaderTypes.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMacHeaderTypes.h
@@ -37,23 +37,160 @@
#ifndef __LORAMAC_HEADER_TYPES_H__
#define __LORAMAC_HEADER_TYPES_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
-/*! Frame header (FHDR) maximum field size */
-#define LORAMAC_FHDR_MAX_FIELD_SIZE 22
+/*! MAC header field size */
+#define LORAMAC_MHDR_FIELD_SIZE 1
+
+/*! ReJoinType field size */
+#define LORAMAC_JOIN_TYPE_FIELD_SIZE 1
+
+/*! Join EUI field size */
+#define LORAMAC_JOIN_EUI_FIELD_SIZE 8
+
+/*! Device EUI field size */
+#define LORAMAC_DEV_EUI_FIELD_SIZE 8
+
+/*! End-device nonce field size */
+#define LORAMAC_DEV_NONCE_FIELD_SIZE 2
+
+/*! Join-server nonce field size */
+#define LORAMAC_JOIN_NONCE_FIELD_SIZE 3
+
+/*! RJcount0 field size */
+#define LORAMAC_RJCOUNT_0_FIELD_SIZE 2
+
+/*! RJcount1 field size */
+#define LORAMAC_RJCOUNT_1_FIELD_SIZE 2
+
+/*! Network ID field size */
+#define LORAMAC_NET_ID_FIELD_SIZE 3
+
+/*! Device address field size */
+#define LORAMAC_DEV_ADDR_FIELD_SIZE 4
+
+/*! DLSettings field size */
+#define LORAMAC_DL_SETTINGS_FIELD_SIZE 1
+
+/*! RxDelay field size */
+#define LORAMAC_RX_DELAY_FIELD_SIZE 1
+
+/*! CFList field size */
+#define LORAMAC_CF_LIST_FIELD_SIZE 16
/*! FHDR Device address field size */
-#define LORAMAC_FHDR_DEV_ADD_FIELD_SIZE 4
+#define LORAMAC_FHDR_DEV_ADDR_FIELD_SIZE LORAMAC_DEV_ADDR_FIELD_SIZE
/*! FHDR Frame control field size */
-#define LORAMAC_FHDR_F_CTRL_FIELD_SIZE 1
+#define LORAMAC_FHDR_F_CTRL_FIELD_SIZE 1
/*! FHDR Frame control field size */
-#define LORAMAC_FHDR_F_CNT_FIELD_SIZE 2
+#define LORAMAC_FHDR_F_CNT_FIELD_SIZE 2
/*! FOpts maximum field size */
-#define LORAMAC_FHDR_F_OPTS_MAX_FIELD_SIZE 15
+#define LORAMAC_FHDR_F_OPTS_MAX_FIELD_SIZE 15
+/*! Port field size */
+#define LORAMAC_F_PORT_FIELD_SIZE 1
+
+/*! Port field size */
+#define LORAMAC_MAC_PAYLOAD_FIELD_MAX_SIZE 242
+
+/*! MIC field size */
+#define LORAMAC_MIC_FIELD_SIZE 4
+
+/*!
+ * JoinRequest frame size
+ *
+ * MHDR(1) + JoinEUI(8) + DevEUI(8) + DevNonce(2) + MIC(4)
+ */
+#define LORAMAC_JOIN_REQ_MSG_SIZE ( LORAMAC_MHDR_FIELD_SIZE + LORAMAC_JOIN_EUI_FIELD_SIZE + \
+ LORAMAC_DEV_EUI_FIELD_SIZE + LORAMAC_DEV_NONCE_FIELD_SIZE + \
+ LORAMAC_MIC_FIELD_SIZE )
+
+/*!
+ * ReJoinRequest type 1 frame size
+ *
+ * MHDR(1) + ReJoinType(1) + JoinEUI(8) + DevEUI(8) + RJcount1(2) + MIC(4)
+ */
+#define LORAMAC_RE_JOIN_1_MSG_SIZE ( LORAMAC_MHDR_FIELD_SIZE + LORAMAC_JOIN_TYPE_FIELD_SIZE + \
+ LORAMAC_JOIN_EUI_FIELD_SIZE + LORAMAC_DEV_EUI_FIELD_SIZE + \
+ LORAMAC_RJCOUNT_1_FIELD_SIZE + \
+ LORAMAC_MIC_FIELD_SIZE )
+
+/*!
+ * ReJoinRequest type 0 or 2 frame size
+ *
+ * MHDR(1) + ReJoinType(1) + NetID(3) + DevEUI(8) + RJcount0(2) + MIC(4)
+ */
+#define LORAMAC_RE_JOIN_0_2_MSG_SIZE ( LORAMAC_MHDR_FIELD_SIZE + LORAMAC_JOIN_TYPE_FIELD_SIZE + \
+ LORAMAC_NET_ID_FIELD_SIZE + LORAMAC_DEV_EUI_FIELD_SIZE + \
+ LORAMAC_RJCOUNT_0_FIELD_SIZE + \
+ LORAMAC_MIC_FIELD_SIZE )
+
+/*!
+ * JoinAccept frame minimum size
+ *
+ * MHDR(1) + AppNonce(3) + NetID(3) + DevAddr(4) + DLSettings(1) + RxDelay(1) + MIC(4)
+ */
+#define LORAMAC_JOIN_ACCEPT_FRAME_MIN_SIZE ( LORAMAC_MHDR_FIELD_SIZE + LORAMAC_JOIN_NONCE_FIELD_SIZE + \
+ LORAMAC_NET_ID_FIELD_SIZE + LORAMAC_DEV_ADDR_FIELD_SIZE + \
+ LORAMAC_DL_SETTINGS_FIELD_SIZE + LORAMAC_RX_DELAY_FIELD_SIZE + \
+ LORAMAC_MIC_FIELD_SIZE )
+
+/*!
+ * JoinAccept frame maximum size
+ *
+ * MHDR(1) + AppNonce(3) + NetID(3) + DevAddr(4) + DLSettings(1) + RxDelay(1) + CFList(16) + MIC(4)
+ */
+#define LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE ( LORAMAC_MHDR_FIELD_SIZE + LORAMAC_JOIN_NONCE_FIELD_SIZE + \
+ LORAMAC_NET_ID_FIELD_SIZE + LORAMAC_DEV_ADDR_FIELD_SIZE + \
+ LORAMAC_DL_SETTINGS_FIELD_SIZE + LORAMAC_RX_DELAY_FIELD_SIZE + \
+ LORAMAC_CF_LIST_FIELD_SIZE + LORAMAC_MIC_FIELD_SIZE )
+
+/*!
+ * MIC computation offset
+ * \remark required for 1.1.x support
+ */
+#define JOIN_ACCEPT_MIC_COMPUTATION_OFFSET \
+ ( LORAMAC_MHDR_FIELD_SIZE + LORAMAC_JOIN_TYPE_FIELD_SIZE + LORAMAC_JOIN_EUI_FIELD_SIZE + \
+ LORAMAC_DEV_NONCE_FIELD_SIZE )
+
+/*!
+ * FRMPayload overhead to be used when setting the Radio.SetMaxPayloadLength
+ *
+ * Overhead to be used when setting the Radio.SetMaxPayloadLength in RxWindowSetup function.
+ *
+ * MHDR(1) + FHDR(7) + Port(1) + MIC(4)
+ *
+ * Maximum PHYPayload = MaxPayloadOfDatarate + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE
+ */
+#define LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE ( LORAMAC_MHDR_FIELD_SIZE + ( LORAMAC_FHDR_DEV_ADDR_FIELD_SIZE + \
+ LORAMAC_FHDR_F_CTRL_FIELD_SIZE + LORAMAC_FHDR_F_CNT_FIELD_SIZE ) + \
+ LORAMAC_F_PORT_FIELD_SIZE + LORAMAC_MIC_FIELD_SIZE )
+
+/*!
+ * FRMPayload minimum size
+ *
+ * MHDR(1) + FHDR(7) + MIC(4)
+ */
+#define LORAMAC_FRAME_PAYLOAD_MIN_SIZE ( LORAMAC_MHDR_FIELD_SIZE + ( LORAMAC_FHDR_DEV_ADDR_FIELD_SIZE + \
+ LORAMAC_FHDR_F_CTRL_FIELD_SIZE + LORAMAC_FHDR_F_CNT_FIELD_SIZE ) + \
+ LORAMAC_MIC_FIELD_SIZE )
+/*!
+ * FRMPayload maximum possible size
+ *
+ * MHDR(1) + FHDR(7) + Port(1) + MACPayload(242) + MIC(4)
+ */
+#define LORAMAC_FRAME_PAYLOAD_MAX_SIZE ( LORAMAC_MHDR_FIELD_SIZE + ( LORAMAC_FHDR_DEV_ADDR_FIELD_SIZE + \
+ LORAMAC_FHDR_F_CTRL_FIELD_SIZE + LORAMAC_FHDR_F_CNT_FIELD_SIZE ) + \
+ LORAMAC_F_PORT_FIELD_SIZE + LORAMAC_MAC_PAYLOAD_FIELD_MAX_SIZE + \
+ LORAMAC_MIC_FIELD_SIZE )
/*!
* LoRaMAC field definition of DLSettings
@@ -183,4 +320,8 @@ typedef struct sLoRaMacFrameHeader
/*! \} addtogroup LORAMAC */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMAC_HEADER_TYPES_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacMessageTypes.h b/components/connectivity/LoraWAN/mac/LoRaMacMessageTypes.h
index de53f52a..c16385e8 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacMessageTypes.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMacMessageTypes.h
@@ -37,43 +37,14 @@
#ifndef __LORAMAC_MESSAGE_TYPES_H__
#define __LORAMAC_MESSAGE_TYPES_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include "LoRaMacHeaderTypes.h"
-
-/*! MAC header field size */
-#define LORAMAC_MHDR_FIELD_SIZE 1
-
-/*! Join EUI field size */
-#define LORAMAC_JOIN_EUI_FIELD_SIZE 8
-
-/*! Device EUI field size */
-#define LORAMAC_DEV_EUI_FIELD_SIZE 8
-
-/*! Join-server nonce field size */
-#define LORAMAC_JOIN_NONCE_FIELD_SIZE 3
-
-/*! Network ID field size */
-#define LORAMAC_NET_ID_FIELD_SIZE 3
-
-/*! Port field size */
-#define LORAMAC_F_PORT_FIELD_SIZE 1
-
-/*! CFList field size */
-#define LORAMAC_C_FLIST_FIELD_SIZE 16
-
-/*! MIC field size */
-#define LORAMAC_MIC_FIELD_SIZE 4
-
-/*! Join-request message size */
-#define LORAMAC_JOIN_REQ_MSG_SIZE 23
-
-/*! ReJoin-request type 1 message size */
-#define LORAMAC_RE_JOIN_1_MSG_SIZE 24
-
-/*! ReJoin-request type 0 or 2 message size */
-#define LORAMAC_RE_JOIN_0_2_MSG_SIZE 19
-
/*!
* LoRaMac type for Join-request message
*/
@@ -324,4 +295,8 @@ typedef struct sLoRaMacMessage
/*! \} addtogroup LORAMAC */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMAC_MESSAGE_TYPES_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacParser.c b/components/connectivity/LoraWAN/mac/LoRaMacParser.c
index 6f29d06d..9c76eb36 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacParser.c
+++ b/components/connectivity/LoraWAN/mac/LoRaMacParser.c
@@ -47,10 +47,10 @@ LoRaMacParserStatus_t LoRaMacParserJoinAccept( LoRaMacMessageJoinAccept_t* macMs
macMsg->RxDelay = macMsg->Buffer[bufItr++];
- if( ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE - bufItr ) == LORAMAC_C_FLIST_FIELD_SIZE )
+ if( ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE - bufItr ) == LORAMAC_CF_LIST_FIELD_SIZE )
{
- memcpy1( macMsg->CFList, &macMsg->Buffer[bufItr], LORAMAC_C_FLIST_FIELD_SIZE );
- bufItr = bufItr + LORAMAC_C_FLIST_FIELD_SIZE;
+ memcpy1( macMsg->CFList, &macMsg->Buffer[bufItr], LORAMAC_CF_LIST_FIELD_SIZE );
+ bufItr = bufItr + LORAMAC_CF_LIST_FIELD_SIZE;
}
else if( ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE - bufItr ) > 0 )
{
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacParser.h b/components/connectivity/LoraWAN/mac/LoRaMacParser.h
index 3446ae19..e9a0a22c 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacParser.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMacParser.h
@@ -37,6 +37,11 @@
#ifndef __LORAMAC_PARSER_H__
#define __LORAMAC_PARSER_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include "LoRaMacMessageTypes.h"
@@ -82,5 +87,9 @@ LoRaMacParserStatus_t LoRaMacParserData( LoRaMacMessageData_t *macMsg );
/*! \} addtogroup LORAMAC */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMAC_PARSER_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacSerializer.c b/components/connectivity/LoraWAN/mac/LoRaMacSerializer.c
index 938919e6..28e4f2a4 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacSerializer.c
+++ b/components/connectivity/LoraWAN/mac/LoRaMacSerializer.c
@@ -107,7 +107,7 @@ LoRaMacSerializerStatus_t LoRaMacSerializerReJoinType0or2( LoRaMacMessageReJoinT
macMsg->Buffer[bufItr++] = macMsg->ReJoinType;
- memcpyr( &macMsg->Buffer[bufItr], macMsg->NetID, LORAMAC_NET_ID_FIELD_SIZE );
+ memcpy1( &macMsg->Buffer[bufItr], macMsg->NetID, LORAMAC_NET_ID_FIELD_SIZE );
bufItr += LORAMAC_NET_ID_FIELD_SIZE;
memcpyr( &macMsg->Buffer[bufItr], macMsg->DevEUI, LORAMAC_DEV_EUI_FIELD_SIZE );
@@ -130,23 +130,23 @@ LoRaMacSerializerStatus_t LoRaMacSerializerData( LoRaMacMessageData_t* macMsg )
// Check macMsg->BufSize
uint16_t computedBufSize = LORAMAC_MHDR_FIELD_SIZE
- + LORAMAC_FHDR_DEV_ADD_FIELD_SIZE
+ + LORAMAC_FHDR_DEV_ADDR_FIELD_SIZE
+ LORAMAC_FHDR_F_CTRL_FIELD_SIZE
+ LORAMAC_FHDR_F_CNT_FIELD_SIZE;
- if( macMsg->FRMPayloadSize == 0 )
+ computedBufSize += macMsg->FHDR.FCtrl.Bits.FOptsLen;
+
+ if( macMsg->FRMPayloadSize > 0 )
{
- if( macMsg->BufSize < computedBufSize )
- {
- return LORAMAC_SERIALIZER_ERROR_BUF_SIZE;
- }
+ computedBufSize += LORAMAC_F_PORT_FIELD_SIZE;
}
- else
- { //If FRMPayload >0, FPort field is present.
- if( macMsg->BufSize < computedBufSize + macMsg->FHDR.FCtrl.Bits.FOptsLen + macMsg->FRMPayloadSize + LORAMAC_F_PORT_FIELD_SIZE )
- {
- return LORAMAC_SERIALIZER_ERROR_BUF_SIZE;
- }
+
+ computedBufSize += macMsg->FRMPayloadSize;
+ computedBufSize += LORAMAC_MIC_FIELD_SIZE;
+
+ if( macMsg->BufSize < computedBufSize )
+ {
+ return LORAMAC_SERIALIZER_ERROR_BUF_SIZE;
}
macMsg->Buffer[bufItr++] = macMsg->MHDR.Value;
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacSerializer.h b/components/connectivity/LoraWAN/mac/LoRaMacSerializer.h
index 0236abee..8588062a 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacSerializer.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMacSerializer.h
@@ -36,6 +36,11 @@
*/
#ifndef __LORAMAC_SERIALIZER_H__
#define __LORAMAC_SERIALIZER_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
#include
#include "LoRaMacMessageTypes.h"
@@ -97,5 +102,9 @@ LoRaMacSerializerStatus_t LoRaMacSerializerData( LoRaMacMessageData_t* macMsg );
/*! \} addtogroup LORAMAC */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMAC_SERIALIZER_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacTest.h b/components/connectivity/LoraWAN/mac/LoRaMacTest.h
index 0c348602..57f49683 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacTest.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMacTest.h
@@ -36,6 +36,11 @@
#ifndef __LORAMACTEST_H__
#define __LORAMACTEST_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
/*!
* \brief Enabled or disables the duty cycle
*
@@ -48,4 +53,8 @@ void LoRaMacTestSetDutyCycleOn( bool enable );
/*! \} defgroup LORAMACTEST */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMACTEST_H__
diff --git a/components/connectivity/LoraWAN/mac/LoRaMacTypes.h b/components/connectivity/LoraWAN/mac/LoRaMacTypes.h
index 2dc84c11..7307157b 100644
--- a/components/connectivity/LoraWAN/mac/LoRaMacTypes.h
+++ b/components/connectivity/LoraWAN/mac/LoRaMacTypes.h
@@ -35,6 +35,11 @@
#ifndef __LORAMAC_TYPES_H__
#define __LORAMAC_TYPES_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include "timer.h"
@@ -47,7 +52,34 @@
/*!
* Start value for multicast keys enumeration
*/
-#define LORAMAC_CRYPTO_MULITCAST_KEYS 127
+#define LORAMAC_CRYPTO_MULTICAST_KEYS 127
+
+/*!
+ * LoRaWAN devices classes definition
+ *
+ * LoRaWAN Specification V1.0.2, chapter 2.1
+ */
+typedef enum DeviceClass_e
+{
+ /*!
+ * LoRaWAN device class A
+ *
+ * LoRaWAN Specification V1.0.2, chapter 3
+ */
+ CLASS_A = 0x00,
+ /*!
+ * LoRaWAN device class B
+ *
+ * LoRaWAN Specification V1.0.2, chapter 8
+ */
+ CLASS_B = 0x01,
+ /*!
+ * LoRaWAN device class C
+ *
+ * LoRaWAN Specification V1.0.2, chapter 17
+ */
+ CLASS_C = 0x02,
+}DeviceClass_t;
/*!
* LoRaWAN Frame type enumeration to differ between the possible data up/down frame configurations.
@@ -162,10 +194,14 @@ typedef enum eKeyIdentifier
* Application session key
*/
APP_S_KEY,
+ /*!
+ * Multicast root key
+ */
+ MC_ROOT_KEY,
/*!
* Multicast key encryption key
*/
- MC_KE_KEY = LORAMAC_CRYPTO_MULITCAST_KEYS,
+ MC_KE_KEY = LORAMAC_CRYPTO_MULTICAST_KEYS,
/*!
* Multicast root key index 0
*/
@@ -251,40 +287,121 @@ typedef enum eAddressIdentifier
UNICAST_DEV_ADDR = 4,
}AddressIdentifier_t;
-/*!
- * Multicast context
+/*
+ * Multicast Rx window parameters
*/
-typedef struct sMulticastCtx
+typedef union uMcRxParams
{
+ struct
+ {
+ /*!
+ * Reception frequency of the ping slot windows
+ */
+ uint32_t Frequency;
+ /*!
+ * Datarate of the ping slot
+ */
+ int8_t Datarate;
+ /*!
+ * This parameter is necessary for class B operation. It defines the
+ * periodicity of the multicast downlink slots
+ */
+ uint16_t Periodicity;
+ }ClassB;
+ struct
+ {
+ /*!
+ * Reception frequency of the ping slot windows
+ */
+ uint32_t Frequency;
+ /*!
+ * Datarate of the ping slot
+ */
+ int8_t Datarate;
+ }ClassC;
+}McRxParams_t;
+
+/*!
+ * Multicast channel
+ */
+typedef struct sMcChannelParams
+{
+ /*!
+ * Indicate if the multicast channel is being setup remotely or locally.
+ * Indicates which set of keys are to be used. \ref uMcKeys
+ */
+ bool IsRemotelySetup;
+ /*!
+ * Multicats channel LoRaWAN class B or C
+ */
+ DeviceClass_t Class;
+ /*!
+ * True if the entry is active
+ */
+ bool IsEnabled;
/*
* Address identifier
*/
- AddressIdentifier_t AddrID;
+ AddressIdentifier_t GroupID;
/*!
* Address
*/
uint32_t Address;
+ /*!
+ * Multicast keys
+ */
+ union uMcKeys
+ {
+ /*!
+ * Encrypted multicast key - Used when IsRemotelySetup equals `true`.
+ * MC_KEY is decrypted and then the session keys ar derived.
+ */
+ uint8_t *McKeyE;
+ /*!
+ * Multicast Session keys - Used when IsRemotelySetup equals `false`
+ */
+ struct
+ {
+ /*!
+ * Multicast application session key
+ */
+ uint8_t *McAppSKey;
+ /*!
+ * Multicast network session key
+ */
+ uint8_t *McNwkSKey;
+ }Session;
+ }McKeys;
+ /*!
+ * Minimum multicast frame counter value
+ */
+ uint32_t FCountMin;
+ /*!
+ * Maximum multicast frame counter value
+ */
+ uint32_t FCountMax;
+ /*!
+ * Multicast reception parameters
+ */
+ McRxParams_t RxParams;
+}McChannelParams_t;
+
+/*!
+ * Multicast context
+ */
+typedef struct sMulticastCtx
+{
+ /*!
+ * Multicast channel parameters
+ */
+ McChannelParams_t ChannelParams;
/*!
* Downlink counter
*/
uint32_t* DownLinkCounter;
- /*!
- * True if the entry is active
+ /*
+ * Following parameters are only used for ClassB multicast channels
*/
- bool IsEnabled;
- /*!
- * Reception frequency of the ping slot windows
- */
- uint32_t Frequency;
- /*!
- * Datarate of the ping slot
- */
- int8_t Datarate;
- /*!
- * This parameter is necessary for class b operation. It defines the
- * periodicity of the multicast downlink slots
- */
- uint16_t Periodicity;
/*!
* Number of multicast slots. The variable can be
* calculated as follows:
@@ -475,17 +592,24 @@ typedef struct sBand
*/
int8_t TxMaxPower;
/*!
- * Time stamp of the last JoinReq Tx frame.
+ * The last time the band has been
+ * synchronized with the current time
*/
- TimerTime_t LastJoinTxDoneTime;
+ TimerTime_t LastBandUpdateTime;
/*!
- * Time stamp of the last Tx frame
+ * Current time credits which are available. This
+ * is a value in ms
*/
- TimerTime_t LastTxDoneTime;
+ TimerTime_t TimeCredits;
/*!
- * Holds the time where the device is off
+ * Maximum time credits which are available. This
+ * is a value in ms
*/
- TimerTime_t TimeOff;
+ TimerTime_t MaxTimeCredits;
+ /*!
+ * Set to true when the band is ready for use.
+ */
+ bool ReadyForTransmission;
}Band_t;
/*!
@@ -548,5 +672,9 @@ typedef enum eLoRaMacBatteryLevel
BAT_LEVEL_NO_MEASURE = 0xFF,
}LoRaMacBatteryLevel_t;
+#ifdef __cplusplus
+}
+#endif
+
#endif // __LORAMAC_TYPES_H__
diff --git a/components/connectivity/LoraWAN/mac/region/Region.c b/components/connectivity/LoraWAN/mac/region/Region.c
index 3d3c0019..727a4694 100644
--- a/components/connectivity/LoraWAN/mac/region/Region.c
+++ b/components/connectivity/LoraWAN/mac/region/Region.c
@@ -51,7 +51,6 @@
#define AS923_TX_PARAM_SETUP_REQ( ) AS923_CASE { return RegionAS923TxParamSetupReq( txParamSetupReq ); }
#define AS923_DL_CHANNEL_REQ( ) AS923_CASE { return RegionAS923DlChannelReq( dlChannelReq ); }
#define AS923_ALTERNATE_DR( ) AS923_CASE { return RegionAS923AlternateDr( currentDr, type ); }
-#define AS923_CALC_BACKOFF( ) AS923_CASE { RegionAS923CalcBackOff( calcBackOff ); break; }
#define AS923_NEXT_CHANNEL( ) AS923_CASE { return RegionAS923NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
#define AS923_CHANNEL_ADD( ) AS923_CASE { return RegionAS923ChannelAdd( channelAdd ); }
#define AS923_CHANNEL_REMOVE( ) AS923_CASE { return RegionAS923ChannelsRemove( channelRemove ); }
@@ -76,7 +75,6 @@
#define AS923_TX_PARAM_SETUP_REQ( )
#define AS923_DL_CHANNEL_REQ( )
#define AS923_ALTERNATE_DR( )
-#define AS923_CALC_BACKOFF( )
#define AS923_NEXT_CHANNEL( )
#define AS923_CHANNEL_ADD( )
#define AS923_CHANNEL_REMOVE( )
@@ -105,7 +103,6 @@
#define AU915_TX_PARAM_SETUP_REQ( ) AU915_CASE { return RegionAU915TxParamSetupReq( txParamSetupReq ); }
#define AU915_DL_CHANNEL_REQ( ) AU915_CASE { return RegionAU915DlChannelReq( dlChannelReq ); }
#define AU915_ALTERNATE_DR( ) AU915_CASE { return RegionAU915AlternateDr( currentDr, type ); }
-#define AU915_CALC_BACKOFF( ) AU915_CASE { RegionAU915CalcBackOff( calcBackOff ); break; }
#define AU915_NEXT_CHANNEL( ) AU915_CASE { return RegionAU915NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
#define AU915_CHANNEL_ADD( ) AU915_CASE { return RegionAU915ChannelAdd( channelAdd ); }
#define AU915_CHANNEL_REMOVE( ) AU915_CASE { return RegionAU915ChannelsRemove( channelRemove ); }
@@ -130,7 +127,6 @@
#define AU915_TX_PARAM_SETUP_REQ( )
#define AU915_DL_CHANNEL_REQ( )
#define AU915_ALTERNATE_DR( )
-#define AU915_CALC_BACKOFF( )
#define AU915_NEXT_CHANNEL( )
#define AU915_CHANNEL_ADD( )
#define AU915_CHANNEL_REMOVE( )
@@ -159,7 +155,6 @@
#define CN470_TX_PARAM_SETUP_REQ( ) CN470_CASE { return RegionCN470TxParamSetupReq( txParamSetupReq ); }
#define CN470_DL_CHANNEL_REQ( ) CN470_CASE { return RegionCN470DlChannelReq( dlChannelReq ); }
#define CN470_ALTERNATE_DR( ) CN470_CASE { return RegionCN470AlternateDr( currentDr, type ); }
-#define CN470_CALC_BACKOFF( ) CN470_CASE { RegionCN470CalcBackOff( calcBackOff ); break; }
#define CN470_NEXT_CHANNEL( ) CN470_CASE { return RegionCN470NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
#define CN470_CHANNEL_ADD( ) CN470_CASE { return RegionCN470ChannelAdd( channelAdd ); }
#define CN470_CHANNEL_REMOVE( ) CN470_CASE { return RegionCN470ChannelsRemove( channelRemove ); }
@@ -184,7 +179,6 @@
#define CN470_TX_PARAM_SETUP_REQ( )
#define CN470_DL_CHANNEL_REQ( )
#define CN470_ALTERNATE_DR( )
-#define CN470_CALC_BACKOFF( )
#define CN470_NEXT_CHANNEL( )
#define CN470_CHANNEL_ADD( )
#define CN470_CHANNEL_REMOVE( )
@@ -213,7 +207,6 @@
#define CN779_TX_PARAM_SETUP_REQ( ) CN779_CASE { return RegionCN779TxParamSetupReq( txParamSetupReq ); }
#define CN779_DL_CHANNEL_REQ( ) CN779_CASE { return RegionCN779DlChannelReq( dlChannelReq ); }
#define CN779_ALTERNATE_DR( ) CN779_CASE { return RegionCN779AlternateDr( currentDr, type ); }
-#define CN779_CALC_BACKOFF( ) CN779_CASE { RegionCN779CalcBackOff( calcBackOff ); break; }
#define CN779_NEXT_CHANNEL( ) CN779_CASE { return RegionCN779NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
#define CN779_CHANNEL_ADD( ) CN779_CASE { return RegionCN779ChannelAdd( channelAdd ); }
#define CN779_CHANNEL_REMOVE( ) CN779_CASE { return RegionCN779ChannelsRemove( channelRemove ); }
@@ -238,7 +231,6 @@
#define CN779_TX_PARAM_SETUP_REQ( )
#define CN779_DL_CHANNEL_REQ( )
#define CN779_ALTERNATE_DR( )
-#define CN779_CALC_BACKOFF( )
#define CN779_NEXT_CHANNEL( )
#define CN779_CHANNEL_ADD( )
#define CN779_CHANNEL_REMOVE( )
@@ -267,7 +259,6 @@
#define EU433_TX_PARAM_SETUP_REQ( ) EU433_CASE { return RegionEU433TxParamSetupReq( txParamSetupReq ); }
#define EU433_DL_CHANNEL_REQ( ) EU433_CASE { return RegionEU433DlChannelReq( dlChannelReq ); }
#define EU433_ALTERNATE_DR( ) EU433_CASE { return RegionEU433AlternateDr( currentDr, type ); }
-#define EU433_CALC_BACKOFF( ) EU433_CASE { RegionEU433CalcBackOff( calcBackOff ); break; }
#define EU433_NEXT_CHANNEL( ) EU433_CASE { return RegionEU433NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
#define EU433_CHANNEL_ADD( ) EU433_CASE { return RegionEU433ChannelAdd( channelAdd ); }
#define EU433_CHANNEL_REMOVE( ) EU433_CASE { return RegionEU433ChannelsRemove( channelRemove ); }
@@ -292,7 +283,6 @@
#define EU433_TX_PARAM_SETUP_REQ( )
#define EU433_DL_CHANNEL_REQ( )
#define EU433_ALTERNATE_DR( )
-#define EU433_CALC_BACKOFF( )
#define EU433_NEXT_CHANNEL( )
#define EU433_CHANNEL_ADD( )
#define EU433_CHANNEL_REMOVE( )
@@ -321,7 +311,6 @@
#define EU868_TX_PARAM_SETUP_REQ( ) EU868_CASE { return RegionEU868TxParamSetupReq( txParamSetupReq ); }
#define EU868_DL_CHANNEL_REQ( ) EU868_CASE { return RegionEU868DlChannelReq( dlChannelReq ); }
#define EU868_ALTERNATE_DR( ) EU868_CASE { return RegionEU868AlternateDr( currentDr, type ); }
-#define EU868_CALC_BACKOFF( ) EU868_CASE { RegionEU868CalcBackOff( calcBackOff ); break; }
#define EU868_NEXT_CHANNEL( ) EU868_CASE { return RegionEU868NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
#define EU868_CHANNEL_ADD( ) EU868_CASE { return RegionEU868ChannelAdd( channelAdd ); }
#define EU868_CHANNEL_REMOVE( ) EU868_CASE { return RegionEU868ChannelsRemove( channelRemove ); }
@@ -346,7 +335,6 @@
#define EU868_TX_PARAM_SETUP_REQ( )
#define EU868_DL_CHANNEL_REQ( )
#define EU868_ALTERNATE_DR( )
-#define EU868_CALC_BACKOFF( )
#define EU868_NEXT_CHANNEL( )
#define EU868_CHANNEL_ADD( )
#define EU868_CHANNEL_REMOVE( )
@@ -375,7 +363,6 @@
#define KR920_TX_PARAM_SETUP_REQ( ) KR920_CASE { return RegionKR920TxParamSetupReq( txParamSetupReq ); }
#define KR920_DL_CHANNEL_REQ( ) KR920_CASE { return RegionKR920DlChannelReq( dlChannelReq ); }
#define KR920_ALTERNATE_DR( ) KR920_CASE { return RegionKR920AlternateDr( currentDr, type ); }
-#define KR920_CALC_BACKOFF( ) KR920_CASE { RegionKR920CalcBackOff( calcBackOff ); break; }
#define KR920_NEXT_CHANNEL( ) KR920_CASE { return RegionKR920NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
#define KR920_CHANNEL_ADD( ) KR920_CASE { return RegionKR920ChannelAdd( channelAdd ); }
#define KR920_CHANNEL_REMOVE( ) KR920_CASE { return RegionKR920ChannelsRemove( channelRemove ); }
@@ -400,7 +387,6 @@
#define KR920_TX_PARAM_SETUP_REQ( )
#define KR920_DL_CHANNEL_REQ( )
#define KR920_ALTERNATE_DR( )
-#define KR920_CALC_BACKOFF( )
#define KR920_NEXT_CHANNEL( )
#define KR920_CHANNEL_ADD( )
#define KR920_CHANNEL_REMOVE( )
@@ -429,7 +415,6 @@
#define IN865_TX_PARAM_SETUP_REQ( ) IN865_CASE { return RegionIN865TxParamSetupReq( txParamSetupReq ); }
#define IN865_DL_CHANNEL_REQ( ) IN865_CASE { return RegionIN865DlChannelReq( dlChannelReq ); }
#define IN865_ALTERNATE_DR( ) IN865_CASE { return RegionIN865AlternateDr( currentDr, type ); }
-#define IN865_CALC_BACKOFF( ) IN865_CASE { RegionIN865CalcBackOff( calcBackOff ); break; }
#define IN865_NEXT_CHANNEL( ) IN865_CASE { return RegionIN865NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
#define IN865_CHANNEL_ADD( ) IN865_CASE { return RegionIN865ChannelAdd( channelAdd ); }
#define IN865_CHANNEL_REMOVE( ) IN865_CASE { return RegionIN865ChannelsRemove( channelRemove ); }
@@ -454,7 +439,6 @@
#define IN865_TX_PARAM_SETUP_REQ( )
#define IN865_DL_CHANNEL_REQ( )
#define IN865_ALTERNATE_DR( )
-#define IN865_CALC_BACKOFF( )
#define IN865_NEXT_CHANNEL( )
#define IN865_CHANNEL_ADD( )
#define IN865_CHANNEL_REMOVE( )
@@ -483,7 +467,6 @@
#define US915_TX_PARAM_SETUP_REQ( ) US915_CASE { return RegionUS915TxParamSetupReq( txParamSetupReq ); }
#define US915_DL_CHANNEL_REQ( ) US915_CASE { return RegionUS915DlChannelReq( dlChannelReq ); }
#define US915_ALTERNATE_DR( ) US915_CASE { return RegionUS915AlternateDr( currentDr, type ); }
-#define US915_CALC_BACKOFF( ) US915_CASE { RegionUS915CalcBackOff( calcBackOff ); break; }
#define US915_NEXT_CHANNEL( ) US915_CASE { return RegionUS915NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
#define US915_CHANNEL_ADD( ) US915_CASE { return RegionUS915ChannelAdd( channelAdd ); }
#define US915_CHANNEL_REMOVE( ) US915_CASE { return RegionUS915ChannelsRemove( channelRemove ); }
@@ -508,7 +491,6 @@
#define US915_TX_PARAM_SETUP_REQ( )
#define US915_DL_CHANNEL_REQ( )
#define US915_ALTERNATE_DR( )
-#define US915_CALC_BACKOFF( )
#define US915_NEXT_CHANNEL( )
#define US915_CHANNEL_ADD( )
#define US915_CHANNEL_REMOVE( )
@@ -537,7 +519,6 @@
#define RU864_TX_PARAM_SETUP_REQ( ) RU864_CASE { return RegionRU864TxParamSetupReq( txParamSetupReq ); }
#define RU864_DL_CHANNEL_REQ( ) RU864_CASE { return RegionRU864DlChannelReq( dlChannelReq ); }
#define RU864_ALTERNATE_DR( ) RU864_CASE { return RegionRU864AlternateDr( currentDr, type ); }
-#define RU864_CALC_BACKOFF( ) RU864_CASE { RegionRU864CalcBackOff( calcBackOff ); break; }
#define RU864_NEXT_CHANNEL( ) RU864_CASE { return RegionRU864NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
#define RU864_CHANNEL_ADD( ) RU864_CASE { return RegionRU864ChannelAdd( channelAdd ); }
#define RU864_CHANNEL_REMOVE( ) RU864_CASE { return RegionRU864ChannelsRemove( channelRemove ); }
@@ -562,7 +543,6 @@
#define RU864_TX_PARAM_SETUP_REQ( )
#define RU864_DL_CHANNEL_REQ( )
#define RU864_ALTERNATE_DR( )
-#define RU864_CALC_BACKOFF( )
#define RU864_NEXT_CHANNEL( )
#define RU864_CHANNEL_ADD( )
#define RU864_CHANNEL_REMOVE( )
@@ -929,27 +909,6 @@ int8_t RegionAlternateDr( LoRaMacRegion_t region, int8_t currentDr, AlternateDrT
}
}
-void RegionCalcBackOff( LoRaMacRegion_t region, CalcBackOffParams_t* calcBackOff )
-{
- switch( region )
- {
- AS923_CALC_BACKOFF( );
- AU915_CALC_BACKOFF( );
- CN470_CALC_BACKOFF( );
- CN779_CALC_BACKOFF( );
- EU433_CALC_BACKOFF( );
- EU868_CALC_BACKOFF( );
- KR920_CALC_BACKOFF( );
- IN865_CALC_BACKOFF( );
- US915_CALC_BACKOFF( );
- RU864_CALC_BACKOFF( );
- default:
- {
- break;
- }
- }
-}
-
LoRaMacStatus_t RegionNextChannel( LoRaMacRegion_t region, NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
switch( region )
@@ -1075,3 +1034,13 @@ void RegionRxBeaconSetup( LoRaMacRegion_t region, RxBeaconSetup_t* rxBeaconSetup
}
}
}
+
+Version_t RegionGetVersion( void )
+{
+ Version_t version;
+
+ version.Value = REGION_VERSION;
+
+ return version;
+}
+
diff --git a/components/connectivity/LoraWAN/mac/region/Region.h b/components/connectivity/LoraWAN/mac/region/Region.h
index e892eb87..c349a2d1 100644
--- a/components/connectivity/LoraWAN/mac/region/Region.h
+++ b/components/connectivity/LoraWAN/mac/region/Region.h
@@ -52,17 +52,32 @@
#ifndef __REGION_H__
#define __REGION_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include "utilities.h"
#include "LoRaMac.h"
#include "timer.h"
+#include "RegionCommon.h"
/*!
* Macro to compute bit of a channel index.
*/
#define LC( channelIndex ) ( uint16_t )( 1 << ( channelIndex - 1 ) )
+#ifndef REGION_VERSION
+/*!
+ * Regional parameters version definition.
+ */
+#define REGION_VERSION 0x00010003
+#endif
+
+
+
/*!
* Region | SF
* ------------ | :-----:
@@ -476,7 +491,7 @@
* EU868 | -
* IN865 | Max EIRP - 18
* KR920 | -
- * US915 | Max ERP - 16
+ * US915 | Max ERP - 18
* RU864 | -
*/
#define TX_POWER_9 9
@@ -492,28 +507,72 @@
* EU868 | -
* IN865 | Max EIRP - 20
* KR920 | -
- * US915 | Max ERP - 10
+ * US915 | Max ERP - 20
* RU864 | -
*/
#define TX_POWER_10 10
/*!
- * RFU
+ * Region | dBM
+ * ------------ | :-----:
+ * AS923 | -
+ * AU915 | Max EIRP - 22
+ * CN470 | -
+ * CN779 | -
+ * EU433 | -
+ * EU868 | -
+ * IN865 | -
+ * KR920 | -
+ * US915 | Max ERP - 22
+ * RU864 | -
*/
#define TX_POWER_11 11
/*!
- * RFU
+ * Region | dBM
+ * ------------ | :-----:
+ * AS923 | -
+ * AU915 | Max EIRP - 24
+ * CN470 | -
+ * CN779 | -
+ * EU433 | -
+ * EU868 | -
+ * IN865 | -
+ * KR920 | -
+ * US915 | Max ERP - 24
+ * RU864 | -
*/
#define TX_POWER_12 12
/*!
- * RFU
+ * Region | dBM
+ * ------------ | :-----:
+ * AS923 | -
+ * AU915 | Max EIRP - 26
+ * CN470 | -
+ * CN779 | -
+ * EU433 | -
+ * EU868 | -
+ * IN865 | -
+ * KR920 | -
+ * US915 | Max ERP - 26
+ * RU864 | -
*/
#define TX_POWER_13 13
/*!
- * RFU
+ * Region | dBM
+ * ------------ | :-----:
+ * AS923 | -
+ * AU915 | Max EIRP - 28
+ * CN470 | -
+ * CN779 | -
+ * EU433 | -
+ * EU868 | -
+ * IN865 | -
+ * KR920 | -
+ * US915 | Max ERP - 28
+ * RU864 | -
*/
#define TX_POWER_14 14
@@ -529,6 +588,11 @@
*/
typedef enum ePhyAttribute
{
+ /*!
+ * Frequency. It is available
+ * to perform a verification with RegionVerify().
+ */
+ PHY_FREQUENCY,
/*!
* Minimum RX datarate.
*/
@@ -585,10 +649,6 @@ typedef enum ePhyAttribute
* Maximum payload possible.
*/
PHY_MAX_PAYLOAD,
- /*!
- * Maximum payload possible when repeater support is enabled.
- */
- PHY_MAX_PAYLOAD_REPEATER,
/*!
* Duty cycle.
*/
@@ -743,10 +803,26 @@ typedef enum ePhyAttribute
* The number of channels for the beacon reception.
*/
PHY_BEACON_NB_CHANNELS,
+ /*!
+ * Ping slot channel frequency.
+ */
+ PHY_PING_SLOT_CHANNEL_FREQ,
/*!
* The datarate of a ping slot channel.
*/
- PHY_PING_SLOT_CHANNEL_DR
+ PHY_PING_SLOT_CHANNEL_DR,
+ /*
+ * The number of channels for the ping slot reception.
+ */
+ PHY_PING_SLOT_NB_CHANNELS,
+ /*!
+ * The equivalent spreading factor value from datarate
+ */
+ PHY_SF_FROM_DR,
+ /*!
+ * The equivalent bandwith index from datarate
+ */
+ PHY_BW_FROM_DR,
}PhyAttribute_t;
/*!
@@ -754,6 +830,10 @@ typedef enum ePhyAttribute
*/
typedef enum eInitType
{
+ /*!
+ * Initializes the band definitions.
+ */
+ INIT_TYPE_BANDS,
/*!
* Initializes the region specific data to defaults, according to the
* LoRaWAN specification.
@@ -825,6 +905,10 @@ typedef union uPhyParam
* Beacon format
*/
BeaconFormat_t BeaconFormat;
+ /*!
+ * Duty Cycle Period
+ */
+ TimerTime_t DutyCycleTimePeriod;
}PhyParam_t;
/*!
@@ -839,23 +923,29 @@ typedef struct sGetPhyParams
/*!
* Datarate.
* The parameter is needed for the following queries:
- * PHY_MAX_PAYLOAD, PHY_MAX_PAYLOAD_REPEATER, PHY_NEXT_LOWER_TX_DR.
+ * PHY_MAX_PAYLOAD, PHY_NEXT_LOWER_TX_DR, PHY_SF_FROM_DR, PHY_BW_FROM_DR.
*/
int8_t Datarate;
/*!
* Uplink dwell time. This parameter must be set to query:
- * PHY_MAX_PAYLOAD, PHY_MAX_PAYLOAD_REPEATER, PHY_MIN_TX_DR.
+ * PHY_MAX_PAYLOAD, PHY_MIN_TX_DR.
* The parameter is needed for the following queries:
- * PHY_MIN_TX_DR, PHY_MAX_PAYLOAD, PHY_MAX_PAYLOAD_REPEATER, PHY_NEXT_LOWER_TX_DR.
+ * PHY_MIN_TX_DR, PHY_MAX_PAYLOAD, PHY_NEXT_LOWER_TX_DR.
*/
uint8_t UplinkDwellTime;
/*!
* Downlink dwell time. This parameter must be set to query:
- * PHY_MAX_PAYLOAD, PHY_MAX_PAYLOAD_REPEATER, PHY_MIN_RX_DR.
+ * PHY_MAX_PAYLOAD, PHY_MIN_RX_DR.
* The parameter is needed for the following queries:
- * PHY_MIN_RX_DR, PHY_MAX_PAYLOAD, PHY_MAX_PAYLOAD_REPEATER.
+ * PHY_MIN_RX_DR, PHY_MAX_PAYLOAD.
*/
uint8_t DownlinkDwellTime;
+ /*!
+ * Specification of the downlink channel. Used in Class B only.
+ * The parameter is needed for the following queries:
+ * PHY_BEACON_CHANNEL_FREQ, PHY_PING_SLOT_CHANNEL_FREQ
+ */
+ uint8_t Channel;
}GetPhyParams_t;
/*!
@@ -875,6 +965,14 @@ typedef struct sSetBandTxDoneParams
* Last TX done time.
*/
TimerTime_t LastTxDoneTime;
+ /*!
+ * Time-on-air of the last transmission.
+ */
+ TimerTime_t LastTxAirTime;
+ /*!
+ * Elapsed time since initialization.
+ */
+ SysTime_t ElapsedTimeSinceStartUp;
}SetBandTxDoneParams_t;
/*!
@@ -909,6 +1007,10 @@ typedef struct sGetNvmCtxParams
*/
typedef union uVerifyParams
{
+ /*!
+ * Channel frequency to verify
+ */
+ uint32_t Frequency;
/*!
* TX power to verify.
*/
@@ -1004,10 +1106,6 @@ typedef struct sRxConfigParams
* Downlink dwell time.
*/
uint8_t DownlinkDwellTime;
- /*!
- * Set to true, if a repeater is supported.
- */
- bool RepeaterSupport;
/*!
* Set to true, if RX should be continuous.
*/
@@ -1171,37 +1269,6 @@ typedef enum eAlternateDrType
ALTERNATE_DR_RESTORE
}AlternateDrType_t;
-/*!
- * Parameter structure for the function RegionCalcBackOff.
- */
-typedef struct sCalcBackOffParams
-{
- /*!
- * Set to true, if the node has already joined a network, otherwise false.
- */
- bool Joined;
- /*!
- * Joined Set to true, if the last uplink was a join request
- */
- bool LastTxIsJoinRequest;
- /*!
- * Set to true, if the duty cycle is enabled, otherwise false.
- */
- bool DutyCycleEnabled;
- /*!
- * Current channel index.
- */
- uint8_t Channel;
- /*!
- * Elapsed time since the start of the node.
- */
- SysTime_t ElapsedTime;
- /*!
- * Time-on-air of the last transmission.
- */
- TimerTime_t TxTimeOnAir;
-}CalcBackOffParams_t;
-
/*!
* Parameter structure for the function RegionNextChannel.
*/
@@ -1227,6 +1294,18 @@ typedef struct sNextChanParams
* Set to true, if the duty cycle is enabled, otherwise false.
*/
bool DutyCycleEnabled;
+ /*!
+ * Elapsed time since the start of the node.
+ */
+ SysTime_t ElapsedTimeSinceStartUp;
+ /*!
+ * Joined Set to true, if the last uplink was a join request
+ */
+ bool LastTxIsJoinRequest;
+ /*!
+ * Payload length of the next frame
+ */
+ uint16_t PktLen;
}NextChanParams_t;
/*!
@@ -1552,15 +1631,6 @@ uint8_t RegionDlChannelReq( LoRaMacRegion_t region, DlChannelReqParams_t* dlChan
*/
int8_t RegionAlternateDr( LoRaMacRegion_t region, int8_t currentDr, AlternateDrType_t type );
-/*!
- * \brief Calculates the back-off time.
- *
- * \param [IN] region LoRaWAN region.
- *
- * \param [IN] calcBackOff Pointer to the function parameters.
- */
-void RegionCalcBackOff( LoRaMacRegion_t region, CalcBackOffParams_t* calcBackOff );
-
/*!
* \brief Searches and set the next random available channel
*
@@ -1630,6 +1700,17 @@ uint8_t RegionApplyDrOffset( LoRaMacRegion_t region, uint8_t downlinkDwellTime,
*/
void RegionRxBeaconSetup( LoRaMacRegion_t region, RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr );
+/*!
+ * \brief Gets the version of the regional parameters implementation.
+ *
+ * \retval Version of the regional parameters.
+ */
+Version_t RegionGetVersion( void );
+
/*! \} defgroup REGION */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __REGION_H__
diff --git a/components/connectivity/LoraWAN/mac/region/RegionAS923.c b/components/connectivity/LoraWAN/mac/region/RegionAS923.c
index 5fceda7a..c83609a2 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionAS923.c
+++ b/components/connectivity/LoraWAN/mac/region/RegionAS923.c
@@ -119,45 +119,21 @@ static bool VerifyRfFreq( uint32_t freq )
return true;
}
-static uint8_t CountNbOfEnabledChannels( bool joined, uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
{
- uint8_t nbEnabledChannels = 0;
- uint8_t delayTransmission = 0;
+ int8_t phyDr = DataratesAS923[datarate];
+ uint32_t bandwidth = GetBandwidth( datarate );
+ TimerTime_t timeOnAir = 0;
- for( uint8_t i = 0, k = 0; i < AS923_MAX_NB_CHANNELS; i += 16, k++ )
- {
- for( uint8_t j = 0; j < 16; j++ )
- {
- if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
- {
- if( channels[i + j].Frequency == 0 )
- { // Check if the channel is enabled
- continue;
- }
- if( joined == false )
- {
- if( ( AS923_JOIN_CHANNELS & ( 1 << j ) ) == 0 )
- {
- continue;
- }
- }
- if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
- channels[i + j].DrRange.Fields.Max ) == false )
- { // Check if the current channel selection supports the given datarate
- continue;
- }
- if( bands[channels[i + j].Band].TimeOff > 0 )
- { // Check if the band is available for transmission
- delayTransmission++;
- continue;
- }
- enabledChannels[nbEnabledChannels++] = i + j;
- }
- }
+ if( datarate == DR_7 )
+ { // High Speed FSK channel
+ timeOnAir = Radio.TimeOnAir( MODEM_FSK, bandwidth, phyDr * 1000, 0, 5, false, pktLen, true );
}
-
- *delayTx = delayTransmission;
- return nbEnabledChannels;
+ else
+ {
+ timeOnAir = Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
+ }
+ return timeOnAir;
}
PhyParam_t RegionAS923GetPhyParam( GetPhyParams_t* getPhy )
@@ -239,18 +215,6 @@ PhyParam_t RegionAS923GetPhyParam( GetPhyParams_t* getPhy )
}
break;
}
- case PHY_MAX_PAYLOAD_REPEATER:
- {
- if( getPhy->UplinkDwellTime == 0 )
- {
- phyParam.Value = MaxPayloadOfDatarateRepeaterDwell0AS923[getPhy->Datarate];
- }
- else
- {
- phyParam.Value = MaxPayloadOfDatarateDwell1UpAS923[getPhy->Datarate];
- }
- break;
- }
case PHY_DUTY_CYCLE:
{
phyParam.Value = AS923_DUTY_CYCLE_ENABLED;
@@ -363,11 +327,26 @@ PhyParam_t RegionAS923GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = AS923_BEACON_CHANNEL_DR;
break;
}
+ case PHY_PING_SLOT_CHANNEL_FREQ:
+ {
+ phyParam.Value = AS923_PING_SLOT_CHANNEL_FREQ;
+ break;
+ }
case PHY_PING_SLOT_CHANNEL_DR:
{
phyParam.Value = AS923_PING_SLOT_CHANNEL_DR;
break;
}
+ case PHY_SF_FROM_DR:
+ {
+ phyParam.Value = DataratesAS923[getPhy->Datarate];
+ break;
+ }
+ case PHY_BW_FROM_DR:
+ {
+ phyParam.Value = GetBandwidth( getPhy->Datarate );
+ break;
+ }
default:
{
break;
@@ -379,7 +358,8 @@ PhyParam_t RegionAS923GetPhyParam( GetPhyParams_t* getPhy )
void RegionAS923SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
- RegionCommonSetBandTxDone( txDone->Joined, &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+ RegionCommonSetBandTxDone( &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band],
+ txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
}
void RegionAS923InitDefaults( InitDefaultsParams_t* params )
@@ -391,10 +371,14 @@ void RegionAS923InitDefaults( InitDefaultsParams_t* params )
switch( params->Type )
{
- case INIT_TYPE_INIT:
+ case INIT_TYPE_BANDS:
{
// Initialize bands
memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * AS923_MAX_NB_BANDS );
+ break;
+ }
+ case INIT_TYPE_INIT:
+ {
// Channels
NvmCtx.Channels[0] = ( ChannelParams_t ) AS923_LC1;
@@ -402,6 +386,7 @@ void RegionAS923InitDefaults( InitDefaultsParams_t* params )
// Initialize the channels default mask
NvmCtx.ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 );
+
// Update the channels mask
RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 1 );
break;
@@ -418,6 +403,10 @@ void RegionAS923InitDefaults( InitDefaultsParams_t* params )
{
// Restore channels default mask
NvmCtx.ChannelsMask[0] |= NvmCtx.ChannelsDefaultMask[0];
+
+ // Channels
+ NvmCtx.Channels[0] = ( ChannelParams_t ) AS923_LC1;
+ NvmCtx.Channels[1] = ( ChannelParams_t ) AS923_LC2;
break;
}
default:
@@ -437,6 +426,10 @@ bool RegionAS923Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
+ case PHY_FREQUENCY:
+ {
+ return VerifyRfFreq( verify->Frequency );
+ }
case PHY_TX_DR:
{
if( verify->DatarateParams.UplinkDwellTime == 0 )
@@ -581,7 +574,6 @@ bool RegionAS923RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
RadioModems_t modem;
int8_t dr = rxConfig->Datarate;
- uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
@@ -618,17 +610,7 @@ bool RegionAS923RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
Radio.SetRxConfig( modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
}
- // Check for repeater support
- if( rxConfig->RepeaterSupport == true )
- {
- maxPayload = MaxPayloadOfDatarateRepeaterDwell0AS923[dr];
- }
- else
- {
- maxPayload = MaxPayloadOfDatarateDwell0AS923[dr];
- }
-
- Radio.SetMaxPayloadLength( modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+ Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateDwell0AS923[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
*datarate = (uint8_t) dr;
return true;
@@ -651,18 +633,19 @@ bool RegionAS923TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime
if( txConfig->Datarate == DR_7 )
{ // High Speed FSK channel
modem = MODEM_FSK;
- Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 4000 );
}
else
{
modem = MODEM_LORA;
- Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
}
+ // Update time-on-air
+ *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
+
// Setup maximum payload lenght of the radio driver
Radio.SetMaxPayloadLength( modem, txConfig->PktLen );
- // Get the time-on-air of the next tx frame
- *txTimeOnAir = Radio.TimeOnAir( modem, txConfig->PktLen );
*txPower = txPowerLimited;
return true;
@@ -888,55 +871,45 @@ int8_t RegionAS923AlternateDr( int8_t currentDr, AlternateDrType_t type )
return AS923_DWELL_LIMIT_DATARATE;
}
-void RegionAS923CalcBackOff( CalcBackOffParams_t* calcBackOff )
-{
- RegionCommonCalcBackOffParams_t calcBackOffParams;
-
- calcBackOffParams.Channels = NvmCtx.Channels;
- calcBackOffParams.Bands = NvmCtx.Bands;
- calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
- calcBackOffParams.Joined = calcBackOff->Joined;
- calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
- calcBackOffParams.Channel = calcBackOff->Channel;
- calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
- calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
-
- RegionCommonCalcBackOff( &calcBackOffParams );
-}
-
LoRaMacStatus_t RegionAS923NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t channelNext = 0;
uint8_t nbEnabledChannels = 0;
- uint8_t delayTx = 0;
+ uint8_t nbRestrictedChannels = 0;
uint8_t enabledChannels[AS923_MAX_NB_CHANNELS] = { 0 };
- TimerTime_t nextTxDelay = 0;
+ RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
+ RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
+ LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
if( RegionCommonCountChannels( NvmCtx.ChannelsMask, 0, 1 ) == 0 )
{ // Reactivate default channels
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 );
}
- if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
- {
- // Reset Aggregated time off
- *aggregatedTimeOff = 0;
+ // Search how many channels are enabled
+ countChannelsParams.Joined = nextChanParams->Joined;
+ countChannelsParams.Datarate = nextChanParams->Datarate;
+ countChannelsParams.ChannelsMask = NvmCtx.ChannelsMask;
+ countChannelsParams.Channels = NvmCtx.Channels;
+ countChannelsParams.Bands = NvmCtx.Bands;
+ countChannelsParams.MaxNbChannels = AS923_MAX_NB_CHANNELS;
+ countChannelsParams.JoinChannels = AS923_JOIN_CHANNELS;
- // Update bands Time OFF
- nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, NvmCtx.Bands, AS923_MAX_NB_BANDS );
+ identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
+ identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
+ identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
+ identifyChannelsParam.MaxBands = AS923_MAX_NB_BANDS;
- // Search how many channels are enabled
- nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Joined, nextChanParams->Datarate,
- NvmCtx.ChannelsMask, NvmCtx.Channels,
- NvmCtx.Bands, enabledChannels, &delayTx );
- }
- else
- {
- delayTx++;
- nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
- }
+ identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
+ identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
+ identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
- if( nbEnabledChannels > 0 )
+ identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
+
+ status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
+ &nbEnabledChannels, &nbRestrictedChannels, time );
+
+ if( status == LORAMAC_STATUS_OK )
{
for( uint8_t i = 0, j = randr( 0, nbEnabledChannels - 1 ); i < AS923_MAX_NB_CHANNELS; i++ )
{
@@ -949,25 +922,19 @@ LoRaMacStatus_t RegionAS923NextChannel( NextChanParams_t* nextChanParams, uint8_
{
// Free channel found
*channel = channelNext;
- *time = 0;
return LORAMAC_STATUS_OK;
}
}
- return LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND;
+ // Even if one or more channels are available according to the channel plan, no free channel
+ // was found during the LBT procedure.
+ status = LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND;
}
- else
+ else if( status == LORAMAC_STATUS_NO_CHANNEL_FOUND )
{
- if( delayTx > 0 )
- {
- // Delay transmission due to AggregatedTimeOff or to a band time off
- *time = nextTxDelay;
- return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
- }
// Datarate not supported by any channel, restore defaults
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 );
- *time = 0;
- return LORAMAC_STATUS_NO_CHANNEL_FOUND;
}
+ return status;
}
LoRaMacStatus_t RegionAS923ChannelAdd( ChannelAddParams_t* channelAdd )
diff --git a/components/connectivity/LoraWAN/mac/region/RegionAS923.h b/components/connectivity/LoraWAN/mac/region/RegionAS923.h
index ab0a3d33..6fe1e8e4 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionAS923.h
+++ b/components/connectivity/LoraWAN/mac/region/RegionAS923.h
@@ -37,6 +37,11 @@
#ifndef __REGION_AS923_H__
#define __REGION_AS923_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "region/Region.h"
/*!
@@ -212,6 +217,11 @@
*/
#define AS923_BEACON_CHANNEL_FREQ 923400000
+/*!
+ * Ping slot channel frequency
+ */
+#define AS923_PING_SLOT_CHANNEL_FREQ 923400000
+
/*!
* Payload size of a beacon frame
*/
@@ -249,9 +259,9 @@
/*!
* Band 0 definition
- * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define AS923_BAND0 { 100, AS923_MAX_TX_POWER, 0, 0, 0 } // 1.0 %
+#define AS923_BAND0 { 100, AS923_MAX_TX_POWER, 0, 0, 0, 0 } // 1.0 %
/*!
* LoRaMac default channel 1
@@ -291,27 +301,20 @@ static const uint8_t DataratesAS923[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
static const uint32_t BandwidthsAS923[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ * Maximum payload with respect to the datarate index.
* The table is valid for the dwell time configuration of 0 for uplinks and downlinks.
*/
static const uint8_t MaxPayloadOfDatarateDwell0AS923[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- * The table is valid for the dwell time configuration of 0 for uplinks and downlinks. The table provides
- * repeater support.
- */
-static const uint8_t MaxPayloadOfDatarateRepeaterDwell0AS923[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
-
-/*!
- * Maximum payload with respect to the datarate index. Can operate with and without repeater.
- * The table proides repeater support. The table is only valid for uplinks.
+ * Maximum payload with respect to the datarate index.
+ * The table is only valid for uplinks.
*/
static const uint8_t MaxPayloadOfDatarateDwell1UpAS923[] = { 0, 0, 11, 53, 125, 242, 242, 242 };
/*!
- * Maximum payload with respect to the datarate index. Can operate with and without repeater.
- * The table proides repeater support. The table is only valid for downlinks.
+ * Maximum payload with respect to the datarate index.
+ * The table is only valid for downlinks.
*/
static const uint8_t MaxPayloadOfDatarateDwell1DownAS923[] = { 0, 0, 11, 53, 126, 242, 242, 242 };
@@ -475,13 +478,6 @@ uint8_t RegionAS923DlChannelReq( DlChannelReqParams_t* dlChannelReq );
*/
int8_t RegionAS923AlternateDr( int8_t currentDr, AlternateDrType_t type );
-/*!
- * \brief Calculates the back-off time.
- *
- * \param [IN] calcBackOff Pointer to the function parameters.
- */
-void RegionAS923CalcBackOff( CalcBackOffParams_t* calcBackOff );
-
/*!
* \brief Searches and set the next random available channel
*
@@ -543,4 +539,8 @@ uint8_t RegionAS923ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t d
/*! \} defgroup REGIONAS923 */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __REGION_AS923_H__
diff --git a/components/connectivity/LoraWAN/mac/region/RegionAU915.c b/components/connectivity/LoraWAN/mac/region/RegionAU915.c
index 87fdb647..7764e9b6 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionAU915.c
+++ b/components/connectivity/LoraWAN/mac/region/RegionAU915.c
@@ -140,38 +140,12 @@ static bool VerifyRfFreq( uint32_t freq )
return true;
}
-static uint8_t CountNbOfEnabledChannels( uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
{
- uint8_t nbEnabledChannels = 0;
- uint8_t delayTransmission = 0;
+ int8_t phyDr = DataratesAU915[datarate];
+ uint32_t bandwidth = GetBandwidth( datarate );
- for( uint8_t i = 0, k = 0; i < AU915_MAX_NB_CHANNELS; i += 16, k++ )
- {
- for( uint8_t j = 0; j < 16; j++ )
- {
- if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
- {
- if( channels[i + j].Frequency == 0 )
- { // Check if the channel is enabled
- continue;
- }
- if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
- channels[i + j].DrRange.Fields.Max ) == false )
- { // Check if the current channel selection supports the given datarate
- continue;
- }
- if( bands[channels[i + j].Band].TimeOff > 0 )
- { // Check if the band is available for transmission
- delayTransmission++;
- continue;
- }
- enabledChannels[nbEnabledChannels++] = i + j;
- }
- }
- }
-
- *delayTx = delayTransmission;
- return nbEnabledChannels;
+ return Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
}
PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy )
@@ -253,18 +227,6 @@ PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy )
}
break;
}
- case PHY_MAX_PAYLOAD_REPEATER:
- {
- if( getPhy->UplinkDwellTime == 0)
- {
- phyParam.Value = MaxPayloadOfDatarateRepeaterDwell0AU915[getPhy->Datarate];
- }
- else
- {
- phyParam.Value = MaxPayloadOfDatarateRepeaterDwell1AU915[getPhy->Datarate];
- }
- break;
- }
case PHY_DUTY_CYCLE:
{
phyParam.Value = AU915_DUTY_CYCLE_ENABLED;
@@ -360,6 +322,11 @@ PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy )
phyParam.fValue = AU915_DEFAULT_ANTENNA_GAIN;
break;
}
+ case PHY_BEACON_CHANNEL_FREQ:
+ {
+ phyParam.Value = AU915_BEACON_CHANNEL_FREQ + ( getPhy->Channel * AU915_BEACON_CHANNEL_STEPWIDTH );
+ break;
+ }
case PHY_BEACON_FORMAT:
{
phyParam.BeaconFormat.BeaconSize = AU915_BEACON_SIZE;
@@ -382,11 +349,26 @@ PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = AU915_BEACON_NB_CHANNELS;
break;
}
+ case PHY_PING_SLOT_CHANNEL_FREQ:
+ {
+ phyParam.Value = AU915_PING_SLOT_CHANNEL_FREQ + ( getPhy->Channel * AU915_BEACON_CHANNEL_STEPWIDTH );
+ break;
+ }
case PHY_PING_SLOT_CHANNEL_DR:
{
phyParam.Value = AU915_PING_SLOT_CHANNEL_DR;
break;
}
+ case PHY_SF_FROM_DR:
+ {
+ phyParam.Value = DataratesAU915[getPhy->Datarate];
+ break;
+ }
+ case PHY_BW_FROM_DR:
+ {
+ phyParam.Value = GetBandwidth( getPhy->Datarate );
+ break;
+ }
default:
{
break;
@@ -398,7 +380,8 @@ PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy )
void RegionAU915SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
- RegionCommonSetBandTxDone( txDone->Joined, &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+ RegionCommonSetBandTxDone( &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band],
+ txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
}
void RegionAU915InitDefaults( InitDefaultsParams_t* params )
@@ -410,11 +393,28 @@ void RegionAU915InitDefaults( InitDefaultsParams_t* params )
switch( params->Type )
{
- case INIT_TYPE_INIT:
+ case INIT_TYPE_BANDS:
{
// Initialize bands
memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * AU915_MAX_NB_BANDS );
+ // Initialize channels default mask
+ NvmCtx.ChannelsDefaultMask[0] = 0xFFFF;
+ NvmCtx.ChannelsDefaultMask[1] = 0xFFFF;
+ NvmCtx.ChannelsDefaultMask[2] = 0xFFFF;
+ NvmCtx.ChannelsDefaultMask[3] = 0xFFFF;
+ NvmCtx.ChannelsDefaultMask[4] = 0x00FF;
+ NvmCtx.ChannelsDefaultMask[5] = 0x0000;
+
+ // Copy channels default mask
+ RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 6 );
+
+ // Copy into channels mask remaining
+ RegionCommonChanMaskCopy( NvmCtx.ChannelsMaskRemaining, NvmCtx.ChannelsMask, 6 );
+ break;
+ }
+ case INIT_TYPE_INIT:
+ {
// Channels
// 125 kHz channels
for( uint8_t i = 0; i < AU915_MAX_NB_CHANNELS - 8; i++ )
@@ -430,20 +430,6 @@ void RegionAU915InitDefaults( InitDefaultsParams_t* params )
NvmCtx.Channels[i].DrRange.Value = ( DR_6 << 4 ) | DR_6;
NvmCtx.Channels[i].Band = 0;
}
-
- // Initialize channels default mask
- NvmCtx.ChannelsDefaultMask[0] = 0xFFFF;
- NvmCtx.ChannelsDefaultMask[1] = 0xFFFF;
- NvmCtx.ChannelsDefaultMask[2] = 0xFFFF;
- NvmCtx.ChannelsDefaultMask[3] = 0xFFFF;
- NvmCtx.ChannelsDefaultMask[4] = 0x00FF;
- NvmCtx.ChannelsDefaultMask[5] = 0x0000;
-
- // Copy channels default mask
- RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 6 );
-
- // Copy into channels mask remaining
- RegionCommonChanMaskCopy( NvmCtx.ChannelsMaskRemaining, NvmCtx.ChannelsMask, 6 );
break;
}
case INIT_TYPE_RESTORE_CTX:
@@ -482,6 +468,10 @@ bool RegionAU915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
+ case PHY_FREQUENCY:
+ {
+ return VerifyRfFreq( verify->Frequency );
+ }
case PHY_TX_DR:
case PHY_DEF_TX_DR:
{
@@ -592,7 +582,6 @@ void RegionAU915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols
bool RegionAU915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
int8_t dr = rxConfig->Datarate;
- uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
@@ -615,15 +604,7 @@ bool RegionAU915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
// Radio configuration
Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
- if( rxConfig->RepeaterSupport == true )
- {
- maxPayload = MaxPayloadOfDatarateRepeaterDwell0AU915[dr];
- }
- else
- {
- maxPayload = MaxPayloadOfDatarateDwell0AU915[dr];
- }
- Radio.SetMaxPayloadLength( MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+ Radio.SetMaxPayloadLength( MODEM_LORA, MaxPayloadOfDatarateDwell0AU915[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
*datarate = (uint8_t) dr;
return true;
@@ -642,14 +623,14 @@ bool RegionAU915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime
// Setup the radio frequency
Radio.SetChannel( NvmCtx.Channels[txConfig->Channel].Frequency );
- Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
// Setup maximum payload lenght of the radio driver
Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
+ // Update time-on-air
+ *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
- *txTimeOnAir = Radio.TimeOnAir( MODEM_LORA, txConfig->PktLen );
*txPower = txPowerLimited;
-
return true;
}
@@ -880,28 +861,14 @@ int8_t RegionAU915AlternateDr( int8_t currentDr, AlternateDrType_t type )
return currentDr;
}
-void RegionAU915CalcBackOff( CalcBackOffParams_t* calcBackOff )
-{
- RegionCommonCalcBackOffParams_t calcBackOffParams;
-
- calcBackOffParams.Channels = NvmCtx.Channels;
- calcBackOffParams.Bands = NvmCtx.Bands;
- calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
- calcBackOffParams.Joined = calcBackOff->Joined;
- calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
- calcBackOffParams.Channel = calcBackOff->Channel;
- calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
- calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
-
- RegionCommonCalcBackOff( &calcBackOffParams );
-}
-
LoRaMacStatus_t RegionAU915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
- uint8_t delayTx = 0;
+ uint8_t nbRestrictedChannels = 0;
uint8_t enabledChannels[AU915_MAX_NB_CHANNELS] = { 0 };
- TimerTime_t nextTxDelay = 0;
+ RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
+ RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
+ LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
// Count 125kHz channels
if( RegionCommonCountChannels( NvmCtx.ChannelsMaskRemaining, 0, 4 ) == 0 )
@@ -917,47 +884,37 @@ LoRaMacStatus_t RegionAU915NextChannel( NextChanParams_t* nextChanParams, uint8_
}
}
- if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
- {
- // Reset Aggregated time off
- *aggregatedTimeOff = 0;
+ // Search how many channels are enabled
+ countChannelsParams.Joined = nextChanParams->Joined;
+ countChannelsParams.Datarate = nextChanParams->Datarate;
+ countChannelsParams.ChannelsMask = NvmCtx.ChannelsMaskRemaining;
+ countChannelsParams.Channels = NvmCtx.Channels;
+ countChannelsParams.Bands = NvmCtx.Bands;
+ countChannelsParams.MaxNbChannels = AU915_MAX_NB_CHANNELS;
+ countChannelsParams.JoinChannels = 0;
- // Update bands Time OFF
- nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, NvmCtx.Bands, AU915_MAX_NB_BANDS );
+ identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
+ identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
+ identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
+ identifyChannelsParam.MaxBands = AU915_MAX_NB_BANDS;
- // Search how many channels are enabled
- nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Datarate,
- NvmCtx.ChannelsMaskRemaining, NvmCtx.Channels,
- NvmCtx.Bands, enabledChannels, &delayTx );
- }
- else
- {
- delayTx++;
- nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
- }
+ identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
+ identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
+ identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
- if( nbEnabledChannels > 0 )
+ identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
+
+ status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
+ &nbEnabledChannels, &nbRestrictedChannels, time );
+
+ if( status == LORAMAC_STATUS_OK )
{
// We found a valid channel
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
// Disable the channel in the mask
RegionCommonChanDisable( NvmCtx.ChannelsMaskRemaining, *channel, AU915_MAX_NB_CHANNELS - 8 );
-
- *time = 0;
- return LORAMAC_STATUS_OK;
- }
- else
- {
- if( delayTx > 0 )
- {
- // Delay transmission due to AggregatedTimeOff or to a band time off
- *time = nextTxDelay;
- return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
- }
- // Datarate not supported by any channel
- *time = 0;
- return LORAMAC_STATUS_NO_CHANNEL_FOUND;
}
+ return status;
}
LoRaMacStatus_t RegionAU915ChannelAdd( ChannelAddParams_t* channelAdd )
diff --git a/components/connectivity/LoraWAN/mac/region/RegionAU915.h b/components/connectivity/LoraWAN/mac/region/RegionAU915.h
index de92a9d9..5e614117 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionAU915.h
+++ b/components/connectivity/LoraWAN/mac/region/RegionAU915.h
@@ -37,6 +37,11 @@
#ifndef __REGION_AU915_H__
#define __REGION_AU915_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "region/Region.h"
/*!
@@ -93,7 +98,7 @@
/*!
* Minimal Tx output power that can be used by the node
*/
-#define AU915_MIN_TX_POWER TX_POWER_10
+#define AU915_MIN_TX_POWER TX_POWER_14
/*!
* Maximal Tx output power that can be used by the node
@@ -203,6 +208,11 @@
*/
#define AU915_BEACON_CHANNEL_STEPWIDTH 600000
+/*!
+ * Ping slot channel frequency
+ */
+#define AU915_PING_SLOT_CHANNEL_FREQ 923300000
+
/*!
* Number of possible beacon channels
*/
@@ -226,7 +236,7 @@
/*!
* Datarate of the beacon channel
*/
-#define AU915_BEACON_CHANNEL_DR DR_10
+#define AU915_BEACON_CHANNEL_DR DR_8
/*!
* Bandwith of the beacon channel
@@ -236,7 +246,7 @@
/*!
* Ping slot channel datarate
*/
-#define AU915_PING_SLOT_CHANNEL_DR DR_10
+#define AU915_PING_SLOT_CHANNEL_DR DR_8
/*!
* LoRaMac maximum number of bands
@@ -245,9 +255,9 @@
/*!
* Band 0 definition
- * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define AU915_BAND0 { 1, AU915_MAX_TX_POWER, 0, 0, 0 } // 100.0 %
+#define AU915_BAND0 { 1, AU915_MAX_TX_POWER, 0, 0, 0, 0 } // 100.0 %
/*!
* Defines the first channel for RX window 1 for US band
@@ -289,30 +299,16 @@ static const int8_t DatarateOffsetsAU915[7][6] =
};
/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ * Maximum payload with respect to the datarate index.
* The table is valid for the dwell time configuration of 0 for uplinks.
*/
-static const uint8_t MaxPayloadOfDatarateDwell0AU915[] = { 51, 51, 51, 115, 242, 242, 242, 242, 0, 53, 129, 242, 242, 242, 242 };
+static const uint8_t MaxPayloadOfDatarateDwell0AU915[] = { 51, 51, 51, 115, 242, 242, 242, 0, 53, 129, 242, 242, 242, 242 };
/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- * The table is valid for the dwell time configuration of 0 for uplinks. The table provides
- * repeater support.
- */
-static const uint8_t MaxPayloadOfDatarateRepeaterDwell0AU915[] = { 51, 51, 51, 115, 222, 222, 222, 0, 33, 109, 222, 222, 222, 222 };
-
-/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ * Maximum payload with respect to the datarate index.
* The table is valid for the dwell time configuration of 1 for uplinks.
*/
-static const uint8_t MaxPayloadOfDatarateDwell1AU915[] = { 0, 0, 11, 53, 125, 242, 242, 0, 53, 129, 129, 242, 242, 242, 242 };
-
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- * The table is valid for the dwell time configuration of 1 for uplinks. The table provides
- * repeater support.
- */
-static const uint8_t MaxPayloadOfDatarateRepeaterDwell1AU915[] = { 0, 0, 11, 53, 125, 242, 242, 0, 33, 119, 129, 242, 242, 242, 242 };
+static const uint8_t MaxPayloadOfDatarateDwell1AU915[] = { 0, 0, 11, 53, 125, 242, 242, 0, 53, 129, 242, 242, 242, 242 };
/*!
* \brief The function gets a value of a specific phy attribute.
@@ -469,13 +465,6 @@ uint8_t RegionAU915DlChannelReq( DlChannelReqParams_t* dlChannelReq );
*/
int8_t RegionAU915AlternateDr( int8_t currentDr, AlternateDrType_t type );
-/*!
- * \brief Calculates the back-off time.
- *
- * \param [IN] calcBackOff Pointer to the function parameters.
- */
-void RegionAU915CalcBackOff( CalcBackOffParams_t* calcBackOff );
-
/*!
* \brief Searches and set the next random available channel
*
@@ -537,4 +526,8 @@ uint8_t RegionAU915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t d
/*! \} defgroup REGIONAU915 */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __REGION_AU915_H__
diff --git a/components/connectivity/LoraWAN/mac/region/RegionCN470.c b/components/connectivity/LoraWAN/mac/region/RegionCN470.c
index 3a9a269b..b2e7c7d5 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionCN470.c
+++ b/components/connectivity/LoraWAN/mac/region/RegionCN470.c
@@ -128,38 +128,12 @@ static bool VerifyRfFreq( uint32_t freq )
return true;
}
-static uint8_t CountNbOfEnabledChannels( uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
{
- uint8_t nbEnabledChannels = 0;
- uint8_t delayTransmission = 0;
+ int8_t phyDr = DataratesCN470[datarate];
+ uint32_t bandwidth = GetBandwidth( datarate );
- for( uint8_t i = 0, k = 0; i < CN470_MAX_NB_CHANNELS; i += 16, k++ )
- {
- for( uint8_t j = 0; j < 16; j++ )
- {
- if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
- {
- if( channels[i + j].Frequency == 0 )
- { // Check if the channel is enabled
- continue;
- }
- if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
- channels[i + j].DrRange.Fields.Max ) == false )
- { // Check if the current channel selection supports the given datarate
- continue;
- }
- if( bands[channels[i + j].Band].TimeOff > 0 )
- { // Check if the band is available for transmission
- delayTransmission++;
- continue;
- }
- enabledChannels[nbEnabledChannels++] = i + j;
- }
- }
- }
-
- *delayTx = delayTransmission;
- return nbEnabledChannels;
+ return Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
}
PhyParam_t RegionCN470GetPhyParam( GetPhyParams_t* getPhy )
@@ -213,11 +187,6 @@ PhyParam_t RegionCN470GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = MaxPayloadOfDatarateCN470[getPhy->Datarate];
break;
}
- case PHY_MAX_PAYLOAD_REPEATER:
- {
- phyParam.Value = MaxPayloadOfDatarateRepeaterCN470[getPhy->Datarate];
- break;
- }
case PHY_DUTY_CYCLE:
{
phyParam.Value = CN470_DUTY_CYCLE_ENABLED;
@@ -309,6 +278,11 @@ PhyParam_t RegionCN470GetPhyParam( GetPhyParams_t* getPhy )
phyParam.fValue = CN470_DEFAULT_ANTENNA_GAIN;
break;
}
+ case PHY_BEACON_CHANNEL_FREQ:
+ {
+ phyParam.Value = CN470_BEACON_CHANNEL_FREQ;
+ break;
+ }
case PHY_BEACON_FORMAT:
{
phyParam.BeaconFormat.BeaconSize = CN470_BEACON_SIZE;
@@ -331,11 +305,26 @@ PhyParam_t RegionCN470GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = CN470_BEACON_NB_CHANNELS;
break;
}
+ case PHY_PING_SLOT_CHANNEL_FREQ:
+ {
+ phyParam.Value = CN470_PING_SLOT_CHANNEL_FREQ;
+ break;
+ }
case PHY_PING_SLOT_CHANNEL_DR:
{
phyParam.Value = CN470_PING_SLOT_CHANNEL_DR;
break;
}
+ case PHY_SF_FROM_DR:
+ {
+ phyParam.Value = DataratesCN470[getPhy->Datarate];
+ break;
+ }
+ case PHY_BW_FROM_DR:
+ {
+ phyParam.Value = GetBandwidth( getPhy->Datarate );
+ break;
+ }
default:
{
break;
@@ -347,7 +336,8 @@ PhyParam_t RegionCN470GetPhyParam( GetPhyParams_t* getPhy )
void RegionCN470SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
- RegionCommonSetBandTxDone( txDone->Joined, &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+ RegionCommonSetBandTxDone( &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band],
+ txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
}
void RegionCN470InitDefaults( InitDefaultsParams_t* params )
@@ -359,11 +349,14 @@ void RegionCN470InitDefaults( InitDefaultsParams_t* params )
switch( params->Type )
{
- case INIT_TYPE_INIT:
+ case INIT_TYPE_BANDS:
{
// Initialize bands
memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * CN470_MAX_NB_BANDS );
-
+ break;
+ }
+ case INIT_TYPE_INIT:
+ {
// Channels
// 125 kHz channels
for( uint8_t i = 0; i < CN470_MAX_NB_CHANNELS; i++ )
@@ -374,21 +367,13 @@ void RegionCN470InitDefaults( InitDefaultsParams_t* params )
}
// Initialize the channels default mask
- #if 0
NvmCtx.ChannelsDefaultMask[0] = 0xFFFF;
NvmCtx.ChannelsDefaultMask[1] = 0xFFFF;
NvmCtx.ChannelsDefaultMask[2] = 0xFFFF;
NvmCtx.ChannelsDefaultMask[3] = 0xFFFF;
NvmCtx.ChannelsDefaultMask[4] = 0xFFFF;
NvmCtx.ChannelsDefaultMask[5] = 0xFFFF;
- #else
- NvmCtx.ChannelsDefaultMask[0] = 0x00FF;
- NvmCtx.ChannelsDefaultMask[1] = 0x0000;
- NvmCtx.ChannelsDefaultMask[2] = 0x0000;
- NvmCtx.ChannelsDefaultMask[3] = 0x0000;
- NvmCtx.ChannelsDefaultMask[4] = 0x0000;
- NvmCtx.ChannelsDefaultMask[5] = 0x0000;
- #endif
+
// Update the channels mask
RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 6 );
break;
@@ -424,6 +409,10 @@ bool RegionCN470Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
+ case PHY_FREQUENCY:
+ {
+ return VerifyRfFreq( verify->Frequency );
+ }
case PHY_TX_DR:
case PHY_DEF_TX_DR:
{
@@ -506,7 +495,6 @@ void RegionCN470ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols
bool RegionCN470RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
int8_t dr = rxConfig->Datarate;
- uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
@@ -529,15 +517,7 @@ bool RegionCN470RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
// Radio configuration
Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
- if( rxConfig->RepeaterSupport == true )
- {
- maxPayload = MaxPayloadOfDatarateRepeaterCN470[dr];
- }
- else
- {
- maxPayload = MaxPayloadOfDatarateCN470[dr];
- }
- Radio.SetMaxPayloadLength( MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+ Radio.SetMaxPayloadLength( MODEM_LORA, MaxPayloadOfDatarateCN470[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
*datarate = (uint8_t) dr;
return true;
@@ -555,11 +535,11 @@ bool RegionCN470TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime
// Setup the radio frequency
Radio.SetChannel( NvmCtx.Channels[txConfig->Channel].Frequency );
- Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, 0, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, 0, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
// Setup maximum payload lenght of the radio driver
Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
- // Get the time-on-air of the next tx frame
- *txTimeOnAir = Radio.TimeOnAir( MODEM_LORA, txConfig->PktLen );
+ // Update time-on-air
+ *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
*txPower = txPowerLimited;
return true;
@@ -708,28 +688,14 @@ int8_t RegionCN470AlternateDr( int8_t currentDr, AlternateDrType_t type )
return currentDr;
}
-void RegionCN470CalcBackOff( CalcBackOffParams_t* calcBackOff )
-{
- RegionCommonCalcBackOffParams_t calcBackOffParams;
-
- calcBackOffParams.Channels = NvmCtx.Channels;
- calcBackOffParams.Bands = NvmCtx.Bands;
- calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
- calcBackOffParams.Joined = calcBackOff->Joined;
- calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
- calcBackOffParams.Channel = calcBackOff->Channel;
- calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
- calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
-
- RegionCommonCalcBackOff( &calcBackOffParams );
-}
-
LoRaMacStatus_t RegionCN470NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
- uint8_t delayTx = 0;
+ uint8_t nbRestrictedChannels = 0;
uint8_t enabledChannels[CN470_MAX_NB_CHANNELS] = { 0 };
- TimerTime_t nextTxDelay = 0;
+ RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
+ RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
+ LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
// Count 125kHz channels
if( RegionCommonCountChannels( NvmCtx.ChannelsMask, 0, 6 ) == 0 )
@@ -742,45 +708,35 @@ LoRaMacStatus_t RegionCN470NextChannel( NextChanParams_t* nextChanParams, uint8_
NvmCtx.ChannelsMask[5] = 0xFFFF;
}
- if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
- {
- // Reset Aggregated time off
- *aggregatedTimeOff = 0;
+ // Search how many channels are enabled
+ countChannelsParams.Joined = nextChanParams->Joined;
+ countChannelsParams.Datarate = nextChanParams->Datarate;
+ countChannelsParams.ChannelsMask = NvmCtx.ChannelsMask;
+ countChannelsParams.Channels = NvmCtx.Channels;
+ countChannelsParams.Bands = NvmCtx.Bands;
+ countChannelsParams.MaxNbChannels = CN470_MAX_NB_CHANNELS;
+ countChannelsParams.JoinChannels = 0;
- // Update bands Time OFF
- nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, NvmCtx.Bands, CN470_MAX_NB_BANDS );
+ identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
+ identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
+ identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
+ identifyChannelsParam.MaxBands = CN470_MAX_NB_BANDS;
- // Search how many channels are enabled
- nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Datarate,
- NvmCtx.ChannelsMask, NvmCtx.Channels,
- NvmCtx.Bands, enabledChannels, &delayTx );
- }
- else
- {
- delayTx++;
- nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
- }
+ identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
+ identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
+ identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
- if( nbEnabledChannels > 0 )
+ identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
+
+ status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
+ &nbEnabledChannels, &nbRestrictedChannels, time );
+
+ if( status == LORAMAC_STATUS_OK )
{
// We found a valid channel
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
-
- *time = 0;
- return LORAMAC_STATUS_OK;
- }
- else
- {
- if( delayTx > 0 )
- {
- // Delay transmission due to AggregatedTimeOff or to a band time off
- *time = nextTxDelay;
- return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
- }
- // Datarate not supported by any channel
- *time = 0;
- return LORAMAC_STATUS_NO_CHANNEL_FOUND;
}
+ return status;
}
LoRaMacStatus_t RegionCN470ChannelAdd( ChannelAddParams_t* channelAdd )
diff --git a/components/connectivity/LoraWAN/mac/region/RegionCN470.h b/components/connectivity/LoraWAN/mac/region/RegionCN470.h
index c3b355db..2125733e 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionCN470.h
+++ b/components/connectivity/LoraWAN/mac/region/RegionCN470.h
@@ -37,6 +37,11 @@
#ifndef __REGION_CN470_H__
#define __REGION_CN470_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "region/Region.h"
/*!
@@ -187,6 +192,11 @@
*/
#define CN470_BEACON_CHANNEL_STEPWIDTH 200000
+/*!
+ * Ping slot channel frequency
+ */
+#define CN470_PING_SLOT_CHANNEL_FREQ 508300000
+
/*!
* Number of possible beacon channels
*/
@@ -229,9 +239,9 @@
/*!
* Band 0 definition
- * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define CN470_BAND0 { 1, CN470_MAX_TX_POWER, 0, 0, 0 } // 100.0 %
+#define CN470_BAND0 { 1, CN470_MAX_TX_POWER, 0, 0, 0, 0 } // 100.0 %
/*!
* Defines the first channel for RX window 1 for CN470 band
@@ -259,14 +269,9 @@ static const uint8_t DataratesCN470[] = { 12, 11, 10, 9, 8, 7 };
static const uint32_t BandwidthsCN470[] = { 125000, 125000, 125000, 125000, 125000, 125000 };
/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ * Maximum payload with respect to the datarate index.
*/
-static const uint8_t MaxPayloadOfDatarateCN470[] = { 51, 51, 51, 115, 222, 222 };
-
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-static const uint8_t MaxPayloadOfDatarateRepeaterCN470[] = { 51, 51, 51, 115, 222, 222 };
+static const uint8_t MaxPayloadOfDatarateCN470[] = { 51, 51, 51, 115, 242, 242 };
/*!
* \brief The function gets a value of a specific phy attribute.
@@ -423,13 +428,6 @@ uint8_t RegionCN470DlChannelReq( DlChannelReqParams_t* dlChannelReq );
*/
int8_t RegionCN470AlternateDr( int8_t currentDr, AlternateDrType_t type );
-/*!
- * \brief Calculates the back-off time.
- *
- * \param [IN] calcBackOff Pointer to the function parameters.
- */
-void RegionCN470CalcBackOff( CalcBackOffParams_t* calcBackOff );
-
/*!
* \brief Searches and set the next random available channel
*
@@ -491,4 +489,8 @@ uint8_t RegionCN470ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t d
/*! \} defgroup REGIONCN470 */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __REGION_CN470_H__
diff --git a/components/connectivity/LoraWAN/mac/region/RegionCN779.c b/components/connectivity/LoraWAN/mac/region/RegionCN779.c
index acf1d7eb..b156d410 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionCN779.c
+++ b/components/connectivity/LoraWAN/mac/region/RegionCN779.c
@@ -119,45 +119,21 @@ static bool VerifyRfFreq( uint32_t freq )
return true;
}
-static uint8_t CountNbOfEnabledChannels( bool joined, uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
{
- uint8_t nbEnabledChannels = 0;
- uint8_t delayTransmission = 0;
+ int8_t phyDr = DataratesCN779[datarate];
+ uint32_t bandwidth = GetBandwidth( datarate );
+ TimerTime_t timeOnAir = 0;
- for( uint8_t i = 0, k = 0; i < CN779_MAX_NB_CHANNELS; i += 16, k++ )
- {
- for( uint8_t j = 0; j < 16; j++ )
- {
- if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
- {
- if( channels[i + j].Frequency == 0 )
- { // Check if the channel is enabled
- continue;
- }
- if( joined == false )
- {
- if( ( CN779_JOIN_CHANNELS & ( 1 << j ) ) == 0 )
- {
- continue;
- }
- }
- if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
- channels[i + j].DrRange.Fields.Max ) == false )
- { // Check if the current channel selection supports the given datarate
- continue;
- }
- if( bands[channels[i + j].Band].TimeOff > 0 )
- { // Check if the band is available for transmission
- delayTransmission++;
- continue;
- }
- enabledChannels[nbEnabledChannels++] = i + j;
- }
- }
+ if( datarate == DR_7 )
+ { // High Speed FSK channel
+ timeOnAir = Radio.TimeOnAir( MODEM_FSK, bandwidth, phyDr * 1000, 0, 5, false, pktLen, true );
}
-
- *delayTx = delayTransmission;
- return nbEnabledChannels;
+ else
+ {
+ timeOnAir = Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
+ }
+ return timeOnAir;
}
PhyParam_t RegionCN779GetPhyParam( GetPhyParams_t* getPhy )
@@ -211,11 +187,6 @@ PhyParam_t RegionCN779GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = MaxPayloadOfDatarateCN779[getPhy->Datarate];
break;
}
- case PHY_MAX_PAYLOAD_REPEATER:
- {
- phyParam.Value = MaxPayloadOfDatarateRepeaterCN779[getPhy->Datarate];
- break;
- }
case PHY_DUTY_CYCLE:
{
phyParam.Value = CN779_DUTY_CYCLE_ENABLED;
@@ -324,11 +295,26 @@ PhyParam_t RegionCN779GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = CN779_BEACON_CHANNEL_DR;
break;
}
+ case PHY_PING_SLOT_CHANNEL_FREQ:
+ {
+ phyParam.Value = CN779_PING_SLOT_CHANNEL_FREQ;
+ break;
+ }
case PHY_PING_SLOT_CHANNEL_DR:
{
phyParam.Value = CN779_PING_SLOT_CHANNEL_DR;
break;
}
+ case PHY_SF_FROM_DR:
+ {
+ phyParam.Value = DataratesCN779[getPhy->Datarate];
+ break;
+ }
+ case PHY_BW_FROM_DR:
+ {
+ phyParam.Value = GetBandwidth( getPhy->Datarate );
+ break;
+ }
default:
{
break;
@@ -340,7 +326,8 @@ PhyParam_t RegionCN779GetPhyParam( GetPhyParams_t* getPhy )
void RegionCN779SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
- RegionCommonSetBandTxDone( txDone->Joined, &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+ RegionCommonSetBandTxDone( &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band],
+ txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
}
void RegionCN779InitDefaults( InitDefaultsParams_t* params )
@@ -352,10 +339,14 @@ void RegionCN779InitDefaults( InitDefaultsParams_t* params )
switch( params->Type )
{
- case INIT_TYPE_INIT:
+ case INIT_TYPE_BANDS:
{
// Initialize bands
memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * CN779_MAX_NB_BANDS );
+ break;
+ }
+ case INIT_TYPE_INIT:
+ {
// Channels
NvmCtx.Channels[0] = ( ChannelParams_t ) CN779_LC1;
@@ -364,6 +355,7 @@ void RegionCN779InitDefaults( InitDefaultsParams_t* params )
// Initialize the channels default mask
NvmCtx.ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
+
// Update the channels mask
RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 1 );
break;
@@ -380,6 +372,11 @@ void RegionCN779InitDefaults( InitDefaultsParams_t* params )
{
// Restore channels default mask
NvmCtx.ChannelsMask[0] |= NvmCtx.ChannelsDefaultMask[0];
+
+ // Channels
+ NvmCtx.Channels[0] = ( ChannelParams_t ) CN779_LC1;
+ NvmCtx.Channels[1] = ( ChannelParams_t ) CN779_LC2;
+ NvmCtx.Channels[2] = ( ChannelParams_t ) CN779_LC3;
break;
}
default:
@@ -399,6 +396,10 @@ bool RegionCN779Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
+ case PHY_FREQUENCY:
+ {
+ return VerifyRfFreq( verify->Frequency );
+ }
case PHY_TX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, CN779_TX_MIN_DATARATE, CN779_TX_MAX_DATARATE );
@@ -529,7 +530,6 @@ bool RegionCN779RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
RadioModems_t modem;
int8_t dr = rxConfig->Datarate;
- uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
@@ -566,15 +566,7 @@ bool RegionCN779RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
Radio.SetRxConfig( modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
}
- if( rxConfig->RepeaterSupport == true )
- {
- maxPayload = MaxPayloadOfDatarateRepeaterCN779[dr];
- }
- else
- {
- maxPayload = MaxPayloadOfDatarateCN779[dr];
- }
- Radio.SetMaxPayloadLength( modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+ Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateCN779[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
*datarate = (uint8_t) dr;
return true;
@@ -597,18 +589,19 @@ bool RegionCN779TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime
if( txConfig->Datarate == DR_7 )
{ // High Speed FSK channel
modem = MODEM_FSK;
- Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 4000 );
}
else
{
modem = MODEM_LORA;
- Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
}
+ // Update time-on-air
+ *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
+
// Setup maximum payload lenght of the radio driver
Radio.SetMaxPayloadLength( modem, txConfig->PktLen );
- // Get the time-on-air of the next tx frame
- *txTimeOnAir = Radio.TimeOnAir( modem, txConfig->PktLen );
*txPower = txPowerLimited;
return true;
@@ -832,74 +825,54 @@ int8_t RegionCN779AlternateDr( int8_t currentDr, AlternateDrType_t type )
return currentDr;
}
-void RegionCN779CalcBackOff( CalcBackOffParams_t* calcBackOff )
-{
- RegionCommonCalcBackOffParams_t calcBackOffParams;
-
- calcBackOffParams.Channels = NvmCtx.Channels;
- calcBackOffParams.Bands = NvmCtx.Bands;
- calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
- calcBackOffParams.Joined = calcBackOff->Joined;
- calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
- calcBackOffParams.Channel = calcBackOff->Channel;
- calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
- calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
-
- RegionCommonCalcBackOff( &calcBackOffParams );
-}
-
LoRaMacStatus_t RegionCN779NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
- uint8_t delayTx = 0;
+ uint8_t nbRestrictedChannels = 0;
uint8_t enabledChannels[CN779_MAX_NB_CHANNELS] = { 0 };
- TimerTime_t nextTxDelay = 0;
+ RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
+ RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
+ LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
if( RegionCommonCountChannels( NvmCtx.ChannelsMask, 0, 1 ) == 0 )
{ // Reactivate default channels
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
}
- if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
- {
- // Reset Aggregated time off
- *aggregatedTimeOff = 0;
+ // Search how many channels are enabled
+ countChannelsParams.Joined = nextChanParams->Joined;
+ countChannelsParams.Datarate = nextChanParams->Datarate;
+ countChannelsParams.ChannelsMask = NvmCtx.ChannelsMask;
+ countChannelsParams.Channels = NvmCtx.Channels;
+ countChannelsParams.Bands = NvmCtx.Bands;
+ countChannelsParams.MaxNbChannels = CN779_MAX_NB_CHANNELS;
+ countChannelsParams.JoinChannels = CN779_JOIN_CHANNELS;
- // Update bands Time OFF
- nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, NvmCtx.Bands, CN779_MAX_NB_BANDS );
+ identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
+ identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
+ identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
+ identifyChannelsParam.MaxBands = CN779_MAX_NB_BANDS;
- // Search how many channels are enabled
- nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Joined, nextChanParams->Datarate,
- NvmCtx.ChannelsMask, NvmCtx.Channels,
- NvmCtx.Bands, enabledChannels, &delayTx );
- }
- else
- {
- delayTx++;
- nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
- }
+ identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
+ identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
+ identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
- if( nbEnabledChannels > 0 )
+ identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
+
+ status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
+ &nbEnabledChannels, &nbRestrictedChannels, time );
+
+ if( status == LORAMAC_STATUS_OK )
{
// We found a valid channel
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
-
- *time = 0;
- return LORAMAC_STATUS_OK;
}
- else
+ else if( status == LORAMAC_STATUS_NO_CHANNEL_FOUND )
{
- if( delayTx > 0 )
- {
- // Delay transmission due to AggregatedTimeOff or to a band time off
- *time = nextTxDelay;
- return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
- }
// Datarate not supported by any channel, restore defaults
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
- *time = 0;
- return LORAMAC_STATUS_NO_CHANNEL_FOUND;
}
+ return status;
}
LoRaMacStatus_t RegionCN779ChannelAdd( ChannelAddParams_t* channelAdd )
diff --git a/components/connectivity/LoraWAN/mac/region/RegionCN779.h b/components/connectivity/LoraWAN/mac/region/RegionCN779.h
index 3c404dd8..5b3a8337 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionCN779.h
+++ b/components/connectivity/LoraWAN/mac/region/RegionCN779.h
@@ -37,6 +37,11 @@
#ifndef __REGION_CN779_H__
#define __REGION_CN779_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "region/Region.h"
/*!
@@ -199,6 +204,11 @@
*/
#define CN779_BEACON_CHANNEL_FREQ 785000000
+/*!
+ * Ping slot channel frequency
+ */
+#define CN779_PING_SLOT_CHANNEL_FREQ 785000000
+
/*!
* Payload size of a beacon frame
*/
@@ -236,9 +246,9 @@
/*!
* Band 0 definition
- * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define CN779_BAND0 { 100, CN779_MAX_TX_POWER, 0, 0, 0 } // 1.0 %
+#define CN779_BAND0 { 100, CN779_MAX_TX_POWER, 0, 0, 0, 0 } // 1.0 %
/*!
* LoRaMac default channel 1
@@ -273,15 +283,10 @@ static const uint8_t DataratesCN779[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
static const uint32_t BandwidthsCN779[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ * Maximum payload with respect to the datarate index.
*/
static const uint8_t MaxPayloadOfDatarateCN779[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-static const uint8_t MaxPayloadOfDatarateRepeaterCN779[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
-
/*!
* \brief The function gets a value of a specific phy attribute.
*
@@ -437,13 +442,6 @@ uint8_t RegionCN779DlChannelReq( DlChannelReqParams_t* dlChannelReq );
*/
int8_t RegionCN779AlternateDr( int8_t currentDr, AlternateDrType_t type );
-/*!
- * \brief Calculates the back-off time.
- *
- * \param [IN] calcBackOff Pointer to the function parameters.
- */
-void RegionCN779CalcBackOff( CalcBackOffParams_t* calcBackOff );
-
/*!
* \brief Searches and set the next random available channel
*
@@ -505,4 +503,8 @@ uint8_t RegionCN779ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t d
/*! \} defgroup REGIONCN779 */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __REGION_CN779_H__
diff --git a/components/connectivity/LoraWAN/mac/region/RegionCommon.c b/components/connectivity/LoraWAN/mac/region/RegionCommon.c
index 2a37026a..85f0078c 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionCommon.c
+++ b/components/connectivity/LoraWAN/mac/region/RegionCommon.c
@@ -33,9 +33,108 @@
#include "utilities.h"
#include "RegionCommon.h"
-#define BACKOFF_DC_1_HOUR 100
-#define BACKOFF_DC_10_HOURS 1000
-#define BACKOFF_DC_24_HOURS 10000
+#define BACKOFF_DC_1_HOUR 100
+#define BACKOFF_DC_10_HOURS 1000
+#define BACKOFF_DC_24_HOURS 10000
+#define BACKOFF_DC_TIMER_PERIOD_FACTOR 100
+
+#ifndef DUTY_CYCLE_TIME_PERIOD
+/*!
+ * Default duty cycle time period is 1 hour = 3600000 ms
+ */
+#define DUTY_CYCLE_TIME_PERIOD 3600000
+#endif
+
+static uint16_t GetDutyCycle( Band_t* band, bool joined, SysTime_t elapsedTimeSinceStartup )
+{
+ uint16_t joinDutyCycle = RegionCommonGetJoinDc( elapsedTimeSinceStartup );
+ uint16_t dutyCycle = band->DCycle;
+
+ if( joined == false )
+ {
+ // Get the join duty cycle which depends on the runtime
+ joinDutyCycle = RegionCommonGetJoinDc( elapsedTimeSinceStartup );
+ // Take the most restrictive duty cycle
+ dutyCycle = MAX( dutyCycle, joinDutyCycle );
+ }
+
+ // Prevent value of 0
+ if( dutyCycle == 0 )
+ {
+ dutyCycle = 1;
+ }
+
+ return dutyCycle;
+}
+
+static uint16_t SetMaxTimeCredits( Band_t* band, bool joined, SysTime_t elapsedTimeSinceStartup )
+{
+ uint16_t dutyCycle = band->DCycle;
+ uint8_t timePeriodFactor = 1;
+
+ // Get the band duty cycle. If not joined, the function either returns the join duty cycle
+ // or the band duty cycle, whichever is more restrictive.
+ dutyCycle = GetDutyCycle( band, joined, elapsedTimeSinceStartup );
+
+ if( joined == false )
+ {
+ // Apply a factor to increase the maximum time period of observation
+ timePeriodFactor = dutyCycle / BACKOFF_DC_TIMER_PERIOD_FACTOR;
+ }
+
+ // Setup the maximum allowed credits
+ band->MaxTimeCredits = DUTY_CYCLE_TIME_PERIOD * timePeriodFactor;
+
+ // In case if it is the first time, update also the current
+ // time credits
+ if( band->LastBandUpdateTime == 0 )
+ {
+ band->TimeCredits = band->MaxTimeCredits;
+ }
+
+ return dutyCycle;
+}
+
+static uint16_t UpdateTimeCredits( Band_t* band, bool joined, bool dutyCycleEnabled,
+ bool lastTxIsJoinRequest, SysTime_t elapsedTimeSinceStartup,
+ TimerTime_t currentTime )
+{
+ uint16_t dutyCycle = SetMaxTimeCredits( band, joined, elapsedTimeSinceStartup );
+
+ if( joined == false )
+ {
+ if( ( dutyCycleEnabled == false ) &&
+ ( lastTxIsJoinRequest == false ) )
+ {
+ // This is the case when the duty cycle is off and the last uplink frame was not a join.
+ // This could happen in case of a rejoin, e.g. in compliance test mode.
+ // In this special case we have to set the time off to 0, since the join duty cycle shall only
+ // be applied after the first join request.
+ band->TimeCredits = band->MaxTimeCredits;
+ }
+ }
+ else
+ {
+ if( dutyCycleEnabled == false )
+ {
+ band->TimeCredits = band->MaxTimeCredits;
+ }
+ }
+
+ // Get the difference between now and the last update
+ band->TimeCredits += TimerGetElapsedTime( band->LastBandUpdateTime );
+
+ // Limit band credits to maximum
+ if( band->TimeCredits > band->MaxTimeCredits )
+ {
+ band->TimeCredits = band->MaxTimeCredits;
+ }
+
+ // Synchronize update time
+ band->LastBandUpdateTime = currentTime;
+
+ return dutyCycle;
+}
static uint8_t CountChannels( uint16_t mask, uint8_t nbBits )
{
@@ -147,62 +246,87 @@ void RegionCommonChanMaskCopy( uint16_t* channelsMaskDest, uint16_t* channelsMas
}
}
-void RegionCommonSetBandTxDone( bool joined, Band_t* band, TimerTime_t lastTxDone )
+void RegionCommonSetBandTxDone( Band_t* band, TimerTime_t lastTxAirTime, bool joined, SysTime_t elapsedTimeSinceStartup )
{
- if( joined == true )
+ // Get the band duty cycle. If not joined, the function either returns the join duty cycle
+ // or the band duty cycle, whichever is more restrictive.
+ uint16_t dutyCycle = GetDutyCycle( band, joined, elapsedTimeSinceStartup );
+
+ // Reduce with transmission time
+ if( band->TimeCredits > ( lastTxAirTime * dutyCycle ) )
{
- band->LastTxDoneTime = lastTxDone;
+ // Reduce time credits by the time of air
+ band->TimeCredits -= ( lastTxAirTime * dutyCycle );
}
else
{
- band->LastTxDoneTime = lastTxDone;
- band->LastJoinTxDoneTime = lastTxDone;
+ band->TimeCredits = 0;
}
}
-TimerTime_t RegionCommonUpdateBandTimeOff( bool joined, bool dutyCycle, Band_t* bands, uint8_t nbBands )
+TimerTime_t RegionCommonUpdateBandTimeOff( bool joined, Band_t* bands,
+ uint8_t nbBands, bool dutyCycleEnabled,
+ bool lastTxIsJoinRequest, SysTime_t elapsedTimeSinceStartup,
+ TimerTime_t expectedTimeOnAir )
{
- TimerTime_t nextTxDelay = ( TimerTime_t )( -1 );
+ TimerTime_t minTimeToWait = TIMERTIME_T_MAX;
+ TimerTime_t currentTime = TimerGetCurrentTime( );
+ TimerTime_t creditCosts = 0;
+ uint16_t dutyCycle = 1;
+ uint8_t validBands = 0;
- // Update bands Time OFF
for( uint8_t i = 0; i < nbBands; i++ )
{
- if( joined == false )
- {
- TimerTime_t txDoneTime = MAX( TimerGetElapsedTime( bands[i].LastJoinTxDoneTime ),
- ( dutyCycle == true ) ? TimerGetElapsedTime( bands[i].LastTxDoneTime ) : 0 );
+ // Synchronization of bands and credits
+ dutyCycle = UpdateTimeCredits( &bands[i], joined, dutyCycleEnabled,
+ lastTxIsJoinRequest, elapsedTimeSinceStartup,
+ currentTime );
- if( bands[i].TimeOff <= txDoneTime )
- {
- bands[i].TimeOff = 0;
- }
- if( bands[i].TimeOff != 0 )
- {
- nextTxDelay = MIN( bands[i].TimeOff - txDoneTime, nextTxDelay );
- }
+ // Calculate the credit costs for the next transmission
+ // with the duty cycle and the expected time on air
+ creditCosts = expectedTimeOnAir * dutyCycle;
+
+ // Check if the band is ready for transmission. Its ready,
+ // when the duty cycle is off, or the TimeCredits of the band
+ // is higher than the credit costs for the transmission.
+ if( ( bands[i].TimeCredits > creditCosts ) ||
+ ( dutyCycleEnabled == false ) )
+ {
+ bands[i].ReadyForTransmission = true;
+ // This band is a potential candidate for an
+ // upcoming transmission, so increase the counter.
+ validBands++;
}
else
{
- if( dutyCycle == true )
+ // In this case, the band has not enough credits
+ // for the next transmission.
+ bands[i].ReadyForTransmission = false;
+
+ if( bands[i].MaxTimeCredits > creditCosts )
{
- if( bands[i].TimeOff <= TimerGetElapsedTime( bands[i].LastTxDoneTime ) )
- {
- bands[i].TimeOff = 0;
- }
- if( bands[i].TimeOff != 0 )
- {
- nextTxDelay = MIN( bands[i].TimeOff - TimerGetElapsedTime( bands[i].LastTxDoneTime ),
- nextTxDelay );
- }
- }
- else
- {
- nextTxDelay = 0;
- bands[i].TimeOff = 0;
+ // The band can only be taken into account, if the maximum credits
+ // of the band are higher than the credit costs.
+ // We calculate the minTimeToWait among the bands which are not
+ // ready for transmission and which are potentially available
+ // for a transmission in the future.
+ minTimeToWait = MIN( minTimeToWait, ( creditCosts - bands[i].TimeCredits ) );
+ // This band is a potential candidate for an
+ // upcoming transmission (even if its time credits are not enough
+ // at the moment), so increase the counter.
+ validBands++;
}
}
}
- return nextTxDelay;
+
+
+ if( validBands == 0 )
+ {
+ // There is no valid band available to handle a transmission
+ // in the given DUTY_CYCLE_TIME_PERIOD.
+ return TIMERTIME_T_MAX;
+ }
+ return minTimeToWait;
}
uint8_t RegionCommonParseLinkAdrReq( uint8_t* payload, RegionCommonLinkAdrParams_t* linkAdrParams )
@@ -311,50 +435,6 @@ int8_t RegionCommonComputeTxPower( int8_t txPowerIndex, float maxEirp, float ant
return phyTxPower;
}
-void RegionCommonCalcBackOff( RegionCommonCalcBackOffParams_t* calcBackOffParams )
-{
- uint8_t bandIdx = calcBackOffParams->Channels[calcBackOffParams->Channel].Band;
- uint16_t dutyCycle = calcBackOffParams->Bands[bandIdx].DCycle;
- uint16_t joinDutyCycle = 0;
-
- // Reset time-off to initial value.
- calcBackOffParams->Bands[bandIdx].TimeOff = 0;
-
- if( calcBackOffParams->Joined == false )
- {
- // Get the join duty cycle
- joinDutyCycle = RegionCommonGetJoinDc( calcBackOffParams->ElapsedTime );
- // Apply the most restricting duty cycle
- dutyCycle = MAX( dutyCycle, joinDutyCycle );
- // Reset the timeoff if the last frame was not a join request and when the duty cycle is not enabled
- if( ( calcBackOffParams->DutyCycleEnabled == false ) && ( calcBackOffParams->LastTxIsJoinRequest == false ) )
- {
- // This is the case when the duty cycle is off and the last uplink frame was not a join.
- // This could happen in case of a rejoin, e.g. in compliance test mode.
- // In this special case we have to set the time off to 0, since the join duty cycle shall only
- // be applied after the first join request.
- calcBackOffParams->Bands[bandIdx].TimeOff = 0;
- }
- else
- {
- // Apply band time-off.
- calcBackOffParams->Bands[bandIdx].TimeOff = calcBackOffParams->TxTimeOnAir * dutyCycle - calcBackOffParams->TxTimeOnAir;
- }
- }
- else
- {
- if( calcBackOffParams->DutyCycleEnabled == true )
- {
- calcBackOffParams->Bands[bandIdx].TimeOff = calcBackOffParams->TxTimeOnAir * dutyCycle - calcBackOffParams->TxTimeOnAir;
- }
- else
- {
- calcBackOffParams->Bands[bandIdx].TimeOff = 0;
- }
- }
-}
-
-
void RegionCommonRxBeaconSetup( RegionCommonRxBeaconSetupParams_t* rxBeaconSetupParams )
{
bool rxContinuous = true;
@@ -382,3 +462,90 @@ void RegionCommonRxBeaconSetup( RegionCommonRxBeaconSetupParams_t* rxBeaconSetup
Radio.Rx( rxBeaconSetupParams->RxTime );
}
+
+void RegionCommonCountNbOfEnabledChannels( RegionCommonCountNbOfEnabledChannelsParams_t* countNbOfEnabledChannelsParams,
+ uint8_t* enabledChannels, uint8_t* nbEnabledChannels, uint8_t* nbRestrictedChannels )
+{
+ uint8_t nbChannelCount = 0;
+ uint8_t nbRestrictedChannelsCount = 0;
+
+ for( uint8_t i = 0, k = 0; i < countNbOfEnabledChannelsParams->MaxNbChannels; i += 16, k++ )
+ {
+ for( uint8_t j = 0; j < 16; j++ )
+ {
+ if( ( countNbOfEnabledChannelsParams->ChannelsMask[k] & ( 1 << j ) ) != 0 )
+ {
+ if( countNbOfEnabledChannelsParams->Channels[i + j].Frequency == 0 )
+ { // Check if the channel is enabled
+ continue;
+ }
+ if( ( countNbOfEnabledChannelsParams->Joined == false ) &&
+ ( countNbOfEnabledChannelsParams->JoinChannels > 0 ) )
+ {
+ if( ( countNbOfEnabledChannelsParams->JoinChannels & ( 1 << j ) ) == 0 )
+ {
+ continue;
+ }
+ }
+ if( RegionCommonValueInRange( countNbOfEnabledChannelsParams->Datarate,
+ countNbOfEnabledChannelsParams->Channels[i + j].DrRange.Fields.Min,
+ countNbOfEnabledChannelsParams->Channels[i + j].DrRange.Fields.Max ) == false )
+ { // Check if the current channel selection supports the given datarate
+ continue;
+ }
+ if( countNbOfEnabledChannelsParams->Bands[countNbOfEnabledChannelsParams->Channels[i + j].Band].ReadyForTransmission == false )
+ { // Check if the band is available for transmission
+ nbRestrictedChannelsCount++;
+ continue;
+ }
+ enabledChannels[nbChannelCount++] = i + j;
+ }
+ }
+ }
+ *nbEnabledChannels = nbChannelCount;
+ *nbRestrictedChannels = nbRestrictedChannelsCount;
+}
+
+LoRaMacStatus_t RegionCommonIdentifyChannels( RegionCommonIdentifyChannelsParam_t* identifyChannelsParam,
+ TimerTime_t* aggregatedTimeOff, uint8_t* enabledChannels,
+ uint8_t* nbEnabledChannels, uint8_t* nbRestrictedChannels,
+ TimerTime_t* nextTxDelay )
+{
+ TimerTime_t elapsed = TimerGetElapsedTime( identifyChannelsParam->LastAggrTx );
+ *nextTxDelay = identifyChannelsParam->AggrTimeOff - elapsed;
+ *nbRestrictedChannels = 1;
+ *nbEnabledChannels = 0;
+
+ if( ( identifyChannelsParam->LastAggrTx == 0 ) ||
+ ( identifyChannelsParam->AggrTimeOff <= elapsed ) )
+ {
+ // Reset Aggregated time off
+ *aggregatedTimeOff = 0;
+
+ // Update bands Time OFF
+ *nextTxDelay = RegionCommonUpdateBandTimeOff( identifyChannelsParam->CountNbOfEnabledChannelsParam->Joined,
+ identifyChannelsParam->CountNbOfEnabledChannelsParam->Bands,
+ identifyChannelsParam->MaxBands,
+ identifyChannelsParam->DutyCycleEnabled,
+ identifyChannelsParam->LastTxIsJoinRequest,
+ identifyChannelsParam->ElapsedTimeSinceStartUp,
+ identifyChannelsParam->ExpectedTimeOnAir );
+
+ RegionCommonCountNbOfEnabledChannels( identifyChannelsParam->CountNbOfEnabledChannelsParam, enabledChannels,
+ nbEnabledChannels, nbRestrictedChannels );
+ }
+
+ if( *nbEnabledChannels > 0 )
+ {
+ *nextTxDelay = 0;
+ return LORAMAC_STATUS_OK;
+ }
+ else if( *nbRestrictedChannels > 0 )
+ {
+ return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
+ }
+ else
+ {
+ return LORAMAC_STATUS_NO_CHANNEL_FOUND;
+ }
+}
diff --git a/components/connectivity/LoraWAN/mac/region/RegionCommon.h b/components/connectivity/LoraWAN/mac/region/RegionCommon.h
index 99fd436f..3f0134be 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionCommon.h
+++ b/components/connectivity/LoraWAN/mac/region/RegionCommon.h
@@ -37,9 +37,23 @@
#ifndef __REGIONCOMMON_H__
#define __REGIONCOMMON_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "LoRaMacTypes.h"
+#include "LoRaMacHeaderTypes.h"
#include "region/Region.h"
+/*!
+ * Default ping slots periodicity
+ *
+ * Periodicity is equal to 2^REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY seconds.
+ * Example: 2^7 = 128 seconds. The end-device will open an Rx slot every 128 seconds.
+ */
+#define REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY 7
+
typedef struct sRegionCommonLinkAdrParams
{
/*!
@@ -132,42 +146,6 @@ typedef struct sRegionCommonLinkAdrReqVerifyParams
int8_t MaxTxPower;
}RegionCommonLinkAdrReqVerifyParams_t;
-typedef struct sRegionCommonCalcBackOffParams
-{
- /*!
- * A pointer to region specific channels.
- */
- ChannelParams_t* Channels;
- /*!
- * A pointer to region specific bands.
- */
- Band_t* Bands;
- /*!
- * Set to true, if the last uplink was a join request.
- */
- bool LastTxIsJoinRequest;
- /*!
- * Set to true, if the node is joined.
- */
- bool Joined;
- /*!
- * Set to true, if the duty cycle is enabled.
- */
- bool DutyCycleEnabled;
- /*!
- * The current channel.
- */
- uint8_t Channel;
- /*!
- * The elapsed time since initialization.
- */
- SysTime_t ElapsedTime;
- /*!
- * The time on air of the last Tx frame.
- */
- TimerTime_t TxTimeOnAir;
-}RegionCommonCalcBackOffParams_t;
-
typedef struct sRegionCommonRxBeaconSetupParams
{
/*!
@@ -200,6 +178,90 @@ typedef struct sRegionCommonRxBeaconSetupParams
uint16_t SymbolTimeout;
}RegionCommonRxBeaconSetupParams_t;
+typedef struct sRegionCommonCountNbOfEnabledChannelsParams
+{
+ /*!
+ * Set to true, if the device is joined.
+ */
+ bool Joined;
+ /*!
+ * The datarate to count the available channels.
+ */
+ uint8_t Datarate;
+ /*!
+ * A pointer to the channels mask to verify.
+ */
+ uint16_t* ChannelsMask;
+ /*!
+ * A pointer to the channels.
+ */
+ ChannelParams_t* Channels;
+ /*!
+ * A pointer to the bands.
+ */
+ Band_t* Bands;
+ /*!
+ * The number of available channels.
+ */
+ uint16_t MaxNbChannels;
+ /*!
+ * A bitmask containing the join channels.
+ */
+ uint16_t JoinChannels;
+}RegionCommonCountNbOfEnabledChannelsParams_t;
+
+typedef struct sRegionCommonIdentifyChannelsParam
+{
+ /*!
+ * Aggregated time-off time.
+ */
+ TimerTime_t AggrTimeOff;
+ /*!
+ * Time of the last aggregated TX.
+ */
+ TimerTime_t LastAggrTx;
+ /*!
+ * Set to true, if the duty cycle is enabled, otherwise false.
+ */
+ bool DutyCycleEnabled;
+ /*!
+ * Maximum number of bands.
+ */
+ uint8_t MaxBands;
+ /*!
+ * Elapsed time since the start of the node.
+ */
+ SysTime_t ElapsedTimeSinceStartUp;
+ /*!
+ * Joined Set to true, if the last uplink was a join request
+ */
+ bool LastTxIsJoinRequest;
+ /*!
+ * Expected time-on-air
+ */
+ TimerTime_t ExpectedTimeOnAir;
+ /*!
+ * Pointer to a structure of RegionCommonCountNbOfEnabledChannelsParams_t.
+ */
+ RegionCommonCountNbOfEnabledChannelsParams_t* CountNbOfEnabledChannelsParam;
+}RegionCommonIdentifyChannelsParam_t;
+
+typedef struct sRegionCommonSetDutyCycleParams
+{
+ /*!
+ * Duty cycle period.
+ */
+ TimerTime_t DutyCycleTimePeriod;
+ /*!
+ * Number of bands available.
+ */
+ uint8_t MaxBands;
+ /*!
+ * A pointer to the bands.
+ */
+ Band_t* Bands;
+}RegionCommonSetDutyCycleParams_t;
+
/*!
* \brief Calculates the join duty cycle.
* This is a generic function and valid for all regions.
@@ -289,13 +351,15 @@ void RegionCommonChanMaskCopy( uint16_t* channelsMaskDest, uint16_t* channelsMas
* \brief Sets the last tx done property.
* This is a generic function and valid for all regions.
*
- * \param [IN] joined Set to true, if the node has joined the network
- *
* \param [IN] band The band to be updated.
*
- * \param [IN] lastTxDone The time of the last TX done.
+ * \param [IN] lastTxAirTime The time on air of the last TX frame.
+ *
+ * \param [IN] joined Set to true if the device has joined.
+ *
+ * \param [IN] elapsedTimeSinceStartup Elapsed time since initialization.
*/
-void RegionCommonSetBandTxDone( bool joined, Band_t* band, TimerTime_t lastTxDone );
+void RegionCommonSetBandTxDone( Band_t* band, TimerTime_t lastTxAirTime, bool joined, SysTime_t elapsedTimeSinceStartup );
/*!
* \brief Updates the time-offs of the bands.
@@ -303,15 +367,24 @@ void RegionCommonSetBandTxDone( bool joined, Band_t* band, TimerTime_t lastTxDon
*
* \param [IN] joined Set to true, if the node has joined the network
*
- * \param [IN] dutyCycle Set to true, if the duty cycle is enabled.
- *
* \param [IN] bands A pointer to the bands.
*
* \param [IN] nbBands The number of bands available.
*
+ * \param [IN] dutyCycleEnabled Set to true, if the duty cycle is enabled.
+ *
+ * \param [IN] lastTxIsJoinRequest Set to true, if the last TX is a join request.
+ *
+ * \param [IN] elapsedTimeSinceStartup Elapsed time since start up.
+ *
+ * \param [IN] expectedTimeOnAir Expected time on air for the next transmission.
+ *
* \retval Returns the time which must be waited to perform the next uplink.
*/
-TimerTime_t RegionCommonUpdateBandTimeOff( bool joined, bool dutyCycle, Band_t* bands, uint8_t nbBands );
+TimerTime_t RegionCommonUpdateBandTimeOff( bool joined, Band_t* bands,
+ uint8_t nbBands, bool dutyCycleEnabled,
+ bool lastTxIsJoinRequest, SysTime_t elapsedTimeSinceStartup,
+ TimerTime_t expectedTimeOnAir );
/*!
* \brief Parses the parameter of an LinkAdrRequest.
@@ -385,7 +458,7 @@ void RegionCommonComputeRxWindowParameters( double tSymbol, uint8_t minRxSymbols
/*!
* \brief Computes the txPower, based on the max EIRP and the antenna gain.
- *
+ *
* \remark US915 region uses a conducted power as input value for maxEirp.
* Thus, the antennaGain parameter must be set to 0.
*
@@ -400,13 +473,6 @@ void RegionCommonComputeRxWindowParameters( double tSymbol, uint8_t minRxSymbols
*/
int8_t RegionCommonComputeTxPower( int8_t txPowerIndex, float maxEirp, float antennaGain );
-/*!
- * \brief Calculates the duty cycle for the current band.
- *
- * \param [IN] calcBackOffParams A pointer to the input parameters.
- */
-void RegionCommonCalcBackOff( RegionCommonCalcBackOffParams_t* calcBackOffParams );
-
/*!
* \brief Sets up the radio into RX beacon mode.
*
@@ -414,6 +480,52 @@ void RegionCommonCalcBackOff( RegionCommonCalcBackOffParams_t* calcBackOffParams
*/
void RegionCommonRxBeaconSetup( RegionCommonRxBeaconSetupParams_t* rxBeaconSetupParams );
+/*!
+ * \brief Counts the number of enabled channels.
+ *
+ * \param [IN] countNbOfEnabledChannelsParams A pointer to the input parameters.
+ *
+ * \param [OUT] enabledChannels A pointer to an array of size XX_MAX_NB_CHANNELS. The function
+ * stores the available channels into this array.
+ *
+ * \param [OUT] nbEnabledChannels The number of available channels found.
+ *
+ * \param [OUT] nbRestrictedChannels It contains the number of channel
+ * which are available, but restricted due to duty cycle.
+ */
+void RegionCommonCountNbOfEnabledChannels( RegionCommonCountNbOfEnabledChannelsParams_t* countNbOfEnabledChannelsParams,
+ uint8_t* enabledChannels, uint8_t* nbEnabledChannels, uint8_t* nbRestrictedChannels );
+
+/*!
+ * \brief Identifies all channels which are available currently.
+ *
+ * \param [IN] identifyChannelsParam A pointer to the input parameters.
+ *
+ * \param [OUT] aggregatedTimeOff The new value of the aggregatedTimeOff. The function
+ * may resets it to 0.
+ *
+ * \param [OUT] enabledChannels A pointer to an array of size XX_MAX_NB_CHANNELS. The function
+ * stores the available channels into this array.
+ *
+ * \param [OUT] nbEnabledChannels The number of available channels found.
+ *
+ * \param [OUT] nbRestrictedChannels It contains the number of channel
+ * which are available, but restricted due to duty cycle.
+ *
+ * \param [OUT] nextTxDelay Holds the time which has to be waited for the next possible
+ * uplink transmission.
+ *
+ *\retval Status of the operation.
+ */
+LoRaMacStatus_t RegionCommonIdentifyChannels( RegionCommonIdentifyChannelsParam_t* identifyChannelsParam,
+ TimerTime_t* aggregatedTimeOff, uint8_t* enabledChannels,
+ uint8_t* nbEnabledChannels, uint8_t* nbRestrictedChannels,
+ TimerTime_t* nextTxDelay );
+
/*! \} defgroup REGIONCOMMON */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __REGIONCOMMON_H__
diff --git a/components/connectivity/LoraWAN/mac/region/RegionEU433.c b/components/connectivity/LoraWAN/mac/region/RegionEU433.c
index 8f0c7e4d..22212d33 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionEU433.c
+++ b/components/connectivity/LoraWAN/mac/region/RegionEU433.c
@@ -119,45 +119,21 @@ static bool VerifyRfFreq( uint32_t freq )
return true;
}
-static uint8_t CountNbOfEnabledChannels( bool joined, uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
{
- uint8_t nbEnabledChannels = 0;
- uint8_t delayTransmission = 0;
+ int8_t phyDr = DataratesEU433[datarate];
+ uint32_t bandwidth = GetBandwidth( datarate );
+ TimerTime_t timeOnAir = 0;
- for( uint8_t i = 0, k = 0; i < EU433_MAX_NB_CHANNELS; i += 16, k++ )
- {
- for( uint8_t j = 0; j < 16; j++ )
- {
- if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
- {
- if( channels[i + j].Frequency == 0 )
- { // Check if the channel is enabled
- continue;
- }
- if( joined == false )
- {
- if( ( EU433_JOIN_CHANNELS & ( 1 << j ) ) == 0 )
- {
- continue;
- }
- }
- if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
- channels[i + j].DrRange.Fields.Max ) == false )
- { // Check if the current channel selection supports the given datarate
- continue;
- }
- if( bands[channels[i + j].Band].TimeOff > 0 )
- { // Check if the band is available for transmission
- delayTransmission++;
- continue;
- }
- enabledChannels[nbEnabledChannels++] = i + j;
- }
- }
+ if( datarate == DR_7 )
+ { // High Speed FSK channel
+ timeOnAir = Radio.TimeOnAir( MODEM_FSK, bandwidth, phyDr * 1000, 0, 5, false, pktLen, true );
}
-
- *delayTx = delayTransmission;
- return nbEnabledChannels;
+ else
+ {
+ timeOnAir = Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
+ }
+ return timeOnAir;
}
PhyParam_t RegionEU433GetPhyParam( GetPhyParams_t* getPhy )
@@ -211,11 +187,6 @@ PhyParam_t RegionEU433GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = MaxPayloadOfDatarateEU433[getPhy->Datarate];
break;
}
- case PHY_MAX_PAYLOAD_REPEATER:
- {
- phyParam.Value = MaxPayloadOfDatarateRepeaterEU433[getPhy->Datarate];
- break;
- }
case PHY_DUTY_CYCLE:
{
phyParam.Value = EU433_DUTY_CYCLE_ENABLED;
@@ -324,11 +295,26 @@ PhyParam_t RegionEU433GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = EU433_BEACON_CHANNEL_DR;
break;
}
+ case PHY_PING_SLOT_CHANNEL_FREQ:
+ {
+ phyParam.Value = EU433_PING_SLOT_CHANNEL_FREQ;
+ break;
+ }
case PHY_PING_SLOT_CHANNEL_DR:
{
phyParam.Value = EU433_PING_SLOT_CHANNEL_DR;
break;
}
+ case PHY_SF_FROM_DR:
+ {
+ phyParam.Value = DataratesEU433[getPhy->Datarate];
+ break;
+ }
+ case PHY_BW_FROM_DR:
+ {
+ phyParam.Value = GetBandwidth( getPhy->Datarate );
+ break;
+ }
default:
{
break;
@@ -340,7 +326,8 @@ PhyParam_t RegionEU433GetPhyParam( GetPhyParams_t* getPhy )
void RegionEU433SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
- RegionCommonSetBandTxDone( txDone->Joined, &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+ RegionCommonSetBandTxDone( &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band],
+ txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
}
void RegionEU433InitDefaults( InitDefaultsParams_t* params )
@@ -352,10 +339,14 @@ void RegionEU433InitDefaults( InitDefaultsParams_t* params )
switch( params->Type )
{
- case INIT_TYPE_INIT:
+ case INIT_TYPE_BANDS:
{
// Initialize bands
memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * EU433_MAX_NB_BANDS );
+ break;
+ }
+ case INIT_TYPE_INIT:
+ {
// Channels
NvmCtx.Channels[0] = ( ChannelParams_t ) EU433_LC1;
@@ -364,6 +355,7 @@ void RegionEU433InitDefaults( InitDefaultsParams_t* params )
// Initialize the channels default mask
NvmCtx.ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
+
// Update the channels mask
RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 1 );
break;
@@ -380,6 +372,11 @@ void RegionEU433InitDefaults( InitDefaultsParams_t* params )
{
// Restore channels default mask
NvmCtx.ChannelsMask[0] |= NvmCtx.ChannelsDefaultMask[0];
+
+ // Channels
+ NvmCtx.Channels[0] = ( ChannelParams_t ) EU433_LC1;
+ NvmCtx.Channels[1] = ( ChannelParams_t ) EU433_LC2;
+ NvmCtx.Channels[2] = ( ChannelParams_t ) EU433_LC3;
break;
}
default:
@@ -399,6 +396,10 @@ bool RegionEU433Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
+ case PHY_FREQUENCY:
+ {
+ return VerifyRfFreq( verify->Frequency );
+ }
case PHY_TX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, EU433_TX_MIN_DATARATE, EU433_TX_MAX_DATARATE );
@@ -529,7 +530,6 @@ bool RegionEU433RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
RadioModems_t modem;
int8_t dr = rxConfig->Datarate;
- uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
@@ -566,15 +566,7 @@ bool RegionEU433RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
Radio.SetRxConfig( modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
}
- if( rxConfig->RepeaterSupport == true )
- {
- maxPayload = MaxPayloadOfDatarateRepeaterEU433[dr];
- }
- else
- {
- maxPayload = MaxPayloadOfDatarateEU433[dr];
- }
- Radio.SetMaxPayloadLength( modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+ Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateEU433[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
*datarate = (uint8_t) dr;
return true;
@@ -597,18 +589,19 @@ bool RegionEU433TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime
if( txConfig->Datarate == DR_7 )
{ // High Speed FSK channel
modem = MODEM_FSK;
- Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 4000 );
}
else
{
modem = MODEM_LORA;
- Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
}
+ // Update time-on-air
+ *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
+
// Setup maximum payload lenght of the radio driver
Radio.SetMaxPayloadLength( modem, txConfig->PktLen );
- // Get the time-on-air of the next tx frame
- *txTimeOnAir = Radio.TimeOnAir( modem, txConfig->PktLen );
*txPower = txPowerLimited;
return true;
@@ -832,74 +825,54 @@ int8_t RegionEU433AlternateDr( int8_t currentDr, AlternateDrType_t type )
return currentDr;
}
-void RegionEU433CalcBackOff( CalcBackOffParams_t* calcBackOff )
-{
- RegionCommonCalcBackOffParams_t calcBackOffParams;
-
- calcBackOffParams.Channels = NvmCtx.Channels;
- calcBackOffParams.Bands = NvmCtx.Bands;
- calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
- calcBackOffParams.Joined = calcBackOff->Joined;
- calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
- calcBackOffParams.Channel = calcBackOff->Channel;
- calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
- calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
-
- RegionCommonCalcBackOff( &calcBackOffParams );
-}
-
LoRaMacStatus_t RegionEU433NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
- uint8_t delayTx = 0;
+ uint8_t nbRestrictedChannels = 0;
uint8_t enabledChannels[EU433_MAX_NB_CHANNELS] = { 0 };
- TimerTime_t nextTxDelay = 0;
+ RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
+ RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
+ LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
if( RegionCommonCountChannels( NvmCtx.ChannelsMask, 0, 1 ) == 0 )
{ // Reactivate default channels
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
}
- if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
- {
- // Reset Aggregated time off
- *aggregatedTimeOff = 0;
+ // Search how many channels are enabled
+ countChannelsParams.Joined = nextChanParams->Joined;
+ countChannelsParams.Datarate = nextChanParams->Datarate;
+ countChannelsParams.ChannelsMask = NvmCtx.ChannelsMask;
+ countChannelsParams.Channels = NvmCtx.Channels;
+ countChannelsParams.Bands = NvmCtx.Bands;
+ countChannelsParams.MaxNbChannels = EU433_MAX_NB_CHANNELS;
+ countChannelsParams.JoinChannels = EU433_JOIN_CHANNELS;
- // Update bands Time OFF
- nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, NvmCtx.Bands, EU433_MAX_NB_BANDS );
+ identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
+ identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
+ identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
+ identifyChannelsParam.MaxBands = EU433_MAX_NB_BANDS;
- // Search how many channels are enabled
- nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Joined, nextChanParams->Datarate,
- NvmCtx.ChannelsMask, NvmCtx.Channels,
- NvmCtx.Bands, enabledChannels, &delayTx );
- }
- else
- {
- delayTx++;
- nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
- }
+ identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
+ identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
+ identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
- if( nbEnabledChannels > 0 )
+ identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
+
+ status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
+ &nbEnabledChannels, &nbRestrictedChannels, time );
+
+ if( status == LORAMAC_STATUS_OK )
{
// We found a valid channel
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
-
- *time = 0;
- return LORAMAC_STATUS_OK;
}
- else
+ else if( status == LORAMAC_STATUS_NO_CHANNEL_FOUND )
{
- if( delayTx > 0 )
- {
- // Delay transmission due to AggregatedTimeOff or to a band time off
- *time = nextTxDelay;
- return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
- }
// Datarate not supported by any channel, restore defaults
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
- *time = 0;
- return LORAMAC_STATUS_NO_CHANNEL_FOUND;
}
+ return status;
}
LoRaMacStatus_t RegionEU433ChannelAdd( ChannelAddParams_t* channelAdd )
diff --git a/components/connectivity/LoraWAN/mac/region/RegionEU433.h b/components/connectivity/LoraWAN/mac/region/RegionEU433.h
index 6f8b38d3..a1c9836d 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionEU433.h
+++ b/components/connectivity/LoraWAN/mac/region/RegionEU433.h
@@ -37,6 +37,11 @@
#ifndef __REGION_EU433_H__
#define __REGION_EU433_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "region/Region.h"
/*!
@@ -204,6 +209,11 @@
*/
#define EU433_BEACON_CHANNEL_FREQ 434665000
+/*!
+ * Ping slot channel frequency
+ */
+#define EU433_PING_SLOT_CHANNEL_FREQ 434665000
+
/*!
* Payload size of a beacon frame
*/
@@ -236,9 +246,9 @@
/*!
* Band 0 definition
- * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define EU433_BAND0 { 100, EU433_MAX_TX_POWER, 0, 0, 0 } // 1.0 %
+#define EU433_BAND0 { 100, EU433_MAX_TX_POWER, 0, 0, 0, 0 } // 1.0 %
/*!
* LoRaMac default channel 1
@@ -274,15 +284,10 @@ static const uint8_t DataratesEU433[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
static const uint32_t BandwidthsEU433[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ * Maximum payload with respect to the datarate index.
*/
static const uint8_t MaxPayloadOfDatarateEU433[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-static const uint8_t MaxPayloadOfDatarateRepeaterEU433[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
-
/*!
* \brief The function gets a value of a specific phy attribute.
*
@@ -438,13 +443,6 @@ uint8_t RegionEU433DlChannelReq( DlChannelReqParams_t* dlChannelReq );
*/
int8_t RegionEU433AlternateDr( int8_t currentDr, AlternateDrType_t type );
-/*!
- * \brief Calculates the back-off time.
- *
- * \param [IN] calcBackOff Pointer to the function parameters.
- */
-void RegionEU433CalcBackOff( CalcBackOffParams_t* calcBackOff );
-
/*!
* \brief Searches and set the next random available channel
*
@@ -502,8 +500,12 @@ uint8_t RegionEU433ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t d
*
* \param [IN] rxBeaconSetup Pointer to the function parameters
*/
- void RegionEU433RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr );
+void RegionEU433RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr );
/*! \} defgroup REGIONEU433 */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __REGION_EU433_H__
diff --git a/components/connectivity/LoraWAN/mac/region/RegionEU868.c b/components/connectivity/LoraWAN/mac/region/RegionEU868.c
index 236e0b8a..ab4ed35a 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionEU868.c
+++ b/components/connectivity/LoraWAN/mac/region/RegionEU868.c
@@ -127,7 +127,7 @@ static bool VerifyRfFreq( uint32_t freq, uint8_t *band )
}
else if( ( freq >= 868700000 ) && ( freq <= 869200000 ) )
{
- *band = 2;
+ *band = 5;
}
else if( ( freq >= 869400000 ) && ( freq <= 869650000 ) )
{
@@ -144,45 +144,21 @@ static bool VerifyRfFreq( uint32_t freq, uint8_t *band )
return true;
}
-static uint8_t CountNbOfEnabledChannels( bool joined, uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
{
- uint8_t nbEnabledChannels = 0;
- uint8_t delayTransmission = 0;
+ int8_t phyDr = DataratesEU868[datarate];
+ uint32_t bandwidth = GetBandwidth( datarate );
+ TimerTime_t timeOnAir = 0;
- for( uint8_t i = 0, k = 0; i < EU868_MAX_NB_CHANNELS; i += 16, k++ )
- {
- for( uint8_t j = 0; j < 16; j++ )
- {
- if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
- {
- if( channels[i + j].Frequency == 0 )
- { // Check if the channel is enabled
- continue;
- }
- if( joined == false )
- {
- if( ( EU868_JOIN_CHANNELS & ( 1 << j ) ) == 0 )
- {
- continue;
- }
- }
- if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
- channels[i + j].DrRange.Fields.Max ) == false )
- { // Check if the current channel selection supports the given datarate
- continue;
- }
- if( bands[channels[i + j].Band].TimeOff > 0 )
- { // Check if the band is available for transmission
- delayTransmission++;
- continue;
- }
- enabledChannels[nbEnabledChannels++] = i + j;
- }
- }
+ if( datarate == DR_7 )
+ { // High Speed FSK channel
+ timeOnAir = Radio.TimeOnAir( MODEM_FSK, bandwidth, phyDr * 1000, 0, 5, false, pktLen, true );
}
-
- *delayTx = delayTransmission;
- return nbEnabledChannels;
+ else
+ {
+ timeOnAir = Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
+ }
+ return timeOnAir;
}
PhyParam_t RegionEU868GetPhyParam( GetPhyParams_t* getPhy )
@@ -236,11 +212,6 @@ PhyParam_t RegionEU868GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = MaxPayloadOfDatarateEU868[getPhy->Datarate];
break;
}
- case PHY_MAX_PAYLOAD_REPEATER:
- {
- phyParam.Value = MaxPayloadOfDatarateRepeaterEU868[getPhy->Datarate];
- break;
- }
case PHY_DUTY_CYCLE:
{
phyParam.Value = EU868_DUTY_CYCLE_ENABLED;
@@ -349,11 +320,26 @@ PhyParam_t RegionEU868GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = EU868_BEACON_CHANNEL_DR;
break;
}
+ case PHY_PING_SLOT_CHANNEL_FREQ:
+ {
+ phyParam.Value = EU868_PING_SLOT_CHANNEL_FREQ;
+ break;
+ }
case PHY_PING_SLOT_CHANNEL_DR:
{
phyParam.Value = EU868_PING_SLOT_CHANNEL_DR;
break;
}
+ case PHY_SF_FROM_DR:
+ {
+ phyParam.Value = DataratesEU868[getPhy->Datarate];
+ break;
+ }
+ case PHY_BW_FROM_DR:
+ {
+ phyParam.Value = GetBandwidth( getPhy->Datarate );
+ break;
+ }
default:
{
break;
@@ -365,7 +351,8 @@ PhyParam_t RegionEU868GetPhyParam( GetPhyParams_t* getPhy )
void RegionEU868SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
- RegionCommonSetBandTxDone( txDone->Joined, &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+ RegionCommonSetBandTxDone( &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band],
+ txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
}
void RegionEU868InitDefaults( InitDefaultsParams_t* params )
@@ -377,14 +364,19 @@ void RegionEU868InitDefaults( InitDefaultsParams_t* params )
EU868_BAND2,
EU868_BAND3,
EU868_BAND4,
+ EU868_BAND5,
};
switch( params->Type )
{
- case INIT_TYPE_INIT:
+ case INIT_TYPE_BANDS:
{
// Initialize bands
memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * EU868_MAX_NB_BANDS );
+ break;
+ }
+ case INIT_TYPE_INIT:
+ {
// Channels
NvmCtx.Channels[0] = ( ChannelParams_t ) EU868_LC1;
@@ -393,6 +385,7 @@ void RegionEU868InitDefaults( InitDefaultsParams_t* params )
// Initialize the channels default mask
NvmCtx.ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
+
// Update the channels mask
RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 1 );
break;
@@ -409,6 +402,11 @@ void RegionEU868InitDefaults( InitDefaultsParams_t* params )
{
// Restore channels default mask
NvmCtx.ChannelsMask[0] |= NvmCtx.ChannelsDefaultMask[0];
+
+ // Channels
+ NvmCtx.Channels[0] = ( ChannelParams_t ) EU868_LC1;
+ NvmCtx.Channels[1] = ( ChannelParams_t ) EU868_LC2;
+ NvmCtx.Channels[2] = ( ChannelParams_t ) EU868_LC3;
break;
}
default:
@@ -428,6 +426,11 @@ bool RegionEU868Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
+ case PHY_FREQUENCY:
+ {
+ uint8_t band = 0;
+ return VerifyRfFreq( verify->Frequency, &band );
+ }
case PHY_TX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, EU868_TX_MIN_DATARATE, EU868_TX_MAX_DATARATE );
@@ -558,7 +561,6 @@ bool RegionEU868RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
RadioModems_t modem;
int8_t dr = rxConfig->Datarate;
- uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
@@ -595,16 +597,7 @@ bool RegionEU868RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
Radio.SetRxConfig( modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
}
- if( rxConfig->RepeaterSupport == true )
- {
- maxPayload = MaxPayloadOfDatarateRepeaterEU868[dr];
- }
- else
- {
- maxPayload = MaxPayloadOfDatarateEU868[dr];
- }
-
- Radio.SetMaxPayloadLength( modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+ Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateEU868[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
*datarate = (uint8_t) dr;
return true;
@@ -627,18 +620,19 @@ bool RegionEU868TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime
if( txConfig->Datarate == DR_7 )
{ // High Speed FSK channel
modem = MODEM_FSK;
- Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 4000 );
}
else
{
modem = MODEM_LORA;
- Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
}
+ // Update time-on-air
+ *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
+
// Setup maximum payload lenght of the radio driver
Radio.SetMaxPayloadLength( modem, txConfig->PktLen );
- // Get the time-on-air of the next tx frame
- *txTimeOnAir = Radio.TimeOnAir( modem, txConfig->PktLen );
*txPower = txPowerLimited;
return true;
@@ -864,74 +858,54 @@ int8_t RegionEU868AlternateDr( int8_t currentDr, AlternateDrType_t type )
return currentDr;
}
-void RegionEU868CalcBackOff( CalcBackOffParams_t* calcBackOff )
-{
- RegionCommonCalcBackOffParams_t calcBackOffParams;
-
- calcBackOffParams.Channels = NvmCtx.Channels;
- calcBackOffParams.Bands = NvmCtx.Bands;
- calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
- calcBackOffParams.Joined = calcBackOff->Joined;
- calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
- calcBackOffParams.Channel = calcBackOff->Channel;
- calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
- calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
-
- RegionCommonCalcBackOff( &calcBackOffParams );
-}
-
LoRaMacStatus_t RegionEU868NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
- uint8_t delayTx = 0;
+ uint8_t nbRestrictedChannels = 0;
uint8_t enabledChannels[EU868_MAX_NB_CHANNELS] = { 0 };
- TimerTime_t nextTxDelay = 0;
+ RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
+ RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
+ LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
if( RegionCommonCountChannels( NvmCtx.ChannelsMask, 0, 1 ) == 0 )
{ // Reactivate default channels
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
}
- if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
- {
- // Reset Aggregated time off
- *aggregatedTimeOff = 0;
+ // Search how many channels are enabled
+ countChannelsParams.Joined = nextChanParams->Joined;
+ countChannelsParams.Datarate = nextChanParams->Datarate;
+ countChannelsParams.ChannelsMask = NvmCtx.ChannelsMask;
+ countChannelsParams.Channels = NvmCtx.Channels;
+ countChannelsParams.Bands = NvmCtx.Bands;
+ countChannelsParams.MaxNbChannels = EU868_MAX_NB_CHANNELS;
+ countChannelsParams.JoinChannels = EU868_JOIN_CHANNELS;
- // Update bands Time OFF
- nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, NvmCtx.Bands, EU868_MAX_NB_BANDS );
+ identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
+ identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
+ identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
+ identifyChannelsParam.MaxBands = EU868_MAX_NB_BANDS;
- // Search how many channels are enabled
- nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Joined, nextChanParams->Datarate,
- NvmCtx.ChannelsMask, NvmCtx.Channels,
- NvmCtx.Bands, enabledChannels, &delayTx );
- }
- else
- {
- delayTx++;
- nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
- }
+ identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
+ identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
+ identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
- if( nbEnabledChannels > 0 )
+ identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
+
+ status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
+ &nbEnabledChannels, &nbRestrictedChannels, time );
+
+ if( status == LORAMAC_STATUS_OK )
{
// We found a valid channel
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
-
- *time = 0;
- return LORAMAC_STATUS_OK;
}
- else
+ else if( status == LORAMAC_STATUS_NO_CHANNEL_FOUND )
{
- if( delayTx > 0 )
- {
- // Delay transmission due to AggregatedTimeOff or to a band time off
- *time = nextTxDelay;
- return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
- }
// Datarate not supported by any channel, restore defaults
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
- *time = 0;
- return LORAMAC_STATUS_NO_CHANNEL_FOUND;
}
+ return status;
}
LoRaMacStatus_t RegionEU868ChannelAdd( ChannelAddParams_t* channelAdd )
diff --git a/components/connectivity/LoraWAN/mac/region/RegionEU868.h b/components/connectivity/LoraWAN/mac/region/RegionEU868.h
index a83fa3c8..a4438e71 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionEU868.h
+++ b/components/connectivity/LoraWAN/mac/region/RegionEU868.h
@@ -37,6 +37,11 @@
#ifndef __REGION_EU868_H__
#define __REGION_EU868_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "region/Region.h"
/*!
@@ -196,6 +201,11 @@
*/
#define EU868_BEACON_CHANNEL_FREQ 869525000
+/*!
+ * Ping slot channel frequency
+ */
+#define EU868_PING_SLOT_CHANNEL_FREQ 869525000
+
/*!
* Payload size of a beacon frame
*/
@@ -229,37 +239,44 @@
/*!
* Maximum number of bands
*/
-#define EU868_MAX_NB_BANDS 5
+#define EU868_MAX_NB_BANDS 6
/*!
* Band 0 definition
- * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define EU868_BAND0 { 100 , EU868_MAX_TX_POWER, 0, 0, 0 } // 1.0 %
+#define EU868_BAND0 { 100 , EU868_MAX_TX_POWER, 0, 0, 0, 0 } // 1.0 %
/*!
* Band 1 definition
- * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define EU868_BAND1 { 100 , EU868_MAX_TX_POWER, 0, 0, 0 } // 1.0 %
+#define EU868_BAND1 { 100 , EU868_MAX_TX_POWER, 0, 0, 0, 0 } // 1.0 %
/*!
* Band 2 definition
- * Band = { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define EU868_BAND2 { 1000, EU868_MAX_TX_POWER, 0, 0, 0 } // 0.1 %
+#define EU868_BAND2 { 1000, EU868_MAX_TX_POWER, 0, 0, 0, 0 } // 0.1 %
/*!
* Band 3 definition
- * Band = { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define EU868_BAND3 { 10 , EU868_MAX_TX_POWER, 0, 0, 0 } // 10.0 %
+#define EU868_BAND3 { 10 , EU868_MAX_TX_POWER, 0, 0, 0, 0 } // 10.0 %
/*!
* Band 4 definition
- * Band = { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define EU868_BAND4 { 100 , EU868_MAX_TX_POWER, 0, 0, 0 } // 1.0 %
+#define EU868_BAND4 { 100 , EU868_MAX_TX_POWER, 0, 0, 0, 0 } // 1.0 %
+
+/*!
+ * Band 5 definition
+ * Band = { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff,
+ * DutyCycleTimePeriod, MaxAllowedTimeOnAir, AggregatedTimeOnAir, StartTimeOfPeriod }
+ */
+#define EU868_BAND5 { 1000, EU868_MAX_TX_POWER, 0, 0, 0, 0 } // 0.1 %
/*!
* LoRaMac default channel 1
@@ -295,15 +312,10 @@ static const uint8_t DataratesEU868[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
static const uint32_t BandwidthsEU868[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ * Maximum payload with respect to the datarate index.
*/
static const uint8_t MaxPayloadOfDatarateEU868[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-static const uint8_t MaxPayloadOfDatarateRepeaterEU868[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
-
/*!
* \brief The function gets a value of a specific phy attribute.
*
@@ -459,13 +471,6 @@ uint8_t RegionEU868DlChannelReq( DlChannelReqParams_t* dlChannelReq );
*/
int8_t RegionEU868AlternateDr( int8_t currentDr, AlternateDrType_t type );
-/*!
- * \brief Calculates the back-off time.
- *
- * \param [IN] calcBackOff Pointer to the function parameters.
- */
-void RegionEU868CalcBackOff( CalcBackOffParams_t* calcBackOff );
-
/*!
* \brief Searches and set the next random available channel
*
@@ -527,4 +532,8 @@ void RegionEU868RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr );
/*! \} defgroup REGIONEU868 */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __REGION_EU868_H__
diff --git a/components/connectivity/LoraWAN/mac/region/RegionIN865.c b/components/connectivity/LoraWAN/mac/region/RegionIN865.c
index 3d1e72dc..a9c2a0a7 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionIN865.c
+++ b/components/connectivity/LoraWAN/mac/region/RegionIN865.c
@@ -123,45 +123,21 @@ static bool VerifyRfFreq( uint32_t freq )
return true;
}
-static uint8_t CountNbOfEnabledChannels( bool joined, uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
{
- uint8_t nbEnabledChannels = 0;
- uint8_t delayTransmission = 0;
+ int8_t phyDr = DataratesIN865[datarate];
+ uint32_t bandwidth = GetBandwidth( datarate );
+ TimerTime_t timeOnAir = 0;
- for( uint8_t i = 0, k = 0; i < IN865_MAX_NB_CHANNELS; i += 16, k++ )
- {
- for( uint8_t j = 0; j < 16; j++ )
- {
- if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
- {
- if( channels[i + j].Frequency == 0 )
- { // Check if the channel is enabled
- continue;
- }
- if( joined == false )
- {
- if( ( IN865_JOIN_CHANNELS & ( 1 << j ) ) == 0 )
- {
- continue;
- }
- }
- if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
- channels[i + j].DrRange.Fields.Max ) == false )
- { // Check if the current channel selection supports the given datarate
- continue;
- }
- if( bands[channels[i + j].Band].TimeOff > 0 )
- { // Check if the band is available for transmission
- delayTransmission++;
- continue;
- }
- enabledChannels[nbEnabledChannels++] = i + j;
- }
- }
+ if( datarate == DR_7 )
+ { // High Speed FSK channel
+ timeOnAir = Radio.TimeOnAir( MODEM_FSK, bandwidth, phyDr * 1000, 0, 5, false, pktLen, true );
}
-
- *delayTx = delayTransmission;
- return nbEnabledChannels;
+ else
+ {
+ timeOnAir = Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
+ }
+ return timeOnAir;
}
PhyParam_t RegionIN865GetPhyParam( GetPhyParams_t* getPhy )
@@ -215,11 +191,6 @@ PhyParam_t RegionIN865GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = MaxPayloadOfDatarateIN865[getPhy->Datarate];
break;
}
- case PHY_MAX_PAYLOAD_REPEATER:
- {
- phyParam.Value = MaxPayloadOfDatarateRepeaterIN865[getPhy->Datarate];
- break;
- }
case PHY_DUTY_CYCLE:
{
phyParam.Value = IN865_DUTY_CYCLE_ENABLED;
@@ -328,11 +299,26 @@ PhyParam_t RegionIN865GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = IN865_BEACON_CHANNEL_DR;
break;
}
+ case PHY_PING_SLOT_CHANNEL_FREQ:
+ {
+ phyParam.Value = IN865_PING_SLOT_CHANNEL_FREQ;
+ break;
+ }
case PHY_PING_SLOT_CHANNEL_DR:
{
phyParam.Value = IN865_PING_SLOT_CHANNEL_DR;
break;
}
+ case PHY_SF_FROM_DR:
+ {
+ phyParam.Value = DataratesIN865[getPhy->Datarate];
+ break;
+ }
+ case PHY_BW_FROM_DR:
+ {
+ phyParam.Value = GetBandwidth( getPhy->Datarate );
+ break;
+ }
default:
{
break;
@@ -344,7 +330,8 @@ PhyParam_t RegionIN865GetPhyParam( GetPhyParams_t* getPhy )
void RegionIN865SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
- RegionCommonSetBandTxDone( txDone->Joined, &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+ RegionCommonSetBandTxDone( &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band],
+ txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
}
void RegionIN865InitDefaults( InitDefaultsParams_t* params )
@@ -356,10 +343,14 @@ void RegionIN865InitDefaults( InitDefaultsParams_t* params )
switch( params->Type )
{
- case INIT_TYPE_INIT:
+ case INIT_TYPE_BANDS:
{
// Initialize bands
memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * IN865_MAX_NB_BANDS );
+ break;
+ }
+ case INIT_TYPE_INIT:
+ {
// Channels
NvmCtx.Channels[0] = ( ChannelParams_t ) IN865_LC1;
@@ -384,6 +375,11 @@ void RegionIN865InitDefaults( InitDefaultsParams_t* params )
{
// Restore channels default mask
NvmCtx.ChannelsMask[0] |= NvmCtx.ChannelsDefaultMask[0];
+
+ // Channels
+ NvmCtx.Channels[0] = ( ChannelParams_t ) IN865_LC1;
+ NvmCtx.Channels[1] = ( ChannelParams_t ) IN865_LC2;
+ NvmCtx.Channels[2] = ( ChannelParams_t ) IN865_LC3;
break;
}
default:
@@ -403,6 +399,10 @@ bool RegionIN865Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
+ case PHY_FREQUENCY:
+ {
+ return VerifyRfFreq( verify->Frequency );
+ }
case PHY_TX_DR:
{
if( verify->DatarateParams.Datarate == DR_6 )
@@ -547,7 +547,6 @@ bool RegionIN865RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
RadioModems_t modem;
int8_t dr = rxConfig->Datarate;
- uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
@@ -584,15 +583,7 @@ bool RegionIN865RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
Radio.SetRxConfig( modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
}
- if( rxConfig->RepeaterSupport == true )
- {
- maxPayload = MaxPayloadOfDatarateRepeaterIN865[dr];
- }
- else
- {
- maxPayload = MaxPayloadOfDatarateIN865[dr];
- }
- Radio.SetMaxPayloadLength( modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+ Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateIN865[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
*datarate = (uint8_t) dr;
return true;
@@ -615,18 +606,19 @@ bool RegionIN865TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime
if( txConfig->Datarate == DR_7 )
{ // High Speed FSK channel
modem = MODEM_FSK;
- Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 4000 );
}
else
{
modem = MODEM_LORA;
- Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
}
+ // Update time-on-air
+ *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
+
// Setup maximum payload lenght of the radio driver
Radio.SetMaxPayloadLength( modem, txConfig->PktLen );
- // Get the time-on-air of the next tx frame
- *txTimeOnAir = Radio.TimeOnAir( modem, txConfig->PktLen );
*txPower = txPowerLimited;
return true;
@@ -857,74 +849,54 @@ int8_t RegionIN865AlternateDr( int8_t currentDr, AlternateDrType_t type )
return currentDr;
}
-void RegionIN865CalcBackOff( CalcBackOffParams_t* calcBackOff )
-{
- RegionCommonCalcBackOffParams_t calcBackOffParams;
-
- calcBackOffParams.Channels = NvmCtx.Channels;
- calcBackOffParams.Bands = NvmCtx.Bands;
- calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
- calcBackOffParams.Joined = calcBackOff->Joined;
- calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
- calcBackOffParams.Channel = calcBackOff->Channel;
- calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
- calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
-
- RegionCommonCalcBackOff( &calcBackOffParams );
-}
-
LoRaMacStatus_t RegionIN865NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
- uint8_t delayTx = 0;
+ uint8_t nbRestrictedChannels = 0;
uint8_t enabledChannels[IN865_MAX_NB_CHANNELS] = { 0 };
- TimerTime_t nextTxDelay = 0;
+ RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
+ RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
+ LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
if( RegionCommonCountChannels( NvmCtx.ChannelsMask, 0, 1 ) == 0 )
{ // Reactivate default channels
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
}
- if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
- {
- // Reset Aggregated time off
- *aggregatedTimeOff = 0;
+ // Search how many channels are enabled
+ countChannelsParams.Joined = nextChanParams->Joined;
+ countChannelsParams.Datarate = nextChanParams->Datarate;
+ countChannelsParams.ChannelsMask = NvmCtx.ChannelsMask;
+ countChannelsParams.Channels = NvmCtx.Channels;
+ countChannelsParams.Bands = NvmCtx.Bands;
+ countChannelsParams.MaxNbChannels = IN865_MAX_NB_CHANNELS;
+ countChannelsParams.JoinChannels = IN865_JOIN_CHANNELS;
- // Update bands Time OFF
- nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, NvmCtx.Bands, IN865_MAX_NB_BANDS );
+ identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
+ identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
+ identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
+ identifyChannelsParam.MaxBands = IN865_MAX_NB_BANDS;
- // Search how many channels are enabled
- nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Joined, nextChanParams->Datarate,
- NvmCtx.ChannelsMask, NvmCtx.Channels,
- NvmCtx.Bands, enabledChannels, &delayTx );
- }
- else
- {
- delayTx++;
- nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
- }
+ identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
+ identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
+ identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
- if( nbEnabledChannels > 0 )
+ identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
+
+ status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
+ &nbEnabledChannels, &nbRestrictedChannels, time );
+
+ if( status == LORAMAC_STATUS_OK )
{
// We found a valid channel
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
-
- *time = 0;
- return LORAMAC_STATUS_OK;
}
- else
+ else if( status == LORAMAC_STATUS_NO_CHANNEL_FOUND )
{
- if( delayTx > 0 )
- {
- // Delay transmission due to AggregatedTimeOff or to a band time off
- *time = nextTxDelay;
- return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
- }
// Datarate not supported by any channel, restore defaults
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
- *time = 0;
- return LORAMAC_STATUS_NO_CHANNEL_FOUND;
}
+ return status;
}
LoRaMacStatus_t RegionIN865ChannelAdd( ChannelAddParams_t* channelAdd )
diff --git a/components/connectivity/LoraWAN/mac/region/RegionIN865.h b/components/connectivity/LoraWAN/mac/region/RegionIN865.h
index 60c871e6..d1df69d6 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionIN865.h
+++ b/components/connectivity/LoraWAN/mac/region/RegionIN865.h
@@ -37,6 +37,11 @@
#ifndef __REGION_IN865_H__
#define __REGION_IN865_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "region/Region.h"
/*!
@@ -132,7 +137,7 @@
/*!
* Enabled or disabled the duty cycle
*/
-#define IN865_DUTY_CYCLE_ENABLED 1
+#define IN865_DUTY_CYCLE_ENABLED 0
/*!
* Maximum RX window duration
@@ -196,6 +201,11 @@
*/
#define IN865_BEACON_CHANNEL_FREQ 866550000
+/*!
+ * Ping slot channel frequency
+ */
+#define IN865_PING_SLOT_CHANNEL_FREQ 866550000
+
/*!
* Payload size of a beacon frame
*/
@@ -233,9 +243,9 @@
/*!
* Band 0 definition
- * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define IN865_BAND0 { 1 , IN865_MAX_TX_POWER, 0, 0, 0 } // 100.0 %
+#define IN865_BAND0 { 1 , IN865_MAX_TX_POWER, 0, 0, 0, 0 } // 100.0 %
/*!
* LoRaMac default channel 1
@@ -271,15 +281,10 @@ static const uint8_t DataratesIN865[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
static const uint32_t BandwidthsIN865[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ * Maximum payload with respect to the datarate index.
*/
static const uint8_t MaxPayloadOfDatarateIN865[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-static const uint8_t MaxPayloadOfDatarateRepeaterIN865[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
-
/*!
* Effective datarate offsets for receive window 1.
*/
@@ -440,13 +445,6 @@ uint8_t RegionIN865DlChannelReq( DlChannelReqParams_t* dlChannelReq );
*/
int8_t RegionIN865AlternateDr( int8_t currentDr, AlternateDrType_t type );
-/*!
- * \brief Calculates the back-off time.
- *
- * \param [IN] calcBackOff Pointer to the function parameters.
- */
-void RegionIN865CalcBackOff( CalcBackOffParams_t* calcBackOff );
-
/*!
* \brief Searches and set the next random available channel
*
@@ -508,4 +506,8 @@ uint8_t RegionIN865ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t d
/*! \} defgroup REGIONIN865 */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __REGION_IN865_H__
diff --git a/components/connectivity/LoraWAN/mac/region/RegionKR920.c b/components/connectivity/LoraWAN/mac/region/RegionKR920.c
index 04745173..1791f90e 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionKR920.c
+++ b/components/connectivity/LoraWAN/mac/region/RegionKR920.c
@@ -138,45 +138,12 @@ static bool VerifyRfFreq( uint32_t freq )
return false;
}
-static uint8_t CountNbOfEnabledChannels( bool joined, uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
{
- uint8_t nbEnabledChannels = 0;
- uint8_t delayTransmission = 0;
+ int8_t phyDr = DataratesKR920[datarate];
+ uint32_t bandwidth = GetBandwidth( datarate );
- for( uint8_t i = 0, k = 0; i < KR920_MAX_NB_CHANNELS; i += 16, k++ )
- {
- for( uint8_t j = 0; j < 16; j++ )
- {
- if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
- {
- if( channels[i + j].Frequency == 0 )
- { // Check if the channel is enabled
- continue;
- }
- if( joined == false )
- {
- if( ( KR920_JOIN_CHANNELS & ( 1 << j ) ) == 0 )
- {
- continue;
- }
- }
- if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
- channels[i + j].DrRange.Fields.Max ) == false )
- { // Check if the current channel selection supports the given datarate
- continue;
- }
- if( bands[channels[i + j].Band].TimeOff > 0 )
- { // Check if the band is available for transmission
- delayTransmission++;
- continue;
- }
- enabledChannels[nbEnabledChannels++] = i + j;
- }
- }
- }
-
- *delayTx = delayTransmission;
- return nbEnabledChannels;
+ return Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
}
PhyParam_t RegionKR920GetPhyParam( GetPhyParams_t* getPhy )
@@ -230,11 +197,6 @@ PhyParam_t RegionKR920GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = MaxPayloadOfDatarateKR920[getPhy->Datarate];
break;
}
- case PHY_MAX_PAYLOAD_REPEATER:
- {
- phyParam.Value = MaxPayloadOfDatarateRepeaterKR920[getPhy->Datarate];
- break;
- }
case PHY_DUTY_CYCLE:
{
phyParam.Value = KR920_DUTY_CYCLE_ENABLED;
@@ -347,11 +309,26 @@ PhyParam_t RegionKR920GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = KR920_BEACON_CHANNEL_DR;
break;
}
+ case PHY_PING_SLOT_CHANNEL_FREQ:
+ {
+ phyParam.Value = KR920_PING_SLOT_CHANNEL_FREQ;
+ break;
+ }
case PHY_PING_SLOT_CHANNEL_DR:
{
phyParam.Value = KR920_PING_SLOT_CHANNEL_DR;
break;
}
+ case PHY_SF_FROM_DR:
+ {
+ phyParam.Value = DataratesKR920[getPhy->Datarate];
+ break;
+ }
+ case PHY_BW_FROM_DR:
+ {
+ phyParam.Value = GetBandwidth( getPhy->Datarate );
+ break;
+ }
default:
{
break;
@@ -363,7 +340,8 @@ PhyParam_t RegionKR920GetPhyParam( GetPhyParams_t* getPhy )
void RegionKR920SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
- RegionCommonSetBandTxDone( txDone->Joined, &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+ RegionCommonSetBandTxDone( &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band],
+ txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
}
void RegionKR920InitDefaults( InitDefaultsParams_t* params )
@@ -375,10 +353,14 @@ void RegionKR920InitDefaults( InitDefaultsParams_t* params )
switch( params->Type )
{
- case INIT_TYPE_INIT:
+ case INIT_TYPE_BANDS:
{
// Initialize bands
memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * KR920_MAX_NB_BANDS );
+ break;
+ }
+ case INIT_TYPE_INIT:
+ {
// Channels
NvmCtx.Channels[0] = ( ChannelParams_t ) KR920_LC1;
@@ -387,6 +369,7 @@ void RegionKR920InitDefaults( InitDefaultsParams_t* params )
// Initialize the channels default mask
NvmCtx.ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
+
// Update the channels mask
RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 1 );
break;
@@ -403,6 +386,11 @@ void RegionKR920InitDefaults( InitDefaultsParams_t* params )
{
// Restore channels default mask
NvmCtx.ChannelsMask[0] |= NvmCtx.ChannelsDefaultMask[0];
+
+ // Channels
+ NvmCtx.Channels[0] = ( ChannelParams_t ) KR920_LC1;
+ NvmCtx.Channels[1] = ( ChannelParams_t ) KR920_LC2;
+ NvmCtx.Channels[2] = ( ChannelParams_t ) KR920_LC3;
break;
}
default:
@@ -422,6 +410,10 @@ bool RegionKR920Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
+ case PHY_FREQUENCY:
+ {
+ return VerifyRfFreq( verify->Frequency );
+ }
case PHY_TX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, KR920_TX_MIN_DATARATE, KR920_TX_MAX_DATARATE );
@@ -544,7 +536,6 @@ void RegionKR920ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols
bool RegionKR920RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
int8_t dr = rxConfig->Datarate;
- uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
@@ -571,8 +562,7 @@ bool RegionKR920RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
// Radio configuration
Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
- maxPayload = MaxPayloadOfDatarateKR920[dr];
- Radio.SetMaxPayloadLength( MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+ Radio.SetMaxPayloadLength( MODEM_LORA, MaxPayloadOfDatarateKR920[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
*datarate = (uint8_t) dr;
return true;
@@ -596,12 +586,12 @@ bool RegionKR920TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime
// Setup the radio frequency
Radio.SetChannel( NvmCtx.Channels[txConfig->Channel].Frequency );
- Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
// Setup maximum payload lenght of the radio driver
Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
- // Get the time-on-air of the next tx frame
- *txTimeOnAir = Radio.TimeOnAir( MODEM_LORA, txConfig->PktLen );
+ // Update time-on-air
+ *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
*txPower = txPowerLimited;
return true;
@@ -825,55 +815,45 @@ int8_t RegionKR920AlternateDr( int8_t currentDr, AlternateDrType_t type )
return currentDr;
}
-void RegionKR920CalcBackOff( CalcBackOffParams_t* calcBackOff )
-{
- RegionCommonCalcBackOffParams_t calcBackOffParams;
-
- calcBackOffParams.Channels = NvmCtx.Channels;
- calcBackOffParams.Bands = NvmCtx.Bands;
- calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
- calcBackOffParams.Joined = calcBackOff->Joined;
- calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
- calcBackOffParams.Channel = calcBackOff->Channel;
- calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
- calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
-
- RegionCommonCalcBackOff( &calcBackOffParams );
-}
-
LoRaMacStatus_t RegionKR920NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t channelNext = 0;
uint8_t nbEnabledChannels = 0;
- uint8_t delayTx = 0;
+ uint8_t nbRestrictedChannels = 0;
uint8_t enabledChannels[KR920_MAX_NB_CHANNELS] = { 0 };
- TimerTime_t nextTxDelay = 0;
+ RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
+ RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
+ LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
if( RegionCommonCountChannels( NvmCtx.ChannelsMask, 0, 1 ) == 0 )
{ // Reactivate default channels
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
}
- if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
- {
- // Reset Aggregated time off
- *aggregatedTimeOff = 0;
+ // Search how many channels are enabled
+ countChannelsParams.Joined = nextChanParams->Joined;
+ countChannelsParams.Datarate = nextChanParams->Datarate;
+ countChannelsParams.ChannelsMask = NvmCtx.ChannelsMask;
+ countChannelsParams.Channels = NvmCtx.Channels;
+ countChannelsParams.Bands = NvmCtx.Bands;
+ countChannelsParams.MaxNbChannels = KR920_MAX_NB_CHANNELS;
+ countChannelsParams.JoinChannels = KR920_JOIN_CHANNELS;
- // Update bands Time OFF
- nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, NvmCtx.Bands, KR920_MAX_NB_BANDS );
+ identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
+ identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
+ identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
+ identifyChannelsParam.MaxBands = KR920_MAX_NB_BANDS;
- // Search how many channels are enabled
- nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Joined, nextChanParams->Datarate,
- NvmCtx.ChannelsMask, NvmCtx.Channels,
- NvmCtx.Bands, enabledChannels, &delayTx );
- }
- else
- {
- delayTx++;
- nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
- }
+ identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
+ identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
+ identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
- if( nbEnabledChannels > 0 )
+ identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
+
+ status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
+ &nbEnabledChannels, &nbRestrictedChannels, time );
+
+ if( status == LORAMAC_STATUS_OK )
{
for( uint8_t i = 0, j = randr( 0, nbEnabledChannels - 1 ); i < KR920_MAX_NB_CHANNELS; i++ )
{
@@ -886,25 +866,19 @@ LoRaMacStatus_t RegionKR920NextChannel( NextChanParams_t* nextChanParams, uint8_
{
// Free channel found
*channel = channelNext;
- *time = 0;
return LORAMAC_STATUS_OK;
}
}
- return LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND;
+ // Even if one or more channels are available according to the channel plan, no free channel
+ // was found during the LBT procedure.
+ status = LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND;
}
- else
+ else if( status == LORAMAC_STATUS_NO_CHANNEL_FOUND )
{
- if( delayTx > 0 )
- {
- // Delay transmission due to AggregatedTimeOff or to a band time off
- *time = nextTxDelay;
- return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
- }
// Datarate not supported by any channel, restore defaults
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
- *time = 0;
- return LORAMAC_STATUS_NO_CHANNEL_FOUND;
}
+ return status;
}
LoRaMacStatus_t RegionKR920ChannelAdd( ChannelAddParams_t* channelAdd )
diff --git a/components/connectivity/LoraWAN/mac/region/RegionKR920.h b/components/connectivity/LoraWAN/mac/region/RegionKR920.h
index 7f5052c2..6a2d60b4 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionKR920.h
+++ b/components/connectivity/LoraWAN/mac/region/RegionKR920.h
@@ -37,6 +37,11 @@
#ifndef __REGION_KR920_H__
#define __REGION_KR920_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "region/Region.h"
/*!
@@ -201,6 +206,11 @@
*/
#define KR920_BEACON_CHANNEL_FREQ 923100000
+/*!
+ * Ping slot channel frequency
+ */
+#define KR920_PING_SLOT_CHANNEL_FREQ 923100000
+
/*!
* Payload size of a beacon frame
*/
@@ -238,9 +248,9 @@
/*!
* Band 0 definition
- * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define KR920_BAND0 { 1 , KR920_MAX_TX_POWER, 0, 0, 0 } // 100.0 %
+#define KR920_BAND0 { 1 , KR920_MAX_TX_POWER, 0, 0, 0, 0 } // 100.0 %
/*!
* LoRaMac default channel 1
@@ -286,15 +296,10 @@ static const uint8_t DataratesKR920[] = { 12, 11, 10, 9, 8, 7 };
static const uint32_t BandwidthsKR920[] = { 125000, 125000, 125000, 125000, 125000, 125000 };
/*!
- * Maximum payload with respect to the datarate index. Can operate with and without a repeater.
+ * Maximum payload with respect to the datarate index.
*/
static const uint8_t MaxPayloadOfDatarateKR920[] = { 51, 51, 51, 115, 242, 242 };
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-static const uint8_t MaxPayloadOfDatarateRepeaterKR920[] = { 51, 51, 51, 115, 222, 222 };
-
/*!
* \brief The function gets a value of a specific phy attribute.
*
@@ -450,13 +455,6 @@ uint8_t RegionKR920DlChannelReq( DlChannelReqParams_t* dlChannelReq );
*/
int8_t RegionKR920AlternateDr( int8_t currentDr, AlternateDrType_t type );
-/*!
- * \brief Calculates the back-off time.
- *
- * \param [IN] calcBackOff Pointer to the function parameters.
- */
-void RegionKR920CalcBackOff( CalcBackOffParams_t* calcBackOff );
-
/*!
* \brief Searches and set the next random available channel
*
@@ -518,4 +516,8 @@ uint8_t RegionKR920ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t d
/*! \} defgroup REGIONKR920 */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __REGION_KR920_H__
diff --git a/components/connectivity/LoraWAN/mac/region/RegionRU864.c b/components/connectivity/LoraWAN/mac/region/RegionRU864.c
index 3369837b..afec4bb6 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionRU864.c
+++ b/components/connectivity/LoraWAN/mac/region/RegionRU864.c
@@ -120,45 +120,21 @@ static bool VerifyRfFreq( uint32_t freq )
return true;
}
-static uint8_t CountNbOfEnabledChannels( bool joined, uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
{
- uint8_t nbEnabledChannels = 0;
- uint8_t delayTransmission = 0;
+ int8_t phyDr = DataratesRU864[datarate];
+ uint32_t bandwidth = GetBandwidth( datarate );
+ TimerTime_t timeOnAir = 0;
- for( uint8_t i = 0, k = 0; i < RU864_MAX_NB_CHANNELS; i += 16, k++ )
- {
- for( uint8_t j = 0; j < 16; j++ )
- {
- if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
- {
- if( channels[i + j].Frequency == 0 )
- { // Check if the channel is enabled
- continue;
- }
- if( joined == false )
- {
- if( ( RU864_JOIN_CHANNELS & ( 1 << j ) ) == 0 )
- {
- continue;
- }
- }
- if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
- channels[i + j].DrRange.Fields.Max ) == false )
- { // Check if the current channel selection supports the given datarate
- continue;
- }
- if( bands[channels[i + j].Band].TimeOff > 0 )
- { // Check if the band is available for transmission
- delayTransmission++;
- continue;
- }
- enabledChannels[nbEnabledChannels++] = i + j;
- }
- }
+ if( datarate == DR_7 )
+ { // High Speed FSK channel
+ timeOnAir = Radio.TimeOnAir( MODEM_FSK, bandwidth, phyDr * 1000, 0, 5, false, pktLen, true );
}
-
- *delayTx = delayTransmission;
- return nbEnabledChannels;
+ else
+ {
+ timeOnAir = Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
+ }
+ return timeOnAir;
}
PhyParam_t RegionRU864GetPhyParam( GetPhyParams_t* getPhy )
@@ -187,6 +163,11 @@ PhyParam_t RegionRU864GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, RU864_TX_MIN_DATARATE );
break;
}
+ case PHY_MAX_TX_POWER:
+ {
+ phyParam.Value = RU864_MAX_TX_POWER;
+ break;
+ }
case PHY_DEF_TX_POWER:
{
phyParam.Value = RU864_DEFAULT_TX_POWER;
@@ -207,11 +188,6 @@ PhyParam_t RegionRU864GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = MaxPayloadOfDatarateRU864[getPhy->Datarate];
break;
}
- case PHY_MAX_PAYLOAD_REPEATER:
- {
- phyParam.Value = MaxPayloadOfDatarateRepeaterRU864[getPhy->Datarate];
- break;
- }
case PHY_DUTY_CYCLE:
{
phyParam.Value = RU864_DUTY_CYCLE_ENABLED;
@@ -320,6 +296,26 @@ PhyParam_t RegionRU864GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = RU864_BEACON_CHANNEL_DR;
break;
}
+ case PHY_PING_SLOT_CHANNEL_FREQ:
+ {
+ phyParam.Value = RU864_PING_SLOT_CHANNEL_FREQ;
+ break;
+ }
+ case PHY_PING_SLOT_CHANNEL_DR:
+ {
+ phyParam.Value = RU864_PING_SLOT_CHANNEL_DR;
+ break;
+ }
+ case PHY_SF_FROM_DR:
+ {
+ phyParam.Value = DataratesRU864[getPhy->Datarate];
+ break;
+ }
+ case PHY_BW_FROM_DR:
+ {
+ phyParam.Value = GetBandwidth( getPhy->Datarate );
+ break;
+ }
default:
{
break;
@@ -331,7 +327,8 @@ PhyParam_t RegionRU864GetPhyParam( GetPhyParams_t* getPhy )
void RegionRU864SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
- RegionCommonSetBandTxDone( txDone->Joined, &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+ RegionCommonSetBandTxDone( &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band],
+ txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
}
void RegionRU864InitDefaults( InitDefaultsParams_t* params )
@@ -343,10 +340,14 @@ void RegionRU864InitDefaults( InitDefaultsParams_t* params )
switch( params->Type )
{
- case INIT_TYPE_INIT:
+ case INIT_TYPE_BANDS:
{
// Initialize bands
memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * RU864_MAX_NB_BANDS );
+ break;
+ }
+ case INIT_TYPE_INIT:
+ {
// Channels
NvmCtx.Channels[0] = ( ChannelParams_t ) RU864_LC1;
@@ -370,6 +371,10 @@ void RegionRU864InitDefaults( InitDefaultsParams_t* params )
{
// Restore channels default mask
NvmCtx.ChannelsMask[0] |= NvmCtx.ChannelsDefaultMask[0];
+
+ // Channels
+ NvmCtx.Channels[0] = ( ChannelParams_t ) RU864_LC1;
+ NvmCtx.Channels[1] = ( ChannelParams_t ) RU864_LC2;
break;
}
default:
@@ -389,6 +394,10 @@ bool RegionRU864Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
+ case PHY_FREQUENCY:
+ {
+ return VerifyRfFreq( verify->Frequency );
+ }
case PHY_TX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, RU864_TX_MIN_DATARATE, RU864_TX_MAX_DATARATE );
@@ -519,7 +528,6 @@ bool RegionRU864RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
RadioModems_t modem;
int8_t dr = rxConfig->Datarate;
- uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
@@ -556,16 +564,7 @@ bool RegionRU864RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
Radio.SetRxConfig( modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
}
- if( rxConfig->RepeaterSupport == true )
- {
- maxPayload = MaxPayloadOfDatarateRepeaterRU864[dr];
- }
- else
- {
- maxPayload = MaxPayloadOfDatarateRU864[dr];
- }
-
- Radio.SetMaxPayloadLength( modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+ Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateRU864[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
*datarate = (uint8_t) dr;
return true;
@@ -588,18 +587,19 @@ bool RegionRU864TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime
if( txConfig->Datarate == DR_7 )
{ // High Speed FSK channel
modem = MODEM_FSK;
- Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 4000 );
}
else
{
modem = MODEM_LORA;
- Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
}
+ // Update time-on-air
+ *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
+
// Setup maximum payload lenght of the radio driver
Radio.SetMaxPayloadLength( modem, txConfig->PktLen );
- // Get the time-on-air of the next tx frame
- *txTimeOnAir = Radio.TimeOnAir( modem, txConfig->PktLen );
*txPower = txPowerLimited;
return true;
@@ -823,74 +823,54 @@ int8_t RegionRU864AlternateDr( int8_t currentDr, AlternateDrType_t type )
return currentDr;
}
-void RegionRU864CalcBackOff( CalcBackOffParams_t* calcBackOff )
-{
- RegionCommonCalcBackOffParams_t calcBackOffParams;
-
- calcBackOffParams.Channels = NvmCtx.Channels;
- calcBackOffParams.Bands = NvmCtx.Bands;
- calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
- calcBackOffParams.Joined = calcBackOff->Joined;
- calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
- calcBackOffParams.Channel = calcBackOff->Channel;
- calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
- calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
-
- RegionCommonCalcBackOff( &calcBackOffParams );
-}
-
LoRaMacStatus_t RegionRU864NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
- uint8_t delayTx = 0;
+ uint8_t nbRestrictedChannels = 0;
uint8_t enabledChannels[RU864_MAX_NB_CHANNELS] = { 0 };
- TimerTime_t nextTxDelay = 0;
+ RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
+ RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
+ LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
if( RegionCommonCountChannels( NvmCtx.ChannelsMask, 0, 1 ) == 0 )
{ // Reactivate default channels
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 );
}
- if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
- {
- // Reset Aggregated time off
- *aggregatedTimeOff = 0;
+ // Search how many channels are enabled
+ countChannelsParams.Joined = nextChanParams->Joined;
+ countChannelsParams.Datarate = nextChanParams->Datarate;
+ countChannelsParams.ChannelsMask = NvmCtx.ChannelsMask;
+ countChannelsParams.Channels = NvmCtx.Channels;
+ countChannelsParams.Bands = NvmCtx.Bands;
+ countChannelsParams.MaxNbChannels = RU864_MAX_NB_CHANNELS;
+ countChannelsParams.JoinChannels = RU864_JOIN_CHANNELS;
- // Update bands Time OFF
- nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, NvmCtx.Bands, RU864_MAX_NB_BANDS );
+ identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
+ identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
+ identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
+ identifyChannelsParam.MaxBands = RU864_MAX_NB_BANDS;
- // Search how many channels are enabled
- nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Joined, nextChanParams->Datarate,
- NvmCtx.ChannelsMask, NvmCtx.Channels,
- NvmCtx.Bands, enabledChannels, &delayTx );
- }
- else
- {
- delayTx++;
- nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
- }
+ identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
+ identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
+ identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
- if( nbEnabledChannels > 0 )
+ identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
+
+ status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
+ &nbEnabledChannels, &nbRestrictedChannels, time );
+
+ if( status == LORAMAC_STATUS_OK )
{
// We found a valid channel
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
-
- *time = 0;
- return LORAMAC_STATUS_OK;
}
- else
+ else if( status == LORAMAC_STATUS_NO_CHANNEL_FOUND )
{
- if( delayTx > 0 )
- {
- // Delay transmission due to AggregatedTimeOff or to a band time off
- *time = nextTxDelay;
- return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
- }
// Datarate not supported by any channel, restore defaults
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 );
- *time = 0;
- return LORAMAC_STATUS_NO_CHANNEL_FOUND;
}
+ return status;
}
LoRaMacStatus_t RegionRU864ChannelAdd( ChannelAddParams_t* channelAdd )
diff --git a/components/connectivity/LoraWAN/mac/region/RegionRU864.h b/components/connectivity/LoraWAN/mac/region/RegionRU864.h
index f623dd2e..fc5a2179 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionRU864.h
+++ b/components/connectivity/LoraWAN/mac/region/RegionRU864.h
@@ -35,6 +35,11 @@
#ifndef __REGION_RU864_H__
#define __REGION_RU864_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "LoRaMac.h"
/*!
@@ -194,6 +199,11 @@
*/
#define RU864_BEACON_CHANNEL_FREQ 869100000
+/*!
+ * Ping slot channel frequency
+ */
+#define RU864_PING_SLOT_CHANNEL_FREQ 868900000
+
/*!
* Payload size of a beacon frame
*/
@@ -219,6 +229,11 @@
*/
#define RU864_BEACON_CHANNEL_BW 0
+/*!
+ * Datarate of the ping slot channel
+ */
+#define RU864_PING_SLOT_CHANNEL_DR DR_3
+
/*!
* Maximum number of bands
*/
@@ -226,9 +241,9 @@
/*!
* Band 0 definition
- * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define RU864_BAND0 { 100 , RU864_MAX_TX_POWER, 0, 0, 0 } // 1.0 %
+#define RU864_BAND0 { 100 , RU864_MAX_TX_POWER, 0, 0, 0, 0 } // 1.0 %
/*!
* LoRaMac default channel 1
@@ -259,15 +274,10 @@ static const uint8_t DataratesRU864[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
static const uint32_t BandwidthsRU864[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ * Maximum payload with respect to the datarate index.
*/
static const uint8_t MaxPayloadOfDatarateRU864[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-static const uint8_t MaxPayloadOfDatarateRepeaterRU864[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
-
/*!
* \brief The function gets a value of a specific phy attribute.
*
@@ -423,13 +433,6 @@ uint8_t RegionRU864DlChannelReq( DlChannelReqParams_t* dlChannelReq );
*/
int8_t RegionRU864AlternateDr( int8_t currentDr, AlternateDrType_t type );
-/*!
- * \brief Calculates the back-off time.
- *
- * \param [IN] calcBackOff Pointer to the function parameters.
- */
-void RegionRU864CalcBackOff( CalcBackOffParams_t* calcBackOff );
-
/*!
* \brief Searches and set the next random available channel
*
@@ -491,4 +494,8 @@ void RegionRU864RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr );
/*! \} defgroup REGIONRU864 */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __REGION_RU864_H__
diff --git a/components/connectivity/LoraWAN/mac/region/RegionUS915.c b/components/connectivity/LoraWAN/mac/region/RegionUS915.c
index e0f492f7..ec93b738 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionUS915.c
+++ b/components/connectivity/LoraWAN/mac/region/RegionUS915.c
@@ -254,38 +254,12 @@ static bool VerifyRfFreq( uint32_t freq )
return true;
}
-static uint8_t CountNbOfEnabledChannels( uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
{
- uint8_t nbEnabledChannels = 0;
- uint8_t delayTransmission = 0;
+ int8_t phyDr = DataratesUS915[datarate];
+ uint32_t bandwidth = GetBandwidth( datarate );
- for( uint8_t i = 0, k = 0; i < US915_MAX_NB_CHANNELS; i += 16, k++ )
- {
- for( uint8_t j = 0; j < 16; j++ )
- {
- if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
- {
- if( channels[i + j].Frequency == 0 )
- { // Check if the channel is enabled
- continue;
- }
- if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
- channels[i + j].DrRange.Fields.Max ) == false )
- { // Check if the current channel selection supports the given datarate
- continue;
- }
- if( bands[channels[i + j].Band].TimeOff > 0 )
- { // Check if the band is available for transmission
- delayTransmission++;
- continue;
- }
- enabledChannels[nbEnabledChannels++] = i + j;
- }
- }
- }
-
- *delayTx = delayTransmission;
- return nbEnabledChannels;
+ return Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
}
PhyParam_t RegionUS915GetPhyParam( GetPhyParams_t* getPhy )
@@ -339,11 +313,6 @@ PhyParam_t RegionUS915GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = MaxPayloadOfDatarateUS915[getPhy->Datarate];
break;
}
- case PHY_MAX_PAYLOAD_REPEATER:
- {
- phyParam.Value = MaxPayloadOfDatarateRepeaterUS915[getPhy->Datarate];
- break;
- }
case PHY_DUTY_CYCLE:
{
phyParam.Value = US915_DUTY_CYCLE_ENABLED;
@@ -427,7 +396,7 @@ PhyParam_t RegionUS915GetPhyParam( GetPhyParams_t* getPhy )
}
case PHY_DEF_MAX_EIRP:
{
- phyParam.fValue = US915_DEFAULT_MAX_ERP + 2.15;
+ phyParam.fValue = US915_DEFAULT_MAX_ERP + 2.15f;
break;
}
case PHY_DEF_ANTENNA_GAIN:
@@ -437,7 +406,7 @@ PhyParam_t RegionUS915GetPhyParam( GetPhyParams_t* getPhy )
}
case PHY_BEACON_CHANNEL_FREQ:
{
- phyParam.Value = US915_BEACON_CHANNEL_FREQ;
+ phyParam.Value = US915_BEACON_CHANNEL_FREQ + ( getPhy->Channel * US915_BEACON_CHANNEL_STEPWIDTH );
break;
}
case PHY_BEACON_FORMAT:
@@ -462,11 +431,26 @@ PhyParam_t RegionUS915GetPhyParam( GetPhyParams_t* getPhy )
phyParam.Value = US915_BEACON_NB_CHANNELS;
break;
}
+ case PHY_PING_SLOT_CHANNEL_FREQ:
+ {
+ phyParam.Value = US915_PING_SLOT_CHANNEL_FREQ + ( getPhy->Channel * US915_BEACON_CHANNEL_STEPWIDTH );
+ break;
+ }
case PHY_PING_SLOT_CHANNEL_DR:
{
phyParam.Value = US915_PING_SLOT_CHANNEL_DR;
break;
}
+ case PHY_SF_FROM_DR:
+ {
+ phyParam.Value = DataratesUS915[getPhy->Datarate];
+ break;
+ }
+ case PHY_BW_FROM_DR:
+ {
+ phyParam.Value = GetBandwidth( getPhy->Datarate );
+ break;
+ }
default:
{
break;
@@ -478,7 +462,8 @@ PhyParam_t RegionUS915GetPhyParam( GetPhyParams_t* getPhy )
void RegionUS915SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
- RegionCommonSetBandTxDone( txDone->Joined, &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+ RegionCommonSetBandTxDone( &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band],
+ txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
}
void RegionUS915InitDefaults( InitDefaultsParams_t* params )
@@ -490,7 +475,7 @@ void RegionUS915InitDefaults( InitDefaultsParams_t* params )
switch( params->Type )
{
- case INIT_TYPE_INIT:
+ case INIT_TYPE_BANDS:
{
// Initialize bands
memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * US915_MAX_NB_BANDS );
@@ -501,6 +486,23 @@ void RegionUS915InitDefaults( InitDefaultsParams_t* params )
// Initialize the join trials counter
NvmCtx.JoinTrialsCounter = 0;
+ // ChannelsMask
+ NvmCtx.ChannelsDefaultMask[0] = 0xFFFF;
+ NvmCtx.ChannelsDefaultMask[1] = 0xFFFF;
+ NvmCtx.ChannelsDefaultMask[2] = 0xFFFF;
+ NvmCtx.ChannelsDefaultMask[3] = 0xFFFF;
+ NvmCtx.ChannelsDefaultMask[4] = 0x00FF;
+ NvmCtx.ChannelsDefaultMask[5] = 0x0000;
+
+ // Copy channels default mask
+ RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 6 );
+
+ // Copy into channels mask remaining
+ RegionCommonChanMaskCopy( NvmCtx.ChannelsMaskRemaining, NvmCtx.ChannelsMask, 6 );
+ break;
+ }
+ case INIT_TYPE_INIT:
+ {
// Channels
// 125 kHz channels
for( uint8_t i = 0; i < US915_MAX_NB_CHANNELS - 8; i++ )
@@ -516,20 +518,6 @@ void RegionUS915InitDefaults( InitDefaultsParams_t* params )
NvmCtx.Channels[i].DrRange.Value = ( DR_4 << 4 ) | DR_4;
NvmCtx.Channels[i].Band = 0;
}
-
- // ChannelsMask
- NvmCtx.ChannelsDefaultMask[0] = 0xFFFF;
- NvmCtx.ChannelsDefaultMask[1] = 0xFFFF;
- NvmCtx.ChannelsDefaultMask[2] = 0xFFFF;
- NvmCtx.ChannelsDefaultMask[3] = 0xFFFF;
- NvmCtx.ChannelsDefaultMask[4] = 0x00FF;
- NvmCtx.ChannelsDefaultMask[5] = 0x0000;
-
- // Copy channels default mask
- RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 6 );
-
- // Copy into channels mask remaining
- RegionCommonChanMaskCopy( NvmCtx.ChannelsMaskRemaining, NvmCtx.ChannelsMask, 6 );
break;
}
case INIT_TYPE_RESTORE_CTX:
@@ -568,6 +556,10 @@ bool RegionUS915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
+ case PHY_FREQUENCY:
+ {
+ return VerifyRfFreq( verify->Frequency );
+ }
case PHY_TX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, US915_TX_MIN_DATARATE, US915_TX_MAX_DATARATE );
@@ -676,7 +668,6 @@ void RegionUS915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols
bool RegionUS915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
int8_t dr = rxConfig->Datarate;
- uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
@@ -699,15 +690,7 @@ bool RegionUS915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
// Radio configuration
Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
- if( rxConfig->RepeaterSupport == true )
- {
- maxPayload = MaxPayloadOfDatarateRepeaterUS915[dr];
- }
- else
- {
- maxPayload = MaxPayloadOfDatarateUS915[dr];
- }
- Radio.SetMaxPayloadLength( MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+ Radio.SetMaxPayloadLength( MODEM_LORA, MaxPayloadOfDatarateUS915[dr] + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
*datarate = (uint8_t) dr;
return true;
@@ -726,14 +709,15 @@ bool RegionUS915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime
// Setup the radio frequency
Radio.SetChannel( NvmCtx.Channels[txConfig->Channel].Frequency );
- Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+ Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
// Setup maximum payload lenght of the radio driver
Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
- // Get the time-on-air of the next tx frame
- *txTimeOnAir = Radio.TimeOnAir( MODEM_LORA, txConfig->PktLen );
- *txPower = txPowerLimited;
+ // Update time-on-air
+ *txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
+
+ *txPower = txPowerLimited;
return true;
}
@@ -969,29 +953,15 @@ int8_t RegionUS915AlternateDr( int8_t currentDr, AlternateDrType_t type )
return currentDr;
}
-void RegionUS915CalcBackOff( CalcBackOffParams_t* calcBackOff )
-{
- RegionCommonCalcBackOffParams_t calcBackOffParams;
-
- calcBackOffParams.Channels = NvmCtx.Channels;
- calcBackOffParams.Bands = NvmCtx.Bands;
- calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
- calcBackOffParams.Joined = calcBackOff->Joined;
- calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
- calcBackOffParams.Channel = calcBackOff->Channel;
- calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
- calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
-
- RegionCommonCalcBackOff( &calcBackOffParams );
-}
-
LoRaMacStatus_t RegionUS915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
- uint8_t delayTx = 0;
+ uint8_t nbRestrictedChannels = 0;
uint8_t enabledChannels[US915_MAX_NB_CHANNELS] = { 0 };
- TimerTime_t nextTxDelay = 0;
- uint8_t newChannelIndex;
+ uint8_t newChannelIndex = 0;
+ RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
+ RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
+ LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
// Count 125kHz channels
if( RegionCommonCountChannels( NvmCtx.ChannelsMaskRemaining, 0, 4 ) == 0 )
@@ -1009,26 +979,30 @@ LoRaMacStatus_t RegionUS915NextChannel( NextChanParams_t* nextChanParams, uint8_
}
}
- if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
- {
- // Reset Aggregated time off
- *aggregatedTimeOff = 0;
+ // Search how many channels are enabled
+ countChannelsParams.Joined = nextChanParams->Joined;
+ countChannelsParams.Datarate = nextChanParams->Datarate;
+ countChannelsParams.ChannelsMask = NvmCtx.ChannelsMaskRemaining;
+ countChannelsParams.Channels = NvmCtx.Channels;
+ countChannelsParams.Bands = NvmCtx.Bands;
+ countChannelsParams.MaxNbChannels = US915_MAX_NB_CHANNELS;
+ countChannelsParams.JoinChannels = 0;
- // Update bands Time OFF
- nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, NvmCtx.Bands, US915_MAX_NB_BANDS );
+ identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
+ identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
+ identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
+ identifyChannelsParam.MaxBands = US915_MAX_NB_BANDS;
- // Search how many channels are enabled
- nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Datarate,
- NvmCtx.ChannelsMaskRemaining, NvmCtx.Channels,
- NvmCtx.Bands, enabledChannels, &delayTx );
- }
- else
- {
- delayTx++;
- nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
- }
+ identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
- if( nbEnabledChannels > 0 )
+ identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
+ identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
+ identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
+
+ status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
+ &nbEnabledChannels, &nbRestrictedChannels, time );
+
+ if( status == LORAMAC_STATUS_OK )
{
if( nextChanParams->Joined == true )
{
@@ -1066,22 +1040,8 @@ LoRaMacStatus_t RegionUS915NextChannel( NextChanParams_t* nextChanParams, uint8_
// Disable the channel in the mask
RegionCommonChanDisable( NvmCtx.ChannelsMaskRemaining, *channel, US915_MAX_NB_CHANNELS );
-
- *time = 0;
- return LORAMAC_STATUS_OK;
- }
- else
- {
- if( delayTx > 0 )
- {
- // Delay transmission due to AggregatedTimeOff or to a band time off
- *time = nextTxDelay;
- return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
- }
- // Datarate not supported by any channel
- *time = 0;
- return LORAMAC_STATUS_NO_CHANNEL_FOUND;
}
+ return status;
}
LoRaMacStatus_t RegionUS915ChannelAdd( ChannelAddParams_t* channelAdd )
diff --git a/components/connectivity/LoraWAN/mac/region/RegionUS915.h b/components/connectivity/LoraWAN/mac/region/RegionUS915.h
index 535c171a..cd11ea97 100644
--- a/components/connectivity/LoraWAN/mac/region/RegionUS915.h
+++ b/components/connectivity/LoraWAN/mac/region/RegionUS915.h
@@ -37,6 +37,11 @@
#ifndef __REGION_US915_H__
#define __REGION_US915_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "region/Region.h"
/*!
@@ -87,7 +92,7 @@
/*!
* Minimal Tx output power that can be used by the node
*/
-#define US915_MIN_TX_POWER TX_POWER_10
+#define US915_MIN_TX_POWER TX_POWER_14
/*!
* Maximal Tx output power that can be used by the node
@@ -182,6 +187,11 @@
*/
#define US915_BEACON_CHANNEL_STEPWIDTH 600000
+/*!
+ * Ping slot channel frequency
+ */
+#define US915_PING_SLOT_CHANNEL_FREQ 923300000
+
/*!
* Number of possible beacon channels
*/
@@ -224,9 +234,9 @@
/*!
* Band 0 definition
- * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ * Band = { DutyCycle, TxMaxPower, LastBandUpdateTime, TimeCredits, MaxTimeCredits, ReadyForTransmission }
*/
-#define US915_BAND0 { 1, US915_MAX_TX_POWER, 0, 0, 0 } // 100.0 %
+#define US915_BAND0 { 1, US915_MAX_TX_POWER, 0, 0, 0, 0 } // 100.0 %
/*!
* Defines the first channel for RX window 1 for US band
@@ -266,15 +276,10 @@ static const int8_t DatarateOffsetsUS915[5][4] =
};
/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ * Maximum payload with respect to the datarate index.
*/
static const uint8_t MaxPayloadOfDatarateUS915[] = { 11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0 };
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-static const uint8_t MaxPayloadOfDatarateRepeaterUS915[] = { 11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0 };
-
/*!
* \brief The function gets a value of a specific phy attribute.
*
@@ -432,13 +437,6 @@ uint8_t RegionUS915DlChannelReq( DlChannelReqParams_t* dlChannelReq );
*/
int8_t RegionUS915AlternateDr( int8_t currentDr, AlternateDrType_t type );
-/*!
- * \brief Calculates the back-off time.
- *
- * \param [IN] calcBackOff Pointer to the function parameters.
- */
-void RegionUS915CalcBackOff( CalcBackOffParams_t* calcBackOff );
-
/*!
* \brief Searches and set the next random available channel
*
@@ -496,8 +494,12 @@ uint8_t RegionUS915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t d
*
* \param [IN] rxBeaconSetup Pointer to the function parameters
*/
- void RegionUS915RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr );
+void RegionUS915RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr );
/*! \} defgroup REGIONUS915 */
+#ifdef __cplusplus
+}
+#endif
+
#endif // __REGION_US915_H__
diff --git a/components/connectivity/LoraWAN/mac/secure-element.h b/components/connectivity/LoraWAN/mac/secure-element.h
index 0ce7d4dc..322b31b3 100644
--- a/components/connectivity/LoraWAN/mac/secure-element.h
+++ b/components/connectivity/LoraWAN/mac/secure-element.h
@@ -30,13 +30,37 @@
*
* \author Johannes Bruder ( STACKFORCE )
*
+ * \defgroup SECUREELEMENT Secure Element API Definition
+ *
+ * \{
+ *
*/
#ifndef __SECURE_ELEMENT_H__
#define __SECURE_ELEMENT_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include "LoRaMacCrypto.h"
+/*!
+ * Secure-element keys size in bytes
+ */
+#define SE_KEY_SIZE 16
+
+/*!
+ * Secure-element EUI size in bytes
+ */
+#define SE_EUI_SIZE 8
+
+/*!
+ * Secure-element pin size in bytes
+ */
+#define SE_PIN_SIZE 4
+
/*!
* Return values.
*/
@@ -70,6 +94,10 @@ typedef enum eSecureElementStatus
* Undefined Error occurred
*/
SECURE_ELEMENT_ERROR,
+ /*!
+ * Failed to encrypt
+ */
+ SECURE_ELEMENT_FAIL_ENCRYPT,
}SecureElementStatus_t;
/*!
@@ -77,7 +105,7 @@ typedef enum eSecureElementStatus
* non volatile context have to be stored.
*
*/
-typedef void ( *EventNvmCtxChanged )( void );
+typedef void ( *SecureElementNvmEvent )( void );
/*!
* Initialization of Secure Element driver
@@ -86,7 +114,7 @@ typedef void ( *EventNvmCtxChanged )( void );
* non-volatile context have to be stored.
* \retval - Status of the operation
*/
-SecureElementStatus_t SecureElementInit( EventNvmCtxChanged seNvmCtxChanged );
+SecureElementStatus_t SecureElementInit( SecureElementNvmEvent seNvmCtxChanged );
/*!
* Restores the internal nvm context from passed pointer.
@@ -114,15 +142,16 @@ void* SecureElementGetNvmCtx( size_t* seNvmCtxSize );
SecureElementStatus_t SecureElementSetKey( KeyIdentifier_t keyID, uint8_t* key );
/*!
- * Computes a CMAC
+ * Computes a CMAC of a message using provided initial Bx block
*
+ * \param[IN] micBxBuffer - Buffer containing the initial Bx block
* \param[IN] buffer - Data buffer
* \param[IN] size - Data buffer size
* \param[IN] keyID - Key identifier to determine the AES key to be used
* \param[OUT] cmac - Computed cmac
* \retval - Status of the operation
*/
-SecureElementStatus_t SecureElementComputeAesCmac( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID, uint32_t* cmac );
+SecureElementStatus_t SecureElementComputeAesCmac( uint8_t* micBxBuffer, uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID, uint32_t* cmac );
/*!
* Verifies a CMAC (computes and compare with expected cmac)
@@ -157,6 +186,22 @@ SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, K
*/
SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t* input, KeyIdentifier_t rootKeyID, KeyIdentifier_t targetKeyID );
+/*!
+ * Process JoinAccept message.
+ *
+ * \param[IN] encJoinAccept - Received encrypted JoinAccept message
+ * \param[IN] encJoinAcceptSize - Received encrypted JoinAccept message Size
+ * \param[OUT] decJoinAccept - Decrypted and validated JoinAccept message
+ * \param[OUT] versionMinor - Detected LoRaWAN specification version minor field.
+ * - 0 -> LoRaWAN 1.0.x
+ * - 1 -> LoRaWAN 1.1.x
+ * \retval - Status of the operation
+ */
+SecureElementStatus_t SecureElementProcessJoinAccept( JoinReqIdentifier_t joinReqType, uint8_t* joinEui,
+ uint16_t devNonce, uint8_t* encJoinAccept,
+ uint8_t encJoinAcceptSize, uint8_t* decJoinAccept,
+ uint8_t* versionMinor );
+
/*!
* Generates a random number
*
@@ -165,4 +210,55 @@ SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t
*/
SecureElementStatus_t SecureElementRandomNumber( uint32_t* randomNum );
+/*!
+ * Sets the DevEUI
+ *
+ * \param[IN] devEui - Pointer to the 8-byte devEUI
+ * \retval - Status of the operation
+ */
+SecureElementStatus_t SecureElementSetDevEui( uint8_t* devEui );
+
+/*!
+ * Gets the DevEUI
+ *
+ * \retval - Pointer to the 8-byte devEUI
+ */
+uint8_t* SecureElementGetDevEui( void );
+
+/*!
+ * Sets the JoinEUI
+ *
+ * \param[IN] joinEui - Pointer to the 8-byte joinEui
+ * \retval - Status of the operation
+ */
+SecureElementStatus_t SecureElementSetJoinEui( uint8_t* joinEui );
+
+/*!
+ * Gets the DevEUI
+ *
+ * \retval - Pointer to the 8-byte joinEui
+ */
+uint8_t* SecureElementGetJoinEui( void );
+
+/*!
+ * Sets the pin
+ *
+ * \param[IN] pin - Pointer to the 4-byte pin
+ * \retval - Status of the operation
+ */
+SecureElementStatus_t SecureElementSetPin( uint8_t* pin );
+
+/*!
+ * Gets the Pin
+ *
+ * \retval - Pointer to the 4-byte pin
+ */
+uint8_t* SecureElementGetPin( void );
+
+/*! \} defgroup SECUREELEMENT */
+
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SECURE_ELEMENT_H__
diff --git a/components/connectivity/LoraWAN/peripherals/CMakeLists.txt b/components/connectivity/LoraWAN/peripherals/CMakeLists.txt
index ce83c2fb..a62f6e44 100644
--- a/components/connectivity/LoraWAN/peripherals/CMakeLists.txt
+++ b/components/connectivity/LoraWAN/peripherals/CMakeLists.txt
@@ -22,17 +22,62 @@ cmake_minimum_required(VERSION 3.6)
# Target
#---------------------------------------------------------------------------------------
-file(GLOB ${PROJECT_NAME}_SOURCES "*.c"
- "soft-se/*.c")
+if(${SECURE_ELEMENT} MATCHES SOFT_SE)
+ file(GLOB ${PROJECT_NAME}_SOURCES "*.c" "soft-se/*.c")
+else()
+ if(${SECURE_ELEMENT} MATCHES LR1110_SE)
+ if (${RADIO} MATCHES lr1110)
+ file(GLOB ${PROJECT_NAME}_SOURCES "*.c" "lr1110-se/*.c")
+ else()
+ message(FATAL_ERROR "LR1110_SE secure elemeent can only be used when LR1110 radio is selected.")
+ endif()
+ elseif((${SECURE_ELEMENT} MATCHES ATECC608A_TNGLORA_SE))
+ file(GLOB ${PROJECT_NAME}_SOURCES "*.c"
+ "atecc608a-tnglora-se/*.c"
+ "atecc608a-tnglora-se/cryptoauthlib/lib/*.c"
+ "atecc608a-tnglora-se/cryptoauthlib/lib/basic/*.c"
+ "atecc608a-tnglora-se/cryptoauthlib/lib/crypto/*.c"
+ "atecc608a-tnglora-se/cryptoauthlib/lib/crypto/hashes/*.c"
+ "atecc608a-tnglora-se/cryptoauthlib/lib/hal/atca_hal.c"
+ "atecc608a-tnglora-se/cryptoauthlib/lib/host/*.c"
+ )
+ else()
+ message(FATAL_ERROR "No secure-element selected.")
+ endif()
+endif()
add_library(${PROJECT_NAME} OBJECT EXCLUDE_FROM_ALL ${${PROJECT_NAME}_SOURCES})
+if(${SECURE_ELEMENT_PRE_PROVISIONED} MATCHES ON)
+ target_compile_definitions(${PROJECT_NAME} PRIVATE -DSECURE_ELEMENT_PRE_PROVISIONED)
+endif()
+
+if(${SECURE_ELEMENT} MATCHES SOFT_SE)
+ target_include_directories( ${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/soft-se)
+else()
+ if(${SECURE_ELEMENT} MATCHES LR1110_SE)
+ if(${RADIO} MATCHES lr1110)
+ target_include_directories( ${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/lr1110-se)
+ endif()
+ elseif((${SECURE_ELEMENT} MATCHES ATECC608A_TNGLORA_SE))
+ target_include_directories( ${PROJECT_NAME} PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se
+ ${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se/cryptoauthlib/lib
+ ${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se/cryptoauthlib/lib/basic
+ ${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se/cryptoauthlib/lib/crypto
+ ${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se/cryptoauthlib/lib/crypto/hashes
+ ${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se/cryptoauthlib/lib/hal
+ ${CMAKE_CURRENT_SOURCE_DIR}/atecc608a-tnglora-se/cryptoauthlib/lib/host
+ )
+ endif()
+endif()
+
target_include_directories( ${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}/soft-se
$
$
$
+ $
)
set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11)
diff --git a/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/atca_config.h b/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/atca_config.h
new file mode 100644
index 00000000..9b06e20b
--- /dev/null
+++ b/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/atca_config.h
@@ -0,0 +1,27 @@
+/* Cryptoauthlib Configuration File */
+#ifndef ATCA_CONFIG_H
+#define ATCA_CONFIG_H
+
+/* Include HALS */
+#define ATCA_HAL_I2C
+
+/* Included device support */
+#define ATCA_ATECC608A_SUPPORT
+
+/* ATECC608A I2C bus configuration */
+#define ATCA_HAL_ATECC608A_I2C_FREQUENCY 100000U
+#define ATCA_HAL_ATECC608A_I2C_BUS_PINS 2U
+#define ATCA_HAL_ATECC608A_I2C_ADDRESS 0x59U
+#define ATCA_HAL_ATECC608A_I2C_RX_RETRIES 20
+#define ATCA_HAL_ATECC608A_I2C_WAKEUP_DELAY 1500U
+
+/* \brief How long to wait after an initial wake failure for the POST to
+ * complete.
+ * If Power-on self test (POST) is enabled, the self test will run on waking
+ * from sleep or during power-on, which delays the wake reply.
+ */
+#ifndef ATCA_POST_DELAY_MSEC
+#define ATCA_POST_DELAY_MSEC 25
+#endif
+
+#endif
\ No newline at end of file
diff --git a/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se-hal.c b/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se-hal.c
new file mode 100644
index 00000000..2966b81f
--- /dev/null
+++ b/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se-hal.c
@@ -0,0 +1,299 @@
+/**
+ * @file atecc608a-tnglora-se-hal.c
+ *
+ * @brief Secure Element hardware abstraction layer implementation
+ *
+ * @remark Current implementation only supports LoRaWAN 1.0.x version
+ *
+ * @copyright Copyright (c) 2020 The Things Industries B.V.
+ *
+ * Revised BSD License
+ * Copyright The Things Industries B.V 2020. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Things Industries B.V nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE THINGS INDUSTRIES B.V BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+#include
+
+#include "atca_hal.h"
+#include "atca_device.h"
+#include "atca_execution.h"
+#include "atca_status.h"
+#include "i2c-board.h"
+#include "delay.h"
+
+#include "radio.h"
+
+#include "atecc608a-tnglora-se-hal.h"
+
+uint32_t ATECC608ASeHalGetRandomNumber( void )
+{
+ return Radio.Random( );
+}
+
+/** @brief This function delays for a number of microseconds.
+ *
+ * @param[in] delay number of 0.001 milliseconds to delay
+ */
+void atca_delay_us(uint32_t delay)
+{
+ // use ASF supplied delay
+ DelayMs(delay / 1000);
+}
+
+/** @brief This function delays for a number of tens of microseconds.
+ *
+ * @param[in] delay number of 0.01 milliseconds to delay
+ */
+void atca_delay_10us(uint32_t delay)
+{
+ // use ASF supplied delay
+ DelayMs(delay / 100);
+}
+
+/** @brief This function delays for a number of milliseconds.
+ *
+ * You can override this function if you like to do
+ * something else in your system while delaying.
+ * @param[in] delay number of milliseconds to delay
+ */
+void atca_delay_ms(uint32_t delay)
+{
+ // use ASF supplied delay
+ DelayMs(delay);
+}
+
+/** @brief discover i2c buses available for this hardware
+ * this maintains a list of logical to physical bus mappings freeing the application
+ * of the a-priori knowledge
+ * @param[in] i2c_buses - an array of logical bus numbers
+ * @param[in] max_buses - maximum number of buses the app wants to attempt to discover
+ * @return ATCA_SUCCESS
+ */
+
+ATCA_STATUS hal_i2c_discover_buses(int i2c_buses[], int max_buses)
+{
+ return ATCA_SUCCESS;
+}
+
+/** @brief discover any CryptoAuth devices on a given logical bus number
+ * @param[in] bus_num logical bus number on which to look for CryptoAuth devices
+ * @param[out] cfg pointer to head of an array of interface config structures which get filled in by this method
+ * @param[out] found number of devices found on this bus
+ * @return ATCA_SUCCESS
+ */
+
+ATCA_STATUS hal_i2c_discover_devices(int bus_num, ATCAIfaceCfg cfg[], int *found)
+{
+ return ATCA_SUCCESS;
+}
+
+/** @brief
+ - this HAL implementation assumes you've included the ASF SERCOM I2C libraries in your project, otherwise,
+ the HAL layer will not compile because the ASF I2C drivers are a dependency *
+ */
+
+/** @brief hal_i2c_init manages requests to initialize a physical interface. it manages use counts so when an interface
+ * has released the physical layer, it will disable the interface for some other use.
+ * You can have multiple ATCAIFace instances using the same bus, and you can have multiple ATCAIFace instances on
+ * multiple i2c buses, so hal_i2c_init manages these things and ATCAIFace is abstracted from the physical details.
+ */
+
+/** @brief initialize an I2C interface using given config
+ * @param[in] hal - opaque ptr to HAL data
+ * @param[in] cfg - interface configuration
+ * @return ATCA_SUCCESS on success, otherwise an error code.
+ */
+ATCA_STATUS hal_i2c_init(void *hal, ATCAIfaceCfg *cfg)
+{
+ return ATCA_SUCCESS;
+}
+
+/** @brief HAL implementation of I2C post init
+ * @param[in] iface instance
+ * @return ATCA_SUCCESS
+ */
+ATCA_STATUS hal_i2c_post_init(ATCAIface iface)
+{
+ return ATCA_SUCCESS;
+}
+
+/** @brief HAL implementation of I2C send over ASF
+ * @param[in] iface instance
+ * @param[in] txdata pointer to space to bytes to send
+ * @param[in] txlength number of bytes to send
+ * @return ATCA_SUCCESS on success, otherwise an error code.
+ */
+
+ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength)
+{
+
+ txdata[0] = 0x3;
+ txlength++;
+ if (I2cMcuWriteBuffer((I2c_t *)NULL, iface->mIfaceCFG->atcai2c.slave_address, 0, txdata, (size_t)txlength) == 1)
+ {
+ return ATCA_SUCCESS;
+ }
+ else
+ {
+ return ATCA_TX_FAIL;
+ }
+}
+
+/** @brief HAL implementation of I2C receive function for ASF I2C
+ * @param[in] iface Device to interact with.
+ * @param[out] rxdata Data received will be returned here.
+ * @param[inout] rxlength As input, the size of the rxdata buffer.
+ * As output, the number of bytes received.
+ * @return ATCA_SUCCESS on success, otherwise an error code.
+ */
+ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength)
+{
+ // read procedure is:
+ // 1. read 1 byte, this will be the length of the package
+ // 2. read the rest of the package
+
+ uint8_t lengthPackage[1] = {0};
+ int r = -1;
+ int retries = iface->mIfaceCFG->rx_retries;
+ while (--retries > 0 && r != 1)
+ {
+ r = I2cMcuReadBuffer((I2c_t *)NULL, iface->mIfaceCFG->atcai2c.slave_address, 0, lengthPackage, 1);
+ }
+
+ if (r != 1)
+ {
+ return ATCA_RX_TIMEOUT;
+ }
+
+ uint8_t bytesToRead = lengthPackage[0] - 1;
+
+ if (bytesToRead > *rxlength)
+ {
+ printf("hal_i2c_receive buffer too small, requested %u, but have %u", bytesToRead, *rxlength);
+ return ATCA_SMALL_BUFFER;
+ }
+
+ memset(rxdata, 0, *rxlength);
+ rxdata[0] = lengthPackage[0];
+
+ r = -1;
+ retries = iface->mIfaceCFG->rx_retries;
+ while (--retries > 0 && r != 1)
+ {
+ r = I2cMcuReadBuffer((I2c_t *)NULL, iface->mIfaceCFG->atcai2c.slave_address, 0, rxdata + 1, bytesToRead);
+ }
+
+ if (r != 1)
+ {
+ return ATCA_RX_TIMEOUT;
+ }
+
+ *rxlength = lengthPackage[0];
+
+ return ATCA_SUCCESS;
+}
+
+/** @brief method to change the bus speec of I2C
+ * @param[in] iface interface on which to change bus speed
+ * @param[in] speed baud rate (typically 100000 or 400000)
+ */
+
+void change_i2c_speed(ATCAIface iface, uint32_t speed)
+{
+ return;
+}
+
+/** @brief wake up CryptoAuth device using I2C bus
+ * @param[in] iface interface to logical device to wakeup
+ * @return ATCA_SUCCESS on success, otherwise an error code.
+ */
+
+ATCA_STATUS hal_i2c_wake(ATCAIface iface)
+{
+ // 2. Send NULL buffer to address 0x0 (NACK)
+ uint8_t emptybuff[1] = {0};
+ int r = I2cMcuWriteBuffer((I2c_t *)NULL, 0x00, 0, emptybuff, (size_t)0);
+
+ // 3. Wait for wake_delay
+ atca_delay_us(iface->mIfaceCFG->wake_delay);
+
+ uint8_t rx_buffer[4] = {0};
+
+ // 4. Read from normal slave_address
+ r = -1;
+ int retries = iface->mIfaceCFG->rx_retries;
+ while (--retries > 0 && r != 1)
+ {
+ r = I2cMcuReadBuffer((I2c_t *)NULL, iface->mIfaceCFG->atcai2c.slave_address, 0, rx_buffer, 4);
+ }
+
+ // 5. Set frequency back to requested one
+ const uint8_t expected_response[4] = {0x04, 0x11, 0x33, 0x43};
+ uint8_t selftest_fail_resp[4] = {0x04, 0x07, 0xC4, 0x40};
+
+ if (memcmp(rx_buffer, expected_response, 4) == 0)
+ {
+ return ATCA_SUCCESS;
+ }
+ if (memcmp(rx_buffer, selftest_fail_resp, 4) == 0)
+ {
+ return ATCA_STATUS_SELFTEST_ERROR;
+ }
+ return ATCA_WAKE_FAILED;
+}
+
+/** @brief idle CryptoAuth device using I2C bus
+ * @param[in] iface interface to logical device to idle
+ * @return ATCA_SUCCESS on success, otherwise an error code.
+ */
+
+ATCA_STATUS hal_i2c_idle(ATCAIface iface)
+{
+ uint8_t buffer[1] = { 0x2 }; // idle word address value
+ I2cMcuWriteBuffer((I2c_t*)NULL, iface->mIfaceCFG->atcai2c.slave_address,0, buffer, (size_t)1);
+ return ATCA_SUCCESS;
+}
+
+/** @brief sleep CryptoAuth device using I2C bus
+ * @param[in] iface interface to logical device to sleep
+ * @return ATCA_SUCCESS on success, otherwise an error code.
+ */
+
+ATCA_STATUS hal_i2c_sleep(ATCAIface iface)
+{
+ uint8_t buffer[1] = { 0x1 }; // sleep word address value
+ I2cMcuWriteBuffer((I2c_t*)NULL, iface->mIfaceCFG->atcai2c.slave_address,0, buffer, (size_t)1);
+ return ATCA_SUCCESS;
+}
+
+/** @brief manages reference count on given bus and releases resource if no more refences exist
+ * @param[in] hal_data - opaque pointer to hal data structure - known only to the HAL implementation
+ * return ATCA_SUCCESS
+ */
+
+ATCA_STATUS hal_i2c_release(void *hal_data)
+{
+ return ATCA_SUCCESS;
+}
diff --git a/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se-hal.h b/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se-hal.h
new file mode 100644
index 00000000..aaa093df
--- /dev/null
+++ b/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se-hal.h
@@ -0,0 +1,58 @@
+/**
+ * @file atecc608a-tnglora-se-hal.h
+ *
+ * @brief Secure Element hardware abstraction layer
+ *
+ * @remark Current implementation only supports LoRaWAN 1.0.x version
+ *
+ * @copyright Copyright (c) 2020 The Things Industries B.V.
+ *
+ * Revised BSD License
+ * Copyright The Things Industries B.V 2020. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Things Industries B.V nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE THINGS INDUSTRIES B.V BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __ATECC608A_TNGLORA_SE_HAL_H__
+#define __ATECC608A_TNGLORA_SE_HAL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+
+/*!
+ * \brief Get a random number
+ *
+ * \remark The number SHALL NOT be generated using a pseudo random number
+ * generator
+ * \retval number 32 bit random value
+ */
+uint32_t ATECC608ASeHalGetRandomNumber( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __ATECC608A_TNGLORA_SE_HAL_H__
diff --git a/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se.c b/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se.c
new file mode 100644
index 00000000..8f2290a8
--- /dev/null
+++ b/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/atecc608a-tnglora-se.c
@@ -0,0 +1,644 @@
+/**
+ * @file atecc608a-tnglora-se.c
+ *
+ * @brief ATECC608A-TNGLORA Secure Element hardware implementation
+ *
+ * @remark Current implementation only supports LoRaWAN 1.0.x version
+ *
+ * @copyright Copyright (c) 2020 The Things Industries B.V.
+ *
+ * Revised BSD License
+ * Copyright The Things Industries B.V 2020. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Things Industries B.V nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE THINGS INDUSTRIES B.V BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "atca_basic.h"
+#include "cryptoauthlib.h"
+#include "atca_devtypes.h"
+
+#include "secure-element.h"
+#include "se-identity.h"
+#include "atecc608a-tnglora-se-hal.h"
+
+/*!
+ * Number of supported crypto keys
+ */
+#define NUM_OF_KEYS 15
+
+#define DEV_EUI_ASCII_SIZE_BYTE 16U
+
+/*!
+ * Identifier value pair type for Keys
+ */
+typedef struct sKey
+{
+ /*
+ * Key identifier (used for maping the stack MAC key to the ATECC608A-TNGLoRaWAN slot)
+ */
+ KeyIdentifier_t KeyID;
+ /*
+ * Key slot number
+ */
+ uint16_t KeySlotNumber;
+ /*
+ * Key block index within slot (each block can contain two keys, so index is either 0 or 1)
+ */
+ uint8_t KeyBlockIndex;
+} Key_t;
+
+/*
+ * Secure Element Non Volatile Context structure
+ */
+typedef struct sSecureElementNvCtx
+{
+ /*!
+ * DevEUI storage
+ */
+ uint8_t DevEui[SE_EUI_SIZE];
+ /*!
+ * Join EUI storage
+ */
+ uint8_t JoinEui[SE_EUI_SIZE];
+ /*!
+ * Pin storage
+ */
+ uint8_t Pin[SE_PIN_SIZE];
+ /*!
+ * LoRaWAN key list
+ */
+ Key_t KeyList[NUM_OF_KEYS];
+} SecureElementNvCtx_t;
+
+/*!
+ * Secure element context
+ */
+static SecureElementNvCtx_t SeNvmCtx = {
+ /*!
+ * end-device IEEE EUI (big endian)
+ */
+ .DevEui = { 0 },
+ /*!
+ * App/Join server IEEE EUI (big endian)
+ */
+ .JoinEui = { 0 },
+ /*!
+ * Secure-element pin (big endian)
+ */
+ .Pin = SECURE_ELEMENT_PIN,
+ /*!
+ * LoRaWAN key list
+ */
+ .KeyList = ATECC608A_SE_KEY_LIST
+};
+
+static SecureElementNvmEvent SeNvmCtxChanged;
+
+static ATCAIfaceCfg atecc608_i2c_config;
+
+static ATCA_STATUS convert_ascii_devEUI( uint8_t* devEUI_ascii, uint8_t* devEUI );
+
+static ATCA_STATUS atcab_read_joinEUI( uint8_t* joinEUI )
+{
+ ATCA_STATUS status = ATCA_GEN_FAIL;
+ uint8_t read_buf[ATCA_BLOCK_SIZE];
+
+ if( joinEUI == NULL )
+ {
+ return ATCA_BAD_PARAM;
+ }
+
+ do
+ {
+ status = atcab_read_zone( ATCA_ZONE_DATA, TNGLORA_JOIN_EUI_SLOT, 0, 0, read_buf, ATCA_BLOCK_SIZE );
+ if( status != ATCA_SUCCESS )
+ {
+ break;
+ }
+ memcpy1( joinEUI, read_buf, SE_EUI_SIZE );
+ } while( 0 );
+
+ return status;
+}
+
+static ATCA_STATUS atcab_read_ascii_devEUI( uint8_t* devEUI_ascii )
+{
+ ATCA_STATUS status = ATCA_GEN_FAIL;
+ uint8_t read_buf[ATCA_BLOCK_SIZE];
+
+ if( devEUI_ascii == NULL )
+ {
+ return ATCA_BAD_PARAM;
+ }
+
+ do
+ {
+ status = atcab_read_zone( ATCA_ZONE_DATA, TNGLORA_DEV_EUI_SLOT, 0, 0, read_buf, ATCA_BLOCK_SIZE );
+ if( status != ATCA_SUCCESS )
+ {
+ break;
+ }
+ memcpy1( devEUI_ascii, read_buf, DEV_EUI_ASCII_SIZE_BYTE );
+ } while( 0 );
+
+ return status;
+}
+
+static ATCA_STATUS convert_ascii_devEUI( uint8_t* devEUI_ascii, uint8_t* devEUI )
+{
+ for( size_t pos = 0; pos < DEV_EUI_ASCII_SIZE_BYTE; pos += 2 )
+ {
+ uint8_t temp = 0;
+ if( ( devEUI_ascii[pos] >= '0' ) && ( devEUI_ascii[pos] <= '9' ) )
+ {
+ temp = ( devEUI_ascii[pos] - '0' ) << 4;
+ }
+ else if( ( devEUI_ascii[pos] >= 'A' ) && ( devEUI_ascii[pos] <= 'F' ) )
+ {
+ temp = ( ( devEUI_ascii[pos] - 'A' ) + 10 ) << 4;
+ }
+ else
+ {
+ return ATCA_BAD_PARAM;
+ }
+ if( ( devEUI_ascii[pos + 1] >= '0' ) && ( devEUI_ascii[pos + 1] <= '9' ) )
+ {
+ temp |= devEUI_ascii[pos + 1] - '0';
+ }
+ else if( ( devEUI_ascii[pos + 1] >= 'A' ) && ( devEUI_ascii[pos + 1] <= 'F' ) )
+ {
+ temp |= ( devEUI_ascii[pos + 1] - 'A' ) + 10;
+ }
+ else
+ {
+ return ATCA_BAD_PARAM;
+ }
+ devEUI[pos / 2] = temp;
+ }
+ return ATCA_SUCCESS;
+}
+
+static ATCA_STATUS atcab_read_devEUI( uint8_t* devEUI )
+{
+ ATCA_STATUS status = ATCA_GEN_FAIL;
+ uint8_t devEUI_ascii[DEV_EUI_ASCII_SIZE_BYTE];
+
+ status = atcab_read_ascii_devEUI( devEUI_ascii );
+ if( status != ATCA_SUCCESS )
+ {
+ return status;
+ }
+ status = convert_ascii_devEUI( devEUI_ascii, devEUI );
+ return status;
+}
+
+/*
+ * Gets key item from key list.
+ *
+ * cmac = aes128_cmac(keyID, B0 | msg)
+ *
+ * \param[IN] keyID - Key identifier
+ * \param[OUT] keyItem - Key item reference
+ * \retval - Status of the operation
+ */
+SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t** keyItem )
+{
+ for( uint8_t i = 0; i < NUM_OF_KEYS; i++ )
+ {
+ if( SeNvmCtx.KeyList[i].KeyID == keyID )
+ {
+ *keyItem = &( SeNvmCtx.KeyList[i] );
+ return SECURE_ELEMENT_SUCCESS;
+ }
+ }
+ return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
+}
+
+/*
+ * Dummy callback in case if the user provides NULL function pointer
+ */
+static void DummyCB( void )
+{
+ return;
+}
+
+/*
+ * Computes a CMAC of a message using provided initial Bx block
+ *
+ * cmac = aes128_cmac(keyID, blocks[i].Buffer)
+ *
+ * \param[IN] micBxBuffer - Buffer containing the initial Bx block
+ * \param[IN] buffer - Data buffer
+ * \param[IN] size - Data buffer size
+ * \param[IN] keyID - Key identifier to determine the AES key to be used
+ * \param[OUT] cmac - Computed cmac
+ * \retval - Status of the operation
+ */
+static SecureElementStatus_t ComputeCmac( uint8_t* micBxBuffer, uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID,
+ uint32_t* cmac )
+{
+ if( ( buffer == NULL ) || ( cmac == NULL ) )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ uint8_t Cmac[16] = { 0 };
+
+ Key_t* keyItem;
+ SecureElementStatus_t retval = GetKeyByID( keyID, &keyItem );
+ if( retval != SECURE_ELEMENT_SUCCESS )
+ {
+ return retval;
+ }
+
+ atca_aes_cmac_ctx_t atcaAesCmacCtx;
+ ATCA_STATUS status =
+ atcab_aes_cmac_init( &atcaAesCmacCtx, keyItem->KeySlotNumber, keyItem->KeyBlockIndex );
+
+ if( ATCA_SUCCESS == status )
+ {
+ if( micBxBuffer != NULL )
+ {
+ atcab_aes_cmac_update( &atcaAesCmacCtx, micBxBuffer, 16 );
+ }
+
+ atcab_aes_cmac_update( &atcaAesCmacCtx, buffer, size );
+
+ atcab_aes_cmac_finish( &atcaAesCmacCtx, Cmac, 16 );
+
+ *cmac = ( uint32_t )( ( uint32_t ) Cmac[3] << 24 | ( uint32_t ) Cmac[2] << 16 | ( uint32_t ) Cmac[1] << 8 |
+ ( uint32_t ) Cmac[0] );
+ return SECURE_ELEMENT_SUCCESS;
+ }
+ else
+ {
+ return SECURE_ELEMENT_ERROR;
+ }
+}
+
+SecureElementStatus_t SecureElementInit( SecureElementNvmEvent seNvmCtxChanged )
+{
+#if !defined( SECURE_ELEMENT_PRE_PROVISIONED )
+#error "ATECC608A is always pre-provisioned. Please set SECURE_ELEMENT_PRE_PROVISIONED to ON"
+#endif
+ atecc608_i2c_config.iface_type = ATCA_I2C_IFACE;
+ atecc608_i2c_config.atcai2c.baud = ATCA_HAL_ATECC608A_I2C_FREQUENCY;
+ atecc608_i2c_config.atcai2c.bus = ATCA_HAL_ATECC608A_I2C_BUS_PINS;
+ atecc608_i2c_config.atcai2c.slave_address = ATCA_HAL_ATECC608A_I2C_ADDRESS;
+ atecc608_i2c_config.devtype = ATECC608A;
+ atecc608_i2c_config.rx_retries = ATCA_HAL_ATECC608A_I2C_RX_RETRIES;
+ atecc608_i2c_config.wake_delay = ATCA_HAL_ATECC608A_I2C_WAKEUP_DELAY;
+
+ if( atcab_init( &atecc608_i2c_config ) != ATCA_SUCCESS )
+ {
+ return SECURE_ELEMENT_ERROR;
+ }
+
+ if( atcab_read_devEUI( SeNvmCtx.DevEui ) != ATCA_SUCCESS )
+ {
+ return SECURE_ELEMENT_ERROR;
+ }
+
+ if( atcab_read_joinEUI( SeNvmCtx.JoinEui ) != ATCA_SUCCESS )
+ {
+ return SECURE_ELEMENT_ERROR;
+ }
+
+ // Assign callback
+ if( seNvmCtxChanged != 0 )
+ {
+ SeNvmCtxChanged = seNvmCtxChanged;
+ }
+ else
+ {
+ SeNvmCtxChanged = DummyCB;
+ }
+
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+SecureElementStatus_t SecureElementRestoreNvmCtx( void* seNvmCtx )
+{
+ // Restore nvm context
+ if( seNvmCtx != 0 )
+ {
+ memcpy1( ( uint8_t* ) &SeNvmCtx, ( uint8_t* ) seNvmCtx, sizeof( SeNvmCtx ) );
+ return SECURE_ELEMENT_SUCCESS;
+ }
+ else
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+}
+
+void* SecureElementGetNvmCtx( size_t* seNvmCtxSize )
+{
+ *seNvmCtxSize = sizeof( SeNvmCtx );
+ return &SeNvmCtx;
+}
+
+SecureElementStatus_t SecureElementSetKey( KeyIdentifier_t keyID, uint8_t* key )
+{
+ // No key setting for HW SE, can only derive keys
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+SecureElementStatus_t SecureElementComputeAesCmac( uint8_t* micBxBuffer, uint8_t* buffer, uint16_t size,
+ KeyIdentifier_t keyID, uint32_t* cmac )
+{
+ if( keyID >= LORAMAC_CRYPTO_MULTICAST_KEYS )
+ {
+ // Never accept multicast key identifier for cmac computation
+ return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
+ }
+ return ComputeCmac( micBxBuffer, buffer, size, keyID, cmac );
+}
+
+SecureElementStatus_t SecureElementVerifyAesCmac( uint8_t* buffer, uint16_t size, uint32_t expectedCmac,
+ KeyIdentifier_t keyID )
+{
+ if( buffer == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
+ uint32_t compCmac = 0;
+
+ retval = ComputeCmac( NULL, buffer, size, keyID, &compCmac );
+ if( retval != SECURE_ELEMENT_SUCCESS )
+ {
+ return retval;
+ }
+
+ if( expectedCmac != compCmac )
+ {
+ retval = SECURE_ELEMENT_FAIL_CMAC;
+ }
+
+ return retval;
+}
+
+SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID,
+ uint8_t* encBuffer )
+{
+ if( buffer == NULL || encBuffer == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ // Check if the size is divisible by 16,
+ if( ( size % 16 ) != 0 )
+ {
+ return SECURE_ELEMENT_ERROR_BUF_SIZE;
+ }
+
+ Key_t* pItem;
+ SecureElementStatus_t retval = GetKeyByID( keyID, &pItem );
+
+ if( retval == SECURE_ELEMENT_SUCCESS )
+ {
+ uint8_t block = 0;
+
+ while( size != 0 )
+ {
+ atcab_aes_encrypt( pItem->KeySlotNumber, pItem->KeyBlockIndex, &buffer[block], &encBuffer[block] );
+ block = block + 16;
+ size = size - 16;
+ }
+ }
+ return retval;
+}
+
+SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t* input, KeyIdentifier_t rootKeyID,
+ KeyIdentifier_t targetKeyID )
+{
+ if( input == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ // Source key slot is the LSB and target key slot is the MSB
+ uint16_t source_target_ids = 0;
+ Key_t* source_key;
+ Key_t* target_key;
+ ATCA_STATUS status = ATCA_SUCCESS;
+
+ // In case of MC_KE_KEY, only McRootKey can be used as root key
+ if( targetKeyID == MC_KE_KEY )
+ {
+ if( rootKeyID != MC_ROOT_KEY )
+ {
+ return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
+ }
+ }
+
+ if( ( rootKeyID == APP_KEY ) || ( rootKeyID == MC_ROOT_KEY ) || ( rootKeyID == MC_KE_KEY ) )
+ {
+ // Allow the stack to move forward as these rootkeys dont exist inside SE.
+ return SECURE_ELEMENT_SUCCESS;
+ }
+
+ if( GetKeyByID( rootKeyID, &source_key ) != SECURE_ELEMENT_SUCCESS )
+ {
+ return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
+ }
+
+ if( GetKeyByID( targetKeyID, &target_key ) != SECURE_ELEMENT_SUCCESS )
+ {
+ return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
+ }
+
+ source_target_ids = target_key->KeySlotNumber << 8;
+ source_target_ids += source_key->KeySlotNumber;
+
+ uint32_t detail = source_key->KeyBlockIndex;
+
+ status = atcab_kdf( KDF_MODE_ALG_AES | KDF_MODE_SOURCE_SLOT | KDF_MODE_TARGET_SLOT, source_target_ids, detail,
+ input, NULL, NULL );
+ if( status == ATCA_SUCCESS )
+ {
+ return SECURE_ELEMENT_SUCCESS;
+ }
+ else
+ {
+ return SECURE_ELEMENT_ERROR;
+ }
+}
+
+SecureElementStatus_t SecureElementProcessJoinAccept( JoinReqIdentifier_t joinReqType, uint8_t* joinEui,
+ uint16_t devNonce, uint8_t* encJoinAccept,
+ uint8_t encJoinAcceptSize, uint8_t* decJoinAccept,
+ uint8_t* versionMinor )
+{
+ if( ( encJoinAccept == NULL ) || ( decJoinAccept == NULL ) || ( versionMinor == NULL ) )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ // Check that frame size isn't bigger than a JoinAccept with CFList size
+ if( encJoinAcceptSize > LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE )
+ {
+ return SECURE_ELEMENT_ERROR_BUF_SIZE;
+ }
+
+ // Determine decryption key
+ KeyIdentifier_t encKeyID = NWK_KEY;
+
+ if( joinReqType != JOIN_REQ )
+ {
+ encKeyID = J_S_ENC_KEY;
+ }
+
+ memcpy1( decJoinAccept, encJoinAccept, encJoinAcceptSize );
+
+ // Decrypt JoinAccept, skip MHDR
+ if( SecureElementAesEncrypt( encJoinAccept + LORAMAC_MHDR_FIELD_SIZE, encJoinAcceptSize - LORAMAC_MHDR_FIELD_SIZE,
+ encKeyID, decJoinAccept + LORAMAC_MHDR_FIELD_SIZE ) != SECURE_ELEMENT_SUCCESS )
+ {
+ return SECURE_ELEMENT_FAIL_ENCRYPT;
+ }
+
+ *versionMinor = ( ( decJoinAccept[11] & 0x80 ) == 0x80 ) ? 1 : 0;
+
+ uint32_t mic = 0;
+
+ mic = ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE] << 0 );
+ mic |= ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE + 1] << 8 );
+ mic |= ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE + 2] << 16 );
+ mic |= ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE + 3] << 24 );
+
+ // - Header buffer to be used for MIC computation
+ // - LoRaWAN 1.0.x : micHeader = [MHDR(1)]
+ // - LoRaWAN 1.1.x : micHeader = [JoinReqType(1), JoinEUI(8), DevNonce(2), MHDR(1)]
+
+ // Verify mic
+ if( *versionMinor == 0 )
+ {
+ // For LoRaWAN 1.0.x
+ // cmac = aes128_cmac(NwkKey, MHDR | JoinNonce | NetID | DevAddr | DLSettings | RxDelay | CFList |
+ // CFListType)
+ if( SecureElementVerifyAesCmac( decJoinAccept, ( encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE ), mic, NWK_KEY ) !=
+ SECURE_ELEMENT_SUCCESS )
+ {
+ return SECURE_ELEMENT_FAIL_CMAC;
+ }
+ }
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
+ else if( *versionMinor == 1 )
+ {
+ uint8_t micHeader11[JOIN_ACCEPT_MIC_COMPUTATION_OFFSET] = { 0 };
+ uint16_t bufItr = 0;
+
+ micHeader11[bufItr++] = ( uint8_t ) joinReqType;
+
+ memcpyr( micHeader11 + bufItr, joinEui, LORAMAC_JOIN_EUI_FIELD_SIZE );
+ bufItr += LORAMAC_JOIN_EUI_FIELD_SIZE;
+
+ micHeader11[bufItr++] = devNonce & 0xFF;
+ micHeader11[bufItr++] = ( devNonce >> 8 ) & 0xFF;
+
+ // For LoRaWAN 1.1.x and later:
+ // cmac = aes128_cmac(JSIntKey, JoinReqType | JoinEUI | DevNonce | MHDR | JoinNonce | NetID | DevAddr |
+ // DLSettings | RxDelay | CFList | CFListType)
+ // Prepare the msg for integrity check (adding JoinReqType, JoinEUI and DevNonce)
+ uint8_t localBuffer[LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE + JOIN_ACCEPT_MIC_COMPUTATION_OFFSET] = { 0 };
+
+ memcpy1( localBuffer, micHeader11, JOIN_ACCEPT_MIC_COMPUTATION_OFFSET );
+ memcpy1( localBuffer + JOIN_ACCEPT_MIC_COMPUTATION_OFFSET - 1, decJoinAccept, encJoinAcceptSize );
+
+ if( SecureElementVerifyAesCmac( localBuffer,
+ encJoinAcceptSize + JOIN_ACCEPT_MIC_COMPUTATION_OFFSET -
+ LORAMAC_MHDR_FIELD_SIZE - LORAMAC_MIC_FIELD_SIZE,
+ mic, J_S_INT_KEY ) != SECURE_ELEMENT_SUCCESS )
+ {
+ return SECURE_ELEMENT_FAIL_CMAC;
+ }
+ }
+#endif
+ else
+ {
+ return SECURE_ELEMENT_ERROR_INVALID_LORAWAM_SPEC_VERSION;
+ }
+
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+SecureElementStatus_t SecureElementRandomNumber( uint32_t* randomNum )
+{
+ if( randomNum == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+ *randomNum = ATECC608ASeHalGetRandomNumber( );
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+SecureElementStatus_t SecureElementSetDevEui( uint8_t* devEui )
+{
+ if( devEui == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+ memcpy1( SeNvmCtx.DevEui, devEui, SE_EUI_SIZE );
+ SeNvmCtxChanged( );
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+uint8_t* SecureElementGetDevEui( void )
+{
+ return SeNvmCtx.DevEui;
+}
+
+SecureElementStatus_t SecureElementSetJoinEui( uint8_t* joinEui )
+{
+ if( joinEui == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+ memcpy1( SeNvmCtx.JoinEui, joinEui, SE_EUI_SIZE );
+ SeNvmCtxChanged( );
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+uint8_t* SecureElementGetJoinEui( void )
+{
+ return SeNvmCtx.JoinEui;
+}
+
+SecureElementStatus_t SecureElementSetPin( uint8_t* pin )
+{
+ if( pin == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ memcpy1( SeNvmCtx.Pin, pin, SE_PIN_SIZE );
+ SeNvmCtxChanged( );
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+uint8_t* SecureElementGetPin( void )
+{
+ return SeNvmCtx.Pin;
+}
diff --git a/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/se-identity.h b/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/se-identity.h
new file mode 100644
index 00000000..70395d06
--- /dev/null
+++ b/components/connectivity/LoraWAN/peripherals/atecc608a-tnglora-se/se-identity.h
@@ -0,0 +1,250 @@
+/*!
+ * \file se-identity.h
+ *
+ * \brief Secure Element identity and keys
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2020 Semtech
+ *
+ * ___ _____ _ ___ _ _____ ___ ___ ___ ___
+ * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
+ * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ * embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ */
+#ifndef __SOFT_SE_IDENTITY_H__
+#define __SOFT_SE_IDENTITY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ ******************************************************************************
+ ********************************** WARNING ***********************************
+ ******************************************************************************
+ The secure-element implementation supports both 1.0.x and 1.1.x LoRaWAN
+ versions of the specification.
+ Thus it has been decided to use the 1.1.x keys and EUI name definitions.
+ The below table shows the names equivalence between versions:
+ +---------------------+-------------------------+
+ | 1.0.x | 1.1.x |
+ +=====================+=========================+
+ | LORAWAN_DEVICE_EUI | LORAWAN_DEVICE_EUI |
+ +---------------------+-------------------------+
+ | LORAWAN_APP_EUI | LORAWAN_JOIN_EUI |
+ +---------------------+-------------------------+
+ | LORAWAN_GEN_APP_KEY | LORAWAN_APP_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_APP_KEY | LORAWAN_NWK_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_NWK_S_KEY | LORAWAN_F_NWK_S_INT_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_NWK_S_KEY | LORAWAN_S_NWK_S_INT_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_NWK_S_KEY | LORAWAN_NWK_S_ENC_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_APP_S_KEY | LORAWAN_APP_S_KEY |
+ +---------------------+-------------------------+
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ */
+
+/*!
+ * Secure-element pin
+ */
+#define SECURE_ELEMENT_PIN \
+ { \
+ 0x00, 0x00, 0x00, 0x00 \
+ }
+
+/*!
+ * When set to 1 DevAdd is LORAWAN_DEVICE_ADDRESS
+ * When set to 0 DevAdd is automatically generated using a pseudo random generator
+ */
+#define STATIC_DEVICE_ADDRESS 0
+
+/*!
+ * Device address on the network (big endian)
+ *
+ * \remark In this application the value is automatically generated using
+ * a pseudo random generator seeded with a value derived from
+ * BoardUniqueId value if LORAWAN_DEVICE_ADDRESS is set to 0
+ */
+#define LORAWAN_DEVICE_ADDRESS ( uint32_t ) 0x00000000
+
+/*
+ * =============================================================================
+ * BELOW LINES SHOULDN'T BE MODIFIED
+ * =============================================================================
+ */
+
+/*!
+ * ATECC608A predefined key slots setup
+ */
+#define TNGLORA_DEV_EUI_SLOT 10U
+#define TNGLORA_JOIN_EUI_SLOT 9U
+#define TNGLORA_APP_KEY_SLOT 0U
+#define TNGLORA_NWK_KEY_SLOT 0U
+#define TNGLORA_S_NWK_S_INT_KEY_SLOT 4U
+#define TNGLORA_F_NWK_S_INT_KEY_SLOT 5U
+#define TNGLORA_J_S_INT_KEY_SLOT 6U
+#define TNGLORA_J_S_ENC_KEY_SLOT 7U
+#define TNGLORA_APP_S_KEY_SLOT 2U
+#define TNGLORA_NWK_S_ENC_KEY_SLOT 3U
+#define TNGLORA_MC_APP_S_KEY_0_SLOT 11U
+#define TNGLORA_MC_NWK_S_KEY_0_SLOT 12U
+#define TNGLORA_APP_KEY_BLOCK_INDEX 1U
+#define TNGLORA_REMAINING_KEYS_BLOCK_INDEX 0U
+
+#define ATECC608A_SE_KEY_LIST \
+ { \
+ { \
+ /*! \
+ * Application root key \
+ * WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_GEN_APP_KEY \
+ */ \
+ .KeyID = APP_KEY, \
+ .KeySlotNumber = TNGLORA_APP_KEY_SLOT, \
+ .KeyBlockIndex = TNGLORA_APP_KEY_BLOCK_INDEX, \
+ }, \
+ { \
+ /*! \
+ * Network root key \
+ * WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_APP_KEY \
+ */ \
+ .KeyID = NWK_KEY, \
+ .KeySlotNumber = TNGLORA_APP_KEY_SLOT, \
+ .KeyBlockIndex = TNGLORA_APP_KEY_BLOCK_INDEX, \
+ }, \
+ { \
+ /*! \
+ * Join session integrity key (Dynamically updated) \
+ * WARNING: NOT USED FOR 1.0.x DEVICES \
+ */ \
+ .KeyID = J_S_INT_KEY, \
+ .KeySlotNumber = TNGLORA_J_S_INT_KEY_SLOT, \
+ .KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
+ }, \
+ { \
+ /*! \
+ * Join session encryption key (Dynamically updated) \
+ * WARNING: NOT USED FOR 1.0.x DEVICES \
+ */ \
+ .KeyID = J_S_ENC_KEY, \
+ .KeySlotNumber = TNGLORA_J_S_ENC_KEY_SLOT, \
+ .KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
+ }, \
+ { \
+ /*! \
+ * Forwarding Network session integrity key \
+ * WARNING: NWK_S_KEY FOR 1.0.x DEVICES \
+ */ \
+ .KeyID = F_NWK_S_INT_KEY, \
+ .KeySlotNumber = TNGLORA_F_NWK_S_INT_KEY_SLOT, \
+ .KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
+ }, \
+ { \
+ /*! \
+ * Serving Network session integrity key \
+ * WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \
+ */ \
+ .KeyID = S_NWK_S_INT_KEY, \
+ .KeySlotNumber = TNGLORA_S_NWK_S_INT_KEY_SLOT, \
+ .KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
+ }, \
+ { \
+ /*! \
+ * Network session encryption key \
+ * WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \
+ */ \
+ .KeyID = NWK_S_ENC_KEY, \
+ .KeySlotNumber = TNGLORA_NWK_S_ENC_KEY_SLOT, \
+ .KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
+ }, \
+ { \
+ /*! \
+ * Application session key \
+ */ \
+ .KeyID = APP_S_KEY, \
+ .KeySlotNumber = TNGLORA_APP_S_KEY_SLOT, \
+ .KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
+ }, \
+ { \
+ /*! \
+ * Multicast root key (Dynamically updated) \
+ * WARNING: NOT CURRENTLY SUPPORTED BY ATECC608A \
+ * TODO: Add support \
+ */ \
+ .KeyID = MC_ROOT_KEY, \
+ .KeySlotNumber = 0, \
+ .KeyBlockIndex = 0, \
+ }, \
+ { \
+ /*! \
+ * Multicast key encryption key (Dynamically updated) \
+ * WARNING: NOT CURRENTLY SUPPORTED BY ATECC608A \
+ * TODO: Add support \
+ */ \
+ .KeyID = MC_KE_KEY, \
+ .KeySlotNumber = 0, \
+ .KeyBlockIndex = 0, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #0 root key (Dynamically updated) \
+ * WARNING: NOT CURRENTLY SUPPORTED BY ATECC608A \
+ * TODO: Add support \
+ */ \
+ .KeyID = MC_KEY_0, \
+ .KeySlotNumber = 0, \
+ .KeyBlockIndex = 0, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #0 application session key (Dynamically updated) \
+ */ \
+ .KeyID = MC_APP_S_KEY_0, \
+ .KeySlotNumber = TNGLORA_MC_APP_S_KEY_0_SLOT, \
+ .KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #0 network session key (Dynamically updated) \
+ */ \
+ .KeyID = MC_NWK_S_KEY_0, \
+ .KeySlotNumber = TNGLORA_MC_NWK_S_KEY_0_SLOT, \
+ .KeyBlockIndex = TNGLORA_REMAINING_KEYS_BLOCK_INDEX, \
+ }, \
+ { \
+ /*! \
+ * All zeros key. (ClassB usage)(constant) \
+ * WARNING: NOT CURRENTLY SUPPORTED BY ATECC608A \
+ * TODO: Add support \
+ * SE should provide a slot for SLOT_RAND_ZERO_KEY. \
+ * .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ * 0x00, 0x00 } \
+ */ \
+ .KeyID = SLOT_RAND_ZERO_KEY, \
+ .KeySlotNumber = 0, \
+ .KeyBlockIndex = 0, \
+ }, \
+ },
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFT_SE_IDENTITY_H__
diff --git a/components/connectivity/LoraWAN/peripherals/gpio-ioe.h b/components/connectivity/LoraWAN/peripherals/gpio-ioe.h
index 6d933f36..51fbe463 100644
--- a/components/connectivity/LoraWAN/peripherals/gpio-ioe.h
+++ b/components/connectivity/LoraWAN/peripherals/gpio-ioe.h
@@ -23,6 +23,11 @@
#ifndef __GPIO_IOE_H__
#define __GPIO_IOE_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include "gpio.h"
@@ -95,4 +100,8 @@ uint32_t GpioIoeRead( Gpio_t *obj );
*/
void GpioIoeInterruptHandler( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __GPIO_IOE_H__
diff --git a/components/connectivity/LoraWAN/peripherals/lr1110-se/lr1110-se-hal.c b/components/connectivity/LoraWAN/peripherals/lr1110-se/lr1110-se-hal.c
new file mode 100644
index 00000000..decd5fa7
--- /dev/null
+++ b/components/connectivity/LoraWAN/peripherals/lr1110-se/lr1110-se-hal.c
@@ -0,0 +1,39 @@
+/*!
+ * \file soft-se-hal.h
+ *
+ * \brief Secure Element hardware abstraction layer implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2020 Semtech
+ *
+ * ___ _____ _ ___ _ _____ ___ ___ ___ ___
+ * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
+ * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ * embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ */
+#include "board.h"
+#include "radio.h"
+
+#include "lr1110-se-hal.h"
+
+void LR1110SeHalGetUniqueId( uint8_t *id )
+{
+ BoardGetUniqueId( id );
+}
+
+uint32_t LR1110SeHalGetRandomNumber( void )
+{
+ return Radio.Random( );
+}
diff --git a/components/connectivity/LoraWAN/peripherals/lr1110-se/lr1110-se-hal.h b/components/connectivity/LoraWAN/peripherals/lr1110-se/lr1110-se-hal.h
new file mode 100644
index 00000000..fdbe7b95
--- /dev/null
+++ b/components/connectivity/LoraWAN/peripherals/lr1110-se/lr1110-se-hal.h
@@ -0,0 +1,56 @@
+/*!
+ * \file lr1110-se-hal.h
+ *
+ * \brief Secure Element hardware abstraction layer
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2020 Semtech
+ *
+ * ___ _____ _ ___ _ _____ ___ ___ ___ ___
+ * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
+ * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ * embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ */
+#ifndef __LR1110_SE_HAL_H__
+#define __LR1110_SE_HAL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+
+/*!
+ * \brief Get a 64 bits unique ID
+ *
+ * \param [IN] id Pointer to an array that will contain the Unique ID
+ */
+void LR1110SeHalGetUniqueId( uint8_t *id );
+
+/*!
+ * \brief Get a random number
+ *
+ * \remark The number SHALL NOT be generated using a pseudo random number
+ * generator
+ * \retval number 32 bit random value
+ */
+uint32_t LR1110SeHalGetRandomNumber( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LR1110_SE_HAL_H__
diff --git a/components/connectivity/LoraWAN/peripherals/lr1110-se/lr1110-se.c b/components/connectivity/LoraWAN/peripherals/lr1110-se/lr1110-se.c
new file mode 100644
index 00000000..56e027df
--- /dev/null
+++ b/components/connectivity/LoraWAN/peripherals/lr1110-se/lr1110-se.c
@@ -0,0 +1,506 @@
+/*!
+ * \file lr1110-se.c
+ *
+ * \brief LR1110 Secure Element hardware implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2019-2019 Semtech
+ *
+ * \endcode
+ *
+ * \authors Semtech WSP Applications Team
+ */
+#include
+#include
+
+#include "lr1110.h"
+#include "lr1110_system.h"
+#include "lr1110_crypto_engine.h"
+
+#include "secure-element.h"
+#include "se-identity.h"
+#include "lr1110-se-hal.h"
+
+/*!
+ * Number of supported crypto keys
+ */
+#define NUM_OF_KEYS 23
+
+/*
+ * CMAC/AES Message Integrity Code (MIC) Block B0 size
+ */
+#define MIC_BLOCK_BX_SIZE 16
+
+/*
+ * Maximum size of the message that can be handled by the crypto operations
+ */
+#define CRYPTO_MAXMESSAGE_SIZE 256
+
+/*
+ * Maximum size of the buffer for crypto operations
+ */
+#define CRYPTO_BUFFER_SIZE CRYPTO_MAXMESSAGE_SIZE + MIC_BLOCK_BX_SIZE
+
+/*!
+ * Secure-element LoRaWAN identity local storage.
+ */
+typedef struct sSecureElementNvCtx
+{
+ /*
+ * DevEUI storage
+ */
+ uint8_t DevEui[SE_EUI_SIZE];
+ /*
+ * Join EUI storage
+ */
+ uint8_t JoinEui[SE_EUI_SIZE];
+ /*
+ * PIN of the LR1110
+ */
+ uint8_t Pin[SE_PIN_SIZE];
+} SecureElementNvCtx_t;
+
+static SecureElementNvCtx_t SeContext = {
+ /*!
+ * end-device IEEE EUI (big endian)
+ *
+ * \remark In this application the value is automatically generated by calling
+ * BoardGetUniqueId function
+ */
+ .DevEui = LORAWAN_DEVICE_EUI,
+ /*!
+ * App/Join server IEEE EUI (big endian)
+ */
+ .JoinEui = LORAWAN_JOIN_EUI,
+ /*!
+ * Secure-element pin (big endian)
+ */
+ .Pin = SECURE_ELEMENT_PIN,
+};
+
+static SecureElementNvmEvent SeNvmCtxChanged;
+
+/*!
+ * LR1110 radio context
+ */
+extern lr1110_t LR1110;
+
+/*!
+ * Converts key ids from SecureElement to LR1110
+ *
+ * \param [IN] key_id SecureElement key id to be converted
+ *
+ * \retval key_id Converted LR1110 key id
+ */
+static lr1110_crypto_keys_idx_t convert_key_id_from_se_to_lr1110( KeyIdentifier_t key_id );
+
+/*!
+ * Dummy callback in case if the user provides NULL function pointer
+ */
+static void DummyCB( void )
+{
+ return;
+}
+
+SecureElementStatus_t SecureElementInit( SecureElementNvmEvent seNvmCtxChanged )
+{
+ lr1110_crypto_status_t status = LR1110_CRYPTO_STATUS_ERROR;
+
+ // Assign callback
+ if( seNvmCtxChanged != 0 )
+ {
+ SeNvmCtxChanged = seNvmCtxChanged;
+ }
+ else
+ {
+ SeNvmCtxChanged = DummyCB;
+ }
+
+ lr1110_crypto_restore_from_flash( &LR1110, &status );
+
+#if defined( SECURE_ELEMENT_PRE_PROVISIONED )
+ // Read LR1110 pre-provisioned identity
+ lr1110_system_read_uid( &LR1110, SeContext.DevEui );
+ lr1110_system_read_join_eui( &LR1110, SeContext.JoinEui );
+ lr1110_system_read_pin( &LR1110, SeContext.Pin );
+#else
+#if( STATIC_DEVICE_EUI == 0 )
+ // Get a DevEUI from MCU unique ID
+ LR1110SeHalGetUniqueId( SeContext.DevEui );
+#endif
+#endif
+
+ SeNvmCtxChanged( );
+
+ return ( SecureElementStatus_t ) status;
+}
+
+SecureElementStatus_t SecureElementRestoreNvmCtx( void* seNvmCtx )
+{
+ lr1110_crypto_status_t status = LR1110_CRYPTO_STATUS_ERROR;
+
+ if( seNvmCtx == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ // Restore lr1110 crypto context
+ lr1110_crypto_restore_from_flash( &LR1110, &status );
+
+ // Restore nvm context
+ memcpy1( ( uint8_t* ) &SeContext, ( uint8_t* ) seNvmCtx, sizeof( SeContext ) );
+
+ return ( SecureElementStatus_t ) status;
+}
+
+void* SecureElementGetNvmCtx( size_t* seNvmCtxSize )
+{
+ *seNvmCtxSize = sizeof( SeContext );
+ return &SeContext;
+}
+
+SecureElementStatus_t SecureElementSetKey( KeyIdentifier_t keyID, uint8_t* key )
+{
+ if( key == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ SecureElementStatus_t status = SECURE_ELEMENT_ERROR;
+
+ if( ( keyID == MC_KEY_0 ) || ( keyID == MC_KEY_1 ) || ( keyID == MC_KEY_2 ) || ( keyID == MC_KEY_3 ) )
+ { // Decrypt the key if its a Mckey
+
+ lr1110_crypto_derive_and_store_key( &LR1110, ( lr1110_crypto_status_t* ) &status,
+ convert_key_id_from_se_to_lr1110( MC_KE_KEY ),
+ convert_key_id_from_se_to_lr1110( keyID ), key );
+
+ if( status == SECURE_ELEMENT_SUCCESS )
+ {
+ lr1110_crypto_store_to_flash( &LR1110, ( lr1110_crypto_status_t* ) &status );
+ }
+ return status;
+ }
+ else
+ {
+ lr1110_crypto_set_key( &LR1110, ( lr1110_crypto_status_t* ) &status, convert_key_id_from_se_to_lr1110( keyID ),
+ key );
+ if( status == SECURE_ELEMENT_SUCCESS )
+ {
+ lr1110_crypto_store_to_flash( &LR1110, ( lr1110_crypto_status_t* ) &status );
+ }
+ return status;
+ }
+}
+
+SecureElementStatus_t SecureElementComputeAesCmac( uint8_t* micBxBuffer, uint8_t* buffer, uint16_t size,
+ KeyIdentifier_t keyID, uint32_t* cmac )
+{
+ SecureElementStatus_t status = SECURE_ELEMENT_ERROR;
+ uint16_t localSize = size;
+ uint8_t* localbuffer = buffer;
+
+ if( micBxBuffer != NULL )
+ {
+ uint8_t micBuff[CRYPTO_BUFFER_SIZE];
+
+ memset1( micBuff, 0, CRYPTO_BUFFER_SIZE );
+
+ memcpy1( micBuff, micBxBuffer, MIC_BLOCK_BX_SIZE );
+ memcpy1( ( micBuff + MIC_BLOCK_BX_SIZE ), buffer, size );
+ localSize += MIC_BLOCK_BX_SIZE;
+ localbuffer = micBuff;
+ }
+
+ lr1110_crypto_compute_aes_cmac( &LR1110, ( lr1110_crypto_status_t* ) &status,
+ convert_key_id_from_se_to_lr1110( keyID ), localbuffer, localSize,
+ ( uint8_t* ) cmac );
+
+ return status;
+}
+
+SecureElementStatus_t SecureElementVerifyAesCmac( uint8_t* buffer, uint16_t size, uint32_t expectedCmac,
+ KeyIdentifier_t keyID )
+{
+ SecureElementStatus_t status = SECURE_ELEMENT_ERROR;
+
+ if( buffer == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ lr1110_crypto_verify_aes_cmac( &LR1110, ( lr1110_crypto_status_t* ) &status,
+ convert_key_id_from_se_to_lr1110( keyID ), buffer, size,
+ ( uint8_t* ) &expectedCmac );
+
+ return status;
+}
+
+SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID,
+ uint8_t* encBuffer )
+{
+ SecureElementStatus_t status = SECURE_ELEMENT_ERROR;
+
+ if( ( buffer == NULL ) || ( encBuffer == NULL ) )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ lr1110_crypto_aes_encrypt_01( &LR1110, ( lr1110_crypto_status_t* ) &status,
+ convert_key_id_from_se_to_lr1110( keyID ), buffer, size, encBuffer );
+
+ return status;
+}
+
+SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t* input, KeyIdentifier_t rootKeyID,
+ KeyIdentifier_t targetKeyID )
+{
+ SecureElementStatus_t status = SECURE_ELEMENT_ERROR;
+
+ if( input == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ lr1110_crypto_derive_and_store_key( &LR1110, ( lr1110_crypto_status_t* ) &status,
+ convert_key_id_from_se_to_lr1110( rootKeyID ),
+ convert_key_id_from_se_to_lr1110( targetKeyID ), input );
+
+ lr1110_crypto_store_to_flash( &LR1110, ( lr1110_crypto_status_t* ) &status );
+ return status;
+}
+
+SecureElementStatus_t SecureElementProcessJoinAccept( JoinReqIdentifier_t joinReqType, uint8_t* joinEui,
+ uint16_t devNonce, uint8_t* encJoinAccept,
+ uint8_t encJoinAcceptSize, uint8_t* decJoinAccept,
+ uint8_t* versionMinor )
+{
+ SecureElementStatus_t status = SECURE_ELEMENT_ERROR;
+
+ if( ( encJoinAccept == NULL ) || ( decJoinAccept == NULL ) || ( versionMinor == NULL ) )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ // Check that frame size isn't bigger than a JoinAccept with CFList size
+ if( encJoinAcceptSize > LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE )
+ {
+ return SECURE_ELEMENT_ERROR_BUF_SIZE;
+ }
+
+ // Determine decryption key
+ KeyIdentifier_t encKeyID = NWK_KEY;
+
+ if( joinReqType != JOIN_REQ )
+ {
+ encKeyID = J_S_ENC_KEY;
+ }
+
+ // - Header buffer to be used for MIC computation
+ // - LoRaWAN 1.0.x : micHeader = [MHDR(1)]
+ // - LoRaWAN 1.1.x : micHeader = [JoinReqType(1), JoinEUI(8), DevNonce(2), MHDR(1)]
+
+ // Try first to process LoRaWAN 1.0.x JoinAccept
+ uint8_t micHeader10[1] = { 0x20 };
+
+ // cmac = aes128_cmac(NwkKey, MHDR | JoinNonce | NetID | DevAddr | DLSettings | RxDelay | CFList |
+ // CFListType)
+ lr1110_crypto_process_join_accept(
+ &LR1110, ( lr1110_crypto_status_t* ) &status, convert_key_id_from_se_to_lr1110( encKeyID ),
+ convert_key_id_from_se_to_lr1110( NWK_KEY ), ( lr1110_crypto_lorawan_version_t ) 0, micHeader10,
+ encJoinAccept + 1, encJoinAcceptSize - 1, decJoinAccept + 1 );
+
+ if( status == SECURE_ELEMENT_SUCCESS )
+ {
+ *versionMinor = ( ( decJoinAccept[11] & 0x80 ) == 0x80 ) ? 1 : 0;
+ if( *versionMinor == 0 )
+ {
+ // Network server is operating according to LoRaWAN 1.0.x
+ return SECURE_ELEMENT_SUCCESS;
+ }
+ }
+
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
+ // 1.0.x trial failed. Trying to process LoRaWAN 1.1.x JoinAccept
+ uint8_t micHeader11[JOIN_ACCEPT_MIC_COMPUTATION_OFFSET] = { 0 };
+ uint16_t bufItr = 0;
+
+ // cmac = aes128_cmac(JSIntKey, JoinReqType | JoinEUI | DevNonce | MHDR | JoinNonce | NetID | DevAddr |
+ // DLSettings | RxDelay | CFList | CFListType)
+ micHeader11[bufItr++] = ( uint8_t ) joinReqType;
+
+ memcpyr( micHeader11 + bufItr, joinEui, LORAMAC_JOIN_EUI_FIELD_SIZE );
+ bufItr += LORAMAC_JOIN_EUI_FIELD_SIZE;
+
+ micHeader11[bufItr++] = devNonce & 0xFF;
+ micHeader11[bufItr++] = ( devNonce >> 8 ) & 0xFF;
+
+ micHeader11[bufItr++] = 0x20;
+
+ lr1110_crypto_process_join_accept(
+ &LR1110, ( lr1110_crypto_status_t* ) &status, convert_key_id_from_se_to_lr1110( encKeyID ),
+ convert_key_id_from_se_to_lr1110( J_S_INT_KEY ), ( lr1110_crypto_lorawan_version_t ) 1, micHeader11,
+ encJoinAccept + 1, encJoinAcceptSize - 1, decJoinAccept + 1 );
+
+ if( status == SECURE_ELEMENT_SUCCESS )
+ {
+ *versionMinor = ( ( decJoinAccept[11] & 0x80 ) == 0x80 ) ? 1 : 0;
+ if( *versionMinor == 1 )
+ {
+ // Network server is operating according to LoRaWAN 1.1.x
+ return SECURE_ELEMENT_SUCCESS;
+ }
+ }
+#endif
+
+ return status;
+}
+
+SecureElementStatus_t SecureElementRandomNumber( uint32_t* randomNum )
+{
+ if( randomNum == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+ *randomNum = LR1110SeHalGetRandomNumber( );
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+SecureElementStatus_t SecureElementSetDevEui( uint8_t* devEui )
+{
+ if( devEui == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+ memcpy1( SeContext.DevEui, devEui, SE_EUI_SIZE );
+ SeNvmCtxChanged( );
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+uint8_t* SecureElementGetDevEui( void )
+{
+ return SeContext.DevEui;
+}
+
+SecureElementStatus_t SecureElementSetJoinEui( uint8_t* joinEui )
+{
+ if( joinEui == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+ memcpy1( SeContext.JoinEui, joinEui, SE_EUI_SIZE );
+ SeNvmCtxChanged( );
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+uint8_t* SecureElementGetJoinEui( void )
+{
+ return SeContext.JoinEui;
+}
+
+SecureElementStatus_t SecureElementSetPin( uint8_t* pin )
+{
+ if( pin == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ memcpy1( SeContext.Pin, pin, SE_PIN_SIZE );
+ SeNvmCtxChanged( );
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+uint8_t* SecureElementGetPin( void )
+{
+ return SeContext.Pin;
+}
+
+static lr1110_crypto_keys_idx_t convert_key_id_from_se_to_lr1110( KeyIdentifier_t key_id )
+{
+ lr1110_crypto_keys_idx_t id = LR1110_CRYPTO_KEYS_IDX_GP0;
+
+ switch( key_id )
+ {
+ case APP_KEY:
+ id = LR1110_CRYPTO_KEYS_IDX_APP_KEY;
+ break;
+ case NWK_KEY:
+ id = LR1110_CRYPTO_KEYS_IDX_NWK_KEY;
+ break;
+ case J_S_INT_KEY:
+ id = LR1110_CRYPTO_KEYS_IDX_J_S_INT_KEY;
+ break;
+ case J_S_ENC_KEY:
+ id = LR1110_CRYPTO_KEYS_IDX_J_S_ENC_KEY;
+ break;
+ case F_NWK_S_INT_KEY:
+ id = LR1110_CRYPTO_KEYS_IDX_F_NWK_S_INT_KEY;
+ break;
+ case S_NWK_S_INT_KEY:
+ id = LR1110_CRYPTO_KEYS_IDX_S_NWK_S_INT_KEY;
+ break;
+ case NWK_S_ENC_KEY:
+ id = LR1110_CRYPTO_KEYS_IDX_NWK_S_ENC_KEY;
+ break;
+ case APP_S_KEY:
+ id = LR1110_CRYPTO_KEYS_IDX_APP_S_KEY;
+ break;
+ case MC_ROOT_KEY:
+ id = LR1110_CRYPTO_KEYS_IDX_GP_KE_KEY_5;
+ break;
+ case MC_KE_KEY:
+ id = LR1110_CRYPTO_KEYS_IDX_GP_KE_KEY_4;
+ break;
+ case MC_KEY_0:
+ id = LR1110_CRYPTO_KEYS_IDX_GP_KE_KEY_0;
+ break;
+ case MC_APP_S_KEY_0:
+ id = LR1110_CRYPTO_KEYS_IDX_MC_APP_S_KEY_0;
+ break;
+ case MC_NWK_S_KEY_0:
+ id = LR1110_CRYPTO_KEYS_IDX_MC_NWK_S_KEY_0;
+ break;
+ case MC_KEY_1:
+ id = LR1110_CRYPTO_KEYS_IDX_GP_KE_KEY_1;
+ break;
+ case MC_APP_S_KEY_1:
+ id = LR1110_CRYPTO_KEYS_IDX_MC_APP_S_KEY_1;
+ break;
+ case MC_NWK_S_KEY_1:
+ id = LR1110_CRYPTO_KEYS_IDX_MC_NWK_S_KEY_1;
+ break;
+ case MC_KEY_2:
+ id = LR1110_CRYPTO_KEYS_IDX_GP_KE_KEY_2;
+ break;
+ case MC_APP_S_KEY_2:
+ id = LR1110_CRYPTO_KEYS_IDX_MC_APP_S_KEY_2;
+ break;
+ case MC_NWK_S_KEY_2:
+ id = LR1110_CRYPTO_KEYS_IDX_MC_NWK_S_KEY_2;
+ break;
+ case MC_KEY_3:
+ id = LR1110_CRYPTO_KEYS_IDX_GP_KE_KEY_3;
+ break;
+ case MC_APP_S_KEY_3:
+ id = LR1110_CRYPTO_KEYS_IDX_MC_APP_S_KEY_3;
+ break;
+ case MC_NWK_S_KEY_3:
+ id = LR1110_CRYPTO_KEYS_IDX_MC_NWK_S_KEY_3;
+ break;
+ case SLOT_RAND_ZERO_KEY:
+ id = LR1110_CRYPTO_KEYS_IDX_GP0;
+ break;
+ default:
+ id = LR1110_CRYPTO_KEYS_IDX_GP1;
+ break;
+ }
+ return id;
+}
diff --git a/components/connectivity/LoraWAN/peripherals/lr1110-se/se-identity.h b/components/connectivity/LoraWAN/peripherals/lr1110-se/se-identity.h
new file mode 100644
index 00000000..db0da13e
--- /dev/null
+++ b/components/connectivity/LoraWAN/peripherals/lr1110-se/se-identity.h
@@ -0,0 +1,102 @@
+/*!
+ * \file se-identity.h
+ *
+ * \brief Secure Element identity and keys
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2020 Semtech
+ *
+ * ___ _____ _ ___ _ _____ ___ ___ ___ ___
+ * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
+ * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ * embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ */
+#ifndef __SOFT_SE_IDENTITY_H__
+#define __SOFT_SE_IDENTITY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ ******************************************************************************
+ ********************************** WARNING ***********************************
+ ******************************************************************************
+ The secure-element implementation supports both 1.0.x and 1.1.x LoRaWAN
+ versions of the specification.
+ Thus it has been decided to use the 1.1.x keys and EUI name definitions.
+ The below table shows the names equivalence between versions:
+ +---------------------+-------------------------+
+ | 1.0.x | 1.1.x |
+ +=====================+=========================+
+ | LORAWAN_DEVICE_EUI | LORAWAN_DEVICE_EUI |
+ +---------------------+-------------------------+
+ | LORAWAN_APP_EUI | LORAWAN_JOIN_EUI |
+ +---------------------+-------------------------+
+ | LORAWAN_GEN_APP_KEY | LORAWAN_APP_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_APP_KEY | LORAWAN_NWK_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_NWK_S_KEY | LORAWAN_F_NWK_S_INT_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_NWK_S_KEY | LORAWAN_S_NWK_S_INT_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_NWK_S_KEY | LORAWAN_NWK_S_ENC_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_APP_S_KEY | LORAWAN_APP_S_KEY |
+ +---------------------+-------------------------+
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ */
+
+/*!
+ * When set to 1 DevEui is LORAWAN_DEVICE_EUI
+ * When set to 0 DevEui is automatically set with a value provided by MCU platform
+ */
+#define STATIC_DEVICE_EUI 0
+
+/*!
+ * end-device IEEE EUI (big endian)
+ */
+#define LORAWAN_DEVICE_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+
+/*!
+ * App/Join server IEEE EUI (big endian)
+ */
+#define LORAWAN_JOIN_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+
+/*!
+ * Secure-element pin
+ */
+#define SECURE_ELEMENT_PIN { 0x00, 0x00, 0x00, 0x00 }
+
+/*!
+ * When set to 1 DevAddr is LORAWAN_DEVICE_ADDRESS
+ * When set to 0 DevAddr is automatically set with a value provided by a pseudo
+ * random generator seeded with a value provided by the MCU platform
+ */
+#define STATIC_DEVICE_ADDRESS 0
+
+/*!
+ * Device address on the network (big endian)
+ */
+#define LORAWAN_DEVICE_ADDRESS ( uint32_t )0x00000000
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFT_SE_IDENTITY_H__
diff --git a/components/connectivity/LoraWAN/peripherals/mag3110.c b/components/connectivity/LoraWAN/peripherals/mag3110.c
index cd6ce140..ac2407c9 100644
--- a/components/connectivity/LoraWAN/peripherals/mag3110.c
+++ b/components/connectivity/LoraWAN/peripherals/mag3110.c
@@ -43,21 +43,21 @@ uint8_t MAG3110Init( void )
MAG3110Read( MAG3110_ID, ®Val );
if( regVal != 0xC4 ) // Fixed Device ID Number = 0xC4
{
- return LORA_FAIL;
+ return FAIL;
}
MAG3110Reset( );
}
- return LORA_SUCCESS;
+ return SUCCESS;
}
uint8_t MAG3110Reset( void )
{
- if( MAG3110Write( 0x11, 0x10 ) == LORA_SUCCESS ) // Reset the MAG3110 with CTRL_REG2
+ if( MAG3110Write( 0x11, 0x10 ) == SUCCESS ) // Reset the MAG3110 with CTRL_REG2
{
- return LORA_SUCCESS;
+ return SUCCESS;
}
- return LORA_FAIL;
+ return FAIL;
}
uint8_t MAG3110Write( uint8_t addr, uint8_t data )
diff --git a/components/connectivity/LoraWAN/peripherals/mag3110.h b/components/connectivity/LoraWAN/peripherals/mag3110.h
index 36d7a532..a16582ff 100644
--- a/components/connectivity/LoraWAN/peripherals/mag3110.h
+++ b/components/connectivity/LoraWAN/peripherals/mag3110.h
@@ -23,6 +23,11 @@
#ifndef __MAG3110_H__
#define __MAG3110_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
/*!
@@ -38,14 +43,14 @@
/*!
* \brief Initializes the device
*
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MAG3110Init( void );
/*!
* \brief Resets the device
*
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MAG3110Reset( void );
@@ -54,7 +59,7 @@ uint8_t MAG3110Reset( void );
*
* \param [IN]: addr
* \param [IN]: data
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MAG3110Write( uint8_t addr, uint8_t data );
@@ -64,7 +69,7 @@ uint8_t MAG3110Write( uint8_t addr, uint8_t data );
* \param [IN]: addr
* \param [IN]: data
* \param [IN]: size
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MAG3110WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -73,7 +78,7 @@ uint8_t MAG3110WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
*
* \param [IN]: addr
* \param [OUT]: data
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MAG3110Read( uint8_t addr, uint8_t *data );
@@ -83,7 +88,7 @@ uint8_t MAG3110Read( uint8_t addr, uint8_t *data );
* \param [IN]: addr
* \param [OUT]: data
* \param [IN]: size
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MAG3110ReadBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -101,4 +106,8 @@ void MAG3110SetDeviceAddr( uint8_t addr );
*/
uint8_t MAG3110GetDeviceAddr( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __MAG3110_H__
diff --git a/components/connectivity/LoraWAN/peripherals/mma8451.c b/components/connectivity/LoraWAN/peripherals/mma8451.c
index cf8e215b..510a41d0 100644
--- a/components/connectivity/LoraWAN/peripherals/mma8451.c
+++ b/components/connectivity/LoraWAN/peripherals/mma8451.c
@@ -36,7 +36,7 @@ static bool MMA8451Initialized = false;
*
* \param [IN]: addr
* \param [IN]: data
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MMA8451Write( uint8_t addr, uint8_t data );
@@ -46,7 +46,7 @@ uint8_t MMA8451Write( uint8_t addr, uint8_t data );
* \param [IN]: addr
* \param [IN]: data
* \param [IN]: size
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MMA8451WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -55,7 +55,7 @@ uint8_t MMA8451WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
*
* \param [IN]: addr
* \param [OUT]: data
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MMA8451Read( uint8_t addr, uint8_t *data );
@@ -65,7 +65,7 @@ uint8_t MMA8451Read( uint8_t addr, uint8_t *data );
* \param [IN]: addr
* \param [OUT]: data
* \param [IN]: size
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MMA8451ReadBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -96,7 +96,7 @@ uint8_t MMA8451Init( void )
MMA8451Read( MMA8451_ID, ®Val );
if( regVal != 0x1A ) // Fixed Device ID Number = 0x1A
{
- return LORA_FAIL;
+ return FAIL;
}
MMA8451Reset( );
@@ -105,17 +105,17 @@ uint8_t MMA8451Init( void )
MMA8451Write( MMA8451_CTRL_REG3, 0x01 );
MMA8451OrientDetect( );
}
- return LORA_SUCCESS;
+ return SUCCESS;
}
uint8_t MMA8451Reset( )
{
- if( MMA8451Write( 0x2B, 0x40 ) == LORA_SUCCESS ) // Reset the MMA8451 with CTRL_REG2
+ if( MMA8451Write( 0x2B, 0x40 ) == SUCCESS ) // Reset the MMA8451 with CTRL_REG2
{
- return LORA_SUCCESS;
+ return SUCCESS;
}
- return LORA_FAIL;
+ return FAIL;
}
uint8_t MMA8451Write( uint8_t addr, uint8_t data )
diff --git a/components/connectivity/LoraWAN/peripherals/mma8451.h b/components/connectivity/LoraWAN/peripherals/mma8451.h
index 694eb5d0..ce8f912f 100644
--- a/components/connectivity/LoraWAN/peripherals/mma8451.h
+++ b/components/connectivity/LoraWAN/peripherals/mma8451.h
@@ -23,6 +23,11 @@
#ifndef __MMA8451_H__
#define __MMA8451_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
/*
@@ -58,14 +63,14 @@
/*!
* \brief Initializes the device
*
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MMA8451Init( void );
/*!
* \brief Resets the device
*
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MMA8451Reset( void );
@@ -83,4 +88,8 @@ void MMA8451OrientDetect( void );
*/
uint8_t MMA8451GetOrientation( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __MMA8451_H__
diff --git a/components/connectivity/LoraWAN/peripherals/mpl3115.c b/components/connectivity/LoraWAN/peripherals/mpl3115.c
index 3d562e29..6a4e8944 100644
--- a/components/connectivity/LoraWAN/peripherals/mpl3115.c
+++ b/components/connectivity/LoraWAN/peripherals/mpl3115.c
@@ -52,7 +52,7 @@ typedef enum
*
* \param [IN]: addr
* \param [IN]: data
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MPL3115Write( uint8_t addr, uint8_t data );
@@ -62,7 +62,7 @@ uint8_t MPL3115Write( uint8_t addr, uint8_t data );
* \param [IN]: addr
* \param [IN]: data
* \param [IN]: size
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MPL3115WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -71,7 +71,7 @@ uint8_t MPL3115WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
*
* \param [IN]: addr
* \param [OUT]: data
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MPL3115Read( uint8_t addr, uint8_t *data );
@@ -81,7 +81,7 @@ uint8_t MPL3115Read( uint8_t addr, uint8_t *data );
* \param [IN]: addr
* \param [OUT]: data
* \param [IN]: size
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MPL3115ReadBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -141,24 +141,24 @@ uint8_t MPL3115Init( void )
MPL3115Read( MPL3115_ID, ®Val );
if( regVal != 0xC4 )
{
- return LORA_FAIL;
+ return FAIL;
}
MPL3115Write( PT_DATA_CFG_REG, DREM | PDEFE | TDEFE ); // Enable data ready flags for pressure and temperature )
MPL3115Write( CTRL_REG1, ALT | OS_32 | SBYB ); // Set sensor to active state with oversampling ratio 128 (512 ms between samples)
MPL3115Initialized = true;
}
- return LORA_SUCCESS;
+ return SUCCESS;
}
uint8_t MPL3115Reset( void )
{
// Reset all registers to POR values
- if( MPL3115Write( CTRL_REG1, RST ) == LORA_SUCCESS )
+ if( MPL3115Write( CTRL_REG1, RST ) == SUCCESS )
{
- return LORA_SUCCESS;
+ return SUCCESS;
}
- return LORA_FAIL;
+ return FAIL;
}
uint8_t MPL3115Write( uint8_t addr, uint8_t data )
diff --git a/components/connectivity/LoraWAN/peripherals/mpl3115.h b/components/connectivity/LoraWAN/peripherals/mpl3115.h
index 7486a850..614ddfe3 100644
--- a/components/connectivity/LoraWAN/peripherals/mpl3115.h
+++ b/components/connectivity/LoraWAN/peripherals/mpl3115.h
@@ -23,6 +23,11 @@
#ifndef __MPL3115_H__
#define __MPL3115_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
/*
@@ -123,14 +128,14 @@
/*!
* \brief Initializes the device
*
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MPL3115Init( void );
/*!
* \brief Resets the device
*
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t MPL3115Reset( void );
@@ -155,4 +160,8 @@ float MPL3115ReadPressure( void );
*/
float MPL3115ReadTemperature( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __MPL3115_H__
diff --git a/components/connectivity/LoraWAN/peripherals/pam7q.c b/components/connectivity/LoraWAN/peripherals/pam7q.c
index 27608487..cce67b5c 100644
--- a/components/connectivity/LoraWAN/peripherals/pam7q.c
+++ b/components/connectivity/LoraWAN/peripherals/pam7q.c
@@ -43,7 +43,7 @@ bool PAM7QGetGpsData( uint8_t *nmeaString, uint8_t *nmeaStringSize, uint16_t nme
status = PAM7QReadBuffer( MESSAGE_SIZE_1, nmeaString, 2 );
- if( status == LORA_SUCCESS )
+ if( status == SUCCESS )
{
// build a 16bit number
pendingBytes = ( uint16_t )( ( nmeaString[0] << 8 ) | nmeaString[1] );
@@ -63,7 +63,7 @@ bool PAM7QGetGpsData( uint8_t *nmeaString, uint8_t *nmeaStringSize, uint16_t nme
status = PAM7QReadBuffer( PAYLOAD, nmeaString, pendingBytes );
// make sure the string is terminated
- if( status == LORA_SUCCESS )
+ if( status == SUCCESS )
{
nmeaString[pendingBytes] = 0x00;
diff --git a/components/connectivity/LoraWAN/peripherals/pam7q.h b/components/connectivity/LoraWAN/peripherals/pam7q.h
index 25fa0b56..26cf63d5 100644
--- a/components/connectivity/LoraWAN/peripherals/pam7q.h
+++ b/components/connectivity/LoraWAN/peripherals/pam7q.h
@@ -23,6 +23,11 @@
#ifndef __PAM7Q_H__
#define __PAM7Q_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
@@ -55,5 +60,9 @@ void GpsMcuOnPpsSignal( void );
#define PAYLOAD 0xFF
+#ifdef __cplusplus
+}
+#endif
+
#endif // __PAM7Q_H__
diff --git a/components/connectivity/LoraWAN/peripherals/soft-se/aes.h b/components/connectivity/LoraWAN/peripherals/soft-se/aes.h
index 2411c2fd..3272d9cf 100644
--- a/components/connectivity/LoraWAN/peripherals/soft-se/aes.h
+++ b/components/connectivity/LoraWAN/peripherals/soft-se/aes.h
@@ -31,6 +31,10 @@
#ifndef AES_H
#define AES_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include
#if 1
@@ -159,4 +163,8 @@ void aes_decrypt_256( const uint8_t in[N_BLOCK],
uint8_t o_key[2 * N_BLOCK] );
#endif
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/components/connectivity/LoraWAN/peripherals/soft-se/cmac.c b/components/connectivity/LoraWAN/peripherals/soft-se/cmac.c
index 9ea1a42b..eb62ba04 100644
--- a/components/connectivity/LoraWAN/peripherals/soft-se/cmac.c
+++ b/components/connectivity/LoraWAN/peripherals/soft-se/cmac.c
@@ -4,150 +4,151 @@ Copyright (C) 2009 Lander Casado, Philippas Tsigas
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files
+a copy of this software and associated documentation files
(the "Software"), to deal with the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
+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 following conditions:
-Redistributions of source code must retain the above copyright notice,
+Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers. Redistributions in
binary form must reproduce the above copyright notice, this list of
-conditions and the following disclaimers in the documentation and/or
+conditions and the following disclaimers in the documentation and/or
other materials provided with the distribution.
In no event shall the authors or copyright holders be liable for any special,
-incidental, indirect or consequential damages of any kind, or any damages
-whatsoever resulting from loss of use, data or profits, whether or not
-advised of the possibility of damage, and on any theory of liability,
+incidental, indirect or consequential damages of any kind, or any damages
+whatsoever resulting from loss of use, data or profits, whether or not
+advised of the possibility of damage, and on any theory of liability,
arising out of or in connection with the use or performance of this 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
CONTRIBUTORS 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
+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 WITH THE SOFTWARE
*****************************************************************************/
-//#include
-//#include
#include
#include "aes.h"
#include "cmac.h"
#include "utilities.h"
-#define LSHIFT(v, r) do { \
- int32_t i; \
- for (i = 0; i < 15; i++) \
- (r)[i] = (v)[i] << 1 | (v)[i + 1] >> 7; \
- (r)[15] = (v)[15] << 1; \
- } while (0)
-
-#define XOR(v, r) do { \
- int32_t i; \
- for (i = 0; i < 16; i++) \
- { \
- (r)[i] = (r)[i] ^ (v)[i]; \
- } \
- } while (0) \
+#define LSHIFT( v, r ) \
+ do \
+ { \
+ int32_t i; \
+ for( i = 0; i < 15; i++ ) \
+ ( r )[i] = ( v )[i] << 1 | ( v )[i + 1] >> 7; \
+ ( r )[15] = ( v )[15] << 1; \
+ } while( 0 )
+#define XOR( v, r ) \
+ do \
+ { \
+ int32_t i; \
+ for( i = 0; i < 16; i++ ) \
+ { \
+ ( r )[i] = ( r )[i] ^ ( v )[i]; \
+ } \
+ } while( 0 )
-void AES_CMAC_Init(AES_CMAC_CTX *ctx)
+void AES_CMAC_Init( AES_CMAC_CTX* ctx )
{
- memset1(ctx->X, 0, sizeof ctx->X);
- ctx->M_n = 0;
- memset1(ctx->rijndael.ksch, '\0', 240);
-}
-
-void AES_CMAC_SetKey(AES_CMAC_CTX *ctx, const uint8_t key[AES_CMAC_KEY_LENGTH])
-{
- //rijndael_set_key_enc_only(&ctx->rijndael, key, 128);
- aes_set_key( key, AES_CMAC_KEY_LENGTH, &ctx->rijndael);
-}
-
-void AES_CMAC_Update(AES_CMAC_CTX *ctx, const uint8_t *data, uint32_t len)
-{
- uint32_t mlen;
- uint8_t in[16];
-
- if (ctx->M_n > 0) {
- mlen = MIN(16 - ctx->M_n, len);
- memcpy1(ctx->M_last + ctx->M_n, data, mlen);
- ctx->M_n += mlen;
- if (ctx->M_n < 16 || len == mlen)
- return;
- XOR(ctx->M_last, ctx->X);
- //rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X);
- aes_encrypt( ctx->X, ctx->X, &ctx->rijndael);
- data += mlen;
- len -= mlen;
- }
- while (len > 16) { /* not last block */
-
- XOR(data, ctx->X);
- //rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X);
-
- memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten
- aes_encrypt( in, in, &ctx->rijndael);
- memcpy1(&ctx->X[0], in, 16);
-
- data += 16;
- len -= 16;
- }
- /* potential last block, save it */
- memcpy1(ctx->M_last, data, len);
- ctx->M_n = len;
-}
-
-void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *ctx)
-{
- uint8_t K[16];
- uint8_t in[16];
- /* generate subkey K1 */
- memset1(K, '\0', 16);
-
- //rijndael_encrypt(&ctx->rijndael, K, K);
-
- aes_encrypt( K, K, &ctx->rijndael);
-
- if (K[0] & 0x80) {
- LSHIFT(K, K);
- K[15] ^= 0x87;
- } else
- LSHIFT(K, K);
-
-
- if (ctx->M_n == 16) {
- /* last block was a complete block */
- XOR(K, ctx->M_last);
-
- } else {
- /* generate subkey K2 */
- if (K[0] & 0x80) {
- LSHIFT(K, K);
- K[15] ^= 0x87;
- } else
- LSHIFT(K, K);
-
- /* padding(M_last) */
- ctx->M_last[ctx->M_n] = 0x80;
- while (++ctx->M_n < 16)
- ctx->M_last[ctx->M_n] = 0;
-
- XOR(K, ctx->M_last);
-
-
- }
- XOR(ctx->M_last, ctx->X);
-
- //rijndael_encrypt(&ctx->rijndael, ctx->X, digest);
-
- memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten
- aes_encrypt(in, digest, &ctx->rijndael);
- memset1(K, 0, sizeof K);
-
+ memset1( ctx->X, 0, sizeof ctx->X );
+ ctx->M_n = 0;
+ memset1( ctx->rijndael.ksch, '\0', 240 );
}
+void AES_CMAC_SetKey( AES_CMAC_CTX* ctx, const uint8_t key[AES_CMAC_KEY_LENGTH] )
+{
+ aes_set_key( key, AES_CMAC_KEY_LENGTH, &ctx->rijndael );
+}
+
+void AES_CMAC_Update( AES_CMAC_CTX* ctx, const uint8_t* data, uint32_t len )
+{
+ uint32_t mlen;
+ uint8_t in[16];
+
+ if( ctx->M_n > 0 )
+ {
+ mlen = MIN( 16 - ctx->M_n, len );
+ memcpy1( ctx->M_last + ctx->M_n, data, mlen );
+ ctx->M_n += mlen;
+ if( ctx->M_n < 16 || len == mlen )
+ return;
+ XOR( ctx->M_last, ctx->X );
+
+ memcpy1( in, &ctx->X[0], 16 ); // Otherwise it does not look good
+ aes_encrypt( in, in, &ctx->rijndael );
+ memcpy1( &ctx->X[0], in, 16 );
+
+ data += mlen;
+ len -= mlen;
+ }
+ while( len > 16 )
+ { /* not last block */
+
+ XOR( data, ctx->X );
+
+ memcpy1( in, &ctx->X[0], 16 ); // Otherwise it does not look good
+ aes_encrypt( in, in, &ctx->rijndael );
+ memcpy1( &ctx->X[0], in, 16 );
+
+ data += 16;
+ len -= 16;
+ }
+ /* potential last block, save it */
+ memcpy1( ctx->M_last, data, len );
+ ctx->M_n = len;
+}
+
+void AES_CMAC_Final( uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX* ctx )
+{
+ uint8_t K[16];
+ uint8_t in[16];
+ /* generate subkey K1 */
+ memset1( K, '\0', 16 );
+
+ aes_encrypt( K, K, &ctx->rijndael );
+
+ if( K[0] & 0x80 )
+ {
+ LSHIFT( K, K );
+ K[15] ^= 0x87;
+ }
+ else
+ LSHIFT( K, K );
+
+ if( ctx->M_n == 16 )
+ {
+ /* last block was a complete block */
+ XOR( K, ctx->M_last );
+ }
+ else
+ {
+ /* generate subkey K2 */
+ if( K[0] & 0x80 )
+ {
+ LSHIFT( K, K );
+ K[15] ^= 0x87;
+ }
+ else
+ LSHIFT( K, K );
+
+ /* padding(M_last) */
+ ctx->M_last[ctx->M_n] = 0x80;
+ while( ++ctx->M_n < 16 )
+ ctx->M_last[ctx->M_n] = 0;
+
+ XOR( K, ctx->M_last );
+ }
+ XOR( ctx->M_last, ctx->X );
+
+ memcpy1( in, &ctx->X[0], 16 ); // Otherwise it does not look good
+ aes_encrypt( in, digest, &ctx->rijndael );
+ memset1( K, 0, sizeof K );
+}
diff --git a/components/connectivity/LoraWAN/peripherals/soft-se/cmac.h b/components/connectivity/LoraWAN/peripherals/soft-se/cmac.h
index af52f5ae..6ebccd8c 100644
--- a/components/connectivity/LoraWAN/peripherals/soft-se/cmac.h
+++ b/components/connectivity/LoraWAN/peripherals/soft-se/cmac.h
@@ -36,6 +36,10 @@ DEALINGS WITH THE SOFTWARE
#ifndef _CMAC_H_
#define _CMAC_H_
+#ifdef __cplusplus
+extern "C"
+#endif
+
#include "aes.h"
#define AES_CMAC_KEY_LENGTH 16
@@ -59,5 +63,9 @@ void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *
// __attribute__((__bounded__(__minbytes__,1,AES_CMAC_DIGEST_LENGTH)));
//__END_DECLS
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _CMAC_H_ */
diff --git a/components/connectivity/LoraWAN/peripherals/soft-se/se-identity.h b/components/connectivity/LoraWAN/peripherals/soft-se/se-identity.h
new file mode 100644
index 00000000..872167b4
--- /dev/null
+++ b/components/connectivity/LoraWAN/peripherals/soft-se/se-identity.h
@@ -0,0 +1,297 @@
+/*!
+ * \file se-identity.h
+ *
+ * \brief Secure Element identity and keys
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2020 Semtech
+ *
+ * ___ _____ _ ___ _ _____ ___ ___ ___ ___
+ * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
+ * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ * embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ */
+#ifndef __SOFT_SE_IDENTITY_H__
+#define __SOFT_SE_IDENTITY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ ******************************************************************************
+ ********************************** WARNING ***********************************
+ ******************************************************************************
+ The secure-element implementation supports both 1.0.x and 1.1.x LoRaWAN
+ versions of the specification.
+ Thus it has been decided to use the 1.1.x keys and EUI name definitions.
+ The below table shows the names equivalence between versions:
+ +---------------------+-------------------------+
+ | 1.0.x | 1.1.x |
+ +=====================+=========================+
+ | LORAWAN_DEVICE_EUI | LORAWAN_DEVICE_EUI |
+ +---------------------+-------------------------+
+ | LORAWAN_APP_EUI | LORAWAN_JOIN_EUI |
+ +---------------------+-------------------------+
+ | LORAWAN_GEN_APP_KEY | LORAWAN_APP_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_APP_KEY | LORAWAN_NWK_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_NWK_S_KEY | LORAWAN_F_NWK_S_INT_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_NWK_S_KEY | LORAWAN_S_NWK_S_INT_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_NWK_S_KEY | LORAWAN_NWK_S_ENC_KEY |
+ +---------------------+-------------------------+
+ | LORAWAN_APP_S_KEY | LORAWAN_APP_S_KEY |
+ +---------------------+-------------------------+
+ ******************************************************************************
+ ******************************************************************************
+ ******************************************************************************
+ */
+
+/*!
+ * When set to 1 DevEui is LORAWAN_DEVICE_EUI
+ * When set to 0 DevEui is automatically set with a value provided by MCU platform
+ */
+#define STATIC_DEVICE_EUI 0
+
+/*!
+ * end-device IEEE EUI (big endian)
+ */
+#define LORAWAN_DEVICE_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+
+/*!
+ * App/Join server IEEE EUI (big endian)
+ */
+#define LORAWAN_JOIN_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+
+/*!
+ * Secure-element pin
+ */
+#define SECURE_ELEMENT_PIN { 0x00, 0x00, 0x00, 0x00 }
+
+/*!
+ * When set to 1 DevAddr is LORAWAN_DEVICE_ADDRESS
+ * When set to 0 DevAddr is automatically set with a value provided by a pseudo
+ * random generator seeded with a value provided by the MCU platform
+ */
+#define STATIC_DEVICE_ADDRESS 0
+
+/*!
+ * Device address on the network (big endian)
+ */
+#define LORAWAN_DEVICE_ADDRESS ( uint32_t )0x00000000
+
+#define SOFT_SE_KEY_LIST \
+ { \
+ { \
+ /*! \
+ * Application root key \
+ * WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_GEN_APP_KEY \
+ */ \
+ .KeyID = APP_KEY, \
+ .KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
+ 0x3C }, \
+ }, \
+ { \
+ /*! \
+ * Network root key \
+ * WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_APP_KEY \
+ */ \
+ .KeyID = NWK_KEY, \
+ .KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
+ 0x3C }, \
+ }, \
+ { \
+ /*! \
+ * Join session integrity key (Dynamically updated) \
+ * WARNING: NOT USED FOR 1.0.x DEVICES \
+ */ \
+ .KeyID = J_S_INT_KEY, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Join session encryption key (Dynamically updated) \
+ * WARNING: NOT USED FOR 1.0.x DEVICES \
+ */ \
+ .KeyID = J_S_ENC_KEY, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Forwarding Network session integrity key \
+ * WARNING: NWK_S_KEY FOR 1.0.x DEVICES \
+ */ \
+ .KeyID = F_NWK_S_INT_KEY, \
+ .KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
+ 0x3C }, \
+ }, \
+ { \
+ /*! \
+ * Serving Network session integrity key \
+ * WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \
+ */ \
+ .KeyID = S_NWK_S_INT_KEY, \
+ .KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
+ 0x3C }, \
+ }, \
+ { \
+ /*! \
+ * Network session encryption key \
+ * WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \
+ */ \
+ .KeyID = NWK_S_ENC_KEY, \
+ .KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
+ 0x3C }, \
+ }, \
+ { \
+ /*! \
+ * Application session key \
+ */ \
+ .KeyID = APP_S_KEY, \
+ .KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
+ 0x3C }, \
+ }, \
+ { \
+ /*! \
+ * Multicast root key (Dynamically updated) \
+ */ \
+ .KeyID = MC_ROOT_KEY, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast key encryption key (Dynamically updated) \
+ */ \
+ .KeyID = MC_KE_KEY, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #0 root key (Dynamically updated) \
+ */ \
+ .KeyID = MC_KEY_0, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #0 application session key (Dynamically updated) \
+ */ \
+ .KeyID = MC_APP_S_KEY_0, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #0 network session key (Dynamically updated) \
+ */ \
+ .KeyID = MC_NWK_S_KEY_0, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #1 root key (Dynamically updated) \
+ */ \
+ .KeyID = MC_KEY_1, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #1 application session key (Dynamically updated) \
+ */ \
+ .KeyID = MC_APP_S_KEY_1, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #1 network session key (Dynamically updated) \
+ */ \
+ .KeyID = MC_NWK_S_KEY_1, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #2 root key (Dynamically updated) \
+ */ \
+ .KeyID = MC_KEY_2, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #2 application session key (Dynamically updated) \
+ */ \
+ .KeyID = MC_APP_S_KEY_2, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #2 network session key (Dynamically updated) \
+ */ \
+ .KeyID = MC_NWK_S_KEY_2, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #3 root key (Dynamically updated) \
+ */ \
+ .KeyID = MC_KEY_3, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #3 application session key (Dynamically updated) \
+ */ \
+ .KeyID = MC_APP_S_KEY_3, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * Multicast group #3 network session key (Dynamically updated) \
+ */ \
+ .KeyID = MC_NWK_S_KEY_3, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ { \
+ /*! \
+ * All zeros key. (ClassB usage)(constant) \
+ */ \
+ .KeyID = SLOT_RAND_ZERO_KEY, \
+ .KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00 }, \
+ }, \
+ },
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFT_SE_IDENTITY_H__
diff --git a/components/connectivity/LoraWAN/peripherals/soft-se/soft-se-hal.c b/components/connectivity/LoraWAN/peripherals/soft-se/soft-se-hal.c
new file mode 100644
index 00000000..28adb235
--- /dev/null
+++ b/components/connectivity/LoraWAN/peripherals/soft-se/soft-se-hal.c
@@ -0,0 +1,39 @@
+/*!
+ * \file soft-se-hal.h
+ *
+ * \brief Secure Element hardware abstraction layer implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2020 Semtech
+ *
+ * ___ _____ _ ___ _ _____ ___ ___ ___ ___
+ * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
+ * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ * embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ */
+#include "board.h"
+#include "radio.h"
+
+#include "soft-se-hal.h"
+
+void SoftSeHalGetUniqueId( uint8_t *id )
+{
+ BoardGetUniqueId( id );
+}
+
+uint32_t SoftSeHalGetRandomNumber( void )
+{
+ return Radio.Random( );
+}
diff --git a/components/connectivity/LoraWAN/peripherals/soft-se/soft-se-hal.h b/components/connectivity/LoraWAN/peripherals/soft-se/soft-se-hal.h
new file mode 100644
index 00000000..2e95a56b
--- /dev/null
+++ b/components/connectivity/LoraWAN/peripherals/soft-se/soft-se-hal.h
@@ -0,0 +1,56 @@
+/*!
+ * \file soft-se-hal.h
+ *
+ * \brief Secure Element hardware abstraction layer
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2020 Semtech
+ *
+ * ___ _____ _ ___ _ _____ ___ ___ ___ ___
+ * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
+ * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ * embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ */
+#ifndef __SOFT_SE_HAL_H__
+#define __SOFT_SE_HAL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+
+/*!
+ * \brief Get a 64 bits unique ID
+ *
+ * \param [IN] id Pointer to an array that will contain the Unique ID
+ */
+void SoftSeHalGetUniqueId( uint8_t *id );
+
+/*!
+ * \brief Get a random number
+ *
+ * \remark The number SHALL NOT be generated using a pseudo random number
+ * generator
+ * \retval number 32 bit random value
+ */
+uint32_t SoftSeHalGetRandomNumber( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFT_SE_HAL_H__
diff --git a/components/connectivity/LoraWAN/peripherals/soft-se/soft-se.c b/components/connectivity/LoraWAN/peripherals/soft-se/soft-se.c
index a9197153..b76153f4 100644
--- a/components/connectivity/LoraWAN/peripherals/soft-se/soft-se.c
+++ b/components/connectivity/LoraWAN/peripherals/soft-se/soft-se.c
@@ -1,36 +1,45 @@
-/*
- / _____) _ | |
-( (____ _____ ____ _| |_ _____ ____| |__
- \____ \| ___ | (_ _) ___ |/ ___) _ \
- _____) ) ____| | | || |_| ____( (___| | | |
-(______/|_____)_|_|_| \__)_____)\____)_| |_|
- (C)2013 Semtech
- ___ _____ _ ___ _ _____ ___ ___ ___ ___
-/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
-\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
-|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
-embedded.connectivity.solutions===============
-
-Description: Secure Element software implementation
-
-License: Revised BSD License, see LICENSE.TXT file include in the project
-
-Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ),
- Daniel Jaeckle ( STACKFORCE ), Johannes Bruder ( STACKFORCE )
-*/
-#include "secure-element.h"
-
+/*!
+ * \file soft-se.c
+ *
+ * \brief Secure Element software implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2020 Semtech
+ *
+ * ___ _____ _ ___ _ _____ ___ ___ ___ ___
+ * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
+ * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ * embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ */
#include
#include
-#include "LoRaMacCrypto.h"
#include "utilities.h"
#include "aes.h"
#include "cmac.h"
-#include "radio.h"
-#define NUM_OF_KEYS 22
-#define KEY_SIZE 16
+#include "LoRaMacHeaderTypes.h"
+
+#include "secure-element.h"
+#include "se-identity.h"
+#include "soft-se-hal.h"
+
+/*!
+ * Number of supported crypto keys
+ */
+#define NUM_OF_KEYS 23
/*!
* Identifier value pair type for Keys
@@ -44,7 +53,7 @@ typedef struct sKey
/*
* Key value
*/
- uint8_t KeyValue[KEY_SIZE];
+ uint8_t KeyValue[SE_KEY_SIZE];
} Key_t;
/*
@@ -53,25 +62,49 @@ typedef struct sKey
typedef struct sSecureElementNvCtx
{
/*
- * AES computation context variable
+ * DevEUI storage
*/
- aes_context AesContext;
+ uint8_t DevEui[SE_EUI_SIZE];
/*
- * CMAC computation context variable
+ * Join EUI storage
*/
- AES_CMAC_CTX AesCmacCtx[1];
+ uint8_t JoinEui[SE_EUI_SIZE];
+ /*
+ * Pin storage
+ */
+ uint8_t Pin[SE_PIN_SIZE];
/*
* Key List
*/
Key_t KeyList[NUM_OF_KEYS];
-}SecureElementNvCtx_t;
+} SecureElementNvCtx_t;
-/*
- * Module context
+/*!
+ * Secure element context
*/
-static SecureElementNvCtx_t SeNvmCtx;
+static SecureElementNvCtx_t SeNvmCtx = {
+ /*!
+ * end-device IEEE EUI (big endian)
+ *
+ * \remark In this application the value is automatically generated by calling
+ * BoardGetUniqueId function
+ */
+ .DevEui = LORAWAN_DEVICE_EUI,
+ /*!
+ * App/Join server IEEE EUI (big endian)
+ */
+ .JoinEui = LORAWAN_JOIN_EUI,
+ /*!
+ * Secure-element pin (big endian)
+ */
+ .Pin = SECURE_ELEMENT_PIN,
+ /*!
+ * LoRaWAN key list
+ */
+ .KeyList = SOFT_SE_KEY_LIST
+};
-static EventNvmCtxChanged SeNvmCtxChanged;
+static SecureElementNvmEvent SeNvmCtxChanged;
/*
* Local functions
@@ -80,13 +113,11 @@ static EventNvmCtxChanged SeNvmCtxChanged;
/*
* Gets key item from key list.
*
- * cmac = aes128_cmac(keyID, B0 | msg)
- *
* \param[IN] keyID - Key identifier
* \param[OUT] keyItem - Key item reference
* \retval - Status of the operation
*/
-SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t** keyItem )
+static SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t** keyItem )
{
for( uint8_t i = 0; i < NUM_OF_KEYS; i++ )
{
@@ -99,44 +130,6 @@ SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t** keyItem )
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
-/*
- * Computes a CMAC
- *
- * \param[IN] buffer - Data buffer
- * \param[IN] size - Data buffer size
- * \param[IN] keyID - Key identifier to determine the AES key to be used
- * \param[OUT] cmac - Computed cmac
- * \retval - Status of the operation
- */
-SecureElementStatus_t ComputeCmac( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID, uint32_t* cmac )
-{
- if( buffer == NULL || cmac == NULL )
- {
- return SECURE_ELEMENT_ERROR_NPE;
- }
-
- uint8_t Cmac[16];
-
- AES_CMAC_Init( SeNvmCtx.AesCmacCtx );
-
- Key_t* keyItem;
- SecureElementStatus_t retval = GetKeyByID( keyID, &keyItem );
-
- if( retval == SECURE_ELEMENT_SUCCESS )
- {
- AES_CMAC_SetKey( SeNvmCtx.AesCmacCtx, keyItem->KeyValue );
-
- AES_CMAC_Update( SeNvmCtx.AesCmacCtx, buffer, size );
-
- AES_CMAC_Final( Cmac, SeNvmCtx.AesCmacCtx );
-
- // Bring into the required format
- *cmac = ( uint32_t )( ( uint32_t ) Cmac[3] << 24 | ( uint32_t ) Cmac[2] << 16 | ( uint32_t ) Cmac[1] << 8 | ( uint32_t ) Cmac[0] );
- }
-
- return retval;
-}
-
/*
* Dummy callback in case if the user provides NULL function pointer
*/
@@ -145,37 +138,61 @@ static void DummyCB( void )
return;
}
+/*
+ * Computes a CMAC of a message using provided initial Bx block
+ *
+ * cmac = aes128_cmac(keyID, blocks[i].Buffer)
+ *
+ * \param[IN] micBxBuffer - Buffer containing the initial Bx block
+ * \param[IN] buffer - Data buffer
+ * \param[IN] size - Data buffer size
+ * \param[IN] keyID - Key identifier to determine the AES key to be used
+ * \param[OUT] cmac - Computed cmac
+ * \retval - Status of the operation
+ */
+static SecureElementStatus_t ComputeCmac( uint8_t* micBxBuffer, uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID,
+ uint32_t* cmac )
+{
+ if( ( buffer == NULL ) || ( cmac == NULL ) )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ uint8_t Cmac[16];
+ AES_CMAC_CTX aesCmacCtx[1];
+
+ AES_CMAC_Init( aesCmacCtx );
+
+ Key_t* keyItem;
+ SecureElementStatus_t retval = GetKeyByID( keyID, &keyItem );
+
+ if( retval == SECURE_ELEMENT_SUCCESS )
+ {
+ AES_CMAC_SetKey( aesCmacCtx, keyItem->KeyValue );
+
+ if( micBxBuffer != NULL )
+ {
+ AES_CMAC_Update( aesCmacCtx, micBxBuffer, 16 );
+ }
+
+ AES_CMAC_Update( aesCmacCtx, buffer, size );
+
+ AES_CMAC_Final( Cmac, aesCmacCtx );
+
+ // Bring into the required format
+ *cmac = ( uint32_t )( ( uint32_t ) Cmac[3] << 24 | ( uint32_t ) Cmac[2] << 16 | ( uint32_t ) Cmac[1] << 8 |
+ ( uint32_t ) Cmac[0] );
+ }
+
+ return retval;
+}
+
/*
* API functions
*/
-SecureElementStatus_t SecureElementInit( EventNvmCtxChanged seNvmCtxChanged )
+SecureElementStatus_t SecureElementInit( SecureElementNvmEvent seNvmCtxChanged )
{
- // Initialize with defaults
- uint8_t itr = 0;
- SeNvmCtx.KeyList[itr++].KeyID = APP_KEY;
- SeNvmCtx.KeyList[itr++].KeyID = NWK_KEY;
- SeNvmCtx.KeyList[itr++].KeyID = J_S_INT_KEY;
- SeNvmCtx.KeyList[itr++].KeyID = J_S_ENC_KEY;
- SeNvmCtx.KeyList[itr++].KeyID = F_NWK_S_INT_KEY;
- SeNvmCtx.KeyList[itr++].KeyID = S_NWK_S_INT_KEY;
- SeNvmCtx.KeyList[itr++].KeyID = NWK_S_ENC_KEY;
- SeNvmCtx.KeyList[itr++].KeyID = APP_S_KEY;
- SeNvmCtx.KeyList[itr++].KeyID = MC_KE_KEY;
- SeNvmCtx.KeyList[itr++].KeyID = MC_KEY_0;
- SeNvmCtx.KeyList[itr++].KeyID = MC_APP_S_KEY_0;
- SeNvmCtx.KeyList[itr++].KeyID = MC_NWK_S_KEY_0;
- SeNvmCtx.KeyList[itr++].KeyID = MC_KEY_1;
- SeNvmCtx.KeyList[itr++].KeyID = MC_APP_S_KEY_1;
- SeNvmCtx.KeyList[itr++].KeyID = MC_NWK_S_KEY_1;
- SeNvmCtx.KeyList[itr++].KeyID = MC_KEY_2;
- SeNvmCtx.KeyList[itr++].KeyID = MC_APP_S_KEY_2;
- SeNvmCtx.KeyList[itr++].KeyID = MC_NWK_S_KEY_2;
- SeNvmCtx.KeyList[itr++].KeyID = MC_KEY_3;
- SeNvmCtx.KeyList[itr++].KeyID = MC_APP_S_KEY_3;
- SeNvmCtx.KeyList[itr++].KeyID = MC_NWK_S_KEY_3;
- SeNvmCtx.KeyList[itr++].KeyID = SLOT_RAND_ZERO_KEY;
-
// Assign callback
if( seNvmCtxChanged != 0 )
{
@@ -186,6 +203,15 @@ SecureElementStatus_t SecureElementInit( EventNvmCtxChanged seNvmCtxChanged )
SeNvmCtxChanged = DummyCB;
}
+#if !defined( SECURE_ELEMENT_PRE_PROVISIONED )
+#if( STATIC_DEVICE_EUI == 0 )
+ // Get a DevEUI from MCU unique ID
+ SoftSeHalGetUniqueId( SeNvmCtx.DevEui );
+#endif
+#endif
+
+ SeNvmCtxChanged( );
+
return SECURE_ELEMENT_SUCCESS;
}
@@ -215,26 +241,26 @@ SecureElementStatus_t SecureElementSetKey( KeyIdentifier_t keyID, uint8_t* key )
{
return SECURE_ELEMENT_ERROR_NPE;
}
- SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
for( uint8_t i = 0; i < NUM_OF_KEYS; i++ )
{
if( SeNvmCtx.KeyList[i].KeyID == keyID )
{
- if( LORAMAC_CRYPTO_MULITCAST_KEYS < SeNvmCtx.KeyList[i].KeyID )
- { // Decrypt the key if its a Mulitcast key
-
- uint8_t decryptedKey[16] = { 0 };
+ if( ( keyID == MC_KEY_0 ) || ( keyID == MC_KEY_1 ) || ( keyID == MC_KEY_2 ) || ( keyID == MC_KEY_3 ) )
+ { // Decrypt the key if its a Mckey
+ SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
+ uint8_t decryptedKey[16] = { 0 };
retval = SecureElementAesEncrypt( key, 16, MC_KE_KEY, decryptedKey );
- if( retval != SECURE_ELEMENT_SUCCESS )
- {
- return retval;
- }
+
+ memcpy1( SeNvmCtx.KeyList[i].KeyValue, decryptedKey, SE_KEY_SIZE );
+ SeNvmCtxChanged( );
+
+ return retval;
}
else
{
- memcpy1( SeNvmCtx.KeyList[i].KeyValue, key, KEY_SIZE );
+ memcpy1( SeNvmCtx.KeyList[i].KeyValue, key, SE_KEY_SIZE );
SeNvmCtxChanged( );
return SECURE_ELEMENT_SUCCESS;
}
@@ -244,28 +270,29 @@ SecureElementStatus_t SecureElementSetKey( KeyIdentifier_t keyID, uint8_t* key )
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
-SecureElementStatus_t SecureElementComputeAesCmac( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID, uint32_t* cmac )
+SecureElementStatus_t SecureElementComputeAesCmac( uint8_t* micBxBuffer, uint8_t* buffer, uint16_t size,
+ KeyIdentifier_t keyID, uint32_t* cmac )
{
- if( keyID >= LORAMAC_CRYPTO_MULITCAST_KEYS )
+ if( keyID >= LORAMAC_CRYPTO_MULTICAST_KEYS )
{
- //Never accept multicast key identifier for cmac computation
+ // Never accept multicast key identifier for cmac computation
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
- return ComputeCmac( buffer, size, keyID, cmac );
+ return ComputeCmac( micBxBuffer, buffer, size, keyID, cmac );
}
-SecureElementStatus_t SecureElementVerifyAesCmac( uint8_t* buffer, uint16_t size, uint32_t expectedCmac, KeyIdentifier_t keyID )
+SecureElementStatus_t SecureElementVerifyAesCmac( uint8_t* buffer, uint16_t size, uint32_t expectedCmac,
+ KeyIdentifier_t keyID )
{
if( buffer == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
- SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
- uint32_t compCmac = 0;
-
- retval = ComputeCmac( buffer, size, keyID, &compCmac );
+ SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
+ uint32_t compCmac = 0;
+ retval = ComputeCmac( NULL, buffer, size, keyID, &compCmac );
if( retval != SECURE_ELEMENT_SUCCESS )
{
return retval;
@@ -279,7 +306,8 @@ SecureElementStatus_t SecureElementVerifyAesCmac( uint8_t* buffer, uint16_t size
return retval;
}
-SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID, uint8_t* encBuffer )
+SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID,
+ uint8_t* encBuffer )
{
if( buffer == NULL || encBuffer == NULL )
{
@@ -292,55 +320,48 @@ SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, K
return SECURE_ELEMENT_ERROR_BUF_SIZE;
}
- memset1( SeNvmCtx.AesContext.ksch, '\0', 240 );
+ aes_context aesContext;
+ memset1( aesContext.ksch, '\0', 240 );
- Key_t* pItem;
+ Key_t* pItem;
SecureElementStatus_t retval = GetKeyByID( keyID, &pItem );
if( retval == SECURE_ELEMENT_SUCCESS )
{
- aes_set_key( pItem->KeyValue, 16, &SeNvmCtx.AesContext );
+ aes_set_key( pItem->KeyValue, 16, &aesContext );
uint8_t block = 0;
while( size != 0 )
{
- aes_encrypt( &buffer[block], &encBuffer[block], &SeNvmCtx.AesContext );
+ aes_encrypt( &buffer[block], &encBuffer[block], &aesContext );
block = block + 16;
- size = size - 16;
+ size = size - 16;
}
}
return retval;
}
-SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t* input, KeyIdentifier_t rootKeyID, KeyIdentifier_t targetKeyID )
+SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t* input, KeyIdentifier_t rootKeyID,
+ KeyIdentifier_t targetKeyID )
{
if( input == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
- SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
- uint8_t key[16] = { 0 };
+ SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
+ uint8_t key[16] = { 0 };
- // In case of MC_KE_KEY, prevent other keys than NwkKey or AppKey for LoRaWAN 1.1 or later
+ // In case of MC_KE_KEY, only McRootKey can be used as root key
if( targetKeyID == MC_KE_KEY )
{
- if( ( ( rootKeyID == APP_KEY ) && ( version.Fields.Minor == 0 ) ) || ( rootKeyID == NWK_KEY ) )
+ if( rootKeyID != MC_ROOT_KEY )
{
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
}
}
- // In case of McKEKey derivation, the parameter input is concatenated: nonce | DevEUI | pad16
- // where nonce SHALL be greater than 15
- uint16_t nonce = input[0];
- nonce |= ( ( uint16_t ) input[1] << 8 );
- if( ( targetKeyID == MC_KE_KEY ) && ( nonce < 16 ) )
- {
- return retval;
- }
-
// Derive key
retval = SecureElementAesEncrypt( input, 16, rootKeyID, key );
if( retval != SECURE_ELEMENT_SUCCESS )
@@ -358,12 +379,159 @@ SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t
return SECURE_ELEMENT_SUCCESS;
}
+SecureElementStatus_t SecureElementProcessJoinAccept( JoinReqIdentifier_t joinReqType, uint8_t* joinEui,
+ uint16_t devNonce, uint8_t* encJoinAccept,
+ uint8_t encJoinAcceptSize, uint8_t* decJoinAccept,
+ uint8_t* versionMinor )
+{
+ if( ( encJoinAccept == NULL ) || ( decJoinAccept == NULL ) || ( versionMinor == NULL ) )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ // Check that frame size isn't bigger than a JoinAccept with CFList size
+ if( encJoinAcceptSize > LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE )
+ {
+ return SECURE_ELEMENT_ERROR_BUF_SIZE;
+ }
+
+ // Determine decryption key
+ KeyIdentifier_t encKeyID = NWK_KEY;
+
+ if( joinReqType != JOIN_REQ )
+ {
+ encKeyID = J_S_ENC_KEY;
+ }
+
+ memcpy1( decJoinAccept, encJoinAccept, encJoinAcceptSize );
+
+ // Decrypt JoinAccept, skip MHDR
+ if( SecureElementAesEncrypt( encJoinAccept + LORAMAC_MHDR_FIELD_SIZE, encJoinAcceptSize - LORAMAC_MHDR_FIELD_SIZE,
+ encKeyID, decJoinAccept + LORAMAC_MHDR_FIELD_SIZE ) != SECURE_ELEMENT_SUCCESS )
+ {
+ return SECURE_ELEMENT_FAIL_ENCRYPT;
+ }
+
+ *versionMinor = ( ( decJoinAccept[11] & 0x80 ) == 0x80 ) ? 1 : 0;
+
+ uint32_t mic = 0;
+
+ mic = ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE] << 0 );
+ mic |= ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE + 1] << 8 );
+ mic |= ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE + 2] << 16 );
+ mic |= ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE + 3] << 24 );
+
+ // - Header buffer to be used for MIC computation
+ // - LoRaWAN 1.0.x : micHeader = [MHDR(1)]
+ // - LoRaWAN 1.1.x : micHeader = [JoinReqType(1), JoinEUI(8), DevNonce(2), MHDR(1)]
+
+ // Verify mic
+ if( *versionMinor == 0 )
+ {
+ // For LoRaWAN 1.0.x
+ // cmac = aes128_cmac(NwkKey, MHDR | JoinNonce | NetID | DevAddr | DLSettings | RxDelay | CFList |
+ // CFListType)
+ if( SecureElementVerifyAesCmac( decJoinAccept, ( encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE ), mic, NWK_KEY ) !=
+ SECURE_ELEMENT_SUCCESS )
+ {
+ return SECURE_ELEMENT_FAIL_CMAC;
+ }
+ }
+#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
+ else if( *versionMinor == 1 )
+ {
+ uint8_t micHeader11[JOIN_ACCEPT_MIC_COMPUTATION_OFFSET] = { 0 };
+ uint16_t bufItr = 0;
+
+ micHeader11[bufItr++] = ( uint8_t ) joinReqType;
+
+ memcpyr( micHeader11 + bufItr, joinEui, LORAMAC_JOIN_EUI_FIELD_SIZE );
+ bufItr += LORAMAC_JOIN_EUI_FIELD_SIZE;
+
+ micHeader11[bufItr++] = devNonce & 0xFF;
+ micHeader11[bufItr++] = ( devNonce >> 8 ) & 0xFF;
+
+ // For LoRaWAN 1.1.x and later:
+ // cmac = aes128_cmac(JSIntKey, JoinReqType | JoinEUI | DevNonce | MHDR | JoinNonce | NetID | DevAddr |
+ // DLSettings | RxDelay | CFList | CFListType)
+ // Prepare the msg for integrity check (adding JoinReqType, JoinEUI and DevNonce)
+ uint8_t localBuffer[LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE + JOIN_ACCEPT_MIC_COMPUTATION_OFFSET] = { 0 };
+
+ memcpy1( localBuffer, micHeader11, JOIN_ACCEPT_MIC_COMPUTATION_OFFSET );
+ memcpy1( localBuffer + JOIN_ACCEPT_MIC_COMPUTATION_OFFSET - 1, decJoinAccept, encJoinAcceptSize );
+
+ if( SecureElementVerifyAesCmac( localBuffer,
+ encJoinAcceptSize + JOIN_ACCEPT_MIC_COMPUTATION_OFFSET -
+ LORAMAC_MHDR_FIELD_SIZE - LORAMAC_MIC_FIELD_SIZE,
+ mic, J_S_INT_KEY ) != SECURE_ELEMENT_SUCCESS )
+ {
+ return SECURE_ELEMENT_FAIL_CMAC;
+ }
+ }
+#endif
+ else
+ {
+ return SECURE_ELEMENT_ERROR_INVALID_LORAWAM_SPEC_VERSION;
+ }
+
+ return SECURE_ELEMENT_SUCCESS;
+}
+
SecureElementStatus_t SecureElementRandomNumber( uint32_t* randomNum )
{
if( randomNum == NULL )
{
return SECURE_ELEMENT_ERROR_NPE;
}
- *randomNum = Radio.Random( );
+ *randomNum = SoftSeHalGetRandomNumber( );
return SECURE_ELEMENT_SUCCESS;
}
+
+SecureElementStatus_t SecureElementSetDevEui( uint8_t* devEui )
+{
+ if( devEui == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+ memcpy1( SeNvmCtx.DevEui, devEui, SE_EUI_SIZE );
+ SeNvmCtxChanged( );
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+uint8_t* SecureElementGetDevEui( void )
+{
+ return SeNvmCtx.DevEui;
+}
+
+SecureElementStatus_t SecureElementSetJoinEui( uint8_t* joinEui )
+{
+ if( joinEui == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+ memcpy1( SeNvmCtx.JoinEui, joinEui, SE_EUI_SIZE );
+ SeNvmCtxChanged( );
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+uint8_t* SecureElementGetJoinEui( void )
+{
+ return SeNvmCtx.JoinEui;
+}
+
+SecureElementStatus_t SecureElementSetPin( uint8_t* pin )
+{
+ if( pin == NULL )
+ {
+ return SECURE_ELEMENT_ERROR_NPE;
+ }
+
+ memcpy1( SeNvmCtx.Pin, pin, SE_PIN_SIZE );
+ SeNvmCtxChanged( );
+ return SECURE_ELEMENT_SUCCESS;
+}
+
+uint8_t* SecureElementGetPin( void )
+{
+ return SeNvmCtx.Pin;
+}
diff --git a/components/connectivity/LoraWAN/peripherals/sx1509.c b/components/connectivity/LoraWAN/peripherals/sx1509.c
index 8a24b103..af9ccab9 100644
--- a/components/connectivity/LoraWAN/peripherals/sx1509.c
+++ b/components/connectivity/LoraWAN/peripherals/sx1509.c
@@ -44,14 +44,14 @@ void SX1509Init( void )
uint8_t SX1509Reset( )
{
- if( SX1509Write( RegReset, 0x12 ) == LORA_SUCCESS )
+ if( SX1509Write( RegReset, 0x12 ) == SUCCESS )
{
- if( SX1509Write( RegReset, 0x34 ) == LORA_SUCCESS )
+ if( SX1509Write( RegReset, 0x34 ) == SUCCESS )
{
- return LORA_SUCCESS;
+ return SUCCESS;
}
}
- return LORA_FAIL;
+ return FAIL;
}
uint8_t SX1509Write( uint8_t addr, uint8_t data )
diff --git a/components/connectivity/LoraWAN/peripherals/sx1509.h b/components/connectivity/LoraWAN/peripherals/sx1509.h
index 21152895..1123d818 100644
--- a/components/connectivity/LoraWAN/peripherals/sx1509.h
+++ b/components/connectivity/LoraWAN/peripherals/sx1509.h
@@ -23,6 +23,11 @@
#ifndef __SX1509_H__
#define __SX1509_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#define SX1509_I2C_ADDRESS 0x3E
@@ -156,7 +161,7 @@ void SX1509Init( void );
/*!
* \brief Resets the device
*
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t SX1509Reset( void );
@@ -165,7 +170,7 @@ uint8_t SX1509Reset( void );
*
* \param [IN]: addr
* \param [IN]: data
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t SX1509Write( uint8_t addr, uint8_t data );
@@ -175,7 +180,7 @@ uint8_t SX1509Write( uint8_t addr, uint8_t data );
* \param [IN]: addr
* \param [IN]: data
* \param [IN]: size
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t SX1509WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -184,7 +189,7 @@ uint8_t SX1509WriteBuffer( uint8_t addr, uint8_t *data, uint8_t size );
*
* \param [IN]: addr
* \param [OUT]: data
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t SX1509Read( uint8_t addr, uint8_t *data );
@@ -194,7 +199,7 @@ uint8_t SX1509Read( uint8_t addr, uint8_t *data );
* \param [IN]: addr
* \param [OUT]: data
* \param [IN]: size
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t SX1509ReadBuffer( uint8_t addr, uint8_t *data, uint8_t size );
@@ -212,4 +217,8 @@ void SX1509SetDeviceAddr( uint8_t addr );
*/
uint8_t SX1509GetDeviceAddr( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SX1509_H__
diff --git a/components/connectivity/LoraWAN/peripherals/sx9500.c b/components/connectivity/LoraWAN/peripherals/sx9500.c
index e3e08f81..26fa2648 100644
--- a/components/connectivity/LoraWAN/peripherals/sx9500.c
+++ b/components/connectivity/LoraWAN/peripherals/sx9500.c
@@ -44,21 +44,21 @@ uint8_t SX9500Init( void )
SX9500Read( SX9500_REG_PROXCTRL0, ®Val );
if( regVal != 0x0F )
{
- return LORA_FAIL;
+ return FAIL;
}
SX9500Reset( );
}
- return LORA_SUCCESS;
+ return SUCCESS;
}
uint8_t SX9500Reset( )
{
- if( SX9500Write( SX9500_REG_RESET, SX9500_RESET_CMD ) == LORA_SUCCESS )
+ if( SX9500Write( SX9500_REG_RESET, SX9500_RESET_CMD ) == SUCCESS )
{
- return LORA_SUCCESS;
+ return SUCCESS;
}
- return LORA_FAIL;
+ return FAIL;
}
uint8_t SX9500Write( uint8_t addr, uint8_t data )
diff --git a/components/connectivity/LoraWAN/peripherals/sx9500.h b/components/connectivity/LoraWAN/peripherals/sx9500.h
index 17342708..74f395b3 100644
--- a/components/connectivity/LoraWAN/peripherals/sx9500.h
+++ b/components/connectivity/LoraWAN/peripherals/sx9500.h
@@ -23,6 +23,11 @@
#ifndef __SX9500_H__
#define __SX9500_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#define SX9500_I2C_ADDRESS 0x28
@@ -118,4 +123,8 @@ uint8_t SX9500GetDeviceAddr( void );
*/
void SX9500LockUntilDetection( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SX1509_H__
diff --git a/components/connectivity/LoraWAN/radio/CMakeLists.txt b/components/connectivity/LoraWAN/radio/CMakeLists.txt
index fcdb81f4..351f2d3e 100644
--- a/components/connectivity/LoraWAN/radio/CMakeLists.txt
+++ b/components/connectivity/LoraWAN/radio/CMakeLists.txt
@@ -23,7 +23,7 @@ cmake_minimum_required(VERSION 3.6)
#---------------------------------------------------------------------------------------
# Allow switching of radios
-set(RADIO_LIST sx1272 sx1276 sx126x)
+set(RADIO_LIST sx1272 sx1276 sx126x lr1110)
set(RADIO sx1272 CACHE STRING "Default radio is sx1272")
set_property(CACHE RADIO PROPERTY STRINGS ${RADIO_LIST})
set_property(CACHE RADIO PROPERTY ADVANCED)
@@ -32,17 +32,47 @@ set_property(CACHE RADIO PROPERTY ADVANCED)
# Target
#---------------------------------------------------------------------------------------
-file(GLOB ${PROJECT_NAME}_SOURCES "${RADIO}/*.c")
+foreach( R ${RADIO_LIST} )
+ if(${R} MATCHES ${RADIO} )
+ list(APPEND ${PROJECT_NAME}_SOURCES
+ ${CMAKE_CURRENT_SOURCE_DIR}/${RADIO}/radio.c
+ )
+ list(APPEND ${PROJECT_NAME}_SOURCES
+ ${CMAKE_CURRENT_SOURCE_DIR}/${RADIO}/${RADIO}_driver/src/lr1110_bootloader.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/${RADIO}/${RADIO}_driver/src/lr1110_crypto_engine.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/${RADIO}/${RADIO}_driver/src/lr1110_gnss.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/${RADIO}/${RADIO}_driver/src/lr1110_radio.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/${RADIO}/${RADIO}_driver/src/lr1110_regmem.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/${RADIO}/${RADIO}_driver/src/lr1110_system.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/${RADIO}/${RADIO}_driver/src/lr1110_wifi.c
+ )
+ else()
+ file(GLOB ${PROJECT_NAME}_SOURCES
+ ${CMAKE_CURRENT_SOURCE_DIR}/${RADIO}/*.c
+ )
+ endif()
+endforeach()
add_library(${PROJECT_NAME} OBJECT EXCLUDE_FROM_ALL ${${PROJECT_NAME}_SOURCES})
add_dependencies(${PROJECT_NAME} board)
+foreach( R ${RADIO_LIST} )
+ if(${R} MATCHES lr1110 )
+ list(APPEND ${PROJECT_NAME}_INCLUDES
+ ${CMAKE_CURRENT_SOURCE_DIR}/${RADIO})
+ list(APPEND ${PROJECT_NAME}_INCLUDES
+ ${CMAKE_CURRENT_SOURCE_DIR}/${RADIO}/${RADIO}_driver/src)
+ else()
+ list(APPEND ${PROJECT_NAME}_INCLUDES
+ ${CMAKE_CURRENT_SOURCE_DIR}/${RADIO}
+ )
+ endif()
+endforeach()
+
target_include_directories(${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}/sx126x
- ${CMAKE_CURRENT_SOURCE_DIR}/sx1272
- ${CMAKE_CURRENT_SOURCE_DIR}/sx1276
+ ${${PROJECT_NAME}_INCLUDES}
$
$
)
diff --git a/components/connectivity/LoraWAN/radio/lr1110/lr1110.h b/components/connectivity/LoraWAN/radio/lr1110/lr1110.h
new file mode 100644
index 00000000..5fcfd40b
--- /dev/null
+++ b/components/connectivity/LoraWAN/radio/lr1110/lr1110.h
@@ -0,0 +1,117 @@
+/*!
+ * \file lr1110.h
+ *
+ * \brief LR1110 driver implementation
+ *
+ * \copyright Revised BSD License, see file LICENSE.txt
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2019-2019 Semtech
+ *
+ * \endcode
+ */
+
+#ifndef __LR1110_H__
+#define __LR1110_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+#include
+#include "gpio.h"
+#include "spi.h"
+#include "radio.h"
+#include "lr1110_hal.h"
+#include "lr1110_radio_types.h"
+
+/*!
+ * \brief The type describing the modulation parameters for every packet types
+ */
+typedef struct
+{
+ lr1110_radio_packet_types_t packet_type; //!< Packet to which the modulation parameters are referring to.
+ struct
+ {
+ lr1110_radio_modulation_param_gfsk_t gfsk;
+ lr1110_radio_modulation_param_lora_t lora;
+ }modulation; //!< Holds the modulation parameters structure
+} lr1110_modulation_params_t;
+
+/*!
+ * \brief The type describing the packet parameters for every packet types
+ */
+typedef struct
+{
+ lr1110_radio_packet_types_t packet_type; //!< Packet to which the packet parameters are referring to.
+ struct
+ {
+ lr1110_radio_packet_param_gfsk_t gfsk;
+ lr1110_radio_packet_param_lora_t lora;
+ }packet; //!< Holds the packet parameters structure
+} lr1110_packet_params_t;
+
+/*!
+ * \brief Radio operating modes
+ */
+typedef enum lr1110_hal_operating_mode_e
+{
+ LR1110_HAL_OP_MODE_SLEEP = 0x00, //! The radio is in sleep mode
+ LR1110_HAL_OP_MODE_STDBY_RC, //! The radio is in standby mode with RC oscillator
+ LR1110_HAL_OP_MODE_STDBY_XOSC, //! The radio is in standby mode with XOSC oscillator
+ LR1110_HAL_OP_MODE_FS, //! The radio is in frequency synthesis mode
+ LR1110_HAL_OP_MODE_TX, //! The radio is in transmit mode
+ LR1110_HAL_OP_MODE_RX, //! The radio is in receive single mode
+ LR1110_HAL_OP_MODE_RX_C, //! The radio is in receive continuous mode
+ LR1110_HAL_OP_MODE_RX_DC, //! The radio is in receive duty cycle mode
+ LR1110_HAL_OP_MODE_CAD //! The radio is in channel activity detection mode
+} lr1110_hal_operating_mode_t;
+
+/*!
+ * Radio hardware and global parameters
+ */
+typedef struct lr1110_s
+{
+ Gpio_t reset;
+ Gpio_t busy;
+ Gpio_t dio_1;
+ Spi_t spi;
+ lr1110_hal_operating_mode_t op_mode;
+ lr1110_modulation_params_t modulation_params;
+ lr1110_packet_params_t packet_params;
+} lr1110_t;
+
+/*!
+ * Hardware IO IRQ callback function definition
+ */
+typedef void ( *lr1110_dio_irq_handler )( void* context );
+
+/*!
+ * Get radio operating mode
+ *
+ * \remark Must be implemented by the upper layer
+ *
+ * \param [in] context Radio implementation parameters
+ * \retval op_mode Radio current operating mode
+ */
+lr1110_hal_operating_mode_t lr1110_hal_get_operating_mode( const void* context );
+
+/*!
+ * Set radio operating mode
+ *
+ * \remark Must be implemented by the upper layer
+ *
+ * \param [in] context Radio implementation parameters
+ * \param [in] op_mode Radio operating mode
+ */
+void lr1110_hal_set_operating_mode( const void* context, const lr1110_hal_operating_mode_t op_mode );
+
+#endif // __LR1110_H__
diff --git a/components/connectivity/LoraWAN/radio/lr1110/radio.c b/components/connectivity/LoraWAN/radio/lr1110/radio.c
new file mode 100644
index 00000000..5a0a5128
--- /dev/null
+++ b/components/connectivity/LoraWAN/radio/lr1110/radio.c
@@ -0,0 +1,1349 @@
+/*!
+ * \file radio.c
+ *
+ * \brief Radio driver API definition
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2013-2017 Semtech
+ *
+ * \endcode
+ *
+ * \author Benjamin Boulet ( Semtech )
+ */
+#include
+#include
+#include "utilities.h"
+#include "timer.h"
+#include "delay.h"
+#include "radio.h"
+#include "lr1110.h"
+#include "lr1110_hal.h"
+#include "lr1110_radio.h"
+#include "lr1110_system.h"
+#include "lr1110_regmem.h"
+#include "lr1110-board.h"
+#include "board.h"
+
+/*!
+ * \brief Initializes the radio
+ *
+ * \param [IN] events Structure containing the driver callback functions
+ */
+void RadioInit( RadioEvents_t* events );
+
+/*!
+ * Return current radio status
+ *
+ * \param status Radio status.[RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING]
+ */
+RadioState_t RadioGetStatus( void );
+
+/*!
+ * \brief Configures the radio with the given modem
+ *
+ * \param [IN] modem Modem to be used [0: FSK, 1: LoRa]
+ */
+void RadioSetModem( RadioModems_t modem );
+
+/*!
+ * \brief Sets the channel frequency
+ *
+ * \param [IN] freq Channel RF frequency
+ */
+void RadioSetChannel( uint32_t freq );
+
+/*!
+ * \brief Checks if the channel is free for the given time
+ *
+ * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
+ * \param [IN] freq Channel RF frequency
+ * \param [IN] rssiThresh RSSI threshold
+ * \param [IN] maxCarrierSenseTime Max time while the RSSI is measured
+ *
+ * \retval isFree [true: Channel is free, false: Channel is not free]
+ */
+bool RadioIsChannelFree( RadioModems_t modem, uint32_t freq, int16_t rssiThresh, uint32_t maxCarrierSenseTime );
+
+/*!
+ * \brief Generates a 32 bits random value based on the RSSI readings
+ *
+ * \remark This function sets the radio in LoRa modem mode and disables
+ * all interrupts.
+ * After calling this function either Radio.SetRxConfig or
+ * Radio.SetTxConfig functions must be called.
+ *
+ * \retval randomValue 32 bits random value
+ */
+uint32_t RadioRandom( void );
+
+/*!
+ * \brief Sets the reception parameters
+ *
+ * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
+ * \param [IN] bandwidth Sets the bandwidth
+ * FSK : >= 2600 and <= 250000 Hz
+ * LoRa: [0: 125 kHz, 1: 250 kHz,
+ * 2: 500 kHz, 3: Reserved]
+ * \param [IN] datarate Sets the Datarate
+ * FSK : 600..300000 bits/s
+ * LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
+ * 10: 1024, 11: 2048, 12: 4096 chips]
+ * \param [IN] coderate Sets the coding rate (LoRa only)
+ * FSK : N/A ( set to 0 )
+ * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
+ * \param [IN] bandwidthAfc Sets the AFC Bandwidth (FSK only)
+ * FSK : >= 2600 and <= 250000 Hz
+ * LoRa: N/A ( set to 0 )
+ * \param [IN] preambleLen Sets the Preamble length
+ * FSK : Number of bytes
+ * LoRa: Length in symbols (the hardware adds 4 more symbols)
+ * \param [IN] symbTimeout Sets the RxSingle timeout value
+ * FSK : timeout in number of bytes
+ * LoRa: timeout in symbols
+ * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
+ * \param [IN] payloadLen Sets payload length when fixed length is used
+ * \param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
+ * \param [IN] FreqHopOn Enables disables the intra-packet frequency hopping
+ * FSK : N/A ( set to 0 )
+ * LoRa: [0: OFF, 1: ON]
+ * \param [IN] HopPeriod Number of symbols between each hop
+ * FSK : N/A ( set to 0 )
+ * LoRa: Number of symbols
+ * \param [IN] iqInverted Inverts IQ signals (LoRa only)
+ * FSK : N/A ( set to 0 )
+ * LoRa: [0: not inverted, 1: inverted]
+ * \param [IN] rxContinuous Sets the reception in continuous mode
+ * [false: single mode, true: continuous mode]
+ */
+void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth, uint32_t datarate, uint8_t coderate,
+ uint32_t bandwidthAfc, uint16_t preambleLen, uint16_t symbTimeout, bool fixLen,
+ uint8_t payloadLen, bool crcOn, bool FreqHopOn, uint8_t HopPeriod, bool iqInverted,
+ bool rxContinuous );
+
+/*!
+ * \brief Sets the transmission parameters
+ *
+ * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
+ * \param [IN] power Sets the output power [dBm]
+ * \param [IN] fdev Sets the frequency deviation (FSK only)
+ * FSK : [Hz]
+ * LoRa: 0
+ * \param [IN] bandwidth Sets the bandwidth (LoRa only)
+ * FSK : 0
+ * LoRa: [0: 125 kHz, 1: 250 kHz,
+ * 2: 500 kHz, 3: Reserved]
+ * \param [IN] datarate Sets the Datarate
+ * FSK : 600..300000 bits/s
+ * LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
+ * 10: 1024, 11: 2048, 12: 4096 chips]
+ * \param [IN] coderate Sets the coding rate (LoRa only)
+ * FSK : N/A ( set to 0 )
+ * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
+ * \param [IN] preambleLen Sets the preamble length
+ * FSK : Number of bytes
+ * LoRa: Length in symbols (the hardware adds 4 more symbols)
+ * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
+ * \param [IN] crcOn Enables disables the CRC [0: OFF, 1: ON]
+ * \param [IN] FreqHopOn Enables disables the intra-packet frequency hopping
+ * FSK : N/A ( set to 0 )
+ * LoRa: [0: OFF, 1: ON]
+ * \param [IN] HopPeriod Number of symbols between each hop
+ * FSK : N/A ( set to 0 )
+ * LoRa: Number of symbols
+ * \param [IN] iqInverted Inverts IQ signals (LoRa only)
+ * FSK : N/A ( set to 0 )
+ * LoRa: [0: not inverted, 1: inverted]
+ * \param [IN] timeout Transmission timeout [ms]
+ */
+void RadioSetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev, uint32_t bandwidth, uint32_t datarate,
+ uint8_t coderate, uint16_t preambleLen, bool fixLen, bool crcOn, bool FreqHopOn,
+ uint8_t HopPeriod, bool iqInverted, uint32_t timeout );
+
+/*!
+ * \brief Checks if the given RF frequency is supported by the hardware
+ *
+ * \param [IN] frequency RF frequency to be checked
+ * \retval isSupported [true: supported, false: unsupported]
+ */
+bool RadioCheckRfFrequency( uint32_t frequency );
+
+/*!
+ * \brief Computes the packet time on air in ms for the given payload
+ *
+ * \Remark Can only be called once SetRxConfig or SetTxConfig have been called
+ *
+ * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
+ * \param [IN] bandwidth Sets the bandwidth
+ * FSK : >= 2600 and <= 250000 Hz
+ * LoRa: [0: 125 kHz, 1: 250 kHz,
+ * 2: 500 kHz, 3: Reserved]
+ * \param [IN] datarate Sets the Datarate
+ * FSK : 600..300000 bits/s
+ * LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
+ * 10: 1024, 11: 2048, 12: 4096 chips]
+ * \param [IN] coderate Sets the coding rate (LoRa only)
+ * FSK : N/A ( set to 0 )
+ * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
+ * \param [IN] preambleLen Sets the Preamble length
+ * FSK : Number of bytes
+ * LoRa: Length in symbols (the hardware adds 4 more symbols)
+ * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
+ * \param [IN] payloadLen Sets payload length when fixed length is used
+ * \param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
+ *
+ * \retval airTime Computed airTime (ms) for the given packet payload length
+ */
+uint32_t RadioTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn );
+
+/*!
+ * \brief Sends the buffer of size. Prepares the packet to be sent and sets
+ * the radio in transmission
+ *
+ * \param [IN]: buffer Buffer pointer
+ * \param [IN]: size Buffer size
+ */
+void RadioSend( uint8_t* buffer, uint8_t size );
+
+/*!
+ * \brief Sets the radio in sleep mode
+ */
+void RadioSleep( void );
+
+/*!
+ * \brief Sets the radio in standby mode
+ */
+void RadioStandby( void );
+
+/*!
+ * \brief Sets the radio in reception mode for the given time
+ * \param [IN] timeout Reception timeout [ms]
+ * [0: continuous, others timeout]
+ */
+void RadioRx( uint32_t timeout );
+
+/*!
+ * \brief Start a Channel Activity Detection
+ */
+void RadioStartCad( void );
+
+/*!
+ * \brief Sets the radio in continuous wave transmission mode
+ *
+ * \param [IN]: freq Channel RF frequency
+ * \param [IN]: power Sets the output power [dBm]
+ * \param [IN]: time Transmission mode timeout [s]
+ */
+void RadioSetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time );
+
+/*!
+ * \brief Reads the current RSSI value
+ *
+ * \retval rssiValue Current RSSI value in [dBm]
+ */
+int16_t RadioRssi( RadioModems_t modem );
+
+/*!
+ * \brief Writes the radio register at the specified address
+ *
+ * \param [IN]: addr Register address
+ * \param [IN]: data New register value
+ */
+void RadioWrite( uint32_t addr, uint8_t data );
+
+/*!
+ * \brief Reads the radio register at the specified address
+ *
+ * \param [IN]: addr Register address
+ * \retval data Register value
+ */
+uint8_t RadioRead( uint32_t addr );
+
+/*!
+ * \brief Writes multiple radio registers starting at address
+ *
+ * \param [IN] addr First Radio register address
+ * \param [IN] buffer Buffer containing the new register's values
+ * \param [IN] size Number of registers to be written
+ */
+void RadioWriteBuffer( uint32_t addr, uint8_t* buffer, uint8_t size );
+
+/*!
+ * \brief Reads multiple radio registers starting at address
+ *
+ * \param [IN] addr First Radio register address
+ * \param [OUT] buffer Buffer where to copy the registers data
+ * \param [IN] size Number of registers to be read
+ */
+void RadioReadBuffer( uint32_t addr, uint8_t* buffer, uint8_t size );
+
+/*!
+ * \brief Sets the maximum payload length.
+ *
+ * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
+ * \param [IN] max Maximum payload length in bytes
+ */
+void RadioSetMaxPayloadLength( RadioModems_t modem, uint8_t max );
+
+/*!
+ * \brief Sets the network to public or private. Updates the sync byte.
+ *
+ * \remark Applies to LoRa modem only
+ *
+ * \param [IN] enable if true, it enables a public network
+ */
+void RadioSetPublicNetwork( bool enable );
+
+/*!
+ * \brief Gets the time required for the board plus radio to get out of sleep.[ms]
+ *
+ * \retval time Radio plus board wakeup time in ms.
+ */
+uint32_t RadioGetWakeupTime( void );
+
+/*!
+ * \brief Process radio irq
+ */
+void RadioIrqProcess( void );
+
+/*!
+ * \brief Sets the radio in reception mode with Max LNA gain for the given time
+ * \param [IN] timeout Reception timeout [ms]
+ * [0: continuous, others timeout]
+ */
+void RadioRxBoosted( uint32_t timeout );
+
+/*!
+ * \brief Sets the Rx duty cycle management parameters
+ *
+ * \param [in] rxTime Structure describing reception timeout value
+ * \param [in] sleepTime Structure describing sleep timeout value
+ */
+void RadioSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime );
+
+/*!
+ * Radio driver structure initialization
+ */
+const struct Radio_s Radio = {
+ RadioInit,
+ RadioGetStatus,
+ RadioSetModem,
+ RadioSetChannel,
+ RadioIsChannelFree,
+ RadioRandom,
+ RadioSetRxConfig,
+ RadioSetTxConfig,
+ RadioCheckRfFrequency,
+ RadioTimeOnAir,
+ RadioSend,
+ RadioSleep,
+ RadioStandby,
+ RadioRx,
+ RadioStartCad,
+ RadioSetTxContinuousWave,
+ RadioRssi,
+ RadioWrite,
+ RadioRead,
+ RadioWriteBuffer,
+ RadioReadBuffer,
+ RadioSetMaxPayloadLength,
+ RadioSetPublicNetwork,
+ RadioGetWakeupTime,
+ RadioIrqProcess,
+ // Available on LR1110 only
+ RadioRxBoosted,
+ RadioSetRxDutyCycle,
+};
+
+/*
+ * Local types definition
+ */
+
+/*!
+ * FSK bandwidth definition
+ */
+typedef struct
+{
+ uint32_t bandwidth;
+ uint8_t RegValue;
+} FskBandwidth_t;
+
+/*!
+ * Precomputed FSK bandwidth registers values
+ */
+const FskBandwidth_t FskBandwidths[] = {
+ { 4800, 0x1F }, { 5800, 0x17 }, { 7300, 0x0F }, { 9700, 0x1E }, { 11700, 0x16 }, { 14600, 0x0E },
+ { 19500, 0x1D }, { 23400, 0x15 }, { 29300, 0x0D }, { 39000, 0x1C }, { 46900, 0x14 }, { 58600, 0x0C },
+ { 78200, 0x1B }, { 93800, 0x13 }, { 117300, 0x0B }, { 156200, 0x1A }, { 187200, 0x12 }, { 234300, 0x0A },
+ { 312000, 0x19 }, { 373600, 0x11 }, { 467000, 0x09 }, { 500000, 0x00 }, // Invalid Bandwidth
+};
+
+const lr1110_radio_lora_bw_t Bandwidths[] = { LR1110_RADIO_LORA_BW125, LR1110_RADIO_LORA_BW250,
+ LR1110_RADIO_LORA_BW500 };
+
+uint8_t MaxPayloadLength = 0xFF;
+
+uint32_t TxTimeout = 0;
+uint32_t RxTimeout = 0;
+
+bool RxContinuous = false;
+
+lr1110_radio_packet_status_lora_t lora_packet_status;
+lr1110_radio_packet_status_gfsk_t gfsk_packet_status;
+uint8_t RadioRxPayload[255];
+
+bool IrqFired = false;
+
+/*
+ * LR1110 DIO IRQ callback functions prototype
+ */
+
+/*!
+ * \brief DIO 0 IRQ callback
+ */
+void RadioOnDioIrq( void* context );
+
+/*!
+ * \brief Tx timeout timer callback
+ */
+void RadioOnTxTimeoutIrq( void* context );
+
+/*!
+ * \brief Rx timeout timer callback
+ */
+void RadioOnRxTimeoutIrq( void* context );
+
+/*
+ * Private global variables
+ */
+
+/*!
+ * Holds the current network type for the radio
+ */
+typedef struct
+{
+ bool Previous;
+ bool Current;
+} RadioPublicNetwork_t;
+
+static RadioPublicNetwork_t RadioPublicNetwork = { false };
+
+/*!
+ * Radio callbacks variable
+ */
+static RadioEvents_t* RadioEvents;
+
+/*
+ * Public global variables
+ */
+
+/*!
+ * Radio hardware and global parameters
+ */
+lr1110_t LR1110;
+
+/*!
+ * Tx and Rx timers
+ */
+TimerEvent_t TxTimeoutTimer;
+TimerEvent_t RxTimeoutTimer;
+
+/*!
+ * Returns the known FSK bandwidth registers value
+ *
+ * \param [IN] bandwidth Bandwidth value in Hz
+ * \retval regValue Bandwidth register value.
+ */
+static uint8_t RadioGetFskBandwidthRegValue( uint32_t bandwidth )
+{
+ uint8_t i;
+
+ if( bandwidth == 0 )
+ {
+ return ( 0x1F );
+ }
+
+ for( i = 0; i < ( sizeof( FskBandwidths ) / sizeof( FskBandwidth_t ) ) - 1; i++ )
+ {
+ if( ( bandwidth >= FskBandwidths[i].bandwidth ) && ( bandwidth < FskBandwidths[i + 1].bandwidth ) )
+ {
+ return FskBandwidths[i + 1].RegValue;
+ }
+ }
+ // ERROR: Value not found
+ while( 1 )
+ ;
+}
+
+void RadioInit( RadioEvents_t* events )
+{
+ RadioEvents = events;
+
+ lr1110_board_init( &LR1110, RadioOnDioIrq );
+
+ lr1110_system_set_standby( &LR1110, LR1110_SYSTEM_STDBY_CONFIG_RC );
+ lr1110_hal_set_operating_mode( &LR1110, LR1110_HAL_OP_MODE_STDBY_RC );
+
+ lr1110_system_set_regmode( &LR1110, LR1110_SYSTEM_REGMODE_DCDC_CONVERTER );
+
+ lr1110_radio_set_tx_params( &LR1110, 0, LR1110_RADIO_RAMP_TIME_200U );
+ lr1110_system_set_dio_irq_params( &LR1110, LR1110_SYSTEM_IRQ_ALL_MASK, LR1110_SYSTEM_IRQ_NONE_MASK );
+
+ // Initialize driver timeout timers
+ TimerInit( &TxTimeoutTimer, RadioOnTxTimeoutIrq );
+ TimerInit( &RxTimeoutTimer, RadioOnRxTimeoutIrq );
+
+ IrqFired = false;
+}
+
+RadioState_t RadioGetStatus( void )
+{
+ switch( lr1110_hal_get_operating_mode( &LR1110 ) )
+ {
+ case LR1110_HAL_OP_MODE_TX:
+ return RF_TX_RUNNING;
+ case LR1110_HAL_OP_MODE_RX:
+ case LR1110_HAL_OP_MODE_RX_C:
+ case LR1110_HAL_OP_MODE_RX_DC:
+ return RF_RX_RUNNING;
+ case LR1110_HAL_OP_MODE_CAD:
+ return RF_CAD;
+ default:
+ return RF_IDLE;
+ }
+}
+
+void RadioSetModem( RadioModems_t modem )
+{
+ switch( modem )
+ {
+ default:
+ case MODEM_FSK:
+ lr1110_radio_set_packet_type( &LR1110, LR1110_RADIO_PACKET_GFSK );
+ // When switching to GFSK mode the LoRa SyncWord register value is reset
+ // Thus, we also reset the RadioPublicNetwork variable
+ RadioPublicNetwork.Current = false;
+ break;
+ case MODEM_LORA:
+ lr1110_radio_set_packet_type( &LR1110, LR1110_RADIO_PACKET_LORA );
+ // Public/Private network register is reset when switching modems
+ if( RadioPublicNetwork.Current != RadioPublicNetwork.Previous )
+ {
+ RadioPublicNetwork.Current = RadioPublicNetwork.Previous;
+ RadioSetPublicNetwork( RadioPublicNetwork.Current );
+ }
+ break;
+ }
+}
+
+void RadioSetChannel( uint32_t freq )
+{
+ lr1110_radio_set_rf_frequency( &LR1110, freq );
+}
+
+bool RadioIsChannelFree( RadioModems_t modem, uint32_t freq, int16_t rssiThresh, uint32_t maxCarrierSenseTime )
+{
+ bool status = true;
+ int16_t rssi = 0;
+ uint32_t carrierSenseTime = 0;
+
+ if( RadioGetStatus( ) != RF_IDLE )
+ {
+ return false;
+ }
+
+ RadioSetModem( modem );
+
+ RadioSetChannel( freq );
+
+ RadioRx( 0 );
+
+ DelayMs( 1 );
+
+ carrierSenseTime = TimerGetCurrentTime( );
+
+ // Perform carrier sense for maxCarrierSenseTime
+ while( TimerGetElapsedTime( carrierSenseTime ) < maxCarrierSenseTime )
+ {
+ rssi = RadioRssi( modem );
+
+ if( rssi > rssiThresh )
+ {
+ status = false;
+ break;
+ }
+ }
+ RadioSleep( );
+ return status;
+}
+
+uint32_t RadioRandom( void )
+{
+ uint32_t rnd = 0;
+
+ RadioStandby( );
+
+ lr1110_system_get_random_number( &LR1110, &rnd );
+
+ return rnd;
+}
+
+void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth, uint32_t datarate, uint8_t coderate,
+ uint32_t bandwidthAfc, uint16_t preambleLen, uint16_t symbTimeout, bool fixLen,
+ uint8_t payloadLen, bool crcOn, bool freqHopOn, uint8_t hopPeriod, bool iqInverted,
+ bool rxContinuous )
+{
+ RxContinuous = rxContinuous;
+ if( rxContinuous == true )
+ {
+ symbTimeout = 0;
+ }
+ if( fixLen == true )
+ {
+ MaxPayloadLength = payloadLen;
+ }
+ else
+ {
+ MaxPayloadLength = 0xFF;
+ }
+
+ switch( modem )
+ {
+ case MODEM_FSK:
+ lr1110_radio_stop_timeout_on_preamble( &LR1110, false );
+ LR1110.modulation_params.packet_type = LR1110_RADIO_PACKET_GFSK;
+
+ LR1110.modulation_params.modulation.gfsk.bitrate = datarate;
+ LR1110.modulation_params.modulation.gfsk.pulse_shape = LR1110_RADIO_PULSESHAPE_GAUSSIANBT1;
+ LR1110.modulation_params.modulation.gfsk.bandwidth =
+ ( lr1110_radio_gfsk_rx_bw_t ) RadioGetFskBandwidthRegValue( bandwidth );
+
+ LR1110.packet_params.packet_type = LR1110_RADIO_PACKET_GFSK;
+ LR1110.packet_params.packet.gfsk.preamble_length_tx_in_bit = ( preambleLen << 3 ); // convert byte into bit
+ LR1110.packet_params.packet.gfsk.preamble_detect = LR1110_RADIO_GFSK_PREAMBLE_DETECTOR_LENGTH_8BITS;
+ LR1110.packet_params.packet.gfsk.sync_word_length_in_bit = 3 << 3; // convert byte into bit
+ LR1110.packet_params.packet.gfsk.address_filtering = LR1110_RADIO_GFSK_ADDRESS_FILTERING_DISABLE;
+ LR1110.packet_params.packet.gfsk.header_type =
+ ( fixLen == true ) ? LR1110_RADIO_GFSK_HEADER_TYPE_IMPLICIT : LR1110_RADIO_GFSK_HEADER_TYPE_EXPLICIT;
+ LR1110.packet_params.packet.gfsk.payload_length_in_byte = MaxPayloadLength;
+ if( crcOn == true )
+ {
+ LR1110.packet_params.packet.gfsk.crc_type = LR1110_RADIO_GFSK_CRC_2BYTES_INV;
+ }
+ else
+ {
+ LR1110.packet_params.packet.gfsk.crc_type = LR1110_RADIO_GFSK_CRC_OFF;
+ }
+ LR1110.packet_params.packet.gfsk.dc_free = LR1110_RADIO_GFSK_DCFREE_WHITENING;
+
+ RadioStandby( );
+ RadioSetModem( ( LR1110.modulation_params.packet_type == LR1110_RADIO_PACKET_GFSK ) ? MODEM_FSK : MODEM_LORA );
+ lr1110_radio_set_modulation_param_gfsk( &LR1110, &LR1110.modulation_params.modulation.gfsk );
+ lr1110_radio_set_packet_param_gfsk( &LR1110, &LR1110.packet_params.packet.gfsk );
+ lr1110_radio_set_gfsk_sync_word( &LR1110, ( uint8_t[] ){ 0xC1, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00 } );
+ lr1110_radio_set_gfsk_crc_params( &LR1110, 0x1D0F, 0x1021 );
+ lr1110_radio_set_gfsk_whitening_params( &LR1110, 0x01FF );
+
+ RxTimeout = ( uint32_t )( symbTimeout * ( ( 1.0 / ( double ) datarate ) * 8.0 ) * 1000 );
+ break;
+
+ case MODEM_LORA:
+ lr1110_radio_stop_timeout_on_preamble( &LR1110, false );
+ lr1110_radio_set_lora_sync_timeout( &LR1110, symbTimeout );
+ LR1110.modulation_params.packet_type = LR1110_RADIO_PACKET_LORA;
+ LR1110.modulation_params.modulation.lora.spreading_factor = ( lr1110_radio_lora_sf_t ) datarate;
+ LR1110.modulation_params.modulation.lora.bandwidth = Bandwidths[bandwidth];
+ LR1110.modulation_params.modulation.lora.coding_rate = ( lr1110_radio_lora_cr_t ) coderate;
+
+ if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
+ ( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
+ {
+ LR1110.modulation_params.modulation.lora.ppm_offset = 0x01;
+ }
+ else
+ {
+ LR1110.modulation_params.modulation.lora.ppm_offset = 0x00;
+ }
+
+ LR1110.packet_params.packet_type = LR1110_RADIO_PACKET_LORA;
+
+ if( ( LR1110.modulation_params.modulation.lora.spreading_factor == LR1110_RADIO_LORA_SF5 ) ||
+ ( LR1110.modulation_params.modulation.lora.spreading_factor == LR1110_RADIO_LORA_SF6 ) )
+ {
+ if( preambleLen < 12 )
+ {
+ LR1110.packet_params.packet.lora.preamble_length_in_symb = 12;
+ }
+ else
+ {
+ LR1110.packet_params.packet.lora.preamble_length_in_symb = preambleLen;
+ }
+ }
+ else
+ {
+ LR1110.packet_params.packet.lora.preamble_length_in_symb = preambleLen;
+ }
+
+ LR1110.packet_params.packet.lora.header_type = ( lr1110_radio_lora_header_type_t ) fixLen;
+
+ LR1110.packet_params.packet.lora.payload_length_in_byte = MaxPayloadLength;
+ LR1110.packet_params.packet.lora.crc = ( lr1110_radio_lora_crc_t ) crcOn;
+ LR1110.packet_params.packet.lora.iq = ( lr1110_radio_lora_iq_t ) iqInverted;
+
+ RadioSetModem( ( LR1110.modulation_params.packet_type == LR1110_RADIO_PACKET_GFSK ) ? MODEM_FSK : MODEM_LORA );
+ lr1110_radio_set_modulation_param_lora( &LR1110, &LR1110.modulation_params.modulation.lora );
+ lr1110_radio_set_packet_param_lora( &LR1110, &LR1110.packet_params.packet.lora );
+
+ // Timeout Max, Timeout handled directly in SetRx function
+ RxTimeout = 0xFFFF;
+
+ break;
+ }
+}
+
+void RadioSetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev, uint32_t bandwidth, uint32_t datarate,
+ uint8_t coderate, uint16_t preambleLen, bool fixLen, bool crcOn, bool freqHopOn,
+ uint8_t hopPeriod, bool iqInverted, uint32_t timeout )
+{
+ switch( modem )
+ {
+ case MODEM_FSK:
+ LR1110.modulation_params.packet_type = LR1110_RADIO_PACKET_GFSK;
+ LR1110.modulation_params.modulation.gfsk.bitrate = datarate;
+
+ LR1110.modulation_params.modulation.gfsk.pulse_shape = LR1110_RADIO_PULSESHAPE_GAUSSIANBT1;
+ LR1110.modulation_params.modulation.gfsk.bandwidth =
+ ( lr1110_radio_gfsk_rx_bw_t ) RadioGetFskBandwidthRegValue( bandwidth );
+ LR1110.modulation_params.modulation.gfsk.fdev = fdev;
+
+ LR1110.packet_params.packet_type = LR1110_RADIO_PACKET_GFSK;
+ LR1110.packet_params.packet.gfsk.preamble_length_tx_in_bit = ( preambleLen << 3 ); // convert byte into bit
+ LR1110.packet_params.packet.gfsk.preamble_detect = LR1110_RADIO_GFSK_PREAMBLE_DETECTOR_LENGTH_8BITS;
+ LR1110.packet_params.packet.gfsk.sync_word_length_in_bit = 3 << 3; // convert byte into bit
+ LR1110.packet_params.packet.gfsk.address_filtering = LR1110_RADIO_GFSK_ADDRESS_FILTERING_DISABLE;
+ LR1110.packet_params.packet.gfsk.header_type =
+ ( fixLen == true ) ? LR1110_RADIO_GFSK_HEADER_TYPE_IMPLICIT : LR1110_RADIO_GFSK_HEADER_TYPE_EXPLICIT;
+
+ if( crcOn == true )
+ {
+ LR1110.packet_params.packet.gfsk.crc_type = LR1110_RADIO_GFSK_CRC_2BYTES_INV;
+ }
+ else
+ {
+ LR1110.packet_params.packet.gfsk.crc_type = LR1110_RADIO_GFSK_CRC_OFF;
+ }
+ LR1110.packet_params.packet.gfsk.dc_free = LR1110_RADIO_GFSK_DCFREE_WHITENING;
+
+ RadioStandby( );
+ RadioSetModem( ( LR1110.modulation_params.packet_type == LR1110_RADIO_PACKET_GFSK ) ? MODEM_FSK : MODEM_LORA );
+ lr1110_radio_set_modulation_param_gfsk( &LR1110, &LR1110.modulation_params.modulation.gfsk );
+ lr1110_radio_set_packet_param_gfsk( &LR1110, &LR1110.packet_params.packet.gfsk );
+ lr1110_radio_set_gfsk_sync_word( &LR1110, ( uint8_t[] ){ 0xC1, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00 } );
+ lr1110_radio_set_gfsk_crc_params( &LR1110, 0x1D0F, 0x1021 );
+ lr1110_radio_set_gfsk_whitening_params( &LR1110, 0x01FF );
+ break;
+
+ case MODEM_LORA:
+ LR1110.modulation_params.packet_type = LR1110_RADIO_PACKET_LORA;
+ LR1110.modulation_params.modulation.lora.spreading_factor = ( lr1110_radio_lora_sf_t ) datarate;
+ LR1110.modulation_params.modulation.lora.bandwidth = Bandwidths[bandwidth];
+ LR1110.modulation_params.modulation.lora.coding_rate = ( lr1110_radio_lora_cr_t ) coderate;
+
+ if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
+ ( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
+ {
+ LR1110.modulation_params.modulation.lora.ppm_offset = 0x01;
+ }
+ else
+ {
+ LR1110.modulation_params.modulation.lora.ppm_offset = 0x00;
+ }
+
+ LR1110.packet_params.packet_type = LR1110_RADIO_PACKET_LORA;
+
+ if( ( LR1110.modulation_params.modulation.lora.spreading_factor == LR1110_RADIO_LORA_SF5 ) ||
+ ( LR1110.modulation_params.modulation.lora.spreading_factor == LR1110_RADIO_LORA_SF6 ) )
+ {
+ if( preambleLen < 12 )
+ {
+ LR1110.packet_params.packet.lora.preamble_length_in_symb = 12;
+ }
+ else
+ {
+ LR1110.packet_params.packet.lora.preamble_length_in_symb = preambleLen;
+ }
+ }
+ else
+ {
+ LR1110.packet_params.packet.lora.preamble_length_in_symb = preambleLen;
+ }
+
+ LR1110.packet_params.packet.lora.header_type = ( lr1110_radio_lora_header_type_t ) fixLen;
+ LR1110.packet_params.packet.lora.payload_length_in_byte = MaxPayloadLength;
+ LR1110.packet_params.packet.lora.crc = ( lr1110_radio_lora_crc_t ) crcOn;
+ LR1110.packet_params.packet.lora.iq = ( lr1110_radio_lora_iq_t ) iqInverted;
+
+ RadioStandby( );
+ RadioSetModem( ( LR1110.modulation_params.packet_type == LR1110_RADIO_PACKET_GFSK ) ? MODEM_FSK : MODEM_LORA );
+ lr1110_radio_set_modulation_param_lora( &LR1110, &LR1110.modulation_params.modulation.lora );
+ lr1110_radio_set_packet_param_lora( &LR1110, &LR1110.packet_params.packet.lora );
+ break;
+ }
+
+ lr1110_board_set_rf_tx_power( &LR1110, power );
+ TxTimeout = timeout;
+}
+
+bool RadioCheckRfFrequency( uint32_t frequency )
+{
+ return true;
+}
+
+static uint32_t RadioGetLoRaBandwidthInHz( lr1110_radio_lora_bw_t bw )
+{
+ uint32_t bandwidthInHz = 0;
+
+ switch( bw )
+ {
+ case LR1110_RADIO_LORA_BW10:
+ bandwidthInHz = 10417UL;
+ break;
+ case LR1110_RADIO_LORA_BW15:
+ bandwidthInHz = 15625UL;
+ break;
+ case LR1110_RADIO_LORA_BW20:
+ bandwidthInHz = 20833UL;
+ break;
+ case LR1110_RADIO_LORA_BW31:
+ bandwidthInHz = 31250UL;
+ break;
+ case LR1110_RADIO_LORA_BW41:
+ bandwidthInHz = 41667UL;
+ break;
+ case LR1110_RADIO_LORA_BW62:
+ bandwidthInHz = 62500UL;
+ break;
+ case LR1110_RADIO_LORA_BW125:
+ bandwidthInHz = 125000UL;
+ break;
+ case LR1110_RADIO_LORA_BW250:
+ bandwidthInHz = 250000UL;
+ break;
+ case LR1110_RADIO_LORA_BW500:
+ bandwidthInHz = 500000UL;
+ break;
+ }
+
+ return bandwidthInHz;
+}
+
+static uint32_t RadioGetGfskTimeOnAirNumerator( uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn )
+{
+ const uint8_t syncWordLength = 3;
+
+ return ( preambleLen << 3 ) +
+ ( ( fixLen == false ) ? 8 : 0 ) +
+ ( syncWordLength << 3 ) +
+ ( ( payloadLen +
+ ( 0 ) +
+ ( ( crcOn == true ) ? 2 : 0 )
+ ) << 3
+ );
+}
+
+static uint32_t RadioGetLoRaTimeOnAirNumerator( uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn )
+{
+ int32_t crDenom = coderate + 4;
+ bool lowDatareOptimize = false;
+
+ // Ensure that the preamble length is at least 12 symbols when using SF5 or
+ // SF6
+ if( ( datarate == 5 ) || ( datarate == 6 ) )
+ {
+ if( preambleLen < 12 )
+ {
+ preambleLen = 12;
+ }
+ }
+
+ if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
+ ( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
+ {
+ lowDatareOptimize = true;
+ }
+
+ int32_t ceilDenominator;
+ int32_t ceilNumerator = ( payloadLen << 3 ) +
+ ( crcOn ? 16 : 0 ) -
+ ( 4 * datarate ) +
+ ( fixLen ? 0 : 20 );
+
+ if( datarate <= 6 )
+ {
+ ceilDenominator = 4 * datarate;
+ }
+ else
+ {
+ ceilNumerator += 8;
+
+ if( lowDatareOptimize == true )
+ {
+ ceilDenominator = 4 * ( datarate - 2 );
+ }
+ else
+ {
+ ceilDenominator = 4 * datarate;
+ }
+ }
+
+ if( ceilNumerator < 0 )
+ {
+ ceilNumerator = 0;
+ }
+
+ // Perform integral ceil()
+ int32_t intermediate =
+ ( ( ceilNumerator + ceilDenominator - 1 ) / ceilDenominator ) * crDenom + preambleLen + 12;
+
+ if( datarate <= 6 )
+ {
+ intermediate += 2;
+ }
+
+ return ( uint32_t )( ( 4 * intermediate + 1 ) * ( 1 << ( datarate - 2 ) ) );
+}
+
+uint32_t RadioTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn )
+{
+ uint32_t numerator = 0;
+ uint32_t denominator = 1;
+
+ switch( modem )
+ {
+ case MODEM_FSK:
+ {
+ numerator = 1000U * RadioGetGfskTimeOnAirNumerator( datarate, coderate,
+ preambleLen, fixLen,
+ payloadLen, crcOn );
+ denominator = datarate;
+ }
+ break;
+ case MODEM_LORA:
+ {
+ numerator = 1000U * RadioGetLoRaTimeOnAirNumerator( bandwidth, datarate,
+ coderate, preambleLen,
+ fixLen, payloadLen, crcOn );
+ denominator = RadioGetLoRaBandwidthInHz( Bandwidths[bandwidth] );
+ }
+ break;
+ }
+ // Perform integral ceil()
+ return ( numerator + denominator - 1 ) / denominator;
+}
+
+void RadioSend( uint8_t* buffer, uint8_t size )
+{
+ lr1110_radio_packet_types_t packet_type;
+
+ lr1110_system_set_dio_irq_params( &LR1110, LR1110_SYSTEM_IRQ_TXDONE_MASK | LR1110_SYSTEM_IRQ_TIMEOUT_MASK,
+ LR1110_SYSTEM_IRQ_NONE_MASK );
+
+ lr1110_radio_get_packet_type( &LR1110, &packet_type );
+ if( packet_type == LR1110_RADIO_PACKET_LORA )
+ {
+ LR1110.packet_params.packet.lora.payload_length_in_byte = size;
+ lr1110_radio_set_packet_param_lora( &LR1110, &LR1110.packet_params.packet.lora );
+ }
+ else
+ {
+ LR1110.packet_params.packet.gfsk.payload_length_in_byte = size;
+ lr1110_radio_set_packet_param_gfsk( &LR1110, &LR1110.packet_params.packet.gfsk );
+ }
+
+ /* Send Payload */
+ lr1110_regmem_write_buffer8( &LR1110, buffer, size );
+ lr1110_radio_set_tx( &LR1110, 0 );
+ lr1110_hal_set_operating_mode( &LR1110, LR1110_HAL_OP_MODE_TX );
+
+ TimerSetValue( &TxTimeoutTimer, TxTimeout );
+ TimerStart( &TxTimeoutTimer );
+}
+
+void RadioSleep( void )
+{
+ lr1110_system_sleep_config_t sleep_config;
+
+ sleep_config.is_warm_start = 1;
+ sleep_config.is_rtc_timeout = 0;
+
+ lr1110_system_set_sleep( &LR1110, sleep_config, 0 );
+ lr1110_hal_set_operating_mode( &LR1110, LR1110_HAL_OP_MODE_SLEEP );
+
+ DelayMs( 2 );
+}
+
+void RadioStandby( void )
+{
+ lr1110_system_set_standby( &LR1110, LR1110_SYSTEM_STDBY_CONFIG_RC );
+ lr1110_hal_set_operating_mode( &LR1110, LR1110_HAL_OP_MODE_STDBY_RC );
+}
+
+void RadioRx( uint32_t timeout )
+{
+ lr1110_system_set_dio_irq_params(
+ &LR1110,
+ LR1110_SYSTEM_IRQ_ALL_MASK, // LR1110_SYSTEM_IRQ_RXDONE_MASK | LR1110_SYSTEM_IRQ_TIMEOUT_MASK,
+ LR1110_SYSTEM_IRQ_NONE_MASK );
+
+ lr1110_radio_set_rx_boosted( &LR1110, false );
+
+ if( timeout != 0 )
+ {
+ TimerSetValue( &RxTimeoutTimer, timeout );
+ TimerStart( &RxTimeoutTimer );
+ }
+
+ if( RxContinuous == true )
+ {
+ lr1110_radio_set_rx( &LR1110, 0xFFFFFF ); // Rx Continuous
+ lr1110_hal_set_operating_mode( &LR1110, LR1110_HAL_OP_MODE_RX_C );
+ }
+ else
+ {
+ lr1110_radio_set_rx( &LR1110, ( RxTimeout * 32768 ) );
+ lr1110_hal_set_operating_mode( &LR1110, LR1110_HAL_OP_MODE_RX );
+ }
+}
+
+void RadioRxBoosted( uint32_t timeout )
+{
+ lr1110_system_set_dio_irq_params(
+ &LR1110,
+ LR1110_SYSTEM_IRQ_ALL_MASK, // LR1110_SYSTEM_IRQ_RXDONE_MASK | LR1110_SYSTEM_IRQ_TIMEOUT_MASK,
+ LR1110_SYSTEM_IRQ_NONE_MASK );
+
+ if( timeout != 0 )
+ {
+ TimerSetValue( &RxTimeoutTimer, timeout );
+ TimerStart( &RxTimeoutTimer );
+ }
+
+ lr1110_radio_set_rx_boosted( &LR1110, true );
+ if( RxContinuous == true )
+ {
+ lr1110_radio_set_rx( &LR1110, 0xFFFFFF ); // Rx Continuous
+ lr1110_hal_set_operating_mode( &LR1110, LR1110_HAL_OP_MODE_RX_C );
+ }
+ else
+ {
+ lr1110_radio_set_rx( &LR1110, ( RxTimeout * 32768 ) );
+ lr1110_hal_set_operating_mode( &LR1110, LR1110_HAL_OP_MODE_RX );
+ }
+}
+
+void RadioSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime )
+{
+ lr1110_radio_set_rx_dutycycle( &LR1110, rxTime, sleepTime, 0 );
+ lr1110_hal_set_operating_mode( &LR1110, LR1110_HAL_OP_MODE_RX_DC );
+}
+
+void RadioStartCad( void )
+{
+ lr1110_radio_set_cad( &LR1110 );
+ lr1110_hal_set_operating_mode( &LR1110, LR1110_HAL_OP_MODE_CAD );
+}
+
+void RadioTx( uint32_t timeout )
+{
+ lr1110_radio_set_tx( &LR1110, timeout * 32768 );
+ lr1110_hal_set_operating_mode( &LR1110, LR1110_HAL_OP_MODE_TX );
+}
+
+void RadioSetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time )
+{
+ uint32_t timeout = ( uint32_t )time * 1000;
+
+ lr1110_radio_set_rf_frequency( &LR1110, freq );
+ lr1110_board_set_rf_tx_power( &LR1110, power );
+ lr1110_radio_set_tx_cw( &LR1110 );
+ lr1110_hal_set_operating_mode( &LR1110, LR1110_HAL_OP_MODE_TX );
+
+ TimerSetValue( &TxTimeoutTimer, timeout );
+ TimerStart( &TxTimeoutTimer );
+}
+
+int16_t RadioRssi( RadioModems_t modem )
+{
+ int8_t rssi = 0;
+
+ lr1110_radio_get_rssi_inst( &LR1110, &rssi );
+
+ return rssi;
+}
+
+void RadioWrite( uint32_t addr, uint8_t data )
+{
+ lr1110_regmem_write_mem8( &LR1110, addr, &data, 1 );
+}
+
+uint8_t RadioRead( uint32_t addr )
+{
+ uint8_t data = 0;
+
+ lr1110_regmem_read_mem8( &LR1110, addr, &data, 1 );
+
+ return data;
+}
+
+void RadioWriteBuffer( uint32_t addr, uint8_t* buffer, uint8_t size )
+{
+ lr1110_regmem_write_buffer8( &LR1110, buffer, size );
+}
+
+void RadioReadBuffer( uint32_t addr, uint8_t* buffer, uint8_t size )
+{
+ lr1110_regmem_read_buffer8( &LR1110, buffer, addr, size );
+}
+
+void RadioWriteFifo( uint8_t* buffer, uint8_t size )
+{
+ lr1110_regmem_write_buffer8( &LR1110, buffer, size );
+}
+
+void RadioReadFifo( uint8_t* buffer, uint8_t offset, uint8_t size )
+{
+ lr1110_regmem_read_buffer8( &LR1110, buffer, offset, size );
+}
+
+void RadioSetMaxPayloadLength( RadioModems_t modem, uint8_t max )
+{
+ if( modem == MODEM_LORA )
+ {
+ LR1110.packet_params.packet.lora.payload_length_in_byte = MaxPayloadLength = max;
+ lr1110_radio_set_packet_param_lora( &LR1110, &LR1110.packet_params.packet.lora );
+ }
+ else
+ {
+ if( LR1110.packet_params.packet.gfsk.header_type == LR1110_RADIO_GFSK_HEADER_TYPE_EXPLICIT )
+ {
+ LR1110.packet_params.packet.gfsk.payload_length_in_byte = MaxPayloadLength = max;
+ lr1110_radio_set_packet_param_gfsk( &LR1110, &LR1110.packet_params.packet.gfsk );
+ }
+ }
+}
+
+void RadioSetPublicNetwork( bool enable )
+{
+ RadioPublicNetwork.Current = RadioPublicNetwork.Previous = enable;
+
+ RadioSetModem( MODEM_LORA );
+ if( enable == true )
+ {
+ // Change LoRa modem SyncWord
+ lr1110_radio_set_lora_sync_word( &LR1110, LR1110_RADIO_LORA_NETWORK_PUBLIC );
+ }
+ else
+ {
+ // Change LoRa modem SyncWord
+ lr1110_radio_set_lora_sync_word( &LR1110, LR1110_RADIO_LORA_NETWORK_PRIVATE );
+ }
+}
+
+uint32_t RadioGetWakeupTime( void )
+{
+ return lr1110_board_get_tcxo_wakeup_time( &LR1110 ) + 3;
+}
+
+void RadioOnTxTimeoutIrq( void* context )
+{
+ if( ( RadioEvents != NULL ) && ( RadioEvents->TxTimeout != NULL ) )
+ {
+ RadioEvents->TxTimeout( );
+ }
+}
+
+void RadioOnRxTimeoutIrq( void* context )
+{
+ if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) )
+ {
+ RadioEvents->RxTimeout( );
+ }
+}
+
+void RadioOnDioIrq( void* context )
+{
+ IrqFired = true;
+}
+
+/*!
+ * \brief Callback - handle the interrupt get & clear
+ *
+ * This function shall be called each time there is an interrupt coming from the
+ * radio. It is responsible for the update of the operating mode.
+ *
+ * \param [in] radio Radio abstraction
+ *
+ * \param [out] irq Pointer to the interrupt field returned to the caller
+ *
+ * \see lr1110_system_get_status, lr1110_system_clear_irq
+ */
+static void lr1110_system_irq_process( const void* radio, uint32_t* irq )
+{
+ lr1110_system_stat1_t stat1;
+ lr1110_system_stat2_t stat2;
+
+ lr1110_hal_operating_mode_t op_mode = lr1110_hal_get_operating_mode( radio );
+
+ lr1110_system_get_status( radio, &stat1, &stat2, irq );
+ lr1110_system_clear_irq( radio, *irq );
+
+ if( ( ( *irq & LR1110_SYSTEM_IRQ_TXDONE_MASK ) != 0 ) || ( ( *irq & LR1110_SYSTEM_IRQ_CADDONE_MASK ) != 0 ) ||
+ ( ( *irq & LR1110_SYSTEM_IRQ_TIMEOUT_MASK ) != 0 ) )
+ {
+ lr1110_hal_set_operating_mode( radio, LR1110_HAL_OP_MODE_STDBY_RC );
+ }
+
+ if( ( ( *irq & LR1110_SYSTEM_IRQ_HEADERERR_MASK ) != 0 ) || ( ( *irq & LR1110_SYSTEM_IRQ_RXDONE_MASK ) != 0 ) ||
+ ( ( *irq & LR1110_SYSTEM_IRQ_CRCERR_MASK ) != 0 ) )
+ {
+ if( op_mode != LR1110_HAL_OP_MODE_RX_C )
+ {
+ lr1110_hal_set_operating_mode( radio, LR1110_HAL_OP_MODE_STDBY_RC );
+ }
+ }
+}
+
+void RadioIrqProcess( void )
+{
+ if( IrqFired == true )
+ {
+ CRITICAL_SECTION_BEGIN( );
+ // Clear IRQ flag
+ IrqFired = false;
+ CRITICAL_SECTION_END( );
+
+ uint32_t irqRegs;
+ // Get Status
+ lr1110_system_irq_process( &LR1110, &irqRegs );
+
+ if( ( irqRegs & LR1110_SYSTEM_IRQ_TXDONE_MASK ) == LR1110_SYSTEM_IRQ_TXDONE_MASK )
+ {
+ TimerStop( &TxTimeoutTimer );
+ if( ( RadioEvents != NULL ) && ( RadioEvents->TxDone != NULL ) )
+ {
+ RadioEvents->TxDone( );
+ }
+ }
+
+ if( ( irqRegs & LR1110_SYSTEM_IRQ_RXDONE_MASK ) == LR1110_SYSTEM_IRQ_RXDONE_MASK )
+ {
+ lr1110_radio_packet_types_t packet_type;
+ lr1110_radio_rxbuffer_status_t rxbuffer_status;
+
+ TimerStop( &RxTimeoutTimer );
+
+ lr1110_radio_get_rxbuffer_status( &LR1110, &rxbuffer_status );
+ lr1110_regmem_read_buffer8( &LR1110, RadioRxPayload, rxbuffer_status.rx_start_buffer_pointer,
+ rxbuffer_status.rx_payload_length );
+
+ lr1110_radio_get_packet_type( &LR1110, &packet_type );
+ if( packet_type == LR1110_RADIO_PACKET_LORA )
+ {
+ lr1110_radio_get_packet_status_lora( &LR1110, &lora_packet_status );
+ if( ( RadioEvents != NULL ) && ( RadioEvents->RxDone != NULL ) )
+ {
+ RadioEvents->RxDone( RadioRxPayload, rxbuffer_status.rx_payload_length,
+ lora_packet_status.rssi_packet_in_dbm, lora_packet_status.snr_packet_in_db );
+ }
+ }
+ else
+ {
+ lr1110_radio_get_packet_status_gfsk( &LR1110, &gfsk_packet_status );
+ if( ( RadioEvents != NULL ) && ( RadioEvents->RxDone != NULL ) )
+ {
+ RadioEvents->RxDone( RadioRxPayload, rxbuffer_status.rx_payload_length,
+ gfsk_packet_status.rssi_avg_in_dbm, 0 );
+ }
+ }
+ }
+
+ if( ( irqRegs & LR1110_SYSTEM_IRQ_CRCERR_MASK ) == LR1110_SYSTEM_IRQ_CRCERR_MASK )
+ {
+ if( ( RadioEvents != NULL ) && ( RadioEvents->RxError != NULL ) )
+ {
+ RadioEvents->RxError( );
+ }
+ }
+
+ if( ( irqRegs & LR1110_SYSTEM_IRQ_CADDONE_MASK ) == LR1110_SYSTEM_IRQ_CADDONE_MASK )
+ {
+ if( ( RadioEvents != NULL ) && ( RadioEvents->CadDone != NULL ) )
+ {
+ RadioEvents->CadDone(
+ ( ( irqRegs & LR1110_SYSTEM_IRQ_CADDETECTED_MASK ) == LR1110_SYSTEM_IRQ_CADDETECTED_MASK ) );
+ }
+ }
+
+ if( ( irqRegs & LR1110_SYSTEM_IRQ_TIMEOUT_MASK ) == LR1110_SYSTEM_IRQ_TIMEOUT_MASK )
+ {
+ TimerStop( &RxTimeoutTimer );
+ if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) )
+ {
+ RadioEvents->RxTimeout( );
+ }
+ }
+
+ if( ( irqRegs & LR1110_SYSTEM_IRQ_PREAMBLEDETECTED_MASK ) == LR1110_SYSTEM_IRQ_PREAMBLEDETECTED_MASK )
+ {
+ //__NOP( );
+ }
+
+ if( ( irqRegs & LR1110_SYSTEM_IRQ_SYNCWORD_HEADERVALID_MASK ) == LR1110_SYSTEM_IRQ_SYNCWORD_HEADERVALID_MASK )
+ {
+ //__NOP( );
+ }
+
+ if( ( irqRegs & LR1110_SYSTEM_IRQ_HEADERERR_MASK ) == LR1110_SYSTEM_IRQ_HEADERERR_MASK )
+ {
+ TimerStop( &RxTimeoutTimer );
+ if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) )
+ {
+ RadioEvents->RxTimeout( );
+ }
+ }
+
+ if( ( irqRegs & LR1110_SYSTEM_IRQ_GNSSSCANDONE_MASK ) == LR1110_SYSTEM_IRQ_GNSSSCANDONE_MASK )
+ {
+ if( ( RadioEvents != NULL ) && ( RadioEvents->GnssDone != NULL ) )
+ {
+ RadioEvents->GnssDone( );
+ }
+ }
+
+ if( ( irqRegs & LR1110_SYSTEM_IRQ_WIFISCANDONE_MASK ) == LR1110_SYSTEM_IRQ_WIFISCANDONE_MASK )
+ {
+ if( ( RadioEvents != NULL ) && ( RadioEvents->WifiDone != NULL ) )
+ {
+ RadioEvents->WifiDone( );
+ }
+ }
+ }
+}
diff --git a/components/connectivity/LoraWAN/radio/radio.h b/components/connectivity/LoraWAN/radio/radio.h
index 06332607..425978d2 100644
--- a/components/connectivity/LoraWAN/radio/radio.h
+++ b/components/connectivity/LoraWAN/radio/radio.h
@@ -23,6 +23,11 @@
#ifndef __RADIO_H__
#define __RADIO_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
@@ -91,6 +96,16 @@ typedef struct
* \param [IN] channelDetected Channel Activity detected during the CAD
*/
void ( *CadDone ) ( bool channelActivityDetected );
+
+ /*!
+ * \brief Gnss Done Done callback prototype.
+ */
+ void ( *GnssDone )( void );
+
+ /*!
+ * \brief Gnss Done Done callback prototype.
+ */
+ void ( *WifiDone )( void );
}RadioEvents_t;
/*!
@@ -243,11 +258,30 @@ struct Radio_s
* \Remark Can only be called once SetRxConfig or SetTxConfig have been called
*
* \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
- * \param [IN] pktLen Packet payload length
+ * \param [IN] bandwidth Sets the bandwidth
+ * FSK : >= 2600 and <= 250000 Hz
+ * LoRa: [0: 125 kHz, 1: 250 kHz,
+ * 2: 500 kHz, 3: Reserved]
+ * \param [IN] datarate Sets the Datarate
+ * FSK : 600..300000 bits/s
+ * LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
+ * 10: 1024, 11: 2048, 12: 4096 chips]
+ * \param [IN] coderate Sets the coding rate (LoRa only)
+ * FSK : N/A ( set to 0 )
+ * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
+ * \param [IN] preambleLen Sets the Preamble length
+ * FSK : Number of bytes
+ * LoRa: Length in symbols (the hardware adds 4 more symbols)
+ * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
+ * \param [IN] payloadLen Sets payload length when fixed length is used
+ * \param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
*
* \retval airTime Computed airTime (ms) for the given packet payload length
*/
- uint32_t ( *TimeOnAir )( RadioModems_t modem, uint8_t pktLen );
+ uint32_t ( *TimeOnAir )( RadioModems_t modem, uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn );
/*!
* \brief Sends the buffer of size. Prepares the packet to be sent and sets
* the radio in transmission
@@ -294,14 +328,14 @@ struct Radio_s
* \param [IN]: addr Register address
* \param [IN]: data New register value
*/
- void ( *Write )( uint16_t addr, uint8_t data );
+ void ( *Write )( uint32_t addr, uint8_t data );
/*!
* \brief Reads the radio register at the specified address
*
* \param [IN]: addr Register address
* \retval data Register value
*/
- uint8_t ( *Read )( uint16_t addr );
+ uint8_t ( *Read )( uint32_t addr );
/*!
* \brief Writes multiple radio registers starting at address
*
@@ -309,7 +343,7 @@ struct Radio_s
* \param [IN] buffer Buffer containing the new register's values
* \param [IN] size Number of registers to be written
*/
- void ( *WriteBuffer )( uint16_t addr, uint8_t *buffer, uint8_t size );
+ void ( *WriteBuffer )( uint32_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Reads multiple radio registers starting at address
*
@@ -317,7 +351,7 @@ struct Radio_s
* \param [OUT] buffer Buffer where to copy the registers data
* \param [IN] size Number of registers to be read
*/
- void ( *ReadBuffer )( uint16_t addr, uint8_t *buffer, uint8_t size );
+ void ( *ReadBuffer )( uint32_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Sets the maximum payload length.
*
@@ -374,4 +408,8 @@ struct Radio_s
*/
extern const struct Radio_s Radio;
+#ifdef __cplusplus
+}
+#endif
+
#endif // __RADIO_H__
diff --git a/components/connectivity/LoraWAN/radio/sx126x/radio.c b/components/connectivity/LoraWAN/radio/sx126x/radio.c
index c2f3e6d2..37ec5de5 100644
--- a/components/connectivity/LoraWAN/radio/sx126x/radio.c
+++ b/components/connectivity/LoraWAN/radio/sx126x/radio.c
@@ -184,11 +184,30 @@ bool RadioCheckRfFrequency( uint32_t frequency );
* \Remark Can only be called once SetRxConfig or SetTxConfig have been called
*
* \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
- * \param [IN] pktLen Packet payload length
+ * \param [IN] bandwidth Sets the bandwidth
+ * FSK : >= 2600 and <= 250000 Hz
+ * LoRa: [0: 125 kHz, 1: 250 kHz,
+ * 2: 500 kHz, 3: Reserved]
+ * \param [IN] datarate Sets the Datarate
+ * FSK : 600..300000 bits/s
+ * LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
+ * 10: 1024, 11: 2048, 12: 4096 chips]
+ * \param [IN] coderate Sets the coding rate (LoRa only)
+ * FSK : N/A ( set to 0 )
+ * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
+ * \param [IN] preambleLen Sets the Preamble length
+ * FSK : Number of bytes
+ * LoRa: Length in symbols (the hardware adds 4 more symbols)
+ * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
+ * \param [IN] payloadLen Sets payload length when fixed length is used
+ * \param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
*
* \retval airTime Computed airTime (ms) for the given packet payload length
*/
-uint32_t RadioTimeOnAir( RadioModems_t modem, uint8_t pktLen );
+uint32_t RadioTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn );
/*!
* \brief Sends the buffer of size. Prepares the packet to be sent and sets
@@ -243,7 +262,7 @@ int16_t RadioRssi( RadioModems_t modem );
* \param [IN]: addr Register address
* \param [IN]: data New register value
*/
-void RadioWrite( uint16_t addr, uint8_t data );
+void RadioWrite( uint32_t addr, uint8_t data );
/*!
* \brief Reads the radio register at the specified address
@@ -251,7 +270,7 @@ void RadioWrite( uint16_t addr, uint8_t data );
* \param [IN]: addr Register address
* \retval data Register value
*/
-uint8_t RadioRead( uint16_t addr );
+uint8_t RadioRead( uint32_t addr );
/*!
* \brief Writes multiple radio registers starting at address
@@ -260,7 +279,7 @@ uint8_t RadioRead( uint16_t addr );
* \param [IN] buffer Buffer containing the new register's values
* \param [IN] size Number of registers to be written
*/
-void RadioWriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size );
+void RadioWriteBuffer( uint32_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Reads multiple radio registers starting at address
@@ -269,7 +288,7 @@ void RadioWriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size );
* \param [OUT] buffer Buffer where to copy the registers data
* \param [IN] size Number of registers to be read
*/
-void RadioReadBuffer( uint16_t addr, uint8_t *buffer, uint8_t size );
+void RadioReadBuffer( uint32_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Sets the maximum payload length.
@@ -395,11 +414,6 @@ const FskBandwidth_t FskBandwidths[] =
const RadioLoRaBandwidths_t Bandwidths[] = { LORA_BW_125, LORA_BW_250, LORA_BW_500 };
-// SF12 SF11 SF10 SF9 SF8 SF7
-static double RadioLoRaSymbTime[3][6] = {{ 32.768, 16.384, 8.192, 4.096, 2.048, 1.024 }, // 125 KHz
- { 16.384, 8.192, 4.096, 2.048, 1.024, 0.512 }, // 250 KHz
- { 8.192, 4.096, 2.048, 1.024, 0.512, 0.256 }}; // 500 KHz
-
uint8_t MaxPayloadLength = 0xFF;
uint32_t TxTimeout = 0;
@@ -562,6 +576,8 @@ bool RadioIsChannelFree( RadioModems_t modem, uint32_t freq, int16_t rssiThresh,
int16_t rssi = 0;
uint32_t carrierSenseTime = 0;
+ RadioSleep( );
+
RadioSetModem( modem );
RadioSetChannel( freq );
@@ -589,7 +605,6 @@ bool RadioIsChannelFree( RadioModems_t modem, uint32_t freq, int16_t rssiThresh,
uint32_t RadioRandom( void )
{
- uint8_t i;
uint32_t rnd = 0;
/*
@@ -598,17 +613,10 @@ uint32_t RadioRandom( void )
// Set LoRa modem ON
RadioSetModem( MODEM_LORA );
- // Set radio in continuous reception
- SX126xSetRx( 0 );
+ // Disable LoRa modem interrupts
+ SX126xSetDioIrqParams( IRQ_RADIO_NONE, IRQ_RADIO_NONE, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
- for( i = 0; i < 32; i++ )
- {
- DelayMs( 1 );
- // Unfiltered RSSI value reading. Only takes the LSB value
- rnd |= ( ( uint32_t )SX126xGetRssiInst( ) & 0x01 ) << i;
- }
-
- RadioSleep( );
+ rnd = SX126xGetRandom( );
return rnd;
}
@@ -675,7 +683,6 @@ void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth,
case MODEM_LORA:
SX126xSetStopRxTimerOnPreambleDetect( false );
- SX126xSetLoRaSymbNumTimeout( symbTimeout );
SX126x.ModulationParams.PacketType = PACKET_TYPE_LORA;
SX126x.ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t )datarate;
SX126x.ModulationParams.Params.LoRa.Bandwidth = Bandwidths[bandwidth];
@@ -716,9 +723,24 @@ void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth,
SX126x.PacketParams.Params.LoRa.CrcMode = ( RadioLoRaCrcModes_t )crcOn;
SX126x.PacketParams.Params.LoRa.InvertIQ = ( RadioLoRaIQModes_t )iqInverted;
+ RadioStandby( );
RadioSetModem( ( SX126x.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA );
SX126xSetModulationParams( &SX126x.ModulationParams );
SX126xSetPacketParams( &SX126x.PacketParams );
+ SX126xSetLoRaSymbNumTimeout( symbTimeout );
+
+ // WORKAROUND - Optimizing the Inverted IQ Operation, see DS_SX1261-2_V1.2 datasheet chapter 15.4
+ if( SX126x.PacketParams.Params.LoRa.InvertIQ == LORA_IQ_INVERTED )
+ {
+ // RegIqPolaritySetup = @address 0x0736
+ SX126xWriteRegister( 0x0736, SX126xReadRegister( 0x0736 ) & ~( 1 << 2 ) );
+ }
+ else
+ {
+ // RegIqPolaritySetup @address 0x0736
+ SX126xWriteRegister( 0x0736, SX126xReadRegister( 0x0736 ) | ( 1 << 2 ) );
+ }
+ // WORKAROUND END
// Timeout Max, Timeout handled directly in SetRx function
RxTimeout = 0xFFFF;
@@ -815,6 +837,20 @@ void RadioSetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev,
SX126xSetPacketParams( &SX126x.PacketParams );
break;
}
+
+ // WORKAROUND - Modulation Quality with 500 kHz LoRa Bandwidth, see DS_SX1261-2_V1.2 datasheet chapter 15.1
+ if( ( modem == MODEM_LORA ) && ( SX126x.ModulationParams.Params.LoRa.Bandwidth == LORA_BW_500 ) )
+ {
+ // RegTxModulation = @address 0x0889
+ SX126xWriteRegister( 0x0889, SX126xReadRegister( 0x0889 ) & ~( 1 << 2 ) );
+ }
+ else
+ {
+ // RegTxModulation = @address 0x0889
+ SX126xWriteRegister( 0x0889, SX126xReadRegister( 0x0889 ) | ( 1 << 2 ) );
+ }
+ // WORKAROUND END
+
SX126xSetRfTxPower( power );
TxTimeout = timeout;
}
@@ -824,44 +860,158 @@ bool RadioCheckRfFrequency( uint32_t frequency )
return true;
}
-uint32_t RadioTimeOnAir( RadioModems_t modem, uint8_t pktLen )
+static uint32_t RadioGetLoRaBandwidthInHz( RadioLoRaBandwidths_t bw )
{
- uint32_t airTime = 0;
+ uint32_t bandwidthInHz = 0;
+
+ switch( bw )
+ {
+ case LORA_BW_007:
+ bandwidthInHz = 7812UL;
+ break;
+ case LORA_BW_010:
+ bandwidthInHz = 10417UL;
+ break;
+ case LORA_BW_015:
+ bandwidthInHz = 15625UL;
+ break;
+ case LORA_BW_020:
+ bandwidthInHz = 20833UL;
+ break;
+ case LORA_BW_031:
+ bandwidthInHz = 31250UL;
+ break;
+ case LORA_BW_041:
+ bandwidthInHz = 41667UL;
+ break;
+ case LORA_BW_062:
+ bandwidthInHz = 62500UL;
+ break;
+ case LORA_BW_125:
+ bandwidthInHz = 125000UL;
+ break;
+ case LORA_BW_250:
+ bandwidthInHz = 250000UL;
+ break;
+ case LORA_BW_500:
+ bandwidthInHz = 500000UL;
+ break;
+ }
+
+ return bandwidthInHz;
+}
+
+static uint32_t RadioGetGfskTimeOnAirNumerator( uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn )
+{
+ const RadioAddressComp_t addrComp = RADIO_ADDRESSCOMP_FILT_OFF;
+ const uint8_t syncWordLength = 3;
+
+ return ( preambleLen << 3 ) +
+ ( ( fixLen == false ) ? 8 : 0 ) +
+ ( syncWordLength << 3 ) +
+ ( ( payloadLen +
+ ( addrComp == RADIO_ADDRESSCOMP_FILT_OFF ? 0 : 1 ) +
+ ( ( crcOn == true ) ? 2 : 0 )
+ ) << 3
+ );
+}
+
+static uint32_t RadioGetLoRaTimeOnAirNumerator( uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn )
+{
+ int32_t crDenom = coderate + 4;
+ bool lowDatareOptimize = false;
+
+ // Ensure that the preamble length is at least 12 symbols when using SF5 or
+ // SF6
+ if( ( datarate == 5 ) || ( datarate == 6 ) )
+ {
+ if( preambleLen < 12 )
+ {
+ preambleLen = 12;
+ }
+ }
+
+ if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
+ ( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
+ {
+ lowDatareOptimize = true;
+ }
+
+ int32_t ceilDenominator;
+ int32_t ceilNumerator = ( payloadLen << 3 ) +
+ ( crcOn ? 16 : 0 ) -
+ ( 4 * datarate ) +
+ ( fixLen ? 0 : 20 );
+
+ if( datarate <= 6 )
+ {
+ ceilDenominator = 4 * datarate;
+ }
+ else
+ {
+ ceilNumerator += 8;
+
+ if( lowDatareOptimize == true )
+ {
+ ceilDenominator = 4 * ( datarate - 2 );
+ }
+ else
+ {
+ ceilDenominator = 4 * datarate;
+ }
+ }
+
+ if( ceilNumerator < 0 )
+ {
+ ceilNumerator = 0;
+ }
+
+ // Perform integral ceil()
+ int32_t intermediate =
+ ( ( ceilNumerator + ceilDenominator - 1 ) / ceilDenominator ) * crDenom + preambleLen + 12;
+
+ if( datarate <= 6 )
+ {
+ intermediate += 2;
+ }
+
+ return ( uint32_t )( ( 4 * intermediate + 1 ) * ( 1 << ( datarate - 2 ) ) );
+}
+
+uint32_t RadioTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn )
+{
+ uint32_t numerator = 0;
+ uint32_t denominator = 1;
switch( modem )
{
case MODEM_FSK:
{
- airTime = rint( ( 8 * ( SX126x.PacketParams.Params.Gfsk.PreambleLength +
- ( SX126x.PacketParams.Params.Gfsk.SyncWordLength >> 3 ) +
- ( ( SX126x.PacketParams.Params.Gfsk.HeaderType == RADIO_PACKET_FIXED_LENGTH ) ? 0.0 : 1.0 ) +
- pktLen +
- ( ( SX126x.PacketParams.Params.Gfsk.CrcLength == RADIO_CRC_2_BYTES ) ? 2.0 : 0 ) ) /
- SX126x.ModulationParams.Params.Gfsk.BitRate ) * 1e3 );
+ numerator = 1000U * RadioGetGfskTimeOnAirNumerator( datarate, coderate,
+ preambleLen, fixLen,
+ payloadLen, crcOn );
+ denominator = datarate;
}
break;
case MODEM_LORA:
{
- double ts = RadioLoRaSymbTime[SX126x.ModulationParams.Params.LoRa.Bandwidth - 4][12 - SX126x.ModulationParams.Params.LoRa.SpreadingFactor];
- // time of preamble
- double tPreamble = ( SX126x.PacketParams.Params.LoRa.PreambleLength + 4.25 ) * ts;
- // Symbol length of payload and time
- double tmp = ceil( ( 8 * pktLen - 4 * SX126x.ModulationParams.Params.LoRa.SpreadingFactor +
- 28 + 16 * SX126x.PacketParams.Params.LoRa.CrcMode -
- ( ( SX126x.PacketParams.Params.LoRa.HeaderType == LORA_PACKET_FIXED_LENGTH ) ? 20 : 0 ) ) /
- ( double )( 4 * ( SX126x.ModulationParams.Params.LoRa.SpreadingFactor -
- ( ( SX126x.ModulationParams.Params.LoRa.LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
- ( ( SX126x.ModulationParams.Params.LoRa.CodingRate % 4 ) + 4 );
- double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
- double tPayload = nPayload * ts;
- // Time on air
- double tOnAir = tPreamble + tPayload;
- // return milli seconds
- airTime = floor( tOnAir + 0.999 );
+ numerator = 1000U * RadioGetLoRaTimeOnAirNumerator( bandwidth, datarate,
+ coderate, preambleLen,
+ fixLen, payloadLen, crcOn );
+ denominator = RadioGetLoRaBandwidthInHz( Bandwidths[bandwidth] );
}
break;
}
- return airTime;
+ // Perform integral ceil()
+ return ( numerator + denominator - 1 ) / denominator;
}
void RadioSend( uint8_t *buffer, uint8_t size )
@@ -954,21 +1104,19 @@ void RadioSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime )
void RadioStartCad( void )
{
+ SX126xSetDioIrqParams( IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, IRQ_CAD_DONE | IRQ_CAD_ACTIVITY_DETECTED, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
SX126xSetCad( );
}
-void RadioTx( uint32_t timeout )
-{
- SX126xSetTx( timeout << 6 );
-}
-
void RadioSetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time )
{
+ uint32_t timeout = ( uint32_t )time * 1000;
+
SX126xSetRfFrequency( freq );
SX126xSetRfTxPower( power );
SX126xSetTxContinuousWave( );
- TimerSetValue( &TxTimeoutTimer, time * 1e3 );
+ TimerSetValue( &TxTimeoutTimer, timeout );
TimerStart( &TxTimeoutTimer );
}
@@ -977,36 +1125,26 @@ int16_t RadioRssi( RadioModems_t modem )
return SX126xGetRssiInst( );
}
-void RadioWrite( uint16_t addr, uint8_t data )
+void RadioWrite( uint32_t addr, uint8_t data )
{
SX126xWriteRegister( addr, data );
}
-uint8_t RadioRead( uint16_t addr )
+uint8_t RadioRead( uint32_t addr )
{
return SX126xReadRegister( addr );
}
-void RadioWriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size )
+void RadioWriteBuffer( uint32_t addr, uint8_t *buffer, uint8_t size )
{
SX126xWriteRegisters( addr, buffer, size );
}
-void RadioReadBuffer( uint16_t addr, uint8_t *buffer, uint8_t size )
+void RadioReadBuffer( uint32_t addr, uint8_t *buffer, uint8_t size )
{
SX126xReadRegisters( addr, buffer, size );
}
-void RadioWriteFifo( uint8_t *buffer, uint8_t size )
-{
- SX126xWriteBuffer( 0, buffer, size );
-}
-
-void RadioReadFifo( uint8_t *buffer, uint8_t size )
-{
- SX126xReadBuffer( 0, buffer, size );
-}
-
void RadioSetMaxPayloadLength( RadioModems_t modem, uint8_t max )
{
if( modem == MODEM_LORA )
@@ -1094,32 +1232,41 @@ void RadioIrqProcess( void )
if( ( irqRegs & IRQ_RX_DONE ) == IRQ_RX_DONE )
{
- uint8_t size;
+ if( ( irqRegs & IRQ_CRC_ERROR ) == IRQ_CRC_ERROR )
+ {
+ if( RxContinuous == false )
+ {
+ //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
+ SX126xSetOperatingMode( MODE_STDBY_RC );
+ }
+ if( ( RadioEvents != NULL ) && ( RadioEvents->RxError ) )
+ {
+ RadioEvents->RxError( );
+ }
+ }
+ else
+ {
+ uint8_t size;
- TimerStop( &RxTimeoutTimer );
- if( RxContinuous == false )
- {
- //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
- SX126xSetOperatingMode( MODE_STDBY_RC );
- }
- SX126xGetPayload( RadioRxPayload, &size , 255 );
- SX126xGetPacketStatus( &RadioPktStatus );
- if( ( RadioEvents != NULL ) && ( RadioEvents->RxDone != NULL ) )
- {
- RadioEvents->RxDone( RadioRxPayload, size, RadioPktStatus.Params.LoRa.RssiPkt, RadioPktStatus.Params.LoRa.SnrPkt );
- }
- }
+ TimerStop( &RxTimeoutTimer );
+ if( RxContinuous == false )
+ {
+ //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
+ SX126xSetOperatingMode( MODE_STDBY_RC );
- if( ( irqRegs & IRQ_CRC_ERROR ) == IRQ_CRC_ERROR )
- {
- if( RxContinuous == false )
- {
- //!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
- SX126xSetOperatingMode( MODE_STDBY_RC );
- }
- if( ( RadioEvents != NULL ) && ( RadioEvents->RxError ) )
- {
- RadioEvents->RxError( );
+ // WORKAROUND - Implicit Header Mode Timeout Behavior, see DS_SX1261-2_V1.2 datasheet chapter 15.3
+ // RegRtcControl = @address 0x0902
+ SX126xWriteRegister( 0x0902, 0x00 );
+ // RegEventMask = @address 0x0944
+ SX126xWriteRegister( 0x0944, SX126xReadRegister( 0x0944 ) | ( 1 << 1 ) );
+ // WORKAROUND END
+ }
+ SX126xGetPayload( RadioRxPayload, &size , 255 );
+ SX126xGetPacketStatus( &RadioPktStatus );
+ if( ( RadioEvents != NULL ) && ( RadioEvents->RxDone != NULL ) )
+ {
+ RadioEvents->RxDone( RadioRxPayload, size, RadioPktStatus.Params.LoRa.RssiPkt, RadioPktStatus.Params.LoRa.SnrPkt );
+ }
}
}
diff --git a/components/connectivity/LoraWAN/radio/sx126x/sx126x.c b/components/connectivity/LoraWAN/radio/sx126x/sx126x.c
index 22087cc0..ca28d881 100644
--- a/components/connectivity/LoraWAN/radio/sx126x/sx126x.c
+++ b/components/connectivity/LoraWAN/radio/sx126x/sx126x.c
@@ -47,6 +47,11 @@ static RadioOperatingModes_t OperatingMode;
*/
static RadioPacketTypes_t PacketType;
+/*!
+ * \brief Stores the current packet header type set in the radio
+ */
+static volatile RadioLoRaPacketLengthsMode_t LoRaHeaderType;
+
/*!
* \brief Stores the last frequency error measured on LoRa received packet
*/
@@ -90,13 +95,8 @@ void SX126xInit( DioIrqHandler dioIrq )
SX126xWakeup( );
SX126xSetStandby( STDBY_RC );
-#ifdef USE_TCXO
- CalibrationParams_t calibParam;
-
- SX126xSetDio3AsTcxoCtrl( TCXO_CTRL_1_7V, SX126xGetBoardTcxoWakeupTime( ) << 6 ); // convert from ms to SX126x time base
- calibParam.Value = 0x7F;
- SX126xCalibrate( calibParam );
-#endif
+ // Initialize TCXO control
+ SX126xIoTcxoInit( );
SX126xSetDio2AsRfSwitchCtrl( true );
SX126xSetOperatingMode( MODE_STDBY_RC );
@@ -227,25 +227,37 @@ void SX126xSetWhiteningSeed( uint16_t seed )
uint32_t SX126xGetRandom( void )
{
- uint8_t buf[] = { 0, 0, 0, 0 };
+ uint32_t number = 0;
+ uint8_t regAnaLna = 0;
+ uint8_t regAnaMixer = 0;
+
+ regAnaLna = SX126xReadRegister( REG_ANA_LNA );
+ SX126xWriteRegister( REG_ANA_LNA, regAnaLna & ~( 1 << 0 ) );
+
+ regAnaMixer = SX126xReadRegister( REG_ANA_MIXER );
+ SX126xWriteRegister( REG_ANA_MIXER, regAnaMixer & ~( 1 << 7 ) );
// Set radio in continuous reception
- SX126xSetRx( 0 );
+ SX126xSetRx( 0xFFFFFF ); // Rx Continuous
- DelayMs( 1 );
-
- SX126xReadRegisters( RANDOM_NUMBER_GENERATORBASEADDR, buf, 4 );
+ SX126xReadRegisters( RANDOM_NUMBER_GENERATORBASEADDR, ( uint8_t* )&number, 4 );
SX126xSetStandby( STDBY_RC );
- return ( buf[0] << 24 ) | ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3];
+ SX126xWriteRegister( REG_ANA_LNA, regAnaLna );
+ SX126xWriteRegister( REG_ANA_MIXER, regAnaMixer );
+
+ return number;
}
void SX126xSetSleep( SleepParams_t sleepConfig )
{
SX126xAntSwOff( );
- SX126xWriteCommand( RADIO_SET_SLEEP, &sleepConfig.Value, 1 );
+ uint8_t value = ( ( ( uint8_t )sleepConfig.Fields.WarmStart << 2 ) |
+ ( ( uint8_t )sleepConfig.Fields.Reset << 1 ) |
+ ( ( uint8_t )sleepConfig.Fields.WakeUpRTC ) );
+ SX126xWriteCommand( RADIO_SET_SLEEP, &value, 1 );
SX126xSetOperatingMode( MODE_SLEEP );
}
@@ -344,6 +356,19 @@ void SX126xSetStopRxTimerOnPreambleDetect( bool enable )
void SX126xSetLoRaSymbNumTimeout( uint8_t SymbNum )
{
SX126xWriteCommand( RADIO_SET_LORASYMBTIMEOUT, &SymbNum, 1 );
+
+ uint8_t mant = SymbNum >> 1;
+ uint8_t exp = 0;
+ uint8_t reg = 0;
+
+ while( mant > 31 )
+ {
+ mant >>= 2;
+ exp++;
+ }
+
+ reg = exp + ( mant << 3 );
+ SX126xWriteRegister( REG_LR_SYNCH_TIMEOUT, reg );
}
void SX126xSetRegulatorMode( RadioRegulatorMode_t mode )
@@ -353,7 +378,15 @@ void SX126xSetRegulatorMode( RadioRegulatorMode_t mode )
void SX126xCalibrate( CalibrationParams_t calibParam )
{
- SX126xWriteCommand( RADIO_CALIBRATE, ( uint8_t* )&calibParam, 1 );
+ uint8_t value = ( ( ( uint8_t )calibParam.Fields.ImgEnable << 6 ) |
+ ( ( uint8_t )calibParam.Fields.ADCBulkPEnable << 5 ) |
+ ( ( uint8_t )calibParam.Fields.ADCBulkNEnable << 4 ) |
+ ( ( uint8_t )calibParam.Fields.ADCPulseEnable << 3 ) |
+ ( ( uint8_t )calibParam.Fields.PLLEnable << 2 ) |
+ ( ( uint8_t )calibParam.Fields.RC13MEnable << 1 ) |
+ ( ( uint8_t )calibParam.Fields.RC64KEnable ) );
+
+ SX126xWriteCommand( RADIO_CALIBRATE, &value, 1 );
}
void SX126xCalibrateImage( uint32_t freq )
@@ -501,6 +534,11 @@ void SX126xSetTxParams( int8_t power, RadioRampTimes_t rampTime )
}
else // sx1262
{
+ // WORKAROUND - Better Resistance of the SX1262 Tx to Antenna Mismatch, see DS_SX1261-2_V1.2 datasheet chapter 15.2
+ // RegTxClampConfig = @address 0x08D8
+ SX126xWriteRegister( 0x08D8, SX126xReadRegister( 0x08D8 ) | ( 0x0F << 1 ) );
+ // WORKAROUND END
+
SX126xSetPaConfig( 0x04, 0x07, 0x00, 0x01 );
if( power > 22 )
{
@@ -609,7 +647,7 @@ void SX126xSetPacketParams( PacketParams_t *packetParams )
n = 6;
buf[0] = ( packetParams->Params.LoRa.PreambleLength >> 8 ) & 0xFF;
buf[1] = packetParams->Params.LoRa.PreambleLength;
- buf[2] = packetParams->Params.LoRa.HeaderType;
+ buf[2] = LoRaHeaderType = packetParams->Params.LoRa.HeaderType;
buf[3] = packetParams->Params.LoRa.PayloadLength;
buf[4] = packetParams->Params.LoRa.CrcMode;
buf[5] = packetParams->Params.LoRa.InvertIQ;
@@ -632,7 +670,7 @@ void SX126xSetCadParams( RadioLoRaCadSymbols_t cadSymbolNum, uint8_t cadDetPeak,
buf[4] = ( uint8_t )( ( cadTimeout >> 16 ) & 0xFF );
buf[5] = ( uint8_t )( ( cadTimeout >> 8 ) & 0xFF );
buf[6] = ( uint8_t )( cadTimeout & 0xFF );
- SX126xWriteCommand( RADIO_SET_CADPARAMS, buf, 5 );
+ SX126xWriteCommand( RADIO_SET_CADPARAMS, buf, 7 );
SX126xSetOperatingMode( MODE_CAD );
}
@@ -648,10 +686,11 @@ void SX126xSetBufferBaseAddress( uint8_t txBaseAddress, uint8_t rxBaseAddress )
RadioStatus_t SX126xGetStatus( void )
{
uint8_t stat = 0;
- RadioStatus_t status;
+ RadioStatus_t status = { .Value = 0 };
- SX126xReadCommand( RADIO_GET_STATUS, ( uint8_t * )&stat, 1 );
- status.Value = stat;
+ stat = SX126xReadCommand( RADIO_GET_STATUS, NULL, 0 );
+ status.Fields.CmdStatus = ( stat & ( 0x07 << 1 ) ) >> 1;
+ status.Fields.ChipMode = ( stat & ( 0x07 << 4 ) ) >> 4;
return status;
}
@@ -673,7 +712,7 @@ void SX126xGetRxBufferStatus( uint8_t *payloadLength, uint8_t *rxStartBufferPoin
// In case of LORA fixed header, the payloadLength is obtained by reading
// the register REG_LR_PAYLOADLENGTH
- if( ( SX126xGetPacketType( ) == PACKET_TYPE_LORA ) && ( SX126xReadRegister( REG_LR_PACKETPARAMS ) >> 7 == 1 ) )
+ if( ( SX126xGetPacketType( ) == PACKET_TYPE_LORA ) && ( LoRaHeaderType == LORA_PACKET_FIXED_LENGTH ) )
{
*payloadLength = SX126xReadRegister( REG_LR_PAYLOADLENGTH );
}
@@ -720,9 +759,18 @@ void SX126xGetPacketStatus( PacketStatus_t *pktStatus )
RadioError_t SX126xGetDeviceErrors( void )
{
- RadioError_t error;
+ uint8_t err[] = { 0, 0 };
+ RadioError_t error = { .Value = 0 };
- SX126xReadCommand( RADIO_GET_ERROR, ( uint8_t * )&error, 2 );
+ SX126xReadCommand( RADIO_GET_ERROR, ( uint8_t* )err, 2 );
+ error.Fields.PaRamp = ( err[0] & ( 1 << 0 ) ) >> 0;
+ error.Fields.PllLock = ( err[1] & ( 1 << 6 ) ) >> 6;
+ error.Fields.XoscStart = ( err[1] & ( 1 << 5 ) ) >> 5;
+ error.Fields.ImgCalib = ( err[1] & ( 1 << 4 ) ) >> 4;
+ error.Fields.AdcCalib = ( err[1] & ( 1 << 3 ) ) >> 3;
+ error.Fields.PllCalib = ( err[1] & ( 1 << 2 ) ) >> 2;
+ error.Fields.Rc13mCalib = ( err[1] & ( 1 << 1 ) ) >> 1;
+ error.Fields.Rc64kCalib = ( err[1] & ( 1 << 0 ) ) >> 0;
return error;
}
diff --git a/components/connectivity/LoraWAN/radio/sx126x/sx126x.h b/components/connectivity/LoraWAN/radio/sx126x/sx126x.h
index 981370f8..c0282b26 100644
--- a/components/connectivity/LoraWAN/radio/sx126x/sx126x.h
+++ b/components/connectivity/LoraWAN/radio/sx126x/sx126x.h
@@ -23,6 +23,11 @@
#ifndef __SX126x_H__
#define __SX126x_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include
@@ -90,6 +95,11 @@
*/
#define REG_LR_PAYLOADLENGTH 0x0702
+/*!
+ * \brief The address of the register holding the re-calculated number of symbols
+ */
+#define REG_LR_SYNCH_TIMEOUT 0x0706
+
/*!
* \brief The addresses of the registers holding SyncWords values
*/
@@ -110,11 +120,22 @@
*/
#define LORA_MAC_PUBLIC_SYNCWORD 0x3444
+
/*!
- * The address of the register giving a 4 bytes random number
+ * The address of the register giving a 32-bit random number
*/
#define RANDOM_NUMBER_GENERATORBASEADDR 0x0819
+/*!
+ * The address of the register used to disable the LNA
+ */
+#define REG_ANA_LNA 0x08E2
+
+/*!
+ * The address of the register used to disable the mixer
+ */
+#define REG_ANA_MIXER 0x08E5
+
/*!
* The address of the register holding RX Gain value (0x94: power saving, 0x96: rx boosted)
*/
@@ -138,10 +159,10 @@ typedef union RadioStatus_u
uint8_t Value;
struct
{ //bit order is lsb -> msb
- uint8_t Reserved : 1; //!< Reserved
+ uint8_t : 1; //!< Reserved
uint8_t CmdStatus : 3; //!< Command status
uint8_t ChipMode : 3; //!< Chip mode
- uint8_t CpuBusy : 1; //!< Flag for CPU radio busy
+ uint8_t : 1; //!< Reserved
}Fields;
}RadioStatus_t;
@@ -643,7 +664,7 @@ typedef union
uint8_t ImgCalib : 1; //!< Image calibration failed
uint8_t XoscStart : 1; //!< XOSC oscillator failed to start
uint8_t PllLock : 1; //!< PLL lock failed
- uint8_t BuckStart : 1; //!< Buck converter failed to start
+ uint8_t : 1; //!< Buck converter failed to start
uint8_t PaRamp : 1; //!< PA ramp failed
uint8_t : 7; //!< Reserved
}Fields;
@@ -796,9 +817,19 @@ void SX126xSetCrcPolynomial( uint16_t polynomial );
void SX126xSetWhiteningSeed( uint16_t seed );
/*!
- * \brief Gets a 32 bits random value generated by the radio
+ * \brief Gets a 32-bit random value generated by the radio
+ *
+ * \remark A valid packet type must have been configured with \ref SX126xSetPacketType
+ * before using this command.
*
* \remark The radio must be in reception mode before executing this function
+ * This code can potentially result in interrupt generation. It is the responsibility of
+ * the calling code to disable radio interrupts before calling this function,
+ * and re-enable them afterwards if necessary, or be certain that any interrupts
+ * generated during this process will not cause undesired side-effects in the software.
+ *
+ * Please note that the random numbers produced by the generator do not have a uniform or Gaussian distribution. If
+ * uniformity is needed, perform appropriate software post-processing.
*
* \retval randomValue 32 bits random value
*/
@@ -1113,4 +1144,8 @@ void SX126xClearDeviceErrors( void );
*/
void SX126xClearIrqStatus( uint16_t irq );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SX126x_H__
diff --git a/components/connectivity/LoraWAN/radio/sx1272/sx1272.c b/components/connectivity/LoraWAN/radio/sx1272/sx1272.c
index bd64c439..3be377ec 100644
--- a/components/connectivity/LoraWAN/radio/sx1272/sx1272.c
+++ b/components/connectivity/LoraWAN/radio/sx1272/sx1272.c
@@ -260,6 +260,8 @@ bool SX1272IsChannelFree( RadioModems_t modem, uint32_t freq, int16_t rssiThresh
int16_t rssi = 0;
uint32_t carrierSenseTime = 0;
+ SX1272SetSleep( );
+
SX1272SetModem( modem );
SX1272SetChannel( freq );
@@ -610,61 +612,136 @@ void SX1272SetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev,
}
}
-uint32_t SX1272GetTimeOnAir( RadioModems_t modem, uint8_t pktLen )
+static uint32_t SX1272GetLoRaBandwidthInHz( uint32_t bw )
{
- uint32_t airTime = 0;
+ uint32_t bandwidthInHz = 0;
+
+ switch( bw )
+ {
+ case 0: // 125 kHz
+ bandwidthInHz = 125000UL;
+ break;
+ case 1: // 250 kHz
+ bandwidthInHz = 250000UL;
+ break;
+ case 2: // 500 kHz
+ bandwidthInHz = 500000UL;
+ break;
+ }
+
+ return bandwidthInHz;
+}
+
+static uint32_t SX1272GetGfskTimeOnAirNumerator( uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn )
+{
+ const uint8_t syncWordLength = 3;
+
+ return ( preambleLen << 3 ) +
+ ( ( fixLen == false ) ? 8 : 0 ) +
+ ( syncWordLength << 3 ) +
+ ( ( payloadLen +
+ ( 0 ) + // Address filter size
+ ( ( crcOn == true ) ? 2 : 0 )
+ ) << 3
+ );
+}
+
+static uint32_t SX1272GetLoRaTimeOnAirNumerator( uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn )
+{
+ int32_t crDenom = coderate + 4;
+ bool lowDatareOptimize = false;
+
+ // Ensure that the preamble length is at least 12 symbols when using SF5 or
+ // SF6
+ if( ( datarate == 5 ) || ( datarate == 6 ) )
+ {
+ if( preambleLen < 12 )
+ {
+ preambleLen = 12;
+ }
+ }
+
+ if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
+ ( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
+ {
+ lowDatareOptimize = true;
+ }
+
+ int32_t ceilDenominator;
+ int32_t ceilNumerator = ( payloadLen << 3 ) +
+ ( crcOn ? 16 : 0 ) -
+ ( 4 * datarate ) +
+ ( fixLen ? 0 : 20 );
+
+ if( datarate <= 6 )
+ {
+ ceilDenominator = 4 * datarate;
+ }
+ else
+ {
+ ceilNumerator += 8;
+
+ if( lowDatareOptimize == true )
+ {
+ ceilDenominator = 4 * ( datarate - 2 );
+ }
+ else
+ {
+ ceilDenominator = 4 * datarate;
+ }
+ }
+
+ if( ceilNumerator < 0 )
+ {
+ ceilNumerator = 0;
+ }
+
+ // Perform integral ceil()
+ int32_t intermediate =
+ ( ( ceilNumerator + ceilDenominator - 1 ) / ceilDenominator ) * crDenom + preambleLen + 12;
+
+ if( datarate <= 6 )
+ {
+ intermediate += 2;
+ }
+
+ return ( uint32_t )( ( 4 * intermediate + 1 ) * ( 1 << ( datarate - 2 ) ) );
+}
+
+uint32_t SX1272GetTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn )
+{
+ uint32_t numerator = 0;
+ uint32_t denominator = 1;
switch( modem )
{
case MODEM_FSK:
{
- airTime = round( ( 8 * ( SX1272.Settings.Fsk.PreambleLen +
- ( ( SX1272Read( REG_SYNCCONFIG ) & ~RF_SYNCCONFIG_SYNCSIZE_MASK ) + 1 ) +
- ( ( SX1272.Settings.Fsk.FixLen == 0x01 ) ? 0.0 : 1.0 ) +
- ( ( ( SX1272Read( REG_PACKETCONFIG1 ) & ~RF_PACKETCONFIG1_ADDRSFILTERING_MASK ) != 0x00 ) ? 1.0 : 0 ) +
- pktLen +
- ( ( SX1272.Settings.Fsk.CrcOn == 0x01 ) ? 2.0 : 0 ) ) /
- SX1272.Settings.Fsk.Datarate ) * 1000 );
+ numerator = 1000U * SX1272GetGfskTimeOnAirNumerator( datarate, coderate,
+ preambleLen, fixLen,
+ payloadLen, crcOn );
+ denominator = datarate;
}
break;
case MODEM_LORA:
{
- double bw = 0.0;
- switch( SX1272.Settings.LoRa.Bandwidth )
- {
- case 0: // 125 kHz
- bw = 125000;
- break;
- case 1: // 250 kHz
- bw = 250000;
- break;
- case 2: // 500 kHz
- bw = 500000;
- break;
- }
-
- // Symbol rate : time for one symbol (secs)
- double rs = bw / ( 1 << SX1272.Settings.LoRa.Datarate );
- double ts = 1 / rs;
- // time of preamble
- double tPreamble = ( SX1272.Settings.LoRa.PreambleLen + 4.25 ) * ts;
- // Symbol length of payload and time
- double tmp = ceil( ( 8 * pktLen - 4 * SX1272.Settings.LoRa.Datarate +
- 28 + 16 * SX1272.Settings.LoRa.CrcOn -
- ( SX1272.Settings.LoRa.FixLen ? 20 : 0 ) ) /
- ( double )( 4 * ( SX1272.Settings.LoRa.Datarate -
- ( ( SX1272.Settings.LoRa.LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
- ( SX1272.Settings.LoRa.Coderate + 4 );
- double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
- double tPayload = nPayload * ts;
- // Time on air
- double tOnAir = tPreamble + tPayload;
- // return ms secs
- airTime = floor( tOnAir * 1000 + 0.999 );
+ numerator = 1000U * SX1272GetLoRaTimeOnAirNumerator( bandwidth, datarate,
+ coderate, preambleLen,
+ fixLen, payloadLen, crcOn );
+ denominator = SX1272GetLoRaBandwidthInHz( bandwidth );
}
break;
}
- return airTime;
+ // Perform integral ceil()
+ return ( numerator + denominator - 1 ) / denominator;
}
void SX1272Send( uint8_t *buffer, uint8_t size )
@@ -745,8 +822,13 @@ void SX1272SetSleep( void )
{
TimerStop( &RxTimeoutTimer );
TimerStop( &TxTimeoutTimer );
+ TimerStop( &RxTimeoutSyncWord );
SX1272SetOpMode( RF_OPMODE_SLEEP );
+
+ // Disable TCXO radio is in SLEEP mode
+ SX1272SetBoardTcxo( false );
+
SX1272.Settings.State = RF_IDLE;
}
@@ -754,6 +836,7 @@ void SX1272SetStby( void )
{
TimerStop( &RxTimeoutTimer );
TimerStop( &TxTimeoutTimer );
+ TimerStop( &RxTimeoutSyncWord );
SX1272SetOpMode( RF_OPMODE_STANDBY );
SX1272.Settings.State = RF_IDLE;
@@ -762,6 +845,7 @@ void SX1272SetStby( void )
void SX1272SetRx( uint32_t timeout )
{
bool rxContinuous = false;
+ TimerStop( &TxTimeoutTimer );
switch( SX1272.Settings.Modem )
{
@@ -880,6 +964,8 @@ void SX1272SetRx( uint32_t timeout )
void SX1272SetTx( uint32_t timeout )
{
+ TimerStop( &RxTimeoutTimer );
+
TimerSetValue( &TxTimeoutTimer, timeout );
switch( SX1272.Settings.Modem )
@@ -976,7 +1062,7 @@ void SX1272StartCad( void )
void SX1272SetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time )
{
- uint32_t timeout = ( uint32_t )( time * 1000 );
+ uint32_t timeout = ( uint32_t )time * 1000;
SX1272SetChannel( freq );
@@ -1039,6 +1125,8 @@ void SX1272SetOpMode( uint8_t opMode )
}
else
{
+ // Enable TCXO if operating mode different from SLEEP.
+ SX1272SetBoardTcxo( true );
SX1272SetAntSwLowPower( false );
SX1272SetAntSw( opMode );
}
@@ -1066,14 +1154,14 @@ void SX1272SetModem( RadioModems_t modem )
{
default:
case MODEM_FSK:
- SX1272SetSleep( );
+ SX1272SetOpMode( RF_OPMODE_SLEEP );
SX1272Write( REG_OPMODE, ( SX1272Read( REG_OPMODE ) & RFLR_OPMODE_LONGRANGEMODE_MASK ) | RFLR_OPMODE_LONGRANGEMODE_OFF );
SX1272Write( REG_DIOMAPPING1, 0x00 );
SX1272Write( REG_DIOMAPPING2, 0x30 ); // DIO5=ModeReady
break;
case MODEM_LORA:
- SX1272SetSleep( );
+ SX1272SetOpMode( RF_OPMODE_SLEEP );
SX1272Write( REG_OPMODE, ( SX1272Read( REG_OPMODE ) & RFLR_OPMODE_LONGRANGEMODE_MASK ) | RFLR_OPMODE_LONGRANGEMODE_ON );
SX1272Write( REG_DIOMAPPING1, 0x00 );
@@ -1082,19 +1170,19 @@ void SX1272SetModem( RadioModems_t modem )
}
}
-void SX1272Write( uint16_t addr, uint8_t data )
+void SX1272Write( uint32_t addr, uint8_t data )
{
SX1272WriteBuffer( addr, &data, 1 );
}
-uint8_t SX1272Read( uint16_t addr )
+uint8_t SX1272Read( uint32_t addr )
{
uint8_t data;
SX1272ReadBuffer( addr, &data, 1 );
return data;
}
-void SX1272WriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size )
+void SX1272WriteBuffer( uint32_t addr, uint8_t *buffer, uint8_t size )
{
uint8_t i;
@@ -1111,7 +1199,7 @@ void SX1272WriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size )
GpioWrite( &SX1272.Spi.Nss, 1 );
}
-void SX1272ReadBuffer( uint16_t addr, uint8_t *buffer, uint8_t size )
+void SX1272ReadBuffer( uint32_t addr, uint8_t *buffer, uint8_t size )
{
uint8_t i;
@@ -1200,7 +1288,6 @@ void SX1272OnTimeoutIrq( void* context )
{
// Continuous mode restart Rx chain
SX1272Write( REG_RXCONFIG, SX1272Read( REG_RXCONFIG ) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK );
- TimerStart( &RxTimeoutSyncWord );
}
else
{
@@ -1215,10 +1302,12 @@ void SX1272OnTimeoutIrq( void* context )
break;
case RF_TX_RUNNING:
// Tx timeout shouldn't happen.
- // But it has been observed that when it happens it is a result of a corrupted SPI transfer
- // it depends on the platform design.
- //
- // The workaround is to put the radio in a known state. Thus, we re-initialize it.
+ // Reported issue of SPI data corruption resulting in TX TIMEOUT
+ // is NOT related to a bug in radio transceiver.
+ // It is mainly caused by improper PCB routing of SPI lines and/or
+ // violation of SPI specifications.
+ // To mitigate redesign, Semtech offers a workaround which resets
+ // the radio transceiver and putting it into a known state.
// BEGIN WORKAROUND
@@ -1284,7 +1373,6 @@ void SX1272OnDio0Irq( void* context )
{
// Continuous mode restart Rx chain
SX1272Write( REG_RXCONFIG, SX1272Read( REG_RXCONFIG ) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK );
- TimerStart( &RxTimeoutSyncWord );
}
if( ( RadioEvents != NULL ) && ( RadioEvents->RxError != NULL ) )
@@ -1330,7 +1418,6 @@ void SX1272OnDio0Irq( void* context )
{
// Continuous mode restart Rx chain
SX1272Write( REG_RXCONFIG, SX1272Read( REG_RXCONFIG ) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK );
- TimerStart( &RxTimeoutSyncWord );
}
if( ( RadioEvents != NULL ) && ( RadioEvents->RxDone != NULL ) )
@@ -1432,6 +1519,9 @@ void SX1272OnDio1Irq( void* context )
switch( SX1272.Settings.Modem )
{
case MODEM_FSK:
+ // Stop timer
+ TimerStop( &RxTimeoutSyncWord );
+
// FifoLevel interrupt
// Read received packet size
if( ( SX1272.Settings.FskPacketHandler.Size == 0 ) && ( SX1272.Settings.FskPacketHandler.NbBytes == 0 ) )
diff --git a/components/connectivity/LoraWAN/radio/sx1272/sx1272.h b/components/connectivity/LoraWAN/radio/sx1272/sx1272.h
index ef1f9376..6468bea7 100644
--- a/components/connectivity/LoraWAN/radio/sx1272/sx1272.h
+++ b/components/connectivity/LoraWAN/radio/sx1272/sx1272.h
@@ -23,6 +23,11 @@
#ifndef __SX1272_H__
#define __SX1272_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include "gpio.h"
@@ -308,12 +313,31 @@ void SX1272SetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev,
*
* \Remark Can only be called once SetRxConfig or SetTxConfig have been called
*
- * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
- * \param [IN] pktLen Packet payload length
+ * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
+ * \param [IN] bandwidth Sets the bandwidth
+ * FSK : >= 2600 and <= 250000 Hz
+ * LoRa: [0: 125 kHz, 1: 250 kHz,
+ * 2: 500 kHz, 3: Reserved]
+ * \param [IN] datarate Sets the Datarate
+ * FSK : 600..300000 bits/s
+ * LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
+ * 10: 1024, 11: 2048, 12: 4096 chips]
+ * \param [IN] coderate Sets the coding rate (LoRa only)
+ * FSK : N/A ( set to 0 )
+ * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
+ * \param [IN] preambleLen Sets the Preamble length
+ * FSK : Number of bytes
+ * LoRa: Length in symbols (the hardware adds 4 more symbols)
+ * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
+ * \param [IN] payloadLen Sets payload length when fixed length is used
+ * \param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
*
* \retval airTime Computed airTime (ms) for the given packet payload length
*/
-uint32_t SX1272GetTimeOnAir( RadioModems_t modem, uint8_t pktLen );
+uint32_t SX1272GetTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn );
/*!
* \brief Sends the buffer of size. Prepares the packet to be sent and sets
@@ -367,7 +391,7 @@ int16_t SX1272ReadRssi( RadioModems_t modem );
* \param [IN]: addr Register address
* \param [IN]: data New register value
*/
-void SX1272Write( uint16_t addr, uint8_t data );
+void SX1272Write( uint32_t addr, uint8_t data );
/*!
* \brief Reads the radio register at the specified address
@@ -375,7 +399,7 @@ void SX1272Write( uint16_t addr, uint8_t data );
* \param [IN]: addr Register address
* \retval data Register value
*/
-uint8_t SX1272Read( uint16_t addr );
+uint8_t SX1272Read( uint32_t addr );
/*!
* \brief Writes multiple radio registers starting at address
@@ -384,7 +408,7 @@ uint8_t SX1272Read( uint16_t addr );
* \param [IN] buffer Buffer containing the new register's values
* \param [IN] size Number of registers to be written
*/
-void SX1272WriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size );
+void SX1272WriteBuffer( uint32_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Reads multiple radio registers starting at address
@@ -393,7 +417,7 @@ void SX1272WriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size );
* \param [OUT] buffer Buffer where to copy the registers data
* \param [IN] size Number of registers to be read
*/
-void SX1272ReadBuffer( uint16_t addr, uint8_t *buffer, uint8_t size );
+void SX1272ReadBuffer( uint32_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Sets the maximum payload length.
@@ -419,4 +443,8 @@ void SX1272SetPublicNetwork( bool enable );
*/
uint32_t SX1272GetWakeupTime( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SX1272_H__
diff --git a/components/connectivity/LoraWAN/radio/sx1272/sx1272Regs-Fsk.h b/components/connectivity/LoraWAN/radio/sx1272/sx1272Regs-Fsk.h
index 01c8de26..b90259e6 100644
--- a/components/connectivity/LoraWAN/radio/sx1272/sx1272Regs-Fsk.h
+++ b/components/connectivity/LoraWAN/radio/sx1272/sx1272Regs-Fsk.h
@@ -23,6 +23,11 @@
#ifndef __SX1272_REGS_FSK_H__
#define __SX1272_REGS_FSK_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
/*!
* ============================================================================
* SX1272 Internal registers Address
@@ -1139,4 +1144,8 @@
*/
#define RF_BITRATEFRAC_MASK 0xF0
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SX1272_REGS_FSK_H__
diff --git a/components/connectivity/LoraWAN/radio/sx1272/sx1272Regs-LoRa.h b/components/connectivity/LoraWAN/radio/sx1272/sx1272Regs-LoRa.h
index 2352dcca..38bc248c 100644
--- a/components/connectivity/LoraWAN/radio/sx1272/sx1272Regs-LoRa.h
+++ b/components/connectivity/LoraWAN/radio/sx1272/sx1272Regs-LoRa.h
@@ -23,6 +23,11 @@
#ifndef __SX1272_REGS_LORA_H__
#define __SX1272_REGS_LORA_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
/*!
* ============================================================================
* SX1272 Internal registers Address
@@ -550,4 +555,8 @@
* RegFormerTemp
*/
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SX1272_REGS_LORA_H__
diff --git a/components/connectivity/LoraWAN/radio/sx1276/sx1276.c b/components/connectivity/LoraWAN/radio/sx1276/sx1276.c
index b57f933f..64c451a4 100644
--- a/components/connectivity/LoraWAN/radio/sx1276/sx1276.c
+++ b/components/connectivity/LoraWAN/radio/sx1276/sx1276.c
@@ -271,6 +271,8 @@ bool SX1276IsChannelFree( RadioModems_t modem, uint32_t freq, int16_t rssiThresh
int16_t rssi = 0;
uint32_t carrierSenseTime = 0;
+ SX1276SetSleep( );
+
SX1276SetModem( modem );
SX1276SetChannel( freq );
@@ -695,83 +697,136 @@ void SX1276SetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev,
}
}
-uint32_t SX1276GetTimeOnAir( RadioModems_t modem, uint8_t pktLen )
+static uint32_t SX1276GetLoRaBandwidthInHz( uint32_t bw )
{
- uint32_t airTime = 0;
+ uint32_t bandwidthInHz = 0;
+
+ switch( bw )
+ {
+ case 0: // 125 kHz
+ bandwidthInHz = 125000UL;
+ break;
+ case 1: // 250 kHz
+ bandwidthInHz = 250000UL;
+ break;
+ case 2: // 500 kHz
+ bandwidthInHz = 500000UL;
+ break;
+ }
+
+ return bandwidthInHz;
+}
+
+static uint32_t SX1276GetGfskTimeOnAirNumerator( uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn )
+{
+ const uint8_t syncWordLength = 3;
+
+ return ( preambleLen << 3 ) +
+ ( ( fixLen == false ) ? 8 : 0 ) +
+ ( syncWordLength << 3 ) +
+ ( ( payloadLen +
+ ( 0 ) + // Address filter size
+ ( ( crcOn == true ) ? 2 : 0 )
+ ) << 3
+ );
+}
+
+static uint32_t SX1276GetLoRaTimeOnAirNumerator( uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn )
+{
+ int32_t crDenom = coderate + 4;
+ bool lowDatareOptimize = false;
+
+ // Ensure that the preamble length is at least 12 symbols when using SF5 or
+ // SF6
+ if( ( datarate == 5 ) || ( datarate == 6 ) )
+ {
+ if( preambleLen < 12 )
+ {
+ preambleLen = 12;
+ }
+ }
+
+ if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
+ ( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
+ {
+ lowDatareOptimize = true;
+ }
+
+ int32_t ceilDenominator;
+ int32_t ceilNumerator = ( payloadLen << 3 ) +
+ ( crcOn ? 16 : 0 ) -
+ ( 4 * datarate ) +
+ ( fixLen ? 0 : 20 );
+
+ if( datarate <= 6 )
+ {
+ ceilDenominator = 4 * datarate;
+ }
+ else
+ {
+ ceilNumerator += 8;
+
+ if( lowDatareOptimize == true )
+ {
+ ceilDenominator = 4 * ( datarate - 2 );
+ }
+ else
+ {
+ ceilDenominator = 4 * datarate;
+ }
+ }
+
+ if( ceilNumerator < 0 )
+ {
+ ceilNumerator = 0;
+ }
+
+ // Perform integral ceil()
+ int32_t intermediate =
+ ( ( ceilNumerator + ceilDenominator - 1 ) / ceilDenominator ) * crDenom + preambleLen + 12;
+
+ if( datarate <= 6 )
+ {
+ intermediate += 2;
+ }
+
+ return ( uint32_t )( ( 4 * intermediate + 1 ) * ( 1 << ( datarate - 2 ) ) );
+}
+
+uint32_t SX1276GetTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn )
+{
+ uint32_t numerator = 0;
+ uint32_t denominator = 1;
switch( modem )
{
case MODEM_FSK:
{
- airTime = round( ( 8 * ( SX1276.Settings.Fsk.PreambleLen +
- ( ( SX1276Read( REG_SYNCCONFIG ) & ~RF_SYNCCONFIG_SYNCSIZE_MASK ) + 1 ) +
- ( ( SX1276.Settings.Fsk.FixLen == 0x01 ) ? 0.0 : 1.0 ) +
- ( ( ( SX1276Read( REG_PACKETCONFIG1 ) & ~RF_PACKETCONFIG1_ADDRSFILTERING_MASK ) != 0x00 ) ? 1.0 : 0 ) +
- pktLen +
- ( ( SX1276.Settings.Fsk.CrcOn == 0x01 ) ? 2.0 : 0 ) ) /
- SX1276.Settings.Fsk.Datarate ) * 1000 );
+ numerator = 1000U * SX1276GetGfskTimeOnAirNumerator( datarate, coderate,
+ preambleLen, fixLen,
+ payloadLen, crcOn );
+ denominator = datarate;
}
break;
case MODEM_LORA:
{
- double bw = 0.0;
- // REMARK: When using LoRa modem only bandwidths 125, 250 and 500 kHz are supported
- switch( SX1276.Settings.LoRa.Bandwidth )
- {
- //case 0: // 7.8 kHz
- // bw = 7800;
- // break;
- //case 1: // 10.4 kHz
- // bw = 10400;
- // break;
- //case 2: // 15.6 kHz
- // bw = 15600;
- // break;
- //case 3: // 20.8 kHz
- // bw = 20800;
- // break;
- //case 4: // 31.2 kHz
- // bw = 31200;
- // break;
- //case 5: // 41.4 kHz
- // bw = 41400;
- // break;
- //case 6: // 62.5 kHz
- // bw = 62500;
- // break;
- case 7: // 125 kHz
- bw = 125000;
- break;
- case 8: // 250 kHz
- bw = 250000;
- break;
- case 9: // 500 kHz
- bw = 500000;
- break;
- }
-
- // Symbol rate : time for one symbol (secs)
- double rs = bw / ( 1 << SX1276.Settings.LoRa.Datarate );
- double ts = 1 / rs;
- // time of preamble
- double tPreamble = ( SX1276.Settings.LoRa.PreambleLen + 4.25 ) * ts;
- // Symbol length of payload and time
- double tmp = ceil( ( 8 * pktLen - 4 * SX1276.Settings.LoRa.Datarate +
- 28 + 16 * SX1276.Settings.LoRa.CrcOn -
- ( SX1276.Settings.LoRa.FixLen ? 20 : 0 ) ) /
- ( double )( 4 * ( SX1276.Settings.LoRa.Datarate -
- ( ( SX1276.Settings.LoRa.LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
- ( SX1276.Settings.LoRa.Coderate + 4 );
- double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
- double tPayload = nPayload * ts;
- // Time on air
- double tOnAir = tPreamble + tPayload;
- // return ms secs
- airTime = floor( tOnAir * 1000 + 0.999 );
+ numerator = 1000U * SX1276GetLoRaTimeOnAirNumerator( bandwidth, datarate,
+ coderate, preambleLen,
+ fixLen, payloadLen, crcOn );
+ denominator = SX1276GetLoRaBandwidthInHz( bandwidth );
}
break;
}
- return airTime;
+ // Perform integral ceil()
+ return ( numerator + denominator - 1 ) / denominator;
}
void SX1276Send( uint8_t *buffer, uint8_t size )
@@ -852,8 +907,13 @@ void SX1276SetSleep( void )
{
TimerStop( &RxTimeoutTimer );
TimerStop( &TxTimeoutTimer );
+ TimerStop( &RxTimeoutSyncWord );
SX1276SetOpMode( RF_OPMODE_SLEEP );
+
+ // Disable TCXO radio is in SLEEP mode
+ SX1276SetBoardTcxo( false );
+
SX1276.Settings.State = RF_IDLE;
}
@@ -861,6 +921,7 @@ void SX1276SetStby( void )
{
TimerStop( &RxTimeoutTimer );
TimerStop( &TxTimeoutTimer );
+ TimerStop( &RxTimeoutSyncWord );
SX1276SetOpMode( RF_OPMODE_STANDBY );
SX1276.Settings.State = RF_IDLE;
@@ -869,6 +930,7 @@ void SX1276SetStby( void )
void SX1276SetRx( uint32_t timeout )
{
bool rxContinuous = false;
+ TimerStop( &TxTimeoutTimer );
switch( SX1276.Settings.Modem )
{
@@ -1034,6 +1096,8 @@ void SX1276SetRx( uint32_t timeout )
void SX1276SetTx( uint32_t timeout )
{
+ TimerStop( &RxTimeoutTimer );
+
TimerSetValue( &TxTimeoutTimer, timeout );
switch( SX1276.Settings.Modem )
@@ -1130,7 +1194,7 @@ void SX1276StartCad( void )
void SX1276SetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time )
{
- uint32_t timeout = ( uint32_t )( time * 1000 );
+ uint32_t timeout = ( uint32_t )time * 1000;
SX1276SetChannel( freq );
@@ -1200,6 +1264,8 @@ void SX1276SetOpMode( uint8_t opMode )
}
else
{
+ // Enable TCXO if operating mode different from SLEEP.
+ SX1276SetBoardTcxo( true );
SX1276SetAntSwLowPower( false );
SX1276SetAntSw( opMode );
}
@@ -1227,14 +1293,14 @@ void SX1276SetModem( RadioModems_t modem )
{
default:
case MODEM_FSK:
- SX1276SetSleep( );
+ SX1276SetOpMode( RF_OPMODE_SLEEP );
SX1276Write( REG_OPMODE, ( SX1276Read( REG_OPMODE ) & RFLR_OPMODE_LONGRANGEMODE_MASK ) | RFLR_OPMODE_LONGRANGEMODE_OFF );
SX1276Write( REG_DIOMAPPING1, 0x00 );
SX1276Write( REG_DIOMAPPING2, 0x30 ); // DIO5=ModeReady
break;
case MODEM_LORA:
- SX1276SetSleep( );
+ SX1276SetOpMode( RF_OPMODE_SLEEP );
SX1276Write( REG_OPMODE, ( SX1276Read( REG_OPMODE ) & RFLR_OPMODE_LONGRANGEMODE_MASK ) | RFLR_OPMODE_LONGRANGEMODE_ON );
SX1276Write( REG_DIOMAPPING1, 0x00 );
@@ -1243,19 +1309,19 @@ void SX1276SetModem( RadioModems_t modem )
}
}
-void SX1276Write( uint16_t addr, uint8_t data )
+void SX1276Write( uint32_t addr, uint8_t data )
{
SX1276WriteBuffer( addr, &data, 1 );
}
-uint8_t SX1276Read( uint16_t addr )
+uint8_t SX1276Read( uint32_t addr )
{
uint8_t data;
SX1276ReadBuffer( addr, &data, 1 );
return data;
}
-void SX1276WriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size )
+void SX1276WriteBuffer( uint32_t addr, uint8_t *buffer, uint8_t size )
{
uint8_t i;
@@ -1272,7 +1338,7 @@ void SX1276WriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size )
GpioWrite( &SX1276.Spi.Nss, 1 );
}
-void SX1276ReadBuffer( uint16_t addr, uint8_t *buffer, uint8_t size )
+void SX1276ReadBuffer( uint32_t addr, uint8_t *buffer, uint8_t size )
{
uint8_t i;
@@ -1361,7 +1427,6 @@ void SX1276OnTimeoutIrq( void* context )
{
// Continuous mode restart Rx chain
SX1276Write( REG_RXCONFIG, SX1276Read( REG_RXCONFIG ) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK );
- TimerStart( &RxTimeoutSyncWord );
}
else
{
@@ -1376,10 +1441,12 @@ void SX1276OnTimeoutIrq( void* context )
break;
case RF_TX_RUNNING:
// Tx timeout shouldn't happen.
- // But it has been observed that when it happens it is a result of a corrupted SPI transfer
- // it depends on the platform design.
- //
- // The workaround is to put the radio in a known state. Thus, we re-initialize it.
+ // Reported issue of SPI data corruption resulting in TX TIMEOUT
+ // is NOT related to a bug in radio transceiver.
+ // It is mainly caused by improper PCB routing of SPI lines and/or
+ // violation of SPI specifications.
+ // To mitigate redesign, Semtech offers a workaround which resets
+ // the radio transceiver and putting it into a known state.
// BEGIN WORKAROUND
@@ -1448,7 +1515,6 @@ void SX1276OnDio0Irq( void* context )
{
// Continuous mode restart Rx chain
SX1276Write( REG_RXCONFIG, SX1276Read( REG_RXCONFIG ) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK );
- TimerStart( &RxTimeoutSyncWord );
}
if( ( RadioEvents != NULL ) && ( RadioEvents->RxError != NULL ) )
@@ -1494,7 +1560,6 @@ void SX1276OnDio0Irq( void* context )
{
// Continuous mode restart Rx chain
SX1276Write( REG_RXCONFIG, SX1276Read( REG_RXCONFIG ) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK );
- TimerStart( &RxTimeoutSyncWord );
}
if( ( RadioEvents != NULL ) && ( RadioEvents->RxDone != NULL ) )
@@ -1611,6 +1676,9 @@ void SX1276OnDio1Irq( void* context )
switch( SX1276.Settings.Modem )
{
case MODEM_FSK:
+ // Stop timer
+ TimerStop( &RxTimeoutSyncWord );
+
// FifoLevel interrupt
// Read received packet size
if( ( SX1276.Settings.FskPacketHandler.Size == 0 ) && ( SX1276.Settings.FskPacketHandler.NbBytes == 0 ) )
diff --git a/components/connectivity/LoraWAN/radio/sx1276/sx1276.h b/components/connectivity/LoraWAN/radio/sx1276/sx1276.h
index 428227ba..c48c3f33 100644
--- a/components/connectivity/LoraWAN/radio/sx1276/sx1276.h
+++ b/components/connectivity/LoraWAN/radio/sx1276/sx1276.h
@@ -23,6 +23,11 @@
#ifndef __SX1276_H__
#define __SX1276_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include "gpio.h"
@@ -312,12 +317,31 @@ void SX1276SetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev,
*
* \Remark Can only be called once SetRxConfig or SetTxConfig have been called
*
- * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
- * \param [IN] pktLen Packet payload length
+ * \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
+ * \param [IN] bandwidth Sets the bandwidth
+ * FSK : >= 2600 and <= 250000 Hz
+ * LoRa: [0: 125 kHz, 1: 250 kHz,
+ * 2: 500 kHz, 3: Reserved]
+ * \param [IN] datarate Sets the Datarate
+ * FSK : 600..300000 bits/s
+ * LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
+ * 10: 1024, 11: 2048, 12: 4096 chips]
+ * \param [IN] coderate Sets the coding rate (LoRa only)
+ * FSK : N/A ( set to 0 )
+ * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
+ * \param [IN] preambleLen Sets the Preamble length
+ * FSK : Number of bytes
+ * LoRa: Length in symbols (the hardware adds 4 more symbols)
+ * \param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
+ * \param [IN] payloadLen Sets payload length when fixed length is used
+ * \param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
*
* \retval airTime Computed airTime (ms) for the given packet payload length
*/
-uint32_t SX1276GetTimeOnAir( RadioModems_t modem, uint8_t pktLen );
+uint32_t SX1276GetTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
+ uint32_t datarate, uint8_t coderate,
+ uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
+ bool crcOn );
/*!
* \brief Sends the buffer of size. Prepares the packet to be sent and sets
@@ -371,7 +395,7 @@ int16_t SX1276ReadRssi( RadioModems_t modem );
* \param [IN]: addr Register address
* \param [IN]: data New register value
*/
-void SX1276Write( uint16_t addr, uint8_t data );
+void SX1276Write( uint32_t addr, uint8_t data );
/*!
* \brief Reads the radio register at the specified address
@@ -379,7 +403,7 @@ void SX1276Write( uint16_t addr, uint8_t data );
* \param [IN]: addr Register address
* \retval data Register value
*/
-uint8_t SX1276Read( uint16_t addr );
+uint8_t SX1276Read( uint32_t addr );
/*!
* \brief Writes multiple radio registers starting at address
@@ -388,7 +412,7 @@ uint8_t SX1276Read( uint16_t addr );
* \param [IN] buffer Buffer containing the new register's values
* \param [IN] size Number of registers to be written
*/
-void SX1276WriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size );
+void SX1276WriteBuffer( uint32_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Reads multiple radio registers starting at address
@@ -397,7 +421,7 @@ void SX1276WriteBuffer( uint16_t addr, uint8_t *buffer, uint8_t size );
* \param [OUT] buffer Buffer where to copy the registers data
* \param [IN] size Number of registers to be read
*/
-void SX1276ReadBuffer( uint16_t addr, uint8_t *buffer, uint8_t size );
+void SX1276ReadBuffer( uint32_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Sets the maximum payload length.
@@ -423,4 +447,8 @@ void SX1276SetPublicNetwork( bool enable );
*/
uint32_t SX1276GetWakeupTime( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SX1276_H__
diff --git a/components/connectivity/LoraWAN/radio/sx1276/sx1276Regs-Fsk.h b/components/connectivity/LoraWAN/radio/sx1276/sx1276Regs-Fsk.h
index 6be048d9..9808e794 100644
--- a/components/connectivity/LoraWAN/radio/sx1276/sx1276Regs-Fsk.h
+++ b/components/connectivity/LoraWAN/radio/sx1276/sx1276Regs-Fsk.h
@@ -23,6 +23,11 @@
#ifndef __SX1276_REGS_FSK_H__
#define __SX1276_REGS_FSK_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
/*!
* ============================================================================
* SX1276 Internal registers Address
@@ -1139,4 +1144,8 @@
#define RF_PLL_BANDWIDTH_225 0x80
#define RF_PLL_BANDWIDTH_300 0xC0 // Default
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SX1276_REGS_FSK_H__
diff --git a/components/connectivity/LoraWAN/radio/sx1276/sx1276Regs-LoRa.h b/components/connectivity/LoraWAN/radio/sx1276/sx1276Regs-LoRa.h
index e5830f47..af9bb74b 100644
--- a/components/connectivity/LoraWAN/radio/sx1276/sx1276Regs-LoRa.h
+++ b/components/connectivity/LoraWAN/radio/sx1276/sx1276Regs-LoRa.h
@@ -23,6 +23,11 @@
#ifndef __SX1276_REGS_LORA_H__
#define __SX1276_REGS_LORA_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
/*!
* ============================================================================
* SX1276 Internal registers Address
@@ -570,4 +575,8 @@
#define RF_PLL_BANDWIDTH_225 0x80
#define RF_PLL_BANDWIDTH_300 0xC0 // Default
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SX1276_REGS_LORA_H__
diff --git a/components/connectivity/LoraWAN/system/adc.h b/components/connectivity/LoraWAN/system/adc.h
index 46f541ff..a29049a9 100644
--- a/components/connectivity/LoraWAN/system/adc.h
+++ b/components/connectivity/LoraWAN/system/adc.h
@@ -23,6 +23,11 @@
#ifndef __ADC_H__
#define __ADC_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include "gpio.h"
@@ -58,4 +63,8 @@ void AdcDeInit( Adc_t *obj );
*/
uint16_t AdcReadChannel( Adc_t *obj, uint32_t channel );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __ADC_H__
diff --git a/components/connectivity/LoraWAN/system/delay.h b/components/connectivity/LoraWAN/system/delay.h
index 57ef3c41..769d28de 100644
--- a/components/connectivity/LoraWAN/system/delay.h
+++ b/components/connectivity/LoraWAN/system/delay.h
@@ -23,6 +23,11 @@
#ifndef __DELAY_H__
#define __DELAY_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
/*!
@@ -35,5 +40,9 @@ void Delay( float s );
*/
void DelayMs( uint32_t ms );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __DELAY_H__
diff --git a/components/connectivity/LoraWAN/system/eeprom.h b/components/connectivity/LoraWAN/system/eeprom.h
index f9b4ab48..be8e4d90 100644
--- a/components/connectivity/LoraWAN/system/eeprom.h
+++ b/components/connectivity/LoraWAN/system/eeprom.h
@@ -23,6 +23,11 @@
#ifndef __EEPROM_H__
#define __EEPROM_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
/*!
@@ -31,7 +36,7 @@
* \param[IN] addr EEPROM address to write to
* \param[IN] buffer Pointer to the buffer to be written.
* \param[IN] size Size of the buffer to be written.
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t EepromWriteBuffer( uint16_t addr, uint8_t *buffer, uint16_t size );
@@ -41,7 +46,7 @@ uint8_t EepromWriteBuffer( uint16_t addr, uint8_t *buffer, uint16_t size );
* \param[IN] addr EEPROM address to read from
* \param[OUT] buffer Pointer to the buffer to be written with read data.
* \param[IN] size Size of the buffer to be read.
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t EepromReadBuffer( uint16_t addr, uint8_t *buffer, uint16_t size );
@@ -63,4 +68,8 @@ void EepromSetDeviceAddr( uint8_t addr );
*/
uint8_t EepromGetDeviceAddr( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __EEPROM_H__
diff --git a/components/connectivity/LoraWAN/system/fifo.h b/components/connectivity/LoraWAN/system/fifo.h
index 3335f5ad..8acbd582 100644
--- a/components/connectivity/LoraWAN/system/fifo.h
+++ b/components/connectivity/LoraWAN/system/fifo.h
@@ -23,6 +23,11 @@
#ifndef __FIFO_H__
#define __FIFO_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
@@ -85,4 +90,8 @@ bool IsFifoEmpty( Fifo_t *fifo );
*/
bool IsFifoFull( Fifo_t *fifo );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __FIFO_H__
diff --git a/components/connectivity/LoraWAN/system/gpio.h b/components/connectivity/LoraWAN/system/gpio.h
index 5d75a5b2..bf9b6f5f 100644
--- a/components/connectivity/LoraWAN/system/gpio.h
+++ b/components/connectivity/LoraWAN/system/gpio.h
@@ -27,6 +27,11 @@
#ifndef __GPIO_H__
#define __GPIO_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include "pinName-board.h"
#include "pinName-ioe.h"
@@ -179,4 +184,8 @@ void GpioToggle( Gpio_t *obj );
*/
uint32_t GpioRead( Gpio_t *obj );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __GPIO_H__
diff --git a/components/connectivity/LoraWAN/system/gps.c b/components/connectivity/LoraWAN/system/gps.c
index bd77bc8c..6f144946 100644
--- a/components/connectivity/LoraWAN/system/gps.c
+++ b/components/connectivity/LoraWAN/system/gps.c
@@ -186,10 +186,10 @@ void GpsConvertPositionFromStringToNumerical( void )
uint8_t GpsGetLatestGpsPositionDouble( double *lati, double *longi )
{
- uint8_t status = LORA_FAIL;
+ uint8_t status = FAIL;
if( HasFix == true )
{
- status = LORA_SUCCESS;
+ status = SUCCESS;
}
else
{
@@ -202,12 +202,12 @@ uint8_t GpsGetLatestGpsPositionDouble( double *lati, double *longi )
uint8_t GpsGetLatestGpsPositionBinary( int32_t *latiBin, int32_t *longiBin )
{
- uint8_t status = LORA_FAIL;
+ uint8_t status = FAIL;
CRITICAL_SECTION_BEGIN( );
if( HasFix == true )
{
- status = LORA_SUCCESS;
+ status = SUCCESS;
}
else
{
@@ -322,12 +322,12 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
if( rxBuffer[0] != '$' )
{
GpsMcuInvertPpsTrigger( );
- return LORA_FAIL;
+ return FAIL;
}
if( GpsNmeaValidateChecksum( rxBuffer, rxBufferSize ) == false )
{
- return LORA_FAIL;
+ return FAIL;
}
fieldSize = 0;
@@ -335,7 +335,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 6 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -351,7 +351,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 11 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -364,7 +364,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 10 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -377,7 +377,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 2 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -390,7 +390,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 11 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -403,7 +403,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 2 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -416,7 +416,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 2 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -429,7 +429,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 3 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -442,7 +442,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 6 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -455,7 +455,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 8 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -468,7 +468,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 2 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -481,7 +481,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 8 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -494,7 +494,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 2 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -503,7 +503,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
}
GpsFormatGpsData( );
- return LORA_SUCCESS;
+ return SUCCESS;
}
else if ( strncmp( ( const char* )NmeaGpsData.NmeaDataType, ( const char* )NmeaDataTypeGPRMC, 5 ) == 0 )
{
@@ -513,7 +513,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 11 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -526,7 +526,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 2 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -539,7 +539,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 10 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -552,7 +552,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 2 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -565,7 +565,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 11 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -578,7 +578,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 2 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -591,7 +591,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 8 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -604,7 +604,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 8 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -617,7 +617,7 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
{
if( fieldSize > 8 )
{
- return LORA_FAIL;
+ return FAIL;
}
}
for( j = 0; j < fieldSize; j++, i++ )
@@ -626,11 +626,11 @@ uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize )
}
GpsFormatGpsData( );
- return LORA_SUCCESS;
+ return SUCCESS;
}
else
{
- return LORA_FAIL;
+ return FAIL;
}
}
diff --git a/components/connectivity/LoraWAN/system/gps.h b/components/connectivity/LoraWAN/system/gps.h
index 238d5f50..ffc5aa88 100644
--- a/components/connectivity/LoraWAN/system/gps.h
+++ b/components/connectivity/LoraWAN/system/gps.h
@@ -23,6 +23,11 @@
#ifndef __GPS_H__
#define __GPS_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
@@ -106,7 +111,7 @@ void GpsConvertPositionFromStringToNumerical( void );
* \param [OUT] lati Latitude value
* \param [OUT] longi Longitude value
*
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t GpsGetLatestGpsPositionDouble ( double *lati, double *longi );
@@ -117,7 +122,7 @@ uint8_t GpsGetLatestGpsPositionDouble ( double *lati, double *longi );
* \param [OUT] latiBin Latitude value
* \param [OUT] longiBin Longitude value
*
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t GpsGetLatestGpsPositionBinary ( int32_t *latiBin, int32_t *longiBin );
@@ -129,7 +134,7 @@ uint8_t GpsGetLatestGpsPositionBinary ( int32_t *latiBin, int32_t *longiBin );
* \param [IN] rxBuffer Data buffer to be parsed
* \param [IN] rxBufferSize Size of data buffer
*
- * \retval status [LORA_SUCCESS, LORA_FAIL]
+ * \retval status [SUCCESS, FAIL]
*/
uint8_t GpsParseGpsData( int8_t *rxBuffer, int32_t rxBufferSize );
@@ -150,4 +155,8 @@ void GpsFormatGpsData( void );
*/
void GpsResetPosition( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __GPS_H__
diff --git a/components/connectivity/LoraWAN/system/i2c.h b/components/connectivity/LoraWAN/system/i2c.h
index 93aff9d1..31127f28 100644
--- a/components/connectivity/LoraWAN/system/i2c.h
+++ b/components/connectivity/LoraWAN/system/i2c.h
@@ -23,6 +23,11 @@
#ifndef __I2C_H__
#define __I2C_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "gpio.h"
/*!
@@ -109,4 +114,8 @@ uint8_t I2cRead( I2c_t *obj, uint8_t deviceAddr, uint16_t addr, uint8_t *data );
*/
uint8_t I2cReadBuffer( I2c_t *obj, uint8_t deviceAddr, uint16_t addr, uint8_t *buffer, uint16_t size );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __I2C_H__
diff --git a/components/connectivity/LoraWAN/system/nvmm.h b/components/connectivity/LoraWAN/system/nvmm.h
index 9b1dea86..795de0c0 100644
--- a/components/connectivity/LoraWAN/system/nvmm.h
+++ b/components/connectivity/LoraWAN/system/nvmm.h
@@ -33,6 +33,11 @@
#ifndef __NVMM_H__
#define __NVMM_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
@@ -112,4 +117,8 @@ NvmmStatus_t NvmmWrite( NvmmDataBlock_t* dataB, void* src, size_t num );
*/
NvmmStatus_t NvmmRead( NvmmDataBlock_t* dataB, void* dst, size_t num );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __NVMM_H__
diff --git a/components/connectivity/LoraWAN/system/serial.h b/components/connectivity/LoraWAN/system/serial.h
index abae1bdf..b35b46ca 100644
--- a/components/connectivity/LoraWAN/system/serial.h
+++ b/components/connectivity/LoraWAN/system/serial.h
@@ -23,4 +23,13 @@
#ifndef __SERIAL_H__
#define __SERIAL_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SERIAL_H__
diff --git a/components/connectivity/LoraWAN/system/spi.h b/components/connectivity/LoraWAN/system/spi.h
index 1d6a08e9..bf63c0cd 100644
--- a/components/connectivity/LoraWAN/system/spi.h
+++ b/components/connectivity/LoraWAN/system/spi.h
@@ -23,6 +23,11 @@
#ifndef __SPI_H__
#define __SPI_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "gpio.h"
/*!
@@ -97,4 +102,8 @@ void SpiFrequency( Spi_t *obj, uint32_t hz );
*/
uint16_t SpiInOut( Spi_t *obj, uint16_t outData );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __SPI_H__
diff --git a/components/connectivity/LoraWAN/system/systime.c b/components/connectivity/LoraWAN/system/systime.c
index 2e029a45..7072d529 100644
--- a/components/connectivity/LoraWAN/system/systime.c
+++ b/components/connectivity/LoraWAN/system/systime.c
@@ -139,7 +139,7 @@ SysTime_t SysTimeGetMcuTime( void )
return calendarTime;
}
-uint32_t SysTime2Ms( SysTime_t sysTime )
+uint32_t SysTimeToMs( SysTime_t sysTime )
{
SysTime_t deltaTime;
RtcBkupRead( &deltaTime.Seconds, ( uint32_t* )&deltaTime.SubSeconds );
@@ -147,6 +147,16 @@ uint32_t SysTime2Ms( SysTime_t sysTime )
return calendarTime.Seconds * 1000 + calendarTime.SubSeconds;
}
+SysTime_t SysTimeFromMs( uint32_t timeMs )
+{
+ uint32_t seconds = timeMs / 1000;
+ SysTime_t sysTime = { .Seconds = seconds, .SubSeconds = timeMs - seconds * 1000 };
+ SysTime_t deltaTime = { 0 };
+ RtcBkupRead( &deltaTime.Seconds, ( uint32_t* )&deltaTime.SubSeconds );
+
+ return SysTimeAdd( sysTime, deltaTime );
+}
+
uint32_t SysTimeMkTime( const struct tm* localtime )
{
uint32_t nbdays;
diff --git a/components/connectivity/LoraWAN/system/systime.h b/components/connectivity/LoraWAN/system/systime.h
index 809fb058..2cb028ff 100644
--- a/components/connectivity/LoraWAN/system/systime.h
+++ b/components/connectivity/LoraWAN/system/systime.h
@@ -29,6 +29,7 @@
extern "C"
{
#endif
+
#include
#include "time.h"
@@ -133,7 +134,16 @@ SysTime_t SysTimeGetMcuTime( void );
*
* \retval timeMs The RTC converted time value in ms
*/
-uint32_t SysTime2Ms( SysTime_t sysTime );
+uint32_t SysTimeToMs( SysTime_t sysTime );
+
+/*!
+ * Converts the given RTC value in milliseconds to the equivalent SysTime
+ *
+ * \param [IN] timeMs The RTC time value in ms to be converted
+ *
+ * \retval sysTime Converted system time
+ */
+SysTime_t SysTimeFromMs( uint32_t timeMs );
/*!
* \brief Convert a calendar time into time since UNIX epoch as a uint32_t.
diff --git a/components/connectivity/LoraWAN/system/timer.c b/components/connectivity/LoraWAN/system/timer.c
index f5820366..317a65c6 100644
--- a/components/connectivity/LoraWAN/system/timer.c
+++ b/components/connectivity/LoraWAN/system/timer.c
@@ -351,6 +351,10 @@ TimerTime_t TimerGetCurrentTime( void )
TimerTime_t TimerGetElapsedTime( TimerTime_t past )
{
+ if ( past == 0 )
+ {
+ return 0;
+ }
uint32_t nowInTicks = RtcGetTimerValue( );
uint32_t pastInTicks = RtcMs2Tick( past );
diff --git a/components/connectivity/LoraWAN/system/timer.h b/components/connectivity/LoraWAN/system/timer.h
index 0e6a1432..3b1e46e0 100644
--- a/components/connectivity/LoraWAN/system/timer.h
+++ b/components/connectivity/LoraWAN/system/timer.h
@@ -23,6 +23,11 @@
#ifndef __TIMER_H__
#define __TIMER_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include
#include
#include
@@ -46,6 +51,7 @@ typedef struct TimerEvent_s
*/
#ifndef TimerTime_t
typedef uint32_t TimerTime_t;
+#define TIMERTIME_T_MAX ( ( uint32_t )~0 )
#endif
/*!
@@ -121,6 +127,8 @@ TimerTime_t TimerGetCurrentTime( void );
/*!
* \brief Return the Time elapsed since a fix moment in Time
*
+ * \remark TimerGetElapsedTime will return 0 for argument 0.
+ *
* \param [IN] past fix moment in Time
* \retval time returns elapsed time
*/
@@ -142,4 +150,8 @@ TimerTime_t TimerTempCompensation( TimerTime_t period, float temperature );
*/
void TimerProcess( void );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __TIMER_H__
diff --git a/components/connectivity/LoraWAN/system/uart.h b/components/connectivity/LoraWAN/system/uart.h
index d2d9b80a..511f3542 100644
--- a/components/connectivity/LoraWAN/system/uart.h
+++ b/components/connectivity/LoraWAN/system/uart.h
@@ -23,9 +23,14 @@
#ifndef __UART_H__
#define __UART_H__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
#include "fifo.h"
#include "gpio.h"
-#include "stdio.h"
+
/*!
* UART peripheral ID
*/
@@ -183,4 +188,8 @@ uint8_t UartGetChar( Uart_t *obj, uint8_t *data );
*/
uint8_t UartGetBuffer( Uart_t *obj, uint8_t *buffer, uint16_t size, uint16_t *nbReadBytes );
+#ifdef __cplusplus
+}
+#endif
+
#endif // __UART_H__