diff --git a/.vscode/settings.json b/.vscode/settings.json index 215a9caec..2598b5645 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -62,6 +62,7 @@ "REGION_AS923":"OFF", "REGION_CN470":"OFF", "REGION_KR920":"OFF", - "REGION_IN865":"OFF" + "REGION_IN865":"OFF", + "REGION_RU864":"OFF" } } diff --git a/Doc/development-environment.md b/Doc/development-environment.md index 0f909ae0b..4f4761078 100644 --- a/Doc/development-environment.md +++ b/Doc/development-environment.md @@ -101,6 +101,7 @@ Alternatively one can use a graphical interface to configure CMake, drop down me * LORAMAC_REGION_CN470 * LORAMAC_REGION_KR920 * LORAMAC_REGION_IN865 + * LORAMAC_REGION_RU864 * `MODULATION` - Type of modulation choice. **Note**: Only applicable to ping-pong or rx-sensi `APPLICATION` choice. The possible choices are: @@ -122,6 +123,7 @@ Alternatively one can use a graphical interface to configure CMake, drop down me * `REGION_CN470` - Enables support for the Region CN470 (Default OFF) * `REGION_KR920` - Enables support for the Region IN865 (Default OFF) * `REGION_IN865` - Enables support for the Region AS923 (Default OFF) +* `REGION_RU864` - Enables support for the Region RU864 (Default OFF) ### Options that are automatically set diff --git a/src/apps/LoRaMac/CMakeLists.txt b/src/apps/LoRaMac/CMakeLists.txt index a02098563..2ad7a0f24 100644 --- a/src/apps/LoRaMac/CMakeLists.txt +++ b/src/apps/LoRaMac/CMakeLists.txt @@ -30,7 +30,7 @@ set_property(CACHE CLASS PROPERTY STRINGS ${CLASS_LIST}) # Allow switching of active region set(ACTIVE_REGION_LIST LORAMAC_REGION_EU868 LORAMAC_REGION_US915 LORAMAC_REGION_CN779 LORAMAC_REGION_EU433 LORAMAC_REGION_AU915 LORAMAC_REGION_AS923 LORAMAC_REGION_CN470 - LORAMAC_REGION_KR920 LORAMAC_REGION_IN865 + LORAMAC_REGION_KR920 LORAMAC_REGION_IN865 LORAMAC_REGION_RU864 ) set(ACTIVE_REGION LORAMAC_REGION_EU868 CACHE STRING "Default active region is EU868") set_property(CACHE ACTIVE_REGION PROPERTY STRINGS ${ACTIVE_REGION_LIST}) diff --git a/src/apps/LoRaMac/classA/NAMote72/main.c b/src/apps/LoRaMac/classA/NAMote72/main.c index 190e7ce05..567baf189 100644 --- a/src/apps/LoRaMac/classA/NAMote72/main.c +++ b/src/apps/LoRaMac/classA/NAMote72/main.c @@ -633,7 +633,7 @@ static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) printf("CHANNEL MASK: "); #if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \ defined( REGION_EU868 ) || defined( REGION_IN865 ) || \ - defined( REGION_KR920 ) + defined( REGION_KR920 ) || defined( REGION_RU864 ) for( uint8_t i = 0; i < 1; i++) diff --git a/src/apps/LoRaMac/classA/NucleoL073/main.c b/src/apps/LoRaMac/classA/NucleoL073/main.c index 9c9297baf..0c965479d 100644 --- a/src/apps/LoRaMac/classA/NucleoL073/main.c +++ b/src/apps/LoRaMac/classA/NucleoL073/main.c @@ -541,7 +541,8 @@ static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) printf("CHANNEL MASK: "); #if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \ defined( REGION_EU868 ) || defined( REGION_IN865 ) || \ - defined( REGION_KR920 ) || defined( REGION_EU433 ) + defined( REGION_KR920 ) || defined( REGION_EU433 ) || \ + defined( REGION_RU864 ) for( uint8_t i = 0; i < 1; i++) diff --git a/src/apps/LoRaMac/classA/NucleoL152/main.c b/src/apps/LoRaMac/classA/NucleoL152/main.c index 08888693f..a1290a915 100644 --- a/src/apps/LoRaMac/classA/NucleoL152/main.c +++ b/src/apps/LoRaMac/classA/NucleoL152/main.c @@ -541,7 +541,8 @@ static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) printf("CHANNEL MASK: "); #if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \ defined( REGION_EU868 ) || defined( REGION_IN865 ) || \ - defined( REGION_KR920 ) || defined( REGION_EU433 ) + defined( REGION_KR920 ) || defined( REGION_EU433 ) || \ + defined( REGION_RU864 ) for( uint8_t i = 0; i < 1; i++) diff --git a/src/apps/LoRaMac/classA/SAML21/main.c b/src/apps/LoRaMac/classA/SAML21/main.c index e0474cc54..0187614d5 100644 --- a/src/apps/LoRaMac/classA/SAML21/main.c +++ b/src/apps/LoRaMac/classA/SAML21/main.c @@ -547,7 +547,8 @@ static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) printf("CHANNEL MASK: "); #if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \ defined( REGION_EU868 ) || defined( REGION_IN865 ) || \ - defined( REGION_KR920 ) || defined( REGION_EU433 ) + defined( REGION_KR920 ) || defined( REGION_EU433 ) || \ + defined( REGION_RU864 ) for( uint8_t i = 0; i < 1; i++) diff --git a/src/apps/LoRaMac/classB/NAMote72/main.c b/src/apps/LoRaMac/classB/NAMote72/main.c index baef6752b..7a2a284e2 100644 --- a/src/apps/LoRaMac/classB/NAMote72/main.c +++ b/src/apps/LoRaMac/classB/NAMote72/main.c @@ -667,7 +667,7 @@ static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) printf("CHANNEL MASK: "); #if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \ defined( REGION_EU868 ) || defined( REGION_IN865 ) || \ - defined( REGION_KR920 ) + defined( REGION_KR920 ) || defined( REGION_RU864 ) for( uint8_t i = 0; i < 1; i++) diff --git a/src/apps/LoRaMac/classB/NucleoL073/main.c b/src/apps/LoRaMac/classB/NucleoL073/main.c index 9dd2fe127..e97c0eebd 100644 --- a/src/apps/LoRaMac/classB/NucleoL073/main.c +++ b/src/apps/LoRaMac/classB/NucleoL073/main.c @@ -575,7 +575,8 @@ static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) printf("CHANNEL MASK: "); #if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \ defined( REGION_EU868 ) || defined( REGION_IN865 ) || \ - defined( REGION_KR920 ) || defined( REGION_EU433 ) + defined( REGION_KR920 ) || defined( REGION_EU433 ) || \ + defined( REGION_RU864 ) for( uint8_t i = 0; i < 1; i++) diff --git a/src/apps/LoRaMac/classB/SAML21/main.c b/src/apps/LoRaMac/classB/SAML21/main.c index de0e43ca8..25847b1bf 100644 --- a/src/apps/LoRaMac/classB/SAML21/main.c +++ b/src/apps/LoRaMac/classB/SAML21/main.c @@ -581,7 +581,8 @@ static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) printf("CHANNEL MASK: "); #if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \ defined( REGION_EU868 ) || defined( REGION_IN865 ) || \ - defined( REGION_KR920 ) || defined( REGION_EU433 ) + defined( REGION_KR920 ) || defined( REGION_EU433 ) || \ + defined( REGION_RU864 ) for( uint8_t i = 0; i < 1; i++) diff --git a/src/apps/LoRaMac/classC/NAMote72/main.c b/src/apps/LoRaMac/classC/NAMote72/main.c index 6b30139b9..fe0205e6a 100644 --- a/src/apps/LoRaMac/classC/NAMote72/main.c +++ b/src/apps/LoRaMac/classC/NAMote72/main.c @@ -633,7 +633,7 @@ static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) printf("CHANNEL MASK: "); #if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \ defined( REGION_EU868 ) || defined( REGION_IN865 ) || \ - defined( REGION_KR920 ) + defined( REGION_KR920 ) || defined( REGION_RU864 ) for( uint8_t i = 0; i < 1; i++) diff --git a/src/apps/LoRaMac/classC/NucleoL073/main.c b/src/apps/LoRaMac/classC/NucleoL073/main.c index ebb84da8c..9889b8d2f 100644 --- a/src/apps/LoRaMac/classC/NucleoL073/main.c +++ b/src/apps/LoRaMac/classC/NucleoL073/main.c @@ -541,7 +541,8 @@ static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) printf("CHANNEL MASK: "); #if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \ defined( REGION_EU868 ) || defined( REGION_IN865 ) || \ - defined( REGION_KR920 ) || defined( REGION_EU433 ) + defined( REGION_KR920 ) || defined( REGION_EU433 ) || \ + defined( REGION_RU864 ) for( uint8_t i = 0; i < 1; i++) diff --git a/src/apps/LoRaMac/classC/NucleoL152/main.c b/src/apps/LoRaMac/classC/NucleoL152/main.c index 89f4d27a8..4b23c0ac9 100644 --- a/src/apps/LoRaMac/classC/NucleoL152/main.c +++ b/src/apps/LoRaMac/classC/NucleoL152/main.c @@ -541,7 +541,8 @@ static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) printf("CHANNEL MASK: "); #if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \ defined( REGION_EU868 ) || defined( REGION_IN865 ) || \ - defined( REGION_KR920 ) || defined( REGION_EU433 ) + defined( REGION_KR920 ) || defined( REGION_EU433 ) || \ + defined( REGION_RU864 ) for( uint8_t i = 0; i < 1; i++) diff --git a/src/apps/LoRaMac/classC/SAML21/main.c b/src/apps/LoRaMac/classC/SAML21/main.c index e11af9b61..ca770256e 100644 --- a/src/apps/LoRaMac/classC/SAML21/main.c +++ b/src/apps/LoRaMac/classC/SAML21/main.c @@ -547,7 +547,8 @@ static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) printf("CHANNEL MASK: "); #if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \ defined( REGION_EU868 ) || defined( REGION_IN865 ) || \ - defined( REGION_KR920 ) || defined( REGION_EU433 ) + defined( REGION_KR920 ) || defined( REGION_EU433 ) || \ + defined( REGION_RU864 ) for( uint8_t i = 0; i < 1; i++) diff --git a/src/apps/ping-pong/NAMote72/main.c b/src/apps/ping-pong/NAMote72/main.c index 30b8cf675..7e34660fd 100644 --- a/src/apps/ping-pong/NAMote72/main.c +++ b/src/apps/ping-pong/NAMote72/main.c @@ -56,6 +56,10 @@ #define RF_FREQUENCY 915000000 // Hz +#elif defined( REGION_RU864 ) + +#define RF_FREQUENCY 864000000 // Hz + #else #error "Please define a frequency band in the compiler options." #endif diff --git a/src/apps/ping-pong/NucleoL073/main.c b/src/apps/ping-pong/NucleoL073/main.c index 8fd762b1a..09b850b42 100644 --- a/src/apps/ping-pong/NucleoL073/main.c +++ b/src/apps/ping-pong/NucleoL073/main.c @@ -63,6 +63,10 @@ #define RF_FREQUENCY 915000000 // Hz +#elif defined( REGION_RU864 ) + +#define RF_FREQUENCY 864000000 // Hz + #else #error "Please define a frequency band in the compiler options." #endif diff --git a/src/apps/ping-pong/NucleoL152/main.c b/src/apps/ping-pong/NucleoL152/main.c index 8fd762b1a..09b850b42 100644 --- a/src/apps/ping-pong/NucleoL152/main.c +++ b/src/apps/ping-pong/NucleoL152/main.c @@ -63,6 +63,10 @@ #define RF_FREQUENCY 915000000 // Hz +#elif defined( REGION_RU864 ) + +#define RF_FREQUENCY 864000000 // Hz + #else #error "Please define a frequency band in the compiler options." #endif diff --git a/src/apps/ping-pong/SAML21/main.c b/src/apps/ping-pong/SAML21/main.c index d48841ff9..7d612060a 100644 --- a/src/apps/ping-pong/SAML21/main.c +++ b/src/apps/ping-pong/SAML21/main.c @@ -57,6 +57,10 @@ #define RF_FREQUENCY 915000000 // Hz +#elif defined( REGION_RU864 ) + +#define RF_FREQUENCY 864000000 // Hz + #else #error "Please define a frequency band in the compiler options." #endif diff --git a/src/apps/rx-sensi/NAMote72/main.c b/src/apps/rx-sensi/NAMote72/main.c index 486e99dde..272298a7f 100644 --- a/src/apps/rx-sensi/NAMote72/main.c +++ b/src/apps/rx-sensi/NAMote72/main.c @@ -59,6 +59,10 @@ #define RF_FREQUENCY 915000000 // Hz +#elif defined( REGION_RU864 ) + +#define RF_FREQUENCY 864000000 // Hz + #else #error "Please define a frequency band in the compiler options." #endif diff --git a/src/apps/rx-sensi/NucleoL073/main.c b/src/apps/rx-sensi/NucleoL073/main.c index 5153f1d8f..1f079e02b 100644 --- a/src/apps/rx-sensi/NucleoL073/main.c +++ b/src/apps/rx-sensi/NucleoL073/main.c @@ -66,6 +66,10 @@ #define RF_FREQUENCY 915000000 // Hz +#elif defined( REGION_RU864 ) + +#define RF_FREQUENCY 864000000 // Hz + #else #error "Please define a frequency band in the compiler options." #endif diff --git a/src/apps/rx-sensi/NucleoL152/main.c b/src/apps/rx-sensi/NucleoL152/main.c index 5153f1d8f..1f079e02b 100644 --- a/src/apps/rx-sensi/NucleoL152/main.c +++ b/src/apps/rx-sensi/NucleoL152/main.c @@ -66,6 +66,10 @@ #define RF_FREQUENCY 915000000 // Hz +#elif defined( REGION_RU864 ) + +#define RF_FREQUENCY 864000000 // Hz + #else #error "Please define a frequency band in the compiler options." #endif diff --git a/src/apps/rx-sensi/SAML21/main.c b/src/apps/rx-sensi/SAML21/main.c index 849daf334..f5eba7065 100644 --- a/src/apps/rx-sensi/SAML21/main.c +++ b/src/apps/rx-sensi/SAML21/main.c @@ -60,6 +60,10 @@ #define RF_FREQUENCY 915000000 // Hz +#elif defined( REGION_RU864 ) + +#define RF_FREQUENCY 864000000 // Hz + #else #error "Please define a frequency band in the compiler options." #endif diff --git a/src/apps/tx-cw/NAMote72/main.c b/src/apps/tx-cw/NAMote72/main.c index b6f4c9809..882e4a983 100644 --- a/src/apps/tx-cw/NAMote72/main.c +++ b/src/apps/tx-cw/NAMote72/main.c @@ -54,6 +54,10 @@ #define RF_FREQUENCY 915000000 // Hz +#elif defined( REGION_RU864 ) + +#define RF_FREQUENCY 864000000 // Hz + #else #error "Please define a frequency band in the compiler options." diff --git a/src/apps/tx-cw/NucleoL073/main.c b/src/apps/tx-cw/NucleoL073/main.c index 0a33ee64f..e05b5bd95 100644 --- a/src/apps/tx-cw/NucleoL073/main.c +++ b/src/apps/tx-cw/NucleoL073/main.c @@ -70,6 +70,11 @@ #define RF_FREQUENCY 915000000 // Hz #define TX_OUTPUT_POWER 14 // 14 dBm +#elif defined( REGION_RU864 ) + +#define RF_FREQUENCY 864000000 // Hz +#define TX_OUTPUT_POWER 14 // 14 dBm + #else #error "Please define a frequency band in the compiler options." diff --git a/src/apps/tx-cw/NucleoL152/main.c b/src/apps/tx-cw/NucleoL152/main.c index 0a33ee64f..e05b5bd95 100644 --- a/src/apps/tx-cw/NucleoL152/main.c +++ b/src/apps/tx-cw/NucleoL152/main.c @@ -70,6 +70,11 @@ #define RF_FREQUENCY 915000000 // Hz #define TX_OUTPUT_POWER 14 // 14 dBm +#elif defined( REGION_RU864 ) + +#define RF_FREQUENCY 864000000 // Hz +#define TX_OUTPUT_POWER 14 // 14 dBm + #else #error "Please define a frequency band in the compiler options." diff --git a/src/apps/tx-cw/SAML21/main.c b/src/apps/tx-cw/SAML21/main.c index df53ef165..b27e89dac 100644 --- a/src/apps/tx-cw/SAML21/main.c +++ b/src/apps/tx-cw/SAML21/main.c @@ -55,6 +55,10 @@ #define RF_FREQUENCY 915000000 // Hz +#elif defined( REGION_RU864 ) + +#define RF_FREQUENCY 864000000 // Hz + #else #error "Please define a frequency band in the compiler options." diff --git a/src/mac/CMakeLists.txt b/src/mac/CMakeLists.txt index b03520218..70eab69bf 100644 --- a/src/mac/CMakeLists.txt +++ b/src/mac/CMakeLists.txt @@ -32,7 +32,8 @@ option(REGION_AS923 "Region AS923" OFF) option(REGION_CN470 "Region CN470" OFF) option(REGION_KR920 "Region KR920" OFF) option(REGION_IN865 "Region IN865" OFF) -set(REGION_LIST REGION_EU868 REGION_US915 REGION_CN779 REGION_EU433 REGION_AU915 REGION_AS923 REGION_CN470 REGION_KR920 REGION_IN865) +option(REGION_RU864 "Region RU864" OFF) +set(REGION_LIST REGION_EU868 REGION_US915 REGION_CN779 REGION_EU433 REGION_AU915 REGION_AS923 REGION_CN470 REGION_KR920 REGION_IN865 REGION_RU864) #--------------------------------------------------------------------------------------- # Target diff --git a/src/mac/LoRaMac.h b/src/mac/LoRaMac.h index ed3dd8cfd..99e4a522d 100644 --- a/src/mac/LoRaMac.h +++ b/src/mac/LoRaMac.h @@ -2213,6 +2213,10 @@ typedef enum eLoRaMacRegion_t * North american band on 915MHz */ LORAMAC_REGION_US915, + /*! + * Russia band on 864MHz + */ + LORAMAC_REGION_RU864, }LoRaMacRegion_t; /*! diff --git a/src/mac/region/Region.c b/src/mac/region/Region.c index de235057f..ef3249efb 100644 --- a/src/mac/region/Region.c +++ b/src/mac/region/Region.c @@ -517,6 +517,60 @@ #define US915_RX_BEACON_SETUP( ) #endif +#ifdef REGION_RU864 +#include "RegionRU864.h" +#define RU864_CASE case LORAMAC_REGION_RU864: +#define RU864_IS_ACTIVE( ) RU864_CASE { return true; } +#define RU864_GET_PHY_PARAM( ) RU864_CASE { return RegionRU864GetPhyParam( getPhy ); } +#define RU864_SET_BAND_TX_DONE( ) RU864_CASE { RegionRU864SetBandTxDone( txDone ); break; } +#define RU864_INIT_DEFAULTS( ) RU864_CASE { RegionRU864InitDefaults( params ); break; } +#define RU864_GET_NVM_CTX( ) RU864_CASE { return RegionRU864GetNvmCtx( params ); } +#define RU864_VERIFY( ) RU864_CASE { return RegionRU864Verify( verify, phyAttribute ); } +#define RU864_APPLY_CF_LIST( ) RU864_CASE { RegionRU864ApplyCFList( applyCFList ); break; } +#define RU864_CHAN_MASK_SET( ) RU864_CASE { return RegionRU864ChanMaskSet( chanMaskSet ); } +#define RU864_COMPUTE_RX_WINDOW_PARAMETERS( ) RU864_CASE { RegionRU864ComputeRxWindowParameters( datarate, minRxSymbols, rxError, rxConfigParams ); break; } +#define RU864_RX_CONFIG( ) RU864_CASE { return RegionRU864RxConfig( rxConfig, datarate ); } +#define RU864_TX_CONFIG( ) RU864_CASE { return RegionRU864TxConfig( txConfig, txPower, txTimeOnAir ); } +#define RU864_LINK_ADR_REQ( ) RU864_CASE { return RegionRU864LinkAdrReq( linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed ); } +#define RU864_RX_PARAM_SETUP_REQ( ) RU864_CASE { return RegionRU864RxParamSetupReq( rxParamSetupReq ); } +#define RU864_NEW_CHANNEL_REQ( ) RU864_CASE { return RegionRU864NewChannelReq( newChannelReq ); } +#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 ); } +#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 ); } +#define RU864_SET_CONTINUOUS_WAVE( ) RU864_CASE { RegionRU864SetContinuousWave( continuousWave ); break; } +#define RU864_APPLY_DR_OFFSET( ) RU864_CASE { return RegionRU864ApplyDrOffset( downlinkDwellTime, dr, drOffset ); } +#define RU864_RX_BEACON_SETUP( ) RU864_CASE { RegionRU864RxBeaconSetup( rxBeaconSetup, outDr ); } +#else +#define RU864_IS_ACTIVE( ) +#define RU864_GET_PHY_PARAM( ) +#define RU864_SET_BAND_TX_DONE( ) +#define RU864_INIT_DEFAULTS( ) +#define RU864_GET_NVM_CTX( ) +#define RU864_VERIFY( ) +#define RU864_APPLY_CF_LIST( ) +#define RU864_CHAN_MASK_SET( ) +#define RU864_COMPUTE_RX_WINDOW_PARAMETERS( ) +#define RU864_RX_CONFIG( ) +#define RU864_TX_CONFIG( ) +#define RU864_LINK_ADR_REQ( ) +#define RU864_RX_PARAM_SETUP_REQ( ) +#define RU864_NEW_CHANNEL_REQ( ) +#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( ) +#define RU864_SET_CONTINUOUS_WAVE( ) +#define RU864_APPLY_DR_OFFSET( ) +#define RU864_RX_BEACON_SETUP( ) +#endif + bool RegionIsActive( LoRaMacRegion_t region ) { switch( region ) @@ -530,6 +584,7 @@ bool RegionIsActive( LoRaMacRegion_t region ) KR920_IS_ACTIVE( ); IN865_IS_ACTIVE( ); US915_IS_ACTIVE( ); + RU864_IS_ACTIVE( ); default: { return false; @@ -551,6 +606,7 @@ PhyParam_t RegionGetPhyParam( LoRaMacRegion_t region, GetPhyParams_t* getPhy ) KR920_GET_PHY_PARAM( ); IN865_GET_PHY_PARAM( ); US915_GET_PHY_PARAM( ); + RU864_GET_PHY_PARAM( ); default: { return phyParam; @@ -571,6 +627,7 @@ void RegionSetBandTxDone( LoRaMacRegion_t region, SetBandTxDoneParams_t* txDone KR920_SET_BAND_TX_DONE( ); IN865_SET_BAND_TX_DONE( ); US915_SET_BAND_TX_DONE( ); + RU864_SET_BAND_TX_DONE( ); default: { return; @@ -591,6 +648,7 @@ void RegionInitDefaults( LoRaMacRegion_t region, InitDefaultsParams_t* params ) KR920_INIT_DEFAULTS( ); IN865_INIT_DEFAULTS( ); US915_INIT_DEFAULTS( ); + RU864_INIT_DEFAULTS( ); default: { break; @@ -611,6 +669,7 @@ void* RegionGetNvmCtx( LoRaMacRegion_t region, GetNvmCtxParams_t* params ) KR920_GET_NVM_CTX( ); IN865_GET_NVM_CTX( ); US915_GET_NVM_CTX( ); + RU864_GET_NVM_CTX( ); default: { return 0; @@ -631,6 +690,7 @@ bool RegionVerify( LoRaMacRegion_t region, VerifyParams_t* verify, PhyAttribute_ KR920_VERIFY( ); IN865_VERIFY( ); US915_VERIFY( ); + RU864_VERIFY( ); default: { return false; @@ -651,6 +711,7 @@ void RegionApplyCFList( LoRaMacRegion_t region, ApplyCFListParams_t* applyCFList KR920_APPLY_CF_LIST( ); IN865_APPLY_CF_LIST( ); US915_APPLY_CF_LIST( ); + RU864_APPLY_CF_LIST( ); default: { break; @@ -671,6 +732,7 @@ bool RegionChanMaskSet( LoRaMacRegion_t region, ChanMaskSetParams_t* chanMaskSet KR920_CHAN_MASK_SET( ); IN865_CHAN_MASK_SET( ); US915_CHAN_MASK_SET( ); + RU864_CHAN_MASK_SET( ); default: { return false; @@ -691,6 +753,7 @@ void RegionComputeRxWindowParameters( LoRaMacRegion_t region, int8_t datarate, u KR920_COMPUTE_RX_WINDOW_PARAMETERS( ); IN865_COMPUTE_RX_WINDOW_PARAMETERS( ); US915_COMPUTE_RX_WINDOW_PARAMETERS( ); + RU864_COMPUTE_RX_WINDOW_PARAMETERS( ); default: { break; @@ -711,6 +774,7 @@ bool RegionRxConfig( LoRaMacRegion_t region, RxConfigParams_t* rxConfig, int8_t* KR920_RX_CONFIG( ); IN865_RX_CONFIG( ); US915_RX_CONFIG( ); + RU864_RX_CONFIG( ); default: { return false; @@ -731,6 +795,7 @@ bool RegionTxConfig( LoRaMacRegion_t region, TxConfigParams_t* txConfig, int8_t* KR920_TX_CONFIG( ); IN865_TX_CONFIG( ); US915_TX_CONFIG( ); + RU864_TX_CONFIG( ); default: { return false; @@ -751,6 +816,7 @@ uint8_t RegionLinkAdrReq( LoRaMacRegion_t region, LinkAdrReqParams_t* linkAdrReq KR920_LINK_ADR_REQ( ); IN865_LINK_ADR_REQ( ); US915_LINK_ADR_REQ( ); + RU864_LINK_ADR_REQ( ); default: { return 0; @@ -771,6 +837,7 @@ uint8_t RegionRxParamSetupReq( LoRaMacRegion_t region, RxParamSetupReqParams_t* KR920_RX_PARAM_SETUP_REQ( ); IN865_RX_PARAM_SETUP_REQ( ); US915_RX_PARAM_SETUP_REQ( ); + RU864_RX_PARAM_SETUP_REQ( ); default: { return 0; @@ -791,6 +858,7 @@ uint8_t RegionNewChannelReq( LoRaMacRegion_t region, NewChannelReqParams_t* newC KR920_NEW_CHANNEL_REQ( ); IN865_NEW_CHANNEL_REQ( ); US915_NEW_CHANNEL_REQ( ); + RU864_NEW_CHANNEL_REQ( ); default: { return 0; @@ -811,6 +879,7 @@ int8_t RegionTxParamSetupReq( LoRaMacRegion_t region, TxParamSetupReqParams_t* t KR920_TX_PARAM_SETUP_REQ( ); IN865_TX_PARAM_SETUP_REQ( ); US915_TX_PARAM_SETUP_REQ( ); + RU864_TX_PARAM_SETUP_REQ( ); default: { return 0; @@ -831,6 +900,7 @@ uint8_t RegionDlChannelReq( LoRaMacRegion_t region, DlChannelReqParams_t* dlChan KR920_DL_CHANNEL_REQ( ); IN865_DL_CHANNEL_REQ( ); US915_DL_CHANNEL_REQ( ); + RU864_DL_CHANNEL_REQ( ); default: { return 0; @@ -851,6 +921,7 @@ int8_t RegionAlternateDr( LoRaMacRegion_t region, int8_t currentDr ) KR920_ALTERNATE_DR( ); IN865_ALTERNATE_DR( ); US915_ALTERNATE_DR( ); + RU864_ALTERNATE_DR( ); default: { return 0; @@ -871,6 +942,7 @@ void RegionCalcBackOff( LoRaMacRegion_t region, CalcBackOffParams_t* calcBackOff KR920_CALC_BACKOFF( ); IN865_CALC_BACKOFF( ); US915_CALC_BACKOFF( ); + RU864_CALC_BACKOFF( ); default: { break; @@ -891,6 +963,7 @@ LoRaMacStatus_t RegionNextChannel( LoRaMacRegion_t region, NextChanParams_t* nex KR920_NEXT_CHANNEL( ); IN865_NEXT_CHANNEL( ); US915_NEXT_CHANNEL( ); + RU864_NEXT_CHANNEL( ); default: { return LORAMAC_STATUS_REGION_NOT_SUPPORTED; @@ -911,6 +984,7 @@ LoRaMacStatus_t RegionChannelAdd( LoRaMacRegion_t region, ChannelAddParams_t* ch KR920_CHANNEL_ADD( ); IN865_CHANNEL_ADD( ); US915_CHANNEL_ADD( ); + RU864_CHANNEL_ADD( ); default: { return LORAMAC_STATUS_PARAMETER_INVALID; @@ -931,6 +1005,7 @@ bool RegionChannelsRemove( LoRaMacRegion_t region, ChannelRemoveParams_t* channe KR920_CHANNEL_REMOVE( ); IN865_CHANNEL_REMOVE( ); US915_CHANNEL_REMOVE( ); + RU864_CHANNEL_REMOVE( ); default: { return false; @@ -951,6 +1026,7 @@ void RegionSetContinuousWave( LoRaMacRegion_t region, ContinuousWaveParams_t* co KR920_SET_CONTINUOUS_WAVE( ); IN865_SET_CONTINUOUS_WAVE( ); US915_SET_CONTINUOUS_WAVE( ); + RU864_SET_CONTINUOUS_WAVE( ); default: { break; @@ -971,6 +1047,7 @@ uint8_t RegionApplyDrOffset( LoRaMacRegion_t region, uint8_t downlinkDwellTime, KR920_APPLY_DR_OFFSET( ); IN865_APPLY_DR_OFFSET( ); US915_APPLY_DR_OFFSET( ); + RU864_APPLY_DR_OFFSET( ); default: { return dr; @@ -991,6 +1068,7 @@ void RegionRxBeaconSetup( LoRaMacRegion_t region, RxBeaconSetup_t* rxBeaconSetup KR920_RX_BEACON_SETUP( ); IN865_RX_BEACON_SETUP( ); US915_RX_BEACON_SETUP( ); + RU864_RX_BEACON_SETUP( ); default: { break; diff --git a/src/mac/region/Region.h b/src/mac/region/Region.h index a2b247169..9b00d6d88 100644 --- a/src/mac/region/Region.h +++ b/src/mac/region/Region.h @@ -45,6 +45,7 @@ * - #define REGION_KR920 * - #define REGION_IN865 * - #define REGION_US915 + * - #define REGION_RU864 * * \{ */ @@ -74,6 +75,7 @@ * IN865 | SF12 - BW125 * KR920 | SF12 - BW125 * US915 | SF10 - BW125 + * RU864 | SF12 - BW125 */ #define DR_0 0 @@ -89,6 +91,7 @@ * IN865 | SF11 - BW125 * KR920 | SF11 - BW125 * US915 | SF9 - BW125 + * RU864 | SF11 - BW125 */ #define DR_1 1 @@ -104,6 +107,7 @@ * IN865 | SF10 - BW125 * KR920 | SF10 - BW125 * US915 | SF8 - BW125 + * RU864 | SF10 - BW125 */ #define DR_2 2 @@ -119,6 +123,7 @@ * IN865 | SF9 - BW125 * KR920 | SF9 - BW125 * US915 | SF7 - BW125 + * RU864 | SF9 - BW125 */ #define DR_3 3 @@ -134,6 +139,7 @@ * IN865 | SF8 - BW125 * KR920 | SF8 - BW125 * US915 | SF8 - BW500 + * RU864 | SF8 - BW125 */ #define DR_4 4 @@ -149,6 +155,7 @@ * IN865 | SF7 - BW125 * KR920 | SF7 - BW125 * US915 | RFU + * RU864 | SF7 - BW125 */ #define DR_5 5 @@ -164,6 +171,7 @@ * IN865 | SF7 - BW250 * KR920 | RFU * US915 | RFU + * RU864 | SF7 - BW250 */ #define DR_6 6 @@ -179,6 +187,7 @@ * IN865 | FSK * KR920 | RFU * US915 | RFU + * RU864 | FSK */ #define DR_7 7 @@ -194,6 +203,7 @@ * IN865 | RFU * KR920 | RFU * US915 | SF12 - BW500 + * RU864 | RFU */ #define DR_8 8 @@ -209,6 +219,7 @@ * IN865 | RFU * KR920 | RFU * US915 | SF11 - BW500 + * RU864 | RFU */ #define DR_9 9 @@ -224,6 +235,7 @@ * IN865 | RFU * KR920 | RFU * US915 | SF10 - BW500 + * RU864 | RFU */ #define DR_10 10 @@ -239,6 +251,7 @@ * IN865 | RFU * KR920 | RFU * US915 | SF9 - BW500 + * RU864 | RFU */ #define DR_11 11 @@ -254,6 +267,7 @@ * IN865 | RFU * KR920 | RFU * US915 | SF8 - BW500 + * RU864 | RFU */ #define DR_12 12 @@ -269,6 +283,7 @@ * IN865 | RFU * KR920 | RFU * US915 | SF7 - BW500 + * RU864 | RFU */ #define DR_13 13 @@ -284,6 +299,7 @@ * IN865 | RFU * KR920 | RFU * US915 | RFU + * RU864 | RFU */ #define DR_14 14 @@ -299,6 +315,7 @@ * IN865 | RFU * KR920 | RFU * US915 | RFU + * RU864 | RFU */ #define DR_15 15 @@ -316,6 +333,7 @@ * IN865 | Max EIRP * KR920 | Max EIRP * US915 | Max ERP + * RU864 | Max EIRP */ #define TX_POWER_0 0 @@ -331,6 +349,7 @@ * IN865 | Max EIRP - 2 * KR920 | Max EIRP - 2 * US915 | Max ERP - 2 + * RU864 | Max EIRP - 2 */ #define TX_POWER_1 1 @@ -346,6 +365,7 @@ * IN865 | Max EIRP - 4 * KR920 | Max EIRP - 4 * US915 | Max ERP - 4 + * RU864 | Max EIRP - 4 */ #define TX_POWER_2 2 @@ -361,6 +381,7 @@ * IN865 | Max EIRP - 6 * KR920 | Max EIRP - 6 * US915 | Max ERP - 6 + * RU864 | Max EIRP - 6 */ #define TX_POWER_3 3 @@ -376,6 +397,7 @@ * IN865 | Max EIRP - 8 * KR920 | Max EIRP - 8 * US915 | Max ERP - 8 + * RU864 | Max EIRP - 8 */ #define TX_POWER_4 4 @@ -391,6 +413,7 @@ * IN865 | Max EIRP - 10 * KR920 | Max EIRP - 10 * US915 | Max ERP - 10 + * RU864 | Max EIRP - 10 */ #define TX_POWER_5 5 @@ -406,6 +429,7 @@ * IN865 | Max EIRP - 12 * KR920 | Max EIRP - 12 * US915 | Max ERP - 12 + * RU864 | Max EIRP - 12 */ #define TX_POWER_6 6 @@ -421,6 +445,7 @@ * IN865 | Max EIRP - 14 * KR920 | Max EIRP - 14 * US915 | Max ERP - 14 + * RU864 | Max EIRP - 14 */ #define TX_POWER_7 7 @@ -436,6 +461,7 @@ * IN865 | Max EIRP - 16 * KR920 | - * US915 | Max ERP - 16 + * RU864 | - */ #define TX_POWER_8 8 @@ -451,6 +477,7 @@ * IN865 | Max EIRP - 18 * KR920 | - * US915 | Max ERP - 16 + * RU864 | - */ #define TX_POWER_9 9 @@ -466,6 +493,7 @@ * IN865 | Max EIRP - 20 * KR920 | - * US915 | Max ERP - 10 + * RU864 | - */ #define TX_POWER_10 10 diff --git a/src/mac/region/RegionRU864.c b/src/mac/region/RegionRU864.c new file mode 100644 index 000000000..36c5732cb --- /dev/null +++ b/src/mac/region/RegionRU864.c @@ -0,0 +1,1031 @@ +/*! + * \file RegionRU864.c + * + * \brief Region implementation for RU864 + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + * + * \author Daniel Jaeckle ( STACKFORCE ) +*/ +#include "utilities.h" + +#include "RegionCommon.h" +#include "RegionRU864.h" + +// Definitions +#define CHANNELS_MASK_SIZE 1 + +/*! + * Region specific context + */ +typedef struct sRegionRU864NvmCtx +{ + /*! + * LoRaMAC channels + */ + ChannelParams_t Channels[ RU864_MAX_NB_CHANNELS ]; + /*! + * LoRaMac bands + */ + Band_t Bands[ RU864_MAX_NB_BANDS ]; + /*! + * LoRaMac channels mask + */ + uint16_t ChannelsMask[ CHANNELS_MASK_SIZE ]; + /*! + * LoRaMac channels default mask + */ + uint16_t ChannelsDefaultMask[ CHANNELS_MASK_SIZE ]; +}RegionRU864NvmCtx_t; + +/* + * Non-volatile module context. + */ +static RegionRU864NvmCtx_t NvmCtx; + +// Static functions +static int8_t GetNextLowerTxDr( int8_t dr, int8_t minDr ) +{ + uint8_t nextLowerDr = 0; + + if( dr == minDr ) + { + nextLowerDr = minDr; + } + else + { + nextLowerDr = dr - 1; + } + return nextLowerDr; +} + +static uint32_t GetBandwidth( uint32_t drIndex ) +{ + switch( BandwidthsRU864[drIndex] ) + { + default: + case 125000: + return 0; + case 250000: + return 1; + case 500000: + return 2; + } +} + +static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t* channelsMask ) +{ + int8_t txPowerResult = txPower; + + // Limit tx power to the band max + txPowerResult = MAX( txPower, maxBandTxPower ); + + return txPowerResult; +} + +static bool VerifyTxFreq( uint32_t freq, uint8_t *band ) +{ + // Check radio driver support + if( Radio.CheckRfFrequency( freq ) == false ) + { + return false; + } + + // Check frequency bands + if( ( freq >= 864000000 ) && ( freq <= 870000000 ) ) + { + *band = 0; + } + else + { + return false; + } + 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 ) +{ + uint8_t nbEnabledChannels = 0; + uint8_t delayTransmission = 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; + } + } + } + + *delayTx = delayTransmission; + return nbEnabledChannels; +} + +PhyParam_t RegionRU864GetPhyParam( GetPhyParams_t* getPhy ) +{ + PhyParam_t phyParam = { 0 }; + + switch( getPhy->Attribute ) + { + case PHY_MIN_RX_DR: + { + phyParam.Value = RU864_RX_MIN_DATARATE; + break; + } + case PHY_MIN_TX_DR: + { + phyParam.Value = RU864_TX_MIN_DATARATE; + break; + } + case PHY_DEF_TX_DR: + { + phyParam.Value = RU864_DEFAULT_DATARATE; + break; + } + case PHY_NEXT_LOWER_TX_DR: + { + phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, RU864_TX_MIN_DATARATE ); + break; + } + case PHY_DEF_TX_POWER: + { + phyParam.Value = RU864_DEFAULT_TX_POWER; + break; + } + case PHY_DEF_ADR_ACK_LIMIT: + { + phyParam.Value = RU864_ADR_ACK_LIMIT; + break; + } + case PHY_DEF_ADR_ACK_DELAY: + { + phyParam.Value = RU864_ADR_ACK_DELAY; + break; + } + case PHY_MAX_PAYLOAD: + { + 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; + break; + } + case PHY_MAX_RX_WINDOW: + { + phyParam.Value = RU864_MAX_RX_WINDOW; + break; + } + case PHY_RECEIVE_DELAY1: + { + phyParam.Value = RU864_RECEIVE_DELAY1; + break; + } + case PHY_RECEIVE_DELAY2: + { + phyParam.Value = RU864_RECEIVE_DELAY2; + break; + } + case PHY_JOIN_ACCEPT_DELAY1: + { + phyParam.Value = RU864_JOIN_ACCEPT_DELAY1; + break; + } + case PHY_JOIN_ACCEPT_DELAY2: + { + phyParam.Value = RU864_JOIN_ACCEPT_DELAY2; + break; + } + case PHY_ACK_TIMEOUT: + { + phyParam.Value = ( RU864_ACKTIMEOUT + randr( -RU864_ACK_TIMEOUT_RND, RU864_ACK_TIMEOUT_RND ) ); + break; + } + case PHY_DEF_DR1_OFFSET: + { + phyParam.Value = RU864_DEFAULT_RX1_DR_OFFSET; + break; + } + case PHY_DEF_RX2_FREQUENCY: + { + phyParam.Value = RU864_RX_WND_2_FREQ; + break; + } + case PHY_DEF_RX2_DR: + { + phyParam.Value = RU864_RX_WND_2_DR; + break; + } + case PHY_CHANNELS_MASK: + { + phyParam.ChannelsMask = NvmCtx.ChannelsMask; + break; + } + case PHY_CHANNELS_DEFAULT_MASK: + { + phyParam.ChannelsMask = NvmCtx.ChannelsDefaultMask; + break; + } + case PHY_MAX_NB_CHANNELS: + { + phyParam.Value = RU864_MAX_NB_CHANNELS; + break; + } + case PHY_CHANNELS: + { + phyParam.Channels = NvmCtx.Channels; + break; + } + case PHY_DEF_UPLINK_DWELL_TIME: + case PHY_DEF_DOWNLINK_DWELL_TIME: + { + phyParam.Value = 0; + break; + } + case PHY_DEF_MAX_EIRP: + { + phyParam.fValue = RU864_DEFAULT_MAX_EIRP; + break; + } + case PHY_DEF_ANTENNA_GAIN: + { + phyParam.fValue = RU864_DEFAULT_ANTENNA_GAIN; + break; + } + case PHY_BEACON_CHANNEL_FREQ: + { + phyParam.Value = RU864_BEACON_CHANNEL_FREQ; + break; + } + case PHY_BEACON_FORMAT: + { + phyParam.BeaconFormat.BeaconSize = RU864_BEACON_SIZE; + phyParam.BeaconFormat.Rfu1Size = RU864_RFU1_SIZE; + phyParam.BeaconFormat.Rfu2Size = RU864_RFU2_SIZE; + break; + } + case PHY_BEACON_CHANNEL_DR: + { + phyParam.Value = RU864_BEACON_CHANNEL_DR; + break; + } + default: + { + break; + } + } + + return phyParam; +} + +void RegionRU864SetBandTxDone( SetBandTxDoneParams_t* txDone ) +{ + RegionCommonSetBandTxDone( txDone->Joined, &NvmCtx.Bands[NvmCtx.Channels[txDone->Channel].Band], txDone->LastTxDoneTime ); +} + +void RegionRU864InitDefaults( InitDefaultsParams_t* params ) +{ + Band_t bands[RU864_MAX_NB_BANDS] = + { + RU864_BAND0 + }; + + switch( params->Type ) + { + case INIT_TYPE_INIT: + { + // Initialize bands + memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * RU864_MAX_NB_BANDS ); + + // Channels + NvmCtx.Channels[0] = ( ChannelParams_t ) RU864_LC1; + NvmCtx.Channels[1] = ( ChannelParams_t ) RU864_LC2; + + // Initialize the channels default mask + NvmCtx.ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 ); + // Update the channels mask + RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 1 ); + break; + } + case INIT_TYPE_RESTORE_CTX: + { + if( params->NvmCtx != 0 ) + { + memcpy1( (uint8_t*) &NvmCtx, (uint8_t*) params->NvmCtx, sizeof( NvmCtx ) ); + } + break; + } + case INIT_TYPE_RESTORE_DEFAULT_CHANNELS: + { + // Restore channels default mask + NvmCtx.ChannelsMask[0] |= NvmCtx.ChannelsDefaultMask[0]; + break; + } + case INIT_TYPE_APP_DEFAULTS: + { + // Update the channels mask defaults + RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 1 ); + break; + } + default: + { + break; + } + } +} + +void* RegionRU864GetNvmCtx( GetNvmCtxParams_t* params ) +{ + params->nvmCtxSize = sizeof( RegionRU864NvmCtx_t ); + return &NvmCtx; +} + +bool RegionRU864Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute ) +{ + switch( phyAttribute ) + { + case PHY_TX_DR: + { + return RegionCommonValueInRange( verify->DatarateParams.Datarate, RU864_TX_MIN_DATARATE, RU864_TX_MAX_DATARATE ); + } + case PHY_DEF_TX_DR: + { + return RegionCommonValueInRange( verify->DatarateParams.Datarate, DR_0, DR_5 ); + } + case PHY_RX_DR: + { + return RegionCommonValueInRange( verify->DatarateParams.Datarate, RU864_RX_MIN_DATARATE, RU864_RX_MAX_DATARATE ); + } + case PHY_DEF_TX_POWER: + case PHY_TX_POWER: + { + // Remark: switched min and max! + return RegionCommonValueInRange( verify->TxPower, RU864_MAX_TX_POWER, RU864_MIN_TX_POWER ); + } + case PHY_DUTY_CYCLE: + { + return RU864_DUTY_CYCLE_ENABLED; + } + default: + return false; + } +} + +void RegionRU864ApplyCFList( ApplyCFListParams_t* applyCFList ) +{ + ChannelParams_t newChannel; + ChannelAddParams_t channelAdd; + ChannelRemoveParams_t channelRemove; + + // Setup default datarate range + newChannel.DrRange.Value = ( DR_5 << 4 ) | DR_0; + + // Size of the optional CF list + if( applyCFList->Size != 16 ) + { + return; + } + + // Last byte CFListType must be 0 to indicate the CFList contains a list of frequencies + if( applyCFList->Payload[15] != 0 ) + { + return; + } + + // Last byte is RFU, don't take it into account + for( uint8_t i = 0, chanIdx = RU864_NUMB_DEFAULT_CHANNELS; chanIdx < RU864_MAX_NB_CHANNELS; i+=3, chanIdx++ ) + { + if( chanIdx < ( RU864_NUMB_CHANNELS_CF_LIST + RU864_NUMB_DEFAULT_CHANNELS ) ) + { + // Channel frequency + newChannel.Frequency = (uint32_t) applyCFList->Payload[i]; + newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 1] << 8 ); + newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 2] << 16 ); + newChannel.Frequency *= 100; + + // Initialize alternative frequency to 0 + newChannel.Rx1Frequency = 0; + } + else + { + newChannel.Frequency = 0; + newChannel.DrRange.Value = 0; + newChannel.Rx1Frequency = 0; + } + + if( newChannel.Frequency != 0 ) + { + channelAdd.NewChannel = &newChannel; + channelAdd.ChannelId = chanIdx; + + // Try to add all channels + RegionRU864ChannelAdd( &channelAdd ); + } + else + { + channelRemove.ChannelId = chanIdx; + + RegionRU864ChannelsRemove( &channelRemove ); + } + } +} + +bool RegionRU864ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ) +{ + switch( chanMaskSet->ChannelsMaskType ) + { + case CHANNELS_MASK: + { + RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, chanMaskSet->ChannelsMaskIn, 1 ); + break; + } + case CHANNELS_DEFAULT_MASK: + { + RegionCommonChanMaskCopy( NvmCtx.ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1 ); + break; + } + default: + return false; + } + return true; +} + +void RegionRU864ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams ) +{ + double tSymbol = 0.0; + + // Get the datarate, perform a boundary check + rxConfigParams->Datarate = MIN( datarate, RU864_RX_MAX_DATARATE ); + rxConfigParams->Bandwidth = GetBandwidth( rxConfigParams->Datarate ); + + if( rxConfigParams->Datarate == DR_7 ) + { // FSK + tSymbol = RegionCommonComputeSymbolTimeFsk( DataratesRU864[rxConfigParams->Datarate] ); + } + else + { // LoRa + tSymbol = RegionCommonComputeSymbolTimeLoRa( DataratesRU864[rxConfigParams->Datarate], BandwidthsRU864[rxConfigParams->Datarate] ); + } + + RegionCommonComputeRxWindowParameters( tSymbol, minRxSymbols, rxError, Radio.GetWakeupTime( ), &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset ); +} + +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; + + if( Radio.GetStatus( ) != RF_IDLE ) + { + return false; + } + + if( rxConfig->RxSlot == RX_SLOT_WIN_1 ) + { + // Apply window 1 frequency + frequency = NvmCtx.Channels[rxConfig->Channel].Frequency; + // Apply the alternative RX 1 window frequency, if it is available + if( NvmCtx.Channels[rxConfig->Channel].Rx1Frequency != 0 ) + { + frequency = NvmCtx.Channels[rxConfig->Channel].Rx1Frequency; + } + } + + // Read the physical datarate from the datarates table + phyDr = DataratesRU864[dr]; + + Radio.SetChannel( frequency ); + + // Radio configuration + if( dr == DR_7 ) + { + modem = MODEM_FSK; + Radio.SetRxConfig( modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous ); + } + else + { + modem = MODEM_LORA; + 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 ); + + *datarate = (uint8_t) dr; + return true; +} + +bool RegionRU864TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir ) +{ + RadioModems_t modem; + int8_t phyDr = DataratesRU864[txConfig->Datarate]; + int8_t txPowerLimited = LimitTxPower( txConfig->TxPower, NvmCtx.Bands[NvmCtx.Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, NvmCtx.ChannelsMask ); + uint32_t bandwidth = GetBandwidth( txConfig->Datarate ); + int8_t phyTxPower = 0; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain ); + + // Setup the radio frequency + Radio.SetChannel( NvmCtx.Channels[txConfig->Channel].Frequency ); + + 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 ); + } + else + { + modem = MODEM_LORA; + Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 ); + } + + // 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; +} + +uint8_t RegionRU864LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed ) +{ + uint8_t status = 0x07; + RegionCommonLinkAdrParams_t linkAdrParams; + uint8_t nextIndex = 0; + uint8_t bytesProcessed = 0; + uint16_t chMask = 0; + GetPhyParams_t getPhy; + PhyParam_t phyParam; + RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams; + + while( bytesProcessed < linkAdrReq->PayloadSize ) + { + // Get ADR request parameters + nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams ); + + if( nextIndex == 0 ) + break; // break loop, since no more request has been found + + // Update bytes processed + bytesProcessed += nextIndex; + + // Revert status, as we only check the last ADR request for the channel mask KO + status = 0x07; + + // Setup temporary channels mask + chMask = linkAdrParams.ChMask; + + // Verify channels mask + if( ( linkAdrParams.ChMaskCtrl == 0 ) && ( chMask == 0 ) ) + { + status &= 0xFE; // Channel mask KO + } + else if( ( ( linkAdrParams.ChMaskCtrl >= 1 ) && ( linkAdrParams.ChMaskCtrl <= 5 )) || + ( linkAdrParams.ChMaskCtrl >= 7 ) ) + { + // RFU + status &= 0xFE; // Channel mask KO + } + else + { + for( uint8_t i = 0; i < RU864_MAX_NB_CHANNELS; i++ ) + { + if( linkAdrParams.ChMaskCtrl == 6 ) + { + if( NvmCtx.Channels[i].Frequency != 0 ) + { + chMask |= 1 << i; + } + } + else + { + if( ( ( chMask & ( 1 << i ) ) != 0 ) && + ( NvmCtx.Channels[i].Frequency == 0 ) ) + {// Trying to enable an undefined channel + status &= 0xFE; // Channel mask KO + } + } + } + } + } + + // Get the minimum possible datarate + getPhy.Attribute = PHY_MIN_TX_DR; + getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime; + phyParam = RegionRU864GetPhyParam( &getPhy ); + + linkAdrVerifyParams.Status = status; + linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled; + linkAdrVerifyParams.Datarate = linkAdrParams.Datarate; + linkAdrVerifyParams.TxPower = linkAdrParams.TxPower; + linkAdrVerifyParams.NbRep = linkAdrParams.NbRep; + linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate; + linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower; + linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep; + linkAdrVerifyParams.NbChannels = RU864_MAX_NB_CHANNELS; + linkAdrVerifyParams.ChannelsMask = &chMask; + linkAdrVerifyParams.MinDatarate = ( int8_t )phyParam.Value; + linkAdrVerifyParams.MaxDatarate = RU864_TX_MAX_DATARATE; + linkAdrVerifyParams.Channels = NvmCtx.Channels; + linkAdrVerifyParams.MinTxPower = RU864_MIN_TX_POWER; + linkAdrVerifyParams.MaxTxPower = RU864_MAX_TX_POWER; + linkAdrVerifyParams.Version = linkAdrReq->Version; + + // Verify the parameters and update, if necessary + status = RegionCommonLinkAdrReqVerifyParams( &linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep ); + + // Update channelsMask if everything is correct + if( status == 0x07 ) + { + // Set the channels mask to a default value + memset1( ( uint8_t* ) NvmCtx.ChannelsMask, 0, sizeof( NvmCtx.ChannelsMask ) ); + // Update the channels mask + NvmCtx.ChannelsMask[0] = chMask; + } + + // Update status variables + *drOut = linkAdrParams.Datarate; + *txPowOut = linkAdrParams.TxPower; + *nbRepOut = linkAdrParams.NbRep; + *nbBytesParsed = bytesProcessed; + + return status; +} + +uint8_t RegionRU864RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq ) +{ + uint8_t status = 0x07; + + // Verify radio frequency + if( Radio.CheckRfFrequency( rxParamSetupReq->Frequency ) == false ) + { + status &= 0xFE; // Channel frequency KO + } + + // Verify datarate + if( RegionCommonValueInRange( rxParamSetupReq->Datarate, RU864_RX_MIN_DATARATE, RU864_RX_MAX_DATARATE ) == false ) + { + status &= 0xFD; // Datarate KO + } + + // Verify datarate offset + if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, RU864_MIN_RX1_DR_OFFSET, RU864_MAX_RX1_DR_OFFSET ) == false ) + { + status &= 0xFB; // Rx1DrOffset range KO + } + + return status; +} + +uint8_t RegionRU864NewChannelReq( NewChannelReqParams_t* newChannelReq ) +{ + uint8_t status = 0x03; + ChannelAddParams_t channelAdd; + ChannelRemoveParams_t channelRemove; + + if( newChannelReq->NewChannel->Frequency == 0 ) + { + channelRemove.ChannelId = newChannelReq->ChannelId; + + // Remove + if( RegionRU864ChannelsRemove( &channelRemove ) == false ) + { + status &= 0xFC; + } + } + else + { + channelAdd.NewChannel = newChannelReq->NewChannel; + channelAdd.ChannelId = newChannelReq->ChannelId; + + switch( RegionRU864ChannelAdd( &channelAdd ) ) + { + case LORAMAC_STATUS_OK: + { + break; + } + case LORAMAC_STATUS_FREQUENCY_INVALID: + { + status &= 0xFE; + break; + } + case LORAMAC_STATUS_DATARATE_INVALID: + { + status &= 0xFD; + break; + } + case LORAMAC_STATUS_FREQ_AND_DR_INVALID: + { + status &= 0xFC; + break; + } + default: + { + status &= 0xFC; + break; + } + } + } + + return status; +} + +int8_t RegionRU864TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq ) +{ + return -1; +} + +uint8_t RegionRU864DlChannelReq( DlChannelReqParams_t* dlChannelReq ) +{ + uint8_t status = 0x03; + uint8_t band = 0; + + // Verify if the frequency is supported + if( VerifyTxFreq( dlChannelReq->Rx1Frequency, &band ) == false ) + { + status &= 0xFE; + } + + // Verify if an uplink frequency exists + if( NvmCtx.Channels[dlChannelReq->ChannelId].Frequency == 0 ) + { + status &= 0xFD; + } + + // Apply Rx1 frequency, if the status is OK + if( status == 0x03 ) + { + NvmCtx.Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency; + } + + return status; +} + +int8_t RegionRU864AlternateDr( int8_t currentDr ) +{ + 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 enabledChannels[RU864_MAX_NB_CHANNELS] = { 0 }; + TimerTime_t nextTxDelay = 0; + + 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; + + // Update bands Time OFF + nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, NvmCtx.Bands, 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 ); + } + + if( nbEnabledChannels > 0 ) + { + // 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, restore defaults + NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 ); + *time = 0; + return LORAMAC_STATUS_NO_CHANNEL_FOUND; + } +} + +LoRaMacStatus_t RegionRU864ChannelAdd( ChannelAddParams_t* channelAdd ) +{ + uint8_t band = 0; + bool drInvalid = false; + bool freqInvalid = false; + uint8_t id = channelAdd->ChannelId; + + if( id >= RU864_MAX_NB_CHANNELS ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + // Validate the datarate range + if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Min, RU864_TX_MIN_DATARATE, RU864_TX_MAX_DATARATE ) == false ) + { + drInvalid = true; + } + if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Max, RU864_TX_MIN_DATARATE, RU864_TX_MAX_DATARATE ) == false ) + { + drInvalid = true; + } + if( channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max ) + { + drInvalid = true; + } + + // Default channels don't accept all values + if( id < RU864_NUMB_DEFAULT_CHANNELS ) + { + // Validate the datarate range for min: must be DR_0 + if( channelAdd->NewChannel->DrRange.Fields.Min > DR_0 ) + { + drInvalid = true; + } + // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE + if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Max, DR_5, RU864_TX_MAX_DATARATE ) == false ) + { + drInvalid = true; + } + // We are not allowed to change the frequency + if( channelAdd->NewChannel->Frequency != NvmCtx.Channels[id].Frequency ) + { + freqInvalid = true; + } + } + + // Check frequency + if( freqInvalid == false ) + { + if( VerifyTxFreq( channelAdd->NewChannel->Frequency, &band ) == false ) + { + freqInvalid = true; + } + } + + // Check status + if( ( drInvalid == true ) && ( freqInvalid == true ) ) + { + return LORAMAC_STATUS_FREQ_AND_DR_INVALID; + } + if( drInvalid == true ) + { + return LORAMAC_STATUS_DATARATE_INVALID; + } + if( freqInvalid == true ) + { + return LORAMAC_STATUS_FREQUENCY_INVALID; + } + + memcpy1( ( uint8_t* ) &(NvmCtx.Channels[id]), ( uint8_t* ) channelAdd->NewChannel, sizeof( NvmCtx.Channels[id] ) ); + NvmCtx.Channels[id].Band = band; + NvmCtx.ChannelsMask[0] |= ( 1 << id ); + return LORAMAC_STATUS_OK; +} + +bool RegionRU864ChannelsRemove( ChannelRemoveParams_t* channelRemove ) +{ + uint8_t id = channelRemove->ChannelId; + + if( id < RU864_NUMB_DEFAULT_CHANNELS ) + { + return false; + } + + // Remove the channel from the list of channels + NvmCtx.Channels[id] = ( ChannelParams_t ){ 0, 0, { 0 }, 0 }; + + return RegionCommonChanDisable( NvmCtx.ChannelsMask, id, RU864_MAX_NB_CHANNELS ); +} + +void RegionRU864SetContinuousWave( ContinuousWaveParams_t* continuousWave ) +{ + int8_t txPowerLimited = LimitTxPower( continuousWave->TxPower, NvmCtx.Bands[NvmCtx.Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, NvmCtx.ChannelsMask ); + int8_t phyTxPower = 0; + uint32_t frequency = NvmCtx.Channels[continuousWave->Channel].Frequency; + + // Calculate physical TX power + phyTxPower = RegionCommonComputeTxPower( txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain ); + + Radio.SetTxContinuousWave( frequency, phyTxPower, continuousWave->Timeout ); +} + +uint8_t RegionRU864ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset ) +{ + int8_t datarate = dr - drOffset; + + if( datarate < 0 ) + { + datarate = DR_0; + } + return datarate; +} + +void RegionRU864RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr ) +{ + RegionCommonRxBeaconSetupParams_t regionCommonRxBeaconSetup; + + regionCommonRxBeaconSetup.Datarates = DataratesRU864; + regionCommonRxBeaconSetup.Frequency = rxBeaconSetup->Frequency; + regionCommonRxBeaconSetup.BeaconSize = RU864_BEACON_SIZE; + regionCommonRxBeaconSetup.BeaconDatarate = RU864_BEACON_CHANNEL_DR; + regionCommonRxBeaconSetup.BeaconChannelBW = RU864_BEACON_CHANNEL_BW; + regionCommonRxBeaconSetup.RxTime = rxBeaconSetup->RxTime; + regionCommonRxBeaconSetup.SymbolTimeout = rxBeaconSetup->SymbolTimeout; + + RegionCommonRxBeaconSetup( ®ionCommonRxBeaconSetup ); + + // Store downlink datarate + *outDr = RU864_BEACON_CHANNEL_DR; +} diff --git a/src/mac/region/RegionRU864.h b/src/mac/region/RegionRU864.h new file mode 100644 index 000000000..e7dbe6e26 --- /dev/null +++ b/src/mac/region/RegionRU864.h @@ -0,0 +1,494 @@ +/*! + * \file RegionRU864.h + * + * \brief Region definition for RU864 + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + * + * \author Daniel Jaeckle ( STACKFORCE ) + * + * \defgroup REGIONRU864 Region RU864 + * Implementation according to LoRaWAN Specification v1.0.2. + * \{ + */ +#ifndef __REGION_RU864_H__ +#define __REGION_RU864_H__ + +#include "LoRaMac.h" + +/*! + * LoRaMac maximum number of channels + */ +#define RU864_MAX_NB_CHANNELS 8 + +/*! + * Number of default channels + */ +#define RU864_NUMB_DEFAULT_CHANNELS 2 + +/*! + * Number of channels to apply for the CF list + */ +#define RU864_NUMB_CHANNELS_CF_LIST 5 + +/*! + * Minimal datarate that can be used by the node + */ +#define RU864_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define RU864_TX_MAX_DATARATE DR_7 + +/*! + * Minimal datarate that can be used by the node + */ +#define RU864_RX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define RU864_RX_MAX_DATARATE DR_7 + +/*! + * Default datarate used by the node + */ +#define RU864_DEFAULT_DATARATE DR_0 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define RU864_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define RU864_MAX_RX1_DR_OFFSET 5 + +/*! + * Default Rx1 receive datarate offset + */ +#define RU864_DEFAULT_RX1_DR_OFFSET 0 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define RU864_MIN_TX_POWER TX_POWER_7 + +/*! + * Maximal Tx output power that can be used by the node + */ +#define RU864_MAX_TX_POWER TX_POWER_0 + +/*! + * Default Tx output power used by the node + */ +#define RU864_DEFAULT_TX_POWER TX_POWER_0 + +/*! + * Default Max EIRP + */ +#define RU864_DEFAULT_MAX_EIRP 16.0f + +/*! + * Default antenna gain + */ +#define RU864_DEFAULT_ANTENNA_GAIN 2.15f + +/*! + * ADR Ack limit + */ +#define RU864_ADR_ACK_LIMIT 64 + +/*! + * ADR Ack delay + */ +#define RU864_ADR_ACK_DELAY 32 + +/*! + * Enabled or disabled the duty cycle + */ +#define RU864_DUTY_CYCLE_ENABLED 1 + +/*! + * Maximum RX window duration + */ +#define RU864_MAX_RX_WINDOW 3000 //TODO + +/*! + * Receive delay 1 + */ +#define RU864_RECEIVE_DELAY1 1000 + +/*! + * Receive delay 2 + */ +#define RU864_RECEIVE_DELAY2 2000 + +/*! + * Join accept delay 1 + */ +#define RU864_JOIN_ACCEPT_DELAY1 5000 + +/*! + * Join accept delay 2 + */ +#define RU864_JOIN_ACCEPT_DELAY2 6000 + +/*! + * Maximum frame counter gap + */ +#define RU864_MAX_FCNT_GAP 16384 + +/*! + * Ack timeout + */ +#define RU864_ACKTIMEOUT 2000 + +/*! + * Random ack timeout limits + */ +#define RU864_ACK_TIMEOUT_RND 1000 + +#if ( RU864_DEFAULT_DATARATE > DR_5 ) +#error "A default DR higher than DR_5 may lead to connectivity loss." +#endif + +/*! + * Second reception window channel frequency definition. + */ +#define RU864_RX_WND_2_FREQ 869100000 + +/*! + * Second reception window channel datarate definition. + */ +#define RU864_RX_WND_2_DR DR_0 + +/* + * CLASS B + */ +/*! + * Beacon frequency + */ +#define RU864_BEACON_CHANNEL_FREQ 869100000 + +/*! + * Payload size of a beacon frame + */ +#define RU864_BEACON_SIZE 17 + +/*! + * Size of RFU 1 field + */ +#define RU864_RFU1_SIZE 2 + +/*! + * Size of RFU 2 field + */ +#define RU864_RFU2_SIZE 0 + +/*! + * Datarate of the beacon channel + */ +#define RU864_BEACON_CHANNEL_DR DR_3 + +/*! + * Bandwith of the beacon channel (Index of BandwidthsRU864[]) + */ +#define RU864_BEACON_CHANNEL_BW 0 + +/*! + * Maximum number of bands + */ +#define RU864_MAX_NB_BANDS 1 + +/*! + * Band 0 definition + * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff } + */ +#define RU864_BAND0 { 100 , RU864_MAX_TX_POWER, 0, 0, 0 } // 1.0 % + +/*! + * LoRaMac default channel 1 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +#define RU864_LC1 { 868900000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } + +/*! + * LoRaMac default channel 2 + * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } + */ +#define RU864_LC2 { 869100000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } + + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define RU864_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) ) + +/*! + * Data rates table definition + */ +static const uint8_t DataratesRU864[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; + +/*! + * Bandwidths table definition in Hz + */ +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. + */ +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. + * + * \param [IN] getPhy Pointer to the function parameters. + * + * \retval Returns a structure containing the PHY parameter. + */ +PhyParam_t RegionRU864GetPhyParam( GetPhyParams_t* getPhy ); + +/*! + * \brief Updates the last TX done parameters of the current channel. + * + * \param [IN] txDone Pointer to the function parameters. + */ +void RegionRU864SetBandTxDone( SetBandTxDoneParams_t* txDone ); + +/*! + * \brief Initializes the channels masks and the channels. + * + * \param [IN] type Sets the initialization type. + */ +void RegionRU864InitDefaults( InitDefaultsParams_t* params ); + +/*! + * \brief Returns a pointer to the internal context and its size. + * + * \param [OUT] params Pointer to the function parameters. + * + * \retval Points to a structure where the module store its non-volatile context. + */ +void* RegionRU864GetNvmCtx( GetNvmCtxParams_t* params ); + +/*! + * \brief Verifies a parameter. + * + * \param [IN] verify Pointer to the function parameters. + * + * \param [IN] type Sets the initialization type. + * + * \retval Returns true, if the parameter is valid. + */ +bool RegionRU864Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute ); + +/*! + * \brief The function parses the input buffer and sets up the channels of the + * CF list. + * + * \param [IN] applyCFList Pointer to the function parameters. + */ +void RegionRU864ApplyCFList( ApplyCFListParams_t* applyCFList ); + +/*! + * \brief Sets a channels mask. + * + * \param [IN] chanMaskSet Pointer to the function parameters. + * + * \retval Returns true, if the channels mask could be set. + */ +bool RegionRU864ChanMaskSet( ChanMaskSetParams_t* chanMaskSet ); + +/*! + * Computes the Rx window timeout and offset. + * + * \param [IN] datarate Rx window datarate index to be used + * + * \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame. + * + * \param [IN] rxError System maximum timing error of the receiver. In milliseconds + * The receiver will turn on in a [-rxError : +rxError] ms + * interval around RxOffset + * + * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields. + */ +void RegionRU864ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams ); + +/*! + * \brief Configuration of the RX windows. + * + * \param [IN] rxConfig Pointer to the function parameters. + * + * \param [OUT] datarate The datarate index which was set. + * + * \retval Returns true, if the configuration was applied successfully. + */ +bool RegionRU864RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate ); + +/*! + * \brief TX configuration. + * + * \param [IN] txConfig Pointer to the function parameters. + * + * \param [OUT] txPower The tx power index which was set. + * + * \param [OUT] txTimeOnAir The time-on-air of the frame. + * + * \retval Returns true, if the configuration was applied successfully. + */ +bool RegionRU864TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir ); + +/*! + * \brief The function processes a Link ADR Request. + * + * \param [IN] linkAdrReq Pointer to the function parameters. + * + * \retval Returns the status of the operation, according to the LoRaMAC specification. + */ +uint8_t RegionRU864LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed ); + +/*! + * \brief The function processes a RX Parameter Setup Request. + * + * \param [IN] rxParamSetupReq Pointer to the function parameters. + * + * \retval Returns the status of the operation, according to the LoRaMAC specification. + */ +uint8_t RegionRU864RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq ); + +/*! + * \brief The function processes a Channel Request. + * + * \param [IN] newChannelReq Pointer to the function parameters. + * + * \retval Returns the status of the operation, according to the LoRaMAC specification. + */ +uint8_t RegionRU864NewChannelReq( NewChannelReqParams_t* newChannelReq ); + +/*! + * \brief The function processes a TX ParamSetup Request. + * + * \param [IN] txParamSetupReq Pointer to the function parameters. + * + * \retval Returns the status of the operation, according to the LoRaMAC specification. + * Returns -1, if the functionality is not implemented. In this case, the end node + * shall not process the command. + */ +int8_t RegionRU864TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq ); + +/*! + * \brief The function processes a DlChannel Request. + * + * \param [IN] dlChannelReq Pointer to the function parameters. + * + * \retval Returns the status of the operation, according to the LoRaMAC specification. + */ +uint8_t RegionRU864DlChannelReq( DlChannelReqParams_t* dlChannelReq ); + +/*! + * \brief Alternates the datarate of the channel for the join request. + * + * \param [IN] currentDr Current datarate. + * + * \retval Datarate to apply. + */ +int8_t RegionRU864AlternateDr( int8_t currentDr ); + +/*! + * \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 + * + * \param [OUT] channel Next channel to use for TX. + * + * \param [OUT] time Time to wait for the next transmission according to the duty + * cycle. + * + * \param [OUT] aggregatedTimeOff Updates the aggregated time off. + * + * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate] + */ +LoRaMacStatus_t RegionRU864NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff ); + +/*! + * \brief Adds a channel. + * + * \param [IN] channelAdd Pointer to the function parameters. + * + * \retval Status of the operation. + */ +LoRaMacStatus_t RegionRU864ChannelAdd( ChannelAddParams_t* channelAdd ); + +/*! + * \brief Removes a channel. + * + * \param [IN] channelRemove Pointer to the function parameters. + * + * \retval Returns true, if the channel was removed successfully. + */ +bool RegionRU864ChannelsRemove( ChannelRemoveParams_t* channelRemove ); + +/*! + * \brief Sets the radio into continuous wave mode. + * + * \param [IN] continuousWave Pointer to the function parameters. + */ +void RegionRU864SetContinuousWave( ContinuousWaveParams_t* continuousWave ); + +/*! + * \brief Computes new datarate according to the given offset + * + * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms + * + * \param [IN] dr Current datarate + * + * \param [IN] drOffset Offset to be applied + * + * \retval newDr Computed datarate. + */ +uint8_t RegionRU864ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset ); + +/*! + * \brief Sets the radio into beacon reception mode + * + * \param [IN] rxBeaconSetup Pointer to the function parameters + */ +void RegionRU864RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr ); + +/*! \} defgroup REGIONRU864 */ + +#endif // __REGION_RU864_H__