1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/pkg/semtech-loramac/patches/0003-add-ru864-region.patch
2018-09-26 16:31:29 +03:00

1998 lines
62 KiB
Diff

From b8dc64684fb4e39d29cbfcb9a23b6e7807d251a0 Mon Sep 17 00:00:00 2001
From: Oleg Artamonov <oleg@unwds.com>
Date: Mon, 6 Aug 2018 21:43:54 +0300
Subject: [PATCH 2/2] Add RU864 LoRaWAN region
---
src/mac/LoRaMac.h | 4 +
src/mac/region/Region.c | 75 +++
src/mac/region/Region.h | 28 +
src/mac/region/RegionRU864.c | 1018 ++++++++++++++++++++++++++++++++++
src/mac/region/RegionRU864.h | 459 +++++++++++++++
5 files changed, 1584 insertions(+)
create mode 100644 src/mac/region/RegionRU864.c
create mode 100644 src/mac/region/RegionRU864.h
diff --git a/src/mac/LoRaMac.h b/src/mac/LoRaMac.h
index 8df8f9e..0067419 100644
--- a/src/mac/LoRaMac.h
+++ b/src/mac/LoRaMac.h
@@ -1739,6 +1739,10 @@ typedef enum eLoRaMacRegion_t
* North american band on 915MHz
*/
LORAMAC_REGION_US915,
+ /*!
+ * Russian band on 864MHz
+ */
+ LORAMAC_REGION_RU864,
/*!
* North american band on 915MHz with a maximum of 16 channels
*/
diff --git a/src/mac/region/Region.c b/src/mac/region/Region.c
index ae3ff77..7463051 100644
--- a/src/mac/region/Region.c
+++ b/src/mac/region/Region.c
@@ -551,6 +551,58 @@
#define US915_HYBRID_APPLY_DR_OFFSET( )
#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( type ); break; }
+#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_ADR_NEXT( ) RU864_CASE { return RegionRU864AdrNext( adrNext, drOut, txPowOut, adrAckCounter ); }
+#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 ); }
+#else
+#define RU864_IS_ACTIVE( )
+#define RU864_GET_PHY_PARAM( )
+#define RU864_SET_BAND_TX_DONE( )
+#define RU864_INIT_DEFAULTS( )
+#define RU864_VERIFY( )
+#define RU864_APPLY_CF_LIST( )
+#define RU864_CHAN_MASK_SET( )
+#define RU864_ADR_NEXT( )
+#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( )
+#endif
+
bool RegionIsActive( LoRaMacRegion_t region )
{
switch( region )
@@ -564,6 +616,7 @@ bool RegionIsActive( LoRaMacRegion_t region )
KR920_IS_ACTIVE( );
IN865_IS_ACTIVE( );
US915_IS_ACTIVE( );
+ RU864_IS_ACTIVE( );
US915_HYBRID_IS_ACTIVE( );
default:
{
@@ -586,6 +639,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( );
US915_HYBRID_GET_PHY_PARAM( );
default:
{
@@ -607,6 +661,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( );
US915_HYBRID_SET_BAND_TX_DONE( );
default:
{
@@ -628,6 +683,7 @@ void RegionInitDefaults( LoRaMacRegion_t region, InitType_t type )
KR920_INIT_DEFAULTS( );
IN865_INIT_DEFAULTS( );
US915_INIT_DEFAULTS( );
+ RU864_INIT_DEFAULTS( );
US915_HYBRID_INIT_DEFAULTS( );
default:
{
@@ -649,6 +705,7 @@ bool RegionVerify( LoRaMacRegion_t region, VerifyParams_t* verify, PhyAttribute_
KR920_VERIFY( );
IN865_VERIFY( );
US915_VERIFY( );
+ RU864_VERIFY( );
US915_HYBRID_VERIFY( );
default:
{
@@ -670,6 +727,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( );
US915_HYBRID_APPLY_CF_LIST( );
default:
{
@@ -691,6 +749,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( );
US915_HYBRID_CHAN_MASK_SET( );
default:
{
@@ -712,6 +771,7 @@ bool RegionAdrNext( LoRaMacRegion_t region, AdrNextParams_t* adrNext, int8_t* dr
KR920_ADR_NEXT( );
IN865_ADR_NEXT( );
US915_ADR_NEXT( );
+ RU864_ADR_NEXT( );
US915_HYBRID_ADR_NEXT( );
default:
{
@@ -733,6 +793,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( );
US915_HYBRID_COMPUTE_RX_WINDOW_PARAMETERS( );
default:
{
@@ -754,6 +815,7 @@ bool RegionRxConfig( LoRaMacRegion_t region, RxConfigParams_t* rxConfig, int8_t*
KR920_RX_CONFIG( );
IN865_RX_CONFIG( );
US915_RX_CONFIG( );
+ RU864_RX_CONFIG( );
US915_HYBRID_RX_CONFIG( );
default:
{
@@ -775,6 +837,7 @@ bool RegionTxConfig( LoRaMacRegion_t region, TxConfigParams_t* txConfig, int8_t*
KR920_TX_CONFIG( );
IN865_TX_CONFIG( );
US915_TX_CONFIG( );
+ RU864_TX_CONFIG( );
US915_HYBRID_TX_CONFIG( );
default:
{
@@ -796,6 +859,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( );
US915_HYBRID_LINK_ADR_REQ( );
default:
{
@@ -817,6 +881,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( );
US915_HYBRID_RX_PARAM_SETUP_REQ( );
default:
{
@@ -838,6 +903,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( );
US915_HYBRID_NEW_CHANNEL_REQ( );
default:
{
@@ -859,6 +925,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( );
US915_HYBRID_TX_PARAM_SETUP_REQ( );
default:
{
@@ -880,6 +947,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( );
US915_HYBRID_DL_CHANNEL_REQ( );
default:
{
@@ -901,6 +969,7 @@ int8_t RegionAlternateDr( LoRaMacRegion_t region, int8_t currentDr )
KR920_ALTERNATE_DR( );
IN865_ALTERNATE_DR( );
US915_ALTERNATE_DR( );
+ RU864_ALTERNATE_DR( );
US915_HYBRID_ALTERNATE_DR( );
default:
{
@@ -922,6 +991,7 @@ void RegionCalcBackOff( LoRaMacRegion_t region, CalcBackOffParams_t* calcBackOff
KR920_CALC_BACKOFF( );
IN865_CALC_BACKOFF( );
US915_CALC_BACKOFF( );
+ RU864_CALC_BACKOFF( );
US915_HYBRID_CALC_BACKOFF( );
default:
{
@@ -943,6 +1013,7 @@ LoRaMacStatus_t RegionNextChannel( LoRaMacRegion_t region, NextChanParams_t* nex
KR920_NEXT_CHANNEL( );
IN865_NEXT_CHANNEL( );
US915_NEXT_CHANNEL( );
+ RU864_NEXT_CHANNEL( );
US915_HYBRID_NEXT_CHANNEL( );
default:
{
@@ -964,6 +1035,7 @@ LoRaMacStatus_t RegionChannelAdd( LoRaMacRegion_t region, ChannelAddParams_t* ch
KR920_CHANNEL_ADD( );
IN865_CHANNEL_ADD( );
US915_CHANNEL_ADD( );
+ RU864_CHANNEL_ADD( );
US915_HYBRID_CHANNEL_ADD( );
default:
{
@@ -985,6 +1057,7 @@ bool RegionChannelsRemove( LoRaMacRegion_t region, ChannelRemoveParams_t* channe
KR920_CHANNEL_REMOVE( );
IN865_CHANNEL_REMOVE( );
US915_CHANNEL_REMOVE( );
+ RU864_CHANNEL_REMOVE( );
US915_HYBRID_CHANNEL_REMOVE( );
default:
{
@@ -1006,6 +1079,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( );
US915_HYBRID_SET_CONTINUOUS_WAVE( );
default:
{
@@ -1027,6 +1101,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( );
US915_HYBRID_APPLY_DR_OFFSET( );
default:
{
diff --git a/src/mac/region/Region.h b/src/mac/region/Region.h
index a1a14c3..71f7580 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
* - #define REGION_US915_HYBRID
*
* \{
@@ -73,6 +74,7 @@
* IN865 | SF12 - BW125
* KR920 | SF12 - BW125
* US915 | SF10 - BW125
+ * RU864 | SF12 - BW125
* US915_HYBRID | SF10 - BW125
*/
#define DR_0 0
@@ -89,6 +91,7 @@
* IN865 | SF11 - BW125
* KR920 | SF11 - BW125
* US915 | SF9 - BW125
+ * RU864 | SF11 - BW125
* US915_HYBRID | SF9 - BW125
*/
#define DR_1 1
@@ -105,6 +108,7 @@
* IN865 | SF10 - BW125
* KR920 | SF10 - BW125
* US915 | SF8 - BW125
+ * RU864 | SF10 - BW125
* US915_HYBRID | SF8 - BW125
*/
#define DR_2 2
@@ -121,6 +125,7 @@
* IN865 | SF9 - BW125
* KR920 | SF9 - BW125
* US915 | SF7 - BW125
+ * RU864 | SF9 - BW125
* US915_HYBRID | SF7 - BW125
*/
#define DR_3 3
@@ -137,6 +142,7 @@
* IN865 | SF8 - BW125
* KR920 | SF8 - BW125
* US915 | SF8 - BW500
+ * RU864 | SF8 - BW125
* US915_HYBRID | SF8 - BW500
*/
#define DR_4 4
@@ -153,6 +159,7 @@
* IN865 | SF7 - BW125
* KR920 | SF7 - BW125
* US915 | RFU
+ * RU864 | SF7 - BW125
* US915_HYBRID | RFU
*/
#define DR_5 5
@@ -169,6 +176,7 @@
* IN865 | SF7 - BW250
* KR920 | RFU
* US915 | RFU
+ * RU864 | SF7 - BW250
* US915_HYBRID | RFU
*/
#define DR_6 6
@@ -185,6 +193,7 @@
* IN865 | FSK
* KR920 | RFU
* US915 | RFU
+ * RU864 | FSK
* US915_HYBRID | RFU
*/
#define DR_7 7
@@ -201,6 +210,7 @@
* IN865 | RFU
* KR920 | RFU
* US915 | SF12 - BW500
+ * RU864 | RFU
* US915_HYBRID | SF12 - BW500
*/
#define DR_8 8
@@ -217,6 +227,7 @@
* IN865 | RFU
* KR920 | RFU
* US915 | SF11 - BW500
+ * RU864 | RFU
* US915_HYBRID | SF11 - BW500
*/
#define DR_9 9
@@ -233,6 +244,7 @@
* IN865 | RFU
* KR920 | RFU
* US915 | SF10 - BW500
+ * RU864 | RFU
* US915_HYBRID | SF10 - BW500
*/
#define DR_10 10
@@ -249,6 +261,7 @@
* IN865 | RFU
* KR920 | RFU
* US915 | SF9 - BW500
+ * RU864 | RFU
* US915_HYBRID | SF9 - BW500
*/
#define DR_11 11
@@ -265,6 +278,7 @@
* IN865 | RFU
* KR920 | RFU
* US915 | SF8 - BW500
+ * RU864 | RFU
* US915_HYBRID | SF8 - BW500
*/
#define DR_12 12
@@ -281,6 +295,7 @@
* IN865 | RFU
* KR920 | RFU
* US915 | SF7 - BW500
+ * RU864 | RFU
* US915_HYBRID | SF7 - BW500
*/
#define DR_13 13
@@ -297,6 +312,7 @@
* IN865 | RFU
* KR920 | RFU
* US915 | RFU
+ * RU864 | RFU
* US915_HYBRID | RFU
*/
#define DR_14 14
@@ -313,6 +329,7 @@
* IN865 | RFU
* KR920 | RFU
* US915 | RFU
+ * RU864 | RFU
* US915_HYBRID | RFU
*/
#define DR_15 15
@@ -331,6 +348,7 @@
* IN865 | Max EIRP
* KR920 | Max EIRP
* US915 | Max ERP
+ * RU864 | Max EIRP
* US915_HYBRID | Max ERP
*/
#define TX_POWER_0 0
@@ -347,6 +365,7 @@
* IN865 | Max EIRP - 2
* KR920 | Max EIRP - 2
* US915 | Max ERP - 2
+ * RU864 | Max EIRP - 2
* US915_HYBRID | Max ERP - 2
*/
#define TX_POWER_1 1
@@ -363,6 +382,7 @@
* IN865 | Max EIRP - 4
* KR920 | Max EIRP - 4
* US915 | Max ERP - 4
+ * RU864 | Max EIRP - 4
* US915_HYBRID | Max ERP - 4
*/
#define TX_POWER_2 2
@@ -379,6 +399,7 @@
* IN865 | Max EIRP - 6
* KR920 | Max EIRP - 6
* US915 | Max ERP - 6
+ * RU864 | Max EIRP - 6
* US915_HYBRID | Max ERP - 6
*/
#define TX_POWER_3 3
@@ -395,6 +416,7 @@
* IN865 | Max EIRP - 8
* KR920 | Max EIRP - 8
* US915 | Max ERP - 8
+ * RU864 | Max EIRP - 8
* US915_HYBRID | Max ERP - 8
*/
#define TX_POWER_4 4
@@ -411,6 +433,7 @@
* IN865 | Max EIRP - 10
* KR920 | Max EIRP - 10
* US915 | Max ERP - 10
+ * RU864 | Max EIRP - 10
* US915_HYBRID | Max ERP - 10
*/
#define TX_POWER_5 5
@@ -427,6 +450,7 @@
* IN865 | Max EIRP - 12
* KR920 | Max EIRP - 12
* US915 | Max ERP - 12
+ * RU864 | Max EIRP - 12
* US915_HYBRID | Max ERP - 12
*/
#define TX_POWER_6 6
@@ -443,6 +467,7 @@
* IN865 | Max EIRP - 14
* KR920 | Max EIRP - 14
* US915 | Max ERP - 14
+ * RU864 | Max EIRP - 14
* US915_HYBRID | Max ERP - 14
*/
#define TX_POWER_7 7
@@ -459,6 +484,7 @@
* IN865 | Max EIRP - 16
* KR920 | -
* US915 | Max ERP - 16
+ * RU864 | -
* US915_HYBRID | Max ERP -16
*/
#define TX_POWER_8 8
@@ -475,6 +501,7 @@
* IN865 | Max EIRP - 18
* KR920 | -
* US915 | Max ERP - 16
+ * RU864 | -
* US915_HYBRID | Max ERP - 16
*/
#define TX_POWER_9 9
@@ -491,6 +518,7 @@
* IN865 | Max EIRP - 20
* KR920 | -
* US915 | Max ERP - 10
+ * RU864 | -
* US915_HYBRID | Max ERP - 10
*/
#define TX_POWER_10 10
diff --git a/src/mac/region/RegionRU864.c b/src/mac/region/RegionRU864.c
new file mode 100644
index 0000000..5286e32
--- /dev/null
+++ b/src/mac/region/RegionRU864.c
@@ -0,0 +1,1018 @@
+/*!
+ * \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 "boards/utilities.h"
+
+#include "RegionCommon.h"
+#include "RegionRU864.h"
+
+// Definitions
+#define CHANNELS_MASK_SIZE 1
+
+// Global attributes
+/*!
+ * LoRaMAC channels
+ */
+static ChannelParams_t Channels[RU864_MAX_NB_CHANNELS];
+
+/*!
+ * LoRaMac bands
+ */
+static Band_t Bands[RU864_MAX_NB_BANDS] =
+{
+ RU864_BAND0,
+};
+
+/*!
+ * LoRaMac channels mask
+ */
+static uint16_t ChannelsMask[CHANNELS_MASK_SIZE];
+
+/*!
+ * LoRaMac channels default mask
+ */
+static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE];
+
+// 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_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_MAX_FCNT_GAP:
+ {
+ phyParam.Value = RU864_MAX_FCNT_GAP;
+ 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 = ChannelsMask;
+ break;
+ }
+ case PHY_CHANNELS_DEFAULT_MASK:
+ {
+ phyParam.ChannelsMask = ChannelsDefaultMask;
+ break;
+ }
+ case PHY_MAX_NB_CHANNELS:
+ {
+ phyParam.Value = RU864_MAX_NB_CHANNELS;
+ break;
+ }
+ case PHY_CHANNELS:
+ {
+ phyParam.Channels = 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;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return phyParam;
+}
+
+void RegionRU864SetBandTxDone( SetBandTxDoneParams_t* txDone )
+{
+ RegionCommonSetBandTxDone( txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+}
+
+void RegionRU864InitDefaults( InitType_t type )
+{
+ switch( type )
+ {
+ case INIT_TYPE_INIT:
+ {
+ // Channels
+ Channels[0] = ( ChannelParams_t ) RU864_LC1;
+ Channels[1] = ( ChannelParams_t ) RU864_LC2;
+
+ // Initialize the channels default mask
+ ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 );
+ // Update the channels mask
+ RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 1 );
+ break;
+ }
+ case INIT_TYPE_RESTORE:
+ {
+ // Restore channels default mask
+ ChannelsMask[0] |= ChannelsDefaultMask[0];
+ break;
+ }
+ case INIT_TYPE_APP_DEFAULTS:
+ {
+ // Update the channels mask defaults
+ RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 1 );
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+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 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( ChannelsMask, chanMaskSet->ChannelsMaskIn, 1 );
+ break;
+ }
+ case CHANNELS_DEFAULT_MASK:
+ {
+ RegionCommonChanMaskCopy( ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1 );
+ break;
+ }
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool RegionRU864AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
+{
+ bool adrAckReq = false;
+ int8_t datarate = adrNext->Datarate;
+ int8_t txPower = adrNext->TxPower;
+ GetPhyParams_t getPhy;
+ PhyParam_t phyParam;
+
+ // Report back the adr ack counter
+ *adrAckCounter = adrNext->AdrAckCounter;
+
+ if( adrNext->AdrEnabled == true )
+ {
+ if( datarate == RU864_TX_MIN_DATARATE )
+ {
+ *adrAckCounter = 0;
+ adrAckReq = false;
+ }
+ else
+ {
+ if( adrNext->AdrAckCounter >= RU864_ADR_ACK_LIMIT )
+ {
+ adrAckReq = true;
+ txPower = RU864_MAX_TX_POWER;
+ }
+ else
+ {
+ adrAckReq = false;
+ }
+ if( adrNext->AdrAckCounter >= ( RU864_ADR_ACK_LIMIT + RU864_ADR_ACK_DELAY ) )
+ {
+ if( ( adrNext->AdrAckCounter % RU864_ADR_ACK_DELAY ) == 1 )
+ {
+ // Decrease the datarate
+ getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
+ getPhy.Datarate = datarate;
+ getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
+ phyParam = RegionRU864GetPhyParam( &getPhy );
+ datarate = phyParam.Value;
+
+ if( datarate == RU864_TX_MIN_DATARATE )
+ {
+ // We must set adrAckReq to false as soon as we reach the lowest datarate
+ adrAckReq = false;
+ if( adrNext->UpdateChanMask == true )
+ {
+ // Re-enable default channels
+ ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ *drOut = datarate;
+ *txPowOut = txPower;
+ return adrAckReq;
+}
+
+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 = Channels[rxConfig->Channel].Frequency;
+ // Apply the alternative RX 1 window frequency, if it is available
+ if( Channels[rxConfig->Channel].Rx1Frequency != 0 )
+ {
+ frequency = 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, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, 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( 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( Channels[i].Frequency != 0 )
+ {
+ chMask |= 1 << i;
+ }
+ }
+ else
+ {
+ if( ( ( chMask & ( 1 << i ) ) != 0 ) &&
+ ( 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 = Channels;
+ linkAdrVerifyParams.MinTxPower = RU864_MIN_TX_POWER;
+ linkAdrVerifyParams.MaxTxPower = RU864_MAX_TX_POWER;
+
+ // 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* )ChannelsMask, 0, sizeof( ChannelsMask ) );
+ // Update the channels mask
+ 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( Channels[dlChannelReq->ChannelId].Frequency == 0 )
+ {
+ status &= 0xFD;
+ }
+
+ // Apply Rx1 frequency, if the status is OK
+ if( status == 0x03 )
+ {
+ 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 = Channels;
+ calcBackOffParams.Bands = 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( ChannelsMask, 0, 1 ) == 0 )
+ { // Reactivate default channels
+ ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
+ }
+
+ if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
+ {
+ // Reset Aggregated time off
+ *aggregatedTimeOff = 0;
+
+ // Update bands Time OFF
+ nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, RU864_MAX_NB_BANDS );
+
+ // Search how many channels are enabled
+ nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Joined, nextChanParams->Datarate,
+ ChannelsMask, Channels,
+ 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
+ ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
+ *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 != 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* )( Channels + id ), ( uint8_t* )channelAdd->NewChannel, sizeof( Channels[id] ) );
+ Channels[id].Band = band;
+ 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
+ Channels[id] = ( ChannelParams_t ){ 0, 0, { 0 }, 0 };
+
+ return RegionCommonChanDisable( ChannelsMask, id, RU864_MAX_NB_CHANNELS );
+}
+
+void RegionRU864SetContinuousWave( ContinuousWaveParams_t* continuousWave )
+{
+ int8_t txPowerLimited = LimitTxPower( continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask );
+ int8_t phyTxPower = 0;
+ uint32_t frequency = 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;
+}
diff --git a/src/mac/region/RegionRU864.h b/src/mac/region/RegionRU864.h
new file mode 100644
index 0000000..5f47a7e
--- /dev/null
+++ b/src/mac/region/RegionRU864.h
@@ -0,0 +1,459 @@
+/*!
+ * \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
+
+/*!
+ * 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
+
+/*!
+ * Maximum number of bands
+ */
+#define RU864_MAX_NB_BANDS 1
+
+/*!
+ * Band 0 definition
+ * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ */
+#define RU864_BAND0 { 1 , RU864_MAX_TX_POWER, 0, 0, 0 } // 100 %
+
+/*!
+ * 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( InitType_t type );
+
+/*!
+ * \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 );
+
+/*!
+ * \brief Calculates the next datarate to set, when ADR is on or off.
+ *
+ * \param [IN] adrNext Pointer to the function parameters.
+ *
+ * \param [OUT] drOut The calculated datarate for the next TX.
+ *
+ * \param [OUT] txPowOut The TX power for the next TX.
+ *
+ * \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
+ *
+ * \retval Returns true, if an ADR request should be performed.
+ */
+bool RegionRU864AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
+
+/*!
+ * 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 );
+
+/*! \} defgroup REGIONRU864 */
+
+#endif // __REGION_RU864_H__
--
2.17.1