2150 lines
64 KiB
C
2150 lines
64 KiB
C
/*!
|
|
* \file LmHandler.c
|
|
*
|
|
* \brief Implements the LoRaMac layer handling.
|
|
* Provides the possibility to register applicative packages.
|
|
*
|
|
* \remark Inspired by the examples provided on the en.i-cube_lrwan fork.
|
|
* MCD Application Team ( STMicroelectronics International )
|
|
*
|
|
* \copyright Revised BSD License, see section \ref LICENSE.txt.
|
|
*
|
|
* \code
|
|
* ______ _
|
|
* / _____) _ | |
|
|
* ( (____ _____ ____ _| |_ _____ ____| |__
|
|
* \____ \| ___ | (_ _) ___ |/ ___) _ \
|
|
* _____) ) ____| | | || |_| ____( (___| | | |
|
|
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
|
|
* (C)2013-2018 Semtech
|
|
*
|
|
* \endcode
|
|
*
|
|
* \author Miguel Luis ( Semtech )
|
|
*/
|
|
/**
|
|
******************************************************************************
|
|
*
|
|
* Portions COPYRIGHT 2020 STMicroelectronics
|
|
*
|
|
* @file LmHandler.c
|
|
* @author MCD Application Team
|
|
* @brief LoRaMAC Layer handling definition
|
|
******************************************************************************
|
|
*/
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "utilities.h"
|
|
#include "timer.h"
|
|
#include "Commissioning.h"
|
|
#include "NvmDataMgmt.h"
|
|
#include "radio.h"
|
|
#include "Region.h"
|
|
#include "LoRaMac.h"
|
|
#include "LoRaMacVersion.h"
|
|
#include "LoRaMacTest.h"
|
|
#include "LmHandler.h"
|
|
#include "LmhPackage.h"
|
|
#include "LmhpCompliance.h"
|
|
#include "secure-element.h"
|
|
#include "mw_log_conf.h" /* needed for MW_LOG */
|
|
#include "lorawan_version.h"
|
|
#include "lora_info.h"
|
|
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
|
|
#else /* LORAWAN_KMS == 1 */
|
|
#include "kms.h"
|
|
#include "kms_platf_objects_interface.h"
|
|
#endif /* LORAWAN_KMS */
|
|
#include "LmhpPackagesRegistration.h"
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
/*!
|
|
* MAC notification type
|
|
*/
|
|
typedef enum PackageNotifyTypes_e
|
|
{
|
|
PACKAGE_MCPS_CONFIRM,
|
|
PACKAGE_MCPS_INDICATION,
|
|
PACKAGE_MLME_CONFIRM,
|
|
PACKAGE_MLME_INDICATION,
|
|
} PackageNotifyTypes_t;
|
|
|
|
/* Private define ------------------------------------------------------------*/
|
|
/*!
|
|
* Package application data buffer size
|
|
*/
|
|
#define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242
|
|
|
|
/* Private macro -------------------------------------------------------------*/
|
|
/*!
|
|
* Hex 8 split buffer
|
|
*/
|
|
#define HEX8(X) X[0], X[1], X[2], X[3], X[4], X[5], X[6], X[7]
|
|
|
|
/*!
|
|
* Hex 16 split buffer
|
|
*/
|
|
#define HEX16(X) HEX8(X), X[8], X[9], X[10], X[11], X[12], X[13], X[14], X[15]
|
|
|
|
/* Private variables ---------------------------------------------------------*/
|
|
static CommissioningParams_t CommissioningParams =
|
|
{
|
|
.DevEui = { 0 }, /* Automatically filed from secure-element */
|
|
.JoinEui = { 0 }, /* Automatically filed from secure-element */
|
|
.DevAddr = 0, /* Automatically filed from secure-element */
|
|
.NetworkId = LORAWAN_NETWORK_ID,
|
|
};
|
|
|
|
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
|
|
/*!
|
|
* LoRaWAN compliance tests handler parameters
|
|
*/
|
|
static LmhpComplianceParams_t LmhpComplianceParams =
|
|
{
|
|
.AdrEnabled = LORAMAC_HANDLER_ADR_ON,
|
|
.DutyCycleEnabled = false,
|
|
.StopPeripherals = NULL,
|
|
.StartPeripherals = NULL,
|
|
};
|
|
#elif (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
/*!
|
|
* LoRaWAN compliance tests handler parameters
|
|
*/
|
|
static LmhpComplianceParams_t LmhpComplianceParams =
|
|
{
|
|
.FwVersion.Value = 0U, /* To be initialized by LmHandler */
|
|
.OnTxPeriodicityChanged = NULL, /* To be initialized by LmHandler */
|
|
.OnTxFrameCtrlChanged = NULL, /* To be initialized by LmHandler */
|
|
.OnPingSlotPeriodicityChanged = NULL, /* To be initialized by LmHandler */
|
|
};
|
|
#endif /* LORAMAC_VERSION */
|
|
|
|
static LmhPackage_t *LmHandlerPackages[PKG_MAX_NUMBER];
|
|
|
|
/*!
|
|
* Upper layer LoRaMac parameters
|
|
*/
|
|
static LmHandlerParams_t LmHandlerParams;
|
|
|
|
/*!
|
|
* Upper layer callbacks
|
|
*/
|
|
static LmHandlerCallbacks_t *LmHandlerCallbacks;
|
|
|
|
/*!
|
|
* Used to notify LmHandler of LoRaMac events
|
|
*/
|
|
static LoRaMacPrimitives_t LoRaMacPrimitives;
|
|
|
|
/*!
|
|
* LoRaMac callbacks
|
|
*/
|
|
static LoRaMacCallback_t LoRaMacCallbacks;
|
|
|
|
static LmHandlerJoinParams_t JoinParams =
|
|
{
|
|
.CommissioningParams = &CommissioningParams,
|
|
.Mode = ACTIVATION_TYPE_NONE,
|
|
.forceRejoin = false,
|
|
.Datarate = DR_0,
|
|
.TxPower = TX_POWER_0,
|
|
.Status = LORAMAC_HANDLER_ERROR
|
|
};
|
|
|
|
static LmHandlerTxParams_t TxParams =
|
|
{
|
|
.CommissioningParams = &CommissioningParams,
|
|
.MsgType = LORAMAC_HANDLER_UNCONFIRMED_MSG,
|
|
.AckReceived = 0,
|
|
.Datarate = DR_0,
|
|
.UplinkCounter = 0,
|
|
.AppData =
|
|
{
|
|
.Port = 0,
|
|
.BufferSize = 0,
|
|
.Buffer = NULL,
|
|
},
|
|
.TxPower = TX_POWER_0,
|
|
.Channel = 0,
|
|
};
|
|
|
|
static LmHandlerRxParams_t RxParams =
|
|
{
|
|
.CommissioningParams = &CommissioningParams,
|
|
.Rssi = 0,
|
|
.Snr = 0,
|
|
.DownlinkCounter = 0,
|
|
.RxSlot = -1,
|
|
.LinkCheck = false,
|
|
.DemodMargin = 0,
|
|
.NbGateways = 0,
|
|
};
|
|
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
static LmHandlerBeaconParams_t BeaconParams =
|
|
{
|
|
.State = LORAMAC_HANDLER_BEACON_ACQUIRING,
|
|
.Info =
|
|
{
|
|
.Time = { .Seconds = 0, .SubSeconds = 0 },
|
|
.Frequency = 0,
|
|
.Datarate = 0,
|
|
.Rssi = 0,
|
|
.Snr = 0,
|
|
.GwSpecific =
|
|
{
|
|
.InfoDesc = 0,
|
|
.Info = { 0 },
|
|
},
|
|
},
|
|
};
|
|
#endif /* LORAMAC_CLASSB_ENABLED == 1 */
|
|
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
/*!
|
|
* Indicates if a switch to Class B operation is pending or not.
|
|
*/
|
|
static bool IsClassBSwitchPending = false;
|
|
#endif /* LORAMAC_CLASSB_ENABLED == 1 */
|
|
|
|
/*!
|
|
* Stores the time to wait before next transmission
|
|
*
|
|
*/
|
|
static TimerTime_t DutyCycleWaitTime = 0;
|
|
|
|
#if (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
/*!
|
|
* Indicates if an uplink is pending upon MAC layer request
|
|
*
|
|
*/
|
|
static bool IsUplinkTxPending = false;
|
|
#endif /* LORAMAC_VERSION */
|
|
|
|
/*!
|
|
* Package Application buffer
|
|
*/
|
|
static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE];
|
|
|
|
/*!
|
|
* Package application data structure
|
|
*/
|
|
static LmHandlerAppData_t AppData = { 0, LORAWAN_APP_DATA_BUFFER_MAX_SIZE, AppDataBuffer };
|
|
|
|
static bool CtxRestoreDone = false;
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
/*!
|
|
* \brief MCPS-Confirm event function
|
|
*
|
|
* \param [in] mcpsConfirm - Pointer to the confirm structure,
|
|
* containing confirm attributes.
|
|
*/
|
|
static void McpsConfirm( McpsConfirm_t *mcpsConfirm );
|
|
|
|
/*!
|
|
* \brief MCPS-Indication event function
|
|
*
|
|
* \param [in] mcpsIndication - Pointer to the indication structure,
|
|
* containing indication attributes.
|
|
* \param [in] rxStatus - Pointer to RX status structure
|
|
*/
|
|
static void McpsIndication( McpsIndication_t *mcpsIndication, LoRaMacRxStatus_t *rxStatus );
|
|
|
|
/*!
|
|
* \brief MLME-Confirm event function
|
|
*
|
|
* \param [in] mlmeConfirm - Pointer to the confirm structure,
|
|
* containing confirm attributes.
|
|
*/
|
|
static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm );
|
|
|
|
/*!
|
|
* \brief MLME-Indication event function
|
|
*
|
|
* \param [in] mlmeIndication - Pointer to the indication structure,
|
|
* containing indication attributes.
|
|
* \param [in] rxStatus - Pointer to RX status structure
|
|
*/
|
|
static void MlmeIndication( MlmeIndication_t *mlmeIndication, LoRaMacRxStatus_t *rxStatus );
|
|
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
/*!
|
|
* \brief Starts the beacon search
|
|
*
|
|
* \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been
|
|
* processed else \ref LORAMAC_HANDLER_ERROR
|
|
*/
|
|
static LmHandlerErrorStatus_t LmHandlerBeaconReq( void );
|
|
|
|
#endif /* LORAMAC_CLASSB_ENABLED == 1 */
|
|
|
|
/*!
|
|
* \brief Notifies the package to process the LoRaMac callbacks.
|
|
*
|
|
* \param [in] notifyType MAC notification type [PACKAGE_MCPS_CONFIRM,
|
|
* PACKAGE_MCPS_INDICATION,
|
|
* PACKAGE_MLME_CONFIRM,
|
|
* PACKAGE_MLME_INDICATION]
|
|
* \param [in] params Notification parameters. The params type can be
|
|
* [McpsConfirm_t, McpsIndication_t, MlmeConfirm_t, MlmeIndication_t]
|
|
*/
|
|
static void LmHandlerPackagesNotify( PackageNotifyTypes_t notifyType, void *params );
|
|
|
|
/*!
|
|
* \brief Returns if at least one package transmission is pending or not
|
|
*
|
|
* \retval status Package transmission status
|
|
* [true: pending, false: Not pending]
|
|
*/
|
|
static bool LmHandlerPackageIsTxPending( void );
|
|
|
|
/*!
|
|
* \brief Processes the internal package events.
|
|
*/
|
|
static void LmHandlerPackagesProcess( void );
|
|
|
|
/*!
|
|
* \brief Check if the package ID is initialized
|
|
*
|
|
* \param [in] id package identifier
|
|
*
|
|
* \retval status Returns true if initialized else false
|
|
*/
|
|
static bool LmHandlerPackageIsInitialized( uint8_t id );
|
|
|
|
#if (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
/*!
|
|
* \brief Will be called to change applicative Tx frame control
|
|
*
|
|
* \param [in] isTxConfirmed set the Tx frame in confirmed/unconfirmed control
|
|
* \note Compliance test protocol callbacks used when TS001-1.0.4 + TS009 1.0.0 are defined
|
|
*/
|
|
static void LmHandlerOnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed );
|
|
|
|
/*!
|
|
* \brief Will be called to change the ping period
|
|
*
|
|
* \param [in] pingSlotPeriodicity index of ping period as 2^X value
|
|
* \note Compliance test protocol callbacks used when TS001-1.0.4 + TS009 1.0.0 are defined
|
|
*/
|
|
static void LmHandlerOnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity );
|
|
#endif /* LORAMAC_VERSION */
|
|
|
|
/* Exported functions ---------------------------------------------------------*/
|
|
LmHandlerErrorStatus_t LmHandlerInit( LmHandlerCallbacks_t *handlerCallbacks, uint32_t fwVersion )
|
|
{
|
|
LmHandlerCallbacks = handlerCallbacks;
|
|
|
|
LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
|
|
LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
|
|
LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
|
|
LoRaMacPrimitives.MacMlmeIndication = MlmeIndication;
|
|
LoRaMacCallbacks.GetBatteryLevel = LmHandlerCallbacks->GetBatteryLevel;
|
|
LoRaMacCallbacks.GetTemperatureLevel = LmHandlerCallbacks->GetTemperature;
|
|
LoRaMacCallbacks.GetUniqueId = LmHandlerCallbacks->GetUniqueId;
|
|
LoRaMacCallbacks.GetDevAddress = LmHandlerCallbacks->GetDevAddr;
|
|
LoRaMacCallbacks.NvmDataChange = NvmDataMgmtEvent;
|
|
LoRaMacCallbacks.MacProcessNotify = LmHandlerCallbacks->OnMacProcess;
|
|
|
|
#if (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
LmhpComplianceParams.FwVersion.Value = fwVersion;
|
|
LmhpComplianceParams.OnTxPeriodicityChanged = LmHandlerCallbacks->OnTxPeriodicityChanged;
|
|
LmhpComplianceParams.OnTxFrameCtrlChanged = LmHandlerOnTxFrameCtrlChanged;
|
|
LmhpComplianceParams.OnPingSlotPeriodicityChanged = LmHandlerOnPingSlotPeriodicityChanged;
|
|
#endif /* LORAMAC_VERSION */
|
|
|
|
/*The LoRa-Alliance Compliance protocol package should always be initialized and activated.*/
|
|
if( LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams ) != LORAMAC_HANDLER_SUCCESS )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
if( LmhpPackagesRegistrationInit( ( Version_t * )&fwVersion ) != LORAMAC_HANDLER_SUCCESS )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerDeInit( void )
|
|
{
|
|
if( LoRaMacDeInitialization() == LORAMAC_STATUS_OK )
|
|
{
|
|
LmHandlerCallbacks = NULL;
|
|
memset1( ( uint8_t * )&LoRaMacPrimitives, 0, sizeof( LoRaMacPrimitives_t ) );
|
|
memset1( ( uint8_t * )&LoRaMacCallbacks, 0, sizeof( LoRaMacCallback_t ) );
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
return LORAMAC_HANDLER_BUSY_ERROR;
|
|
}
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerConfigure( LmHandlerParams_t *handlerParams )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
LoraInfo_t *loraInfo;
|
|
|
|
memcpy1( ( void * )&LmHandlerParams, ( const void * )handlerParams, sizeof( LmHandlerParams_t ) );
|
|
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
IsClassBSwitchPending = false;
|
|
#endif /* LORAMAC_CLASSB_ENABLED == 1 */
|
|
#if (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
IsUplinkTxPending = false;
|
|
#endif /* LORAMAC_VERSION */
|
|
|
|
loraInfo = LoraInfo_GetPtr();
|
|
|
|
if( 0U == ( ( 1 << ( LmHandlerParams.ActiveRegion ) ) & ( loraInfo->Region ) ) )
|
|
{
|
|
MW_LOG( TS_ON, VLEVEL_ALWAYS, "error: Region is not defined in the MW: set lorawan_conf.h accordingly\r\n" );
|
|
while( 1 ) {} /* error: Region is not defined in the MW */
|
|
}
|
|
|
|
if( LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LmHandlerParams.ActiveRegion ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
#if (defined( CONTEXT_MANAGEMENT_ENABLED ) && ( CONTEXT_MANAGEMENT_ENABLED == 1 ))
|
|
/* Try the restore context from the Backup RAM structure if data retention is available */
|
|
mibReq.Type = MIB_NVM_CTXS;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
|
|
{
|
|
CtxRestoreDone = true;
|
|
}
|
|
else
|
|
{
|
|
/* Restore context data backup from user callback (stored in FLASH) */
|
|
mibReq.Type = MIB_NVM_BKP_CTXS;
|
|
if( LmHandlerCallbacks->OnRestoreContextRequest != NULL )
|
|
{
|
|
LoRaMacMibGetRequestConfirm( &mibReq );
|
|
LmHandlerCallbacks->OnRestoreContextRequest( mibReq.Param.BackupContexts, sizeof( LoRaMacNvmData_t ) );
|
|
}
|
|
/* Restore context data from backup to main nvm structure */
|
|
mibReq.Type = MIB_NVM_CTXS;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
|
|
{
|
|
mibReq.Type = MIB_NETWORK_ACTIVATION;
|
|
LoRaMacMibGetRequestConfirm( &mibReq );
|
|
if( mibReq.Param.NetworkActivation != ACTIVATION_TYPE_NONE )
|
|
{
|
|
CtxRestoreDone = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( CtxRestoreDone == true )
|
|
{
|
|
if( LmHandlerCallbacks->OnNvmDataChange != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnNvmDataChange( LORAMAC_HANDLER_NVM_RESTORE );
|
|
}
|
|
|
|
//BZ #156695
|
|
if(( LmHandlerJoinStatus() == LORAMAC_HANDLER_SET) && LoRaMacIsStopped())
|
|
{
|
|
LoRaMacStart();
|
|
}
|
|
|
|
mibReq.Type = MIB_NVM_CTXS;
|
|
LoRaMacMibGetRequestConfirm( &mibReq );
|
|
LoRaMacNvmData_t *current_nvm = mibReq.Param.Contexts;
|
|
|
|
LmHandlerParams.ActiveRegion = current_nvm->MacGroup2.Region;
|
|
LmHandlerParams.DefaultClass = current_nvm->MacGroup2.DeviceClass;
|
|
LmHandlerParams.AdrEnable = current_nvm->MacGroup2.AdrCtrlOn;
|
|
}
|
|
else
|
|
#endif /* CONTEXT_MANAGEMENT_ENABLED == 1 */
|
|
{
|
|
mibReq.Type = MIB_NET_ID;
|
|
mibReq.Param.NetID = LORAWAN_NETWORK_ID;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
}
|
|
|
|
/* Restore ID struct from NVM or Init from callbacks */
|
|
if( SecureElementInitMcuID( LoRaMacCallbacks.GetUniqueId, LoRaMacCallbacks.GetDevAddress ) != SECURE_ELEMENT_SUCCESS )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
/* Read secure-element DEV_EUI, JOIN_EUI and DEV_ADDR values. */
|
|
mibReq.Type = MIB_DEV_ADDR;
|
|
LoRaMacMibGetRequestConfirm( &mibReq );
|
|
CommissioningParams.DevAddr = mibReq.Param.DevAddr;
|
|
|
|
/* Override DevAddress value after init from callbacks */
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
|
|
mibReq.Type = MIB_DEV_EUI;
|
|
mibReq.Param.DevEui = CommissioningParams.DevEui;
|
|
LoRaMacMibGetRequestConfirm( &mibReq );
|
|
|
|
mibReq.Type = MIB_JOIN_EUI;
|
|
mibReq.Param.JoinEui = CommissioningParams.JoinEui;
|
|
LoRaMacMibGetRequestConfirm( &mibReq );
|
|
|
|
SecureElementPrintKeys();
|
|
|
|
#if (defined (LORAWAN_KMS) && (LORAWAN_KMS == 1))
|
|
MW_LOG( TS_OFF, VLEVEL_L, "###### KMS ENABLED \r\n" );
|
|
#endif /* LORAWAN_KMS == 1 */
|
|
|
|
mibReq.Type = MIB_PUBLIC_NETWORK;
|
|
mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
|
|
mibReq.Type = MIB_REPEATER_SUPPORT;
|
|
mibReq.Param.EnableRepeaterSupport = LORAWAN_REPEATER_SUPPORT;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
|
|
mibReq.Type = MIB_ADR;
|
|
mibReq.Param.AdrEnable = LmHandlerParams.AdrEnable;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
|
|
mibReq.Type = MIB_RXB_C_TIMEOUT;
|
|
mibReq.Param.RxBCTimeout = LmHandlerParams.RxBCTimeout;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
|
|
GetPhyParams_t getPhy;
|
|
PhyParam_t phyParam;
|
|
getPhy.Attribute = PHY_DUTY_CYCLE;
|
|
phyParam = RegionGetPhyParam( LmHandlerParams.ActiveRegion, &getPhy );
|
|
LmHandlerParams.DutyCycleEnabled = ( bool ) phyParam.Value;
|
|
|
|
/* Set system maximum tolerated rx error in milliseconds */
|
|
LmHandlerSetSystemMaxRxError( 20 );
|
|
|
|
/* override previous value if reconfigure new region */
|
|
LoRaMacTestSetDutyCycleOn( LmHandlerParams.DutyCycleEnabled );
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
bool LmHandlerIsBusy( void )
|
|
{
|
|
if( LoRaMacIsBusy( ) == true )
|
|
{
|
|
return true;
|
|
}
|
|
if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET )
|
|
{
|
|
/* The network isn't yet joined, try again later. */
|
|
LmHandlerJoin( JoinParams.Mode, JoinParams.forceRejoin );
|
|
return true;
|
|
}
|
|
|
|
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
|
|
if( LmHandlerPackages[PACKAGE_ID_COMPLIANCE]->IsRunning( ) == true )
|
|
{
|
|
return true;
|
|
}
|
|
#endif /* LORAMAC_VERSION */
|
|
|
|
if( LmHandlerPackageIsTxPending( ) == true )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void LmHandlerProcess( void )
|
|
{
|
|
/* Call at first the LoRaMAC process before to run all package process features */
|
|
/* Processes the LoRaMac events */
|
|
LoRaMacProcess( );
|
|
|
|
/* Call all packages process functions */
|
|
LmHandlerPackagesProcess( );
|
|
|
|
/* Check if a package transmission is pending. */
|
|
/* If it is the case exit function earlier */
|
|
if( LmHandlerPackageIsTxPending( ) == true )
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
/* If a MAC layer scheduled uplink is still pending try to send it. */
|
|
if( IsUplinkTxPending == true )
|
|
{
|
|
/* Send an empty message */
|
|
LmHandlerAppData_t appData =
|
|
{
|
|
.Buffer = NULL,
|
|
.BufferSize = 0,
|
|
.Port = 0,
|
|
};
|
|
|
|
if( LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed, false ) == LORAMAC_HANDLER_SUCCESS )
|
|
{
|
|
IsUplinkTxPending = false;
|
|
}
|
|
}
|
|
#endif /* LORAMAC_VERSION */
|
|
}
|
|
|
|
TimerTime_t LmHandlerGetDutyCycleWaitTime( void )
|
|
{
|
|
return DutyCycleWaitTime;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerJoin( ActivationType_t mode, bool forceRejoin )
|
|
{
|
|
LmHandlerErrorStatus_t lmhStatus = LORAMAC_HANDLER_ERROR;
|
|
LoRaMacStatus_t status;
|
|
MlmeReq_t mlmeReq;
|
|
|
|
mlmeReq.Type = MLME_JOIN;
|
|
mlmeReq.Req.Join.Datarate = LmHandlerParams.TxDatarate;
|
|
mlmeReq.Req.Join.TxPower = LmHandlerParams.TxPower;
|
|
|
|
if( mode == ACTIVATION_TYPE_OTAA )
|
|
{
|
|
mlmeReq.Req.Join.NetworkActivation = ACTIVATION_TYPE_OTAA;
|
|
JoinParams.Mode = ACTIVATION_TYPE_OTAA;
|
|
JoinParams.forceRejoin = forceRejoin;
|
|
LoRaMacStart();
|
|
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
|
|
/* Starts the OTAA join procedure */
|
|
status = LoRaMacMlmeRequest( &mlmeReq );
|
|
|
|
if( status == LORAMAC_STATUS_OK )
|
|
{
|
|
lmhStatus = LORAMAC_STATUS_OK;
|
|
}
|
|
#endif /* LORAMAC_VERSION */
|
|
}
|
|
else
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
mlmeReq.Req.Join.NetworkActivation = ACTIVATION_TYPE_ABP;
|
|
JoinParams.Mode = ACTIVATION_TYPE_ABP;
|
|
JoinParams.Datarate = LmHandlerParams.TxDatarate;
|
|
JoinParams.TxPower = LmHandlerParams.TxPower;
|
|
JoinParams.Status = LORAMAC_HANDLER_SUCCESS;
|
|
JoinParams.forceRejoin = forceRejoin;
|
|
|
|
if( CtxRestoreDone == false )
|
|
{
|
|
/* Configure the default datarate */
|
|
mibReq.Type = MIB_CHANNELS_DEFAULT_DATARATE;
|
|
mibReq.Param.ChannelsDefaultDatarate = LmHandlerParams.TxDatarate;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
|
|
mibReq.Type = MIB_CHANNELS_DATARATE;
|
|
mibReq.Param.ChannelsDatarate = LmHandlerParams.TxDatarate;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
|
|
/* Configure the default Tx Power */
|
|
mibReq.Type = MIB_CHANNELS_DEFAULT_TX_POWER;
|
|
mibReq.Param.ChannelsDefaultTxPower = LmHandlerParams.TxPower;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
|
|
mibReq.Type = MIB_CHANNELS_TX_POWER;
|
|
mibReq.Param.ChannelsTxPower = LmHandlerParams.TxPower;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
|
|
/* Tell the MAC layer which network server version are we connecting too. */
|
|
mibReq.Type = MIB_ABP_LORAWAN_VERSION;
|
|
mibReq.Param.AbpLrWanVersion.Value = ABP_ACTIVATION_LRWAN_VERSION;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
}
|
|
|
|
LoRaMacStart();
|
|
mibReq.Type = MIB_NETWORK_ACTIVATION;
|
|
mibReq.Param.NetworkActivation = ACTIVATION_TYPE_ABP;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
|
|
/* Notify upper layer */
|
|
if( LmHandlerCallbacks->OnJoinRequest != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnJoinRequest( &JoinParams );
|
|
}
|
|
lmhStatus = LmHandlerRequestClass( LmHandlerParams.DefaultClass );
|
|
#endif /* LORAMAC_VERSION */
|
|
}
|
|
|
|
#if (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
if( ( CtxRestoreDone == false ) || ( forceRejoin == true ) )
|
|
{
|
|
/* Starts the join procedure */
|
|
status = LoRaMacMlmeRequest( &mlmeReq );
|
|
|
|
if( status == LORAMAC_STATUS_OK )
|
|
{
|
|
lmhStatus = LORAMAC_STATUS_OK;
|
|
}
|
|
}
|
|
DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
|
|
#endif /* LORAMAC_VERSION */
|
|
|
|
return lmhStatus;
|
|
}
|
|
|
|
LmHandlerFlagStatus_t LmHandlerJoinStatus( void )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
LoRaMacStatus_t status;
|
|
|
|
mibReq.Type = MIB_NETWORK_ACTIVATION;
|
|
status = LoRaMacMibGetRequestConfirm( &mibReq );
|
|
|
|
if( status == LORAMAC_STATUS_OK )
|
|
{
|
|
if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE )
|
|
{
|
|
return LORAMAC_HANDLER_RESET;
|
|
}
|
|
else
|
|
{
|
|
return LORAMAC_HANDLER_SET;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return LORAMAC_HANDLER_RESET;
|
|
}
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSend( LmHandlerAppData_t *appData, LmHandlerMsgTypes_t isTxConfirmed,
|
|
bool allowDelayedTx )
|
|
{
|
|
LoRaMacStatus_t status;
|
|
LmHandlerErrorStatus_t lmhStatus = LORAMAC_HANDLER_ERROR;
|
|
McpsReq_t mcpsReq;
|
|
LoRaMacTxInfo_t txInfo;
|
|
|
|
if( LoRaMacIsBusy() == true )
|
|
{
|
|
return LORAMAC_HANDLER_BUSY_ERROR;
|
|
}
|
|
|
|
if( LoRaMacIsStopped() == true )
|
|
{
|
|
return LORAMAC_HANDLER_NO_NETWORK_JOINED;
|
|
}
|
|
|
|
if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET )
|
|
{
|
|
/* The network isn't joined, try again. */
|
|
LmHandlerJoin( JoinParams.Mode, JoinParams.forceRejoin );
|
|
return LORAMAC_HANDLER_NO_NETWORK_JOINED;
|
|
}
|
|
|
|
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
|
|
if( ( LmHandlerPackages[PACKAGE_ID_COMPLIANCE]->IsRunning( ) == true )
|
|
&& ( appData->Port != LmHandlerPackages[PACKAGE_ID_COMPLIANCE]->Port ) && ( appData->Port != 0 ) )
|
|
{
|
|
return LORAMAC_HANDLER_COMPLIANCE_RUNNING;
|
|
}
|
|
#endif /* LORAMAC_VERSION */
|
|
|
|
TxParams.MsgType = isTxConfirmed;
|
|
mcpsReq.Type = ( isTxConfirmed == LORAMAC_HANDLER_UNCONFIRMED_MSG ) ? MCPS_UNCONFIRMED : MCPS_CONFIRMED;
|
|
mcpsReq.Req.Unconfirmed.Datarate = LmHandlerParams.TxDatarate;
|
|
if( LoRaMacQueryTxPossible( appData->BufferSize, &txInfo ) != LORAMAC_STATUS_OK )
|
|
{
|
|
/* Send empty frame in order to flush MAC commands */
|
|
mcpsReq.Type = MCPS_UNCONFIRMED;
|
|
mcpsReq.Req.Unconfirmed.fBuffer = NULL;
|
|
mcpsReq.Req.Unconfirmed.fBufferSize = 0;
|
|
lmhStatus = LORAMAC_HANDLER_PAYLOAD_LENGTH_RESTRICTED;
|
|
}
|
|
else
|
|
{
|
|
mcpsReq.Req.Unconfirmed.fPort = appData->Port;
|
|
mcpsReq.Req.Unconfirmed.fBufferSize = appData->BufferSize;
|
|
mcpsReq.Req.Unconfirmed.fBuffer = appData->Buffer;
|
|
}
|
|
|
|
TxParams.AppData = *appData;
|
|
TxParams.Datarate = LmHandlerParams.TxDatarate;
|
|
|
|
status = LoRaMacMcpsRequest( &mcpsReq, allowDelayedTx );
|
|
DutyCycleWaitTime = mcpsReq.ReqReturn.DutyCycleWaitTime;
|
|
|
|
switch( status )
|
|
{
|
|
case LORAMAC_STATUS_OK:
|
|
#if (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
IsUplinkTxPending = false;
|
|
#endif /* LORAMAC_VERSION */
|
|
if( lmhStatus != LORAMAC_HANDLER_PAYLOAD_LENGTH_RESTRICTED )
|
|
{
|
|
lmhStatus = LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
break;
|
|
case LORAMAC_STATUS_BUSY:
|
|
case LORAMAC_STATUS_BUSY_UPLINK_COLLISION:
|
|
case LORAMAC_STATUS_BUSY_BEACON_RESERVED_TIME:
|
|
case LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME:
|
|
lmhStatus = LORAMAC_HANDLER_BUSY_ERROR;
|
|
break;
|
|
case LORAMAC_STATUS_NO_NETWORK_JOINED:
|
|
lmhStatus = LORAMAC_HANDLER_NO_NETWORK_JOINED;
|
|
break;
|
|
case LORAMAC_STATUS_CRYPTO_ERROR:
|
|
lmhStatus = LORAMAC_HANDLER_CRYPTO_ERROR;
|
|
break;
|
|
case LORAMAC_STATUS_DUTYCYCLE_RESTRICTED:
|
|
lmhStatus = LORAMAC_HANDLER_DUTYCYCLE_RESTRICTED;
|
|
break;
|
|
case LORAMAC_STATUS_SERVICE_UNKNOWN:
|
|
case LORAMAC_STATUS_PARAMETER_INVALID:
|
|
case LORAMAC_STATUS_MAC_COMMAD_ERROR:
|
|
case LORAMAC_STATUS_FCNT_HANDLER_ERROR:
|
|
case LORAMAC_STATUS_REGION_NOT_SUPPORTED:
|
|
case LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND:
|
|
case LORAMAC_STATUS_NO_CHANNEL_FOUND:
|
|
case LORAMAC_STATUS_LENGTH_ERROR:
|
|
default:
|
|
lmhStatus = LORAMAC_HANDLER_ERROR;
|
|
break;
|
|
}
|
|
|
|
return lmhStatus;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerDeviceTimeReq( void )
|
|
{
|
|
LoRaMacStatus_t status;
|
|
MlmeReq_t mlmeReq;
|
|
|
|
mlmeReq.Type = MLME_DEVICE_TIME;
|
|
|
|
status = LoRaMacMlmeRequest( &mlmeReq );
|
|
DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
|
|
|
|
if( status == LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
static LmHandlerErrorStatus_t LmHandlerBeaconReq( void )
|
|
{
|
|
LoRaMacStatus_t status;
|
|
MlmeReq_t mlmeReq;
|
|
|
|
mlmeReq.Type = MLME_BEACON_ACQUISITION;
|
|
|
|
status = LoRaMacMlmeRequest( &mlmeReq );
|
|
DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
|
|
|
|
if( status == LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
#endif /* LORAMAC_CLASSB_ENABLED == 1 */
|
|
|
|
LmHandlerErrorStatus_t LmHandlerPingSlotReq( uint8_t periodicity )
|
|
{
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
LoRaMacStatus_t status;
|
|
MlmeReq_t mlmeReq;
|
|
|
|
mlmeReq.Type = MLME_PING_SLOT_INFO;
|
|
mlmeReq.Req.PingSlotInfo.PingSlot.Fields.Periodicity = periodicity;
|
|
mlmeReq.Req.PingSlotInfo.PingSlot.Fields.RFU = 0;
|
|
|
|
status = LoRaMacMlmeRequest( &mlmeReq );
|
|
DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
|
|
|
|
if( status == LORAMAC_STATUS_OK )
|
|
{
|
|
LmHandlerParams.PingSlotPeriodicity = periodicity;
|
|
/* Send an empty message */
|
|
LmHandlerAppData_t appData =
|
|
{
|
|
.Buffer = NULL,
|
|
.BufferSize = 0,
|
|
.Port = 0,
|
|
};
|
|
return LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed, false );
|
|
}
|
|
else
|
|
#endif /* LORAMAC_CLASSB_ENABLED == 1 */
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerRequestClass( DeviceClass_t newClass )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
DeviceClass_t currentClass;
|
|
LmHandlerErrorStatus_t errorStatus = LORAMAC_HANDLER_SUCCESS;
|
|
|
|
if( LoRaMacIsBusy() == true )
|
|
{
|
|
return LORAMAC_HANDLER_BUSY_ERROR;
|
|
}
|
|
|
|
if( LmHandlerJoinStatus() != LORAMAC_HANDLER_SET )
|
|
{
|
|
return LORAMAC_HANDLER_NO_NETWORK_JOINED;
|
|
}
|
|
|
|
mibReq.Type = MIB_DEVICE_CLASS;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
currentClass = mibReq.Param.Class;
|
|
|
|
/* Attempt to switch only if class update */
|
|
if( currentClass != newClass )
|
|
{
|
|
switch( newClass )
|
|
{
|
|
case CLASS_A:
|
|
{
|
|
if( currentClass != CLASS_A )
|
|
{
|
|
mibReq.Param.Class = newClass;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
|
|
{
|
|
/* Switch is instantaneous */
|
|
if( LmHandlerCallbacks->OnClassChange != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnClassChange( newClass );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errorStatus = LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case CLASS_B:
|
|
{
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
if( currentClass != CLASS_A )
|
|
{
|
|
errorStatus = LORAMAC_HANDLER_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* Beacon must first be acquired */
|
|
errorStatus = LmHandlerDeviceTimeReq( );
|
|
IsClassBSwitchPending = true;
|
|
}
|
|
#else /* LORAMAC_CLASSB_ENABLED == 0 */
|
|
errorStatus = LORAMAC_HANDLER_ERROR;
|
|
#endif /* LORAMAC_CLASSB_ENABLED */
|
|
}
|
|
break;
|
|
case CLASS_C:
|
|
{
|
|
if( currentClass != CLASS_A )
|
|
{
|
|
errorStatus = LORAMAC_HANDLER_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* Switch is instantaneous */
|
|
mibReq.Param.Class = newClass;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
|
|
{
|
|
if( LmHandlerCallbacks->OnClassChange != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnClassChange( newClass );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errorStatus = LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return errorStatus;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetCurrentClass( DeviceClass_t *deviceClass )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
if( deviceClass == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
mibReq.Type = MIB_DEVICE_CLASS;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
*deviceClass = mibReq.Param.Class;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetTxDatarate( int8_t *txDatarate )
|
|
{
|
|
MibRequestConfirm_t mibGet;
|
|
if( txDatarate == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
mibGet.Type = MIB_CHANNELS_DATARATE;
|
|
if( LoRaMacMibGetRequestConfirm( &mibGet ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
*txDatarate = mibGet.Param.ChannelsDatarate;
|
|
LmHandlerParams.TxDatarate = *txDatarate;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetActiveRegion( LoRaMacRegion_t *region )
|
|
{
|
|
if( region == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
*region = LmHandlerParams.ActiveRegion;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetSystemMaxRxError( uint32_t maxErrorInMs )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
mibReq.Type = MIB_SYSTEM_MAX_RX_ERROR;
|
|
mibReq.Param.SystemMaxRxError = maxErrorInMs;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*=============================================================================
|
|
* LORAMAC NOTIFICATIONS HANDLING
|
|
*=============================================================================
|
|
*/
|
|
|
|
static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
|
|
{
|
|
TxParams.IsMcpsConfirm = 1;
|
|
TxParams.Status = mcpsConfirm->Status;
|
|
TxParams.Datarate = mcpsConfirm->Datarate;
|
|
TxParams.UplinkCounter = mcpsConfirm->UpLinkCounter;
|
|
TxParams.TxPower = mcpsConfirm->TxPower;
|
|
TxParams.Channel = mcpsConfirm->Channel;
|
|
TxParams.AckReceived = mcpsConfirm->AckReceived;
|
|
|
|
if( LmHandlerCallbacks->OnTxData != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnTxData( &TxParams );
|
|
}
|
|
|
|
LmHandlerPackagesNotify( PACKAGE_MCPS_CONFIRM, mcpsConfirm );
|
|
}
|
|
|
|
static void McpsIndication( McpsIndication_t *mcpsIndication, LoRaMacRxStatus_t *rxStatus )
|
|
{
|
|
LmHandlerAppData_t appData;
|
|
DeviceClass_t deviceClass = CLASS_A;
|
|
RxParams.IsMcpsIndication = 1;
|
|
RxParams.Status = mcpsIndication->Status;
|
|
|
|
if( RxParams.Status != LORAMAC_EVENT_INFO_STATUS_OK )
|
|
{
|
|
return;
|
|
}
|
|
|
|
RxParams.Datarate = mcpsIndication->RxDatarate;
|
|
RxParams.Rssi = rxStatus->Rssi;
|
|
RxParams.Snr = rxStatus->Snr;
|
|
RxParams.RxSlot = rxStatus->RxSlot;
|
|
RxParams.DownlinkCounter = mcpsIndication->DownLinkCounter;
|
|
|
|
appData.Port = mcpsIndication->Port;
|
|
appData.BufferSize = mcpsIndication->BufferSize;
|
|
appData.Buffer = mcpsIndication->Buffer;
|
|
|
|
if( LmHandlerCallbacks->OnRxData != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnRxData( &appData, &RxParams );
|
|
}
|
|
|
|
if( ( LmHandlerCallbacks->OnSysTimeUpdate != NULL ) && ( mcpsIndication->DeviceTimeAnsReceived == true ) )
|
|
{
|
|
LmHandlerCallbacks->OnSysTimeUpdate( );
|
|
}
|
|
/* Call packages RxProcess function */
|
|
LmHandlerPackagesNotify( PACKAGE_MCPS_INDICATION, mcpsIndication );
|
|
|
|
LmHandlerGetCurrentClass( &deviceClass );
|
|
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
|
|
if( mcpsIndication->IsUplinkTxPending != 0 )
|
|
{
|
|
/* The server signals that it has pending data to be sent. */
|
|
/* We schedule an uplink as soon as possible to flush the server. */
|
|
|
|
/* Send an empty message */
|
|
LmHandlerAppData_t appData =
|
|
{
|
|
.Buffer = NULL,
|
|
.BufferSize = 0,
|
|
.Port = 0
|
|
};
|
|
LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG, true );
|
|
}
|
|
#elif (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
if( mcpsIndication->IsUplinkTxPending != 0 )
|
|
{
|
|
/* The server signals that it has pending data to be sent. */
|
|
/* We schedule an uplink as soon as possible to flush the server. */
|
|
IsUplinkTxPending = true;
|
|
}
|
|
#endif /* LORAMAC_VERSION */
|
|
}
|
|
|
|
static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm )
|
|
{
|
|
TxParams.IsMcpsConfirm = 0;
|
|
TxParams.Status = mlmeConfirm->Status;
|
|
if( LmHandlerCallbacks->OnTxData != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnTxData( &TxParams );
|
|
}
|
|
|
|
LmHandlerPackagesNotify( PACKAGE_MLME_CONFIRM, mlmeConfirm );
|
|
|
|
switch( mlmeConfirm->MlmeRequest )
|
|
{
|
|
case MLME_JOIN:
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
mibReq.Type = MIB_DEV_ADDR;
|
|
LoRaMacMibGetRequestConfirm( &mibReq );
|
|
if( SecureElementSetDevAddr( JoinParams.Mode, mibReq.Param.DevAddr ) == SECURE_ELEMENT_SUCCESS )
|
|
{
|
|
CommissioningParams.DevAddr = mibReq.Param.DevAddr;
|
|
}
|
|
LmHandlerGetTxDatarate( &JoinParams.Datarate );
|
|
LmHandlerGetTxPower( &JoinParams.TxPower );
|
|
|
|
if( TxParams.Status == LORAMAC_EVENT_INFO_STATUS_OK )
|
|
{
|
|
/* Status is OK, node has joined the network */
|
|
JoinParams.Status = LORAMAC_HANDLER_SUCCESS;
|
|
LmHandlerRequestClass( LmHandlerParams.DefaultClass );
|
|
}
|
|
else
|
|
{
|
|
/* Join was not successful. Try to join again */
|
|
JoinParams.Status = LORAMAC_HANDLER_ERROR;
|
|
}
|
|
/* Notify upper layer */
|
|
if( LmHandlerCallbacks->OnJoinRequest != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnJoinRequest( &JoinParams );
|
|
}
|
|
if( TxParams.Status == LORAMAC_EVENT_INFO_STATUS_OK )
|
|
{
|
|
SecureElementPrintSessionKeys( JoinParams.Mode );
|
|
}
|
|
}
|
|
break;
|
|
case MLME_LINK_CHECK:
|
|
{
|
|
RxParams.LinkCheck = true;
|
|
RxParams.DemodMargin = mlmeConfirm->DemodMargin;
|
|
RxParams.NbGateways = mlmeConfirm->NbGateways;
|
|
}
|
|
break;
|
|
case MLME_DEVICE_TIME:
|
|
{
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
if( IsClassBSwitchPending == true )
|
|
{
|
|
LmHandlerBeaconReq( );
|
|
}
|
|
#endif /* LORAMAC_CLASSB_ENABLED == 1 */
|
|
}
|
|
break;
|
|
case MLME_BEACON_ACQUISITION:
|
|
{
|
|
if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
|
|
{
|
|
/* Beacon has been acquired */
|
|
/* Request server for ping slot */
|
|
LmHandlerPingSlotReq( LmHandlerParams.PingSlotPeriodicity );
|
|
}
|
|
else
|
|
{
|
|
/* Beacon not acquired */
|
|
/* Request Device Time again. */
|
|
LmHandlerDeviceTimeReq( );
|
|
}
|
|
}
|
|
break;
|
|
case MLME_PING_SLOT_INFO:
|
|
{
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
/* Class B is now activated */
|
|
mibReq.Type = MIB_DEVICE_CLASS;
|
|
mibReq.Param.Class = CLASS_B;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
/* Notify upper layer */
|
|
if( LmHandlerCallbacks->OnClassChange != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnClassChange( CLASS_B );
|
|
}
|
|
IsClassBSwitchPending = false;
|
|
}
|
|
else
|
|
{
|
|
LmHandlerPingSlotReq( LmHandlerParams.PingSlotPeriodicity );
|
|
}
|
|
#endif /* LORAMAC_CLASSB_ENABLED == 1 */
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void MlmeIndication( MlmeIndication_t *mlmeIndication, LoRaMacRxStatus_t *rxStatus )
|
|
{
|
|
RxParams.IsMcpsIndication = 0;
|
|
RxParams.Status = mlmeIndication->Status;
|
|
RxParams.Datarate = mlmeIndication->RxDatarate;
|
|
RxParams.Rssi = rxStatus->Rssi;
|
|
RxParams.Snr = rxStatus->Snr;
|
|
RxParams.RxSlot = rxStatus->RxSlot;
|
|
RxParams.DownlinkCounter = mlmeIndication->DownLinkCounter;
|
|
if( ( LmHandlerCallbacks->OnRxData != NULL ) && ( mlmeIndication->MlmeIndication != MLME_BEACON ) && ( mlmeIndication->MlmeIndication != MLME_BEACON_LOST ) )
|
|
{
|
|
LmHandlerCallbacks->OnRxData( NULL, &RxParams );
|
|
}
|
|
|
|
/* Call packages RxProcess function */
|
|
LmHandlerPackagesNotify( PACKAGE_MLME_INDICATION, mlmeIndication );
|
|
|
|
switch( mlmeIndication->MlmeIndication )
|
|
{
|
|
case MLME_BEACON_LOST:
|
|
{
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
MibRequestConfirm_t mibReq;
|
|
/* Switch to class A again */
|
|
mibReq.Type = MIB_DEVICE_CLASS;
|
|
mibReq.Param.Class = CLASS_A;
|
|
LoRaMacMibSetRequestConfirm( &mibReq );
|
|
|
|
BeaconParams.State = LORAMAC_HANDLER_BEACON_LOST;
|
|
BeaconParams.Info.Time.Seconds = 0;
|
|
BeaconParams.Info.GwSpecific.InfoDesc = 0;
|
|
memset1( BeaconParams.Info.GwSpecific.Info, 0, 6 );
|
|
|
|
if( LmHandlerCallbacks->OnClassChange != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnClassChange( CLASS_A );
|
|
}
|
|
if( LmHandlerCallbacks->OnBeaconStatusChange != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams );
|
|
}
|
|
|
|
LmHandlerDeviceTimeReq( );
|
|
#endif /* LORAMAC_CLASSB_ENABLED == 1 */
|
|
}
|
|
break;
|
|
case MLME_BEACON:
|
|
{
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
if( mlmeIndication->Status == LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED )
|
|
{
|
|
BeaconParams.State = LORAMAC_HANDLER_BEACON_RX;
|
|
BeaconParams.Info = mlmeIndication->BeaconInfo;
|
|
|
|
if( LmHandlerCallbacks->OnBeaconStatusChange != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams );
|
|
}
|
|
}
|
|
else if( mlmeIndication->Status == LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND )
|
|
{
|
|
BeaconParams.State = LORAMAC_HANDLER_BEACON_NRX;
|
|
BeaconParams.Info = mlmeIndication->BeaconInfo;
|
|
|
|
if( LmHandlerCallbacks->OnBeaconStatusChange != NULL )
|
|
{
|
|
LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams );
|
|
}
|
|
}
|
|
#endif /* LORAMAC_CLASSB_ENABLED == 1 */
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
*=============================================================================
|
|
* PACKAGES HANDLING
|
|
*=============================================================================
|
|
*/
|
|
|
|
LmHandlerErrorStatus_t LmHandlerPackageRegister( uint8_t id, void *params )
|
|
{
|
|
LmhPackage_t *package = NULL;
|
|
switch( id )
|
|
{
|
|
case PACKAGE_ID_COMPLIANCE:
|
|
{
|
|
package = LmhpCompliancePackageFactory( );
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
if( LORAMAC_HANDLER_SUCCESS != LmhpPackagesRegister( id, &package ) )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if( package != NULL )
|
|
{
|
|
LmHandlerPackages[id] = package;
|
|
LmHandlerPackages[id]->OnJoinRequest = LmHandlerJoin;
|
|
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
|
|
LmHandlerPackages[id]->OnSendRequest = LmHandlerSend;
|
|
#elif (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
LmHandlerPackages[id]->OnSysTimeUpdate = LmHandlerCallbacks->OnSysTimeUpdate;
|
|
LmHandlerPackages[id]->OnSystemReset = LmHandlerCallbacks->OnSystemReset;
|
|
#endif /* LORAMAC_VERSION */
|
|
LmHandlerPackages[id]->OnDeviceTimeRequest = LmHandlerDeviceTimeReq;
|
|
LmHandlerPackages[id]->OnPackageProcessEvent = LmHandlerCallbacks->OnMacProcess;
|
|
LmHandlerPackages[id]->Init( params, AppData.Buffer, AppData.BufferSize );
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
|
|
static bool LmHandlerPackageIsInitialized( uint8_t id )
|
|
{
|
|
if( ( id < PKG_MAX_NUMBER ) && ( LmHandlerPackages[id]->IsInitialized != NULL ) )
|
|
{
|
|
return LmHandlerPackages[id]->IsInitialized( );
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static void LmHandlerPackagesNotify( PackageNotifyTypes_t notifyType, void *params )
|
|
{
|
|
for( int8_t i = 0; i < PKG_MAX_NUMBER; i++ )
|
|
{
|
|
if( LmHandlerPackages[i] != NULL )
|
|
{
|
|
switch( notifyType )
|
|
{
|
|
case PACKAGE_MCPS_CONFIRM:
|
|
{
|
|
if( LmHandlerPackages[i]->OnMcpsConfirmProcess != NULL )
|
|
{
|
|
LmHandlerPackages[i]->OnMcpsConfirmProcess( ( McpsConfirm_t * ) params );
|
|
}
|
|
break;
|
|
}
|
|
case PACKAGE_MCPS_INDICATION:
|
|
{
|
|
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
|
|
if( ( LmHandlerPackages[i]->OnMcpsIndicationProcess != NULL ) &&
|
|
( ( LmHandlerPackages[i]->Port == ( ( McpsIndication_t * )params )->Port ) ||
|
|
( ( i == PACKAGE_ID_COMPLIANCE ) && ( LmHandlerPackages[PACKAGE_ID_COMPLIANCE]->IsRunning() ) ) ) )
|
|
#elif (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
if( LmHandlerPackages[i]->OnMcpsIndicationProcess != NULL )
|
|
#endif /* LORAMAC_VERSION */
|
|
{
|
|
LmHandlerPackages[i]->OnMcpsIndicationProcess( ( McpsIndication_t * )params );
|
|
}
|
|
break;
|
|
}
|
|
case PACKAGE_MLME_CONFIRM:
|
|
{
|
|
if( LmHandlerPackages[i]->OnMlmeConfirmProcess != NULL )
|
|
{
|
|
LmHandlerPackages[i]->OnMlmeConfirmProcess( ( MlmeConfirm_t * )params );
|
|
}
|
|
break;
|
|
}
|
|
case PACKAGE_MLME_INDICATION:
|
|
{
|
|
if( LmHandlerPackages[i]->OnMlmeIndicationProcess != NULL )
|
|
{
|
|
LmHandlerPackages[i]->OnMlmeIndicationProcess( params );
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool LmHandlerPackageIsTxPending( void )
|
|
{
|
|
for( int8_t i = 0; i < PKG_MAX_NUMBER; i++ )
|
|
{
|
|
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
|
|
if( ( LmHandlerPackages[i] != NULL ) && ( i != PACKAGE_ID_COMPLIANCE ) )
|
|
#else
|
|
if( LmHandlerPackages[i] != NULL )
|
|
#endif /* LORAMAC_VERSION */
|
|
{
|
|
if( LmHandlerPackages[i]->IsTxPending( ) == true )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void LmHandlerPackagesProcess( void )
|
|
{
|
|
for( int8_t i = 0; i < PKG_MAX_NUMBER; i++ )
|
|
{
|
|
if( ( LmHandlerPackages[i] != NULL ) &&
|
|
( LmHandlerPackages[i]->Process != NULL ) &&
|
|
( LmHandlerPackageIsInitialized( i ) != false ) )
|
|
{
|
|
LmHandlerPackages[i]->Process( );
|
|
}
|
|
}
|
|
}
|
|
|
|
#if (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 )))
|
|
static void LmHandlerOnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed )
|
|
{
|
|
LmHandlerParams.IsTxConfirmed = isTxConfirmed;
|
|
|
|
if (LmHandlerCallbacks->OnTxFrameCtrlChanged != NULL)
|
|
{
|
|
LmHandlerCallbacks->OnTxFrameCtrlChanged( isTxConfirmed );
|
|
}
|
|
}
|
|
|
|
static void LmHandlerOnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity )
|
|
{
|
|
LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity;
|
|
|
|
if (LmHandlerCallbacks->OnPingSlotPeriodicityChanged != NULL)
|
|
{
|
|
LmHandlerCallbacks->OnPingSlotPeriodicityChanged( pingSlotPeriodicity );
|
|
}
|
|
}
|
|
#endif /* LORAMAC_VERSION */
|
|
|
|
/*
|
|
*=============================================================================
|
|
* ST ADDITIONAL FUNCTIONS
|
|
*=============================================================================
|
|
*/
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetVersion( LmHandlerVersionType_t lmhType, uint32_t *featureVersion )
|
|
{
|
|
if( featureVersion == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
switch( lmhType )
|
|
{
|
|
case LORAMAC_HANDLER_L2_VERSION:
|
|
*featureVersion = LORAMAC_VERSION;
|
|
break;
|
|
case LORAMAC_HANDLER_REGION_VERSION:
|
|
*featureVersion = REGION_VERSION;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerStop( void )
|
|
{
|
|
if( LoRaMacDeInitialization() == LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
return LORAMAC_HANDLER_BUSY_ERROR;
|
|
}
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerHalt( void )
|
|
{
|
|
if( LoRaMacHalt() == LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
return LORAMAC_HANDLER_BUSY_ERROR;
|
|
}
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerLinkCheckReq( void )
|
|
{
|
|
LoRaMacStatus_t status;
|
|
MlmeReq_t mlmeReq;
|
|
|
|
mlmeReq.Type = MLME_LINK_CHECK;
|
|
|
|
status = LoRaMacMlmeRequest( &mlmeReq );
|
|
|
|
if( status == LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetDevEUI( uint8_t *devEUI )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
if( devEUI == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
mibReq.Type = MIB_DEV_EUI;
|
|
mibReq.Param.DevEui = devEUI;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetDevEUI( uint8_t *devEUI )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
/* Not yet joined */
|
|
if( LmHandlerJoinStatus() != LORAMAC_HANDLER_SET )
|
|
{
|
|
mibReq.Type = MIB_DEV_EUI;
|
|
mibReq.Param.DevEui = devEUI;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Cannot change Keys in running state */
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetAppEUI( uint8_t *appEUI )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
if( appEUI == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
mibReq.Type = MIB_JOIN_EUI;
|
|
mibReq.Param.JoinEui = appEUI;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetAppEUI( uint8_t *appEUI )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
/* Not yet joined */
|
|
if( LmHandlerJoinStatus() != LORAMAC_HANDLER_SET )
|
|
{
|
|
mibReq.Type = MIB_JOIN_EUI;
|
|
mibReq.Param.JoinEui = appEUI;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Cannot change Keys in running state */
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetNetworkID( uint32_t *networkId )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
if( networkId == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
mibReq.Type = MIB_NET_ID;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
*networkId = mibReq.Param.NetID;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetNetworkID( uint32_t networkId )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
/* Not yet joined */
|
|
if( LmHandlerJoinStatus() != LORAMAC_HANDLER_SET )
|
|
{
|
|
mibReq.Type = MIB_NET_ID;
|
|
mibReq.Param.NetID = networkId;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Cannot change NetworkID in running state */
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetDevAddr( uint32_t *devAddr )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
if( devAddr == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
mibReq.Type = MIB_DEV_ADDR;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
*devAddr = mibReq.Param.DevAddr;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetDevAddr( uint32_t devAddr )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
/* Not yet joined */
|
|
if( LmHandlerJoinStatus() != LORAMAC_HANDLER_SET )
|
|
{
|
|
mibReq.Type = MIB_DEV_ADDR;
|
|
mibReq.Param.DevAddr = devAddr;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Cannot change DevAddr in running state */
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetActiveRegion( LoRaMacRegion_t region )
|
|
{
|
|
/* Not yet joined */
|
|
if( LmHandlerJoinStatus() != LORAMAC_HANDLER_SET )
|
|
{
|
|
LmHandlerParams.ActiveRegion = region;
|
|
return LmHandlerConfigure( &LmHandlerParams );
|
|
}
|
|
else
|
|
{
|
|
/* Cannot change Region in running state */
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetAdrEnable( bool *adrEnable )
|
|
{
|
|
if( adrEnable == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
*adrEnable = LmHandlerParams.AdrEnable;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetAdrEnable( bool adrEnable )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
mibReq.Type = MIB_ADR;
|
|
mibReq.Param.AdrEnable = adrEnable;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
LmHandlerParams.AdrEnable = adrEnable;
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetTxDatarate( int8_t txDatarate )
|
|
{
|
|
if( LmHandlerParams.AdrEnable == true )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
MibRequestConfirm_t mibReq;
|
|
mibReq.Type = MIB_CHANNELS_DATARATE;
|
|
mibReq.Param.ChannelsDatarate = txDatarate;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
LmHandlerParams.TxDatarate = txDatarate;
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetDutyCycleEnable( bool *dutyCycleEnable )
|
|
{
|
|
if( dutyCycleEnable == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
*dutyCycleEnable = LmHandlerParams.DutyCycleEnabled;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetDutyCycleEnable( bool dutyCycleEnable )
|
|
{
|
|
LmHandlerParams.DutyCycleEnabled = dutyCycleEnable;
|
|
LoRaMacTestSetDutyCycleOn( dutyCycleEnable );
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetRX2Params( RxChannelParams_t *rxParams )
|
|
{
|
|
if( rxParams == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
mibReq.Type = MIB_RX2_CHANNEL;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
rxParams->Frequency = mibReq.Param.Rx2Channel.Frequency;
|
|
rxParams->Datarate = mibReq.Param.Rx2Channel.Datarate;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetTxPower( int8_t *txPower )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
if( txPower == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
mibReq.Type = MIB_CHANNELS_TX_POWER;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
*txPower = mibReq.Param.ChannelsTxPower;
|
|
LmHandlerParams.TxPower = *txPower;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetRx1Delay( uint32_t *rxDelay )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
if( rxDelay == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
mibReq.Type = MIB_RECEIVE_DELAY_1;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
*rxDelay = mibReq.Param.ReceiveDelay1;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetRx2Delay( uint32_t *rxDelay )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
if( rxDelay == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
mibReq.Type = MIB_RECEIVE_DELAY_2;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
*rxDelay = mibReq.Param.ReceiveDelay2;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetJoinRx1Delay( uint32_t *rxDelay )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
if( rxDelay == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
mibReq.Type = MIB_JOIN_ACCEPT_DELAY_1;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
*rxDelay = mibReq.Param.JoinAcceptDelay1;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetJoinRx2Delay( uint32_t *rxDelay )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
if( rxDelay == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
mibReq.Type = MIB_JOIN_ACCEPT_DELAY_2;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
*rxDelay = mibReq.Param.JoinAcceptDelay2;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetTxPower( int8_t txPower )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
mibReq.Type = MIB_CHANNELS_TX_POWER;
|
|
mibReq.Param.ChannelsTxPower = txPower;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
LmHandlerParams.TxPower = txPower;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetRX2Params( RxChannelParams_t *rxParams )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
mibReq.Type = MIB_RX2_CHANNEL;
|
|
mibReq.Param.Rx2Channel.Frequency = rxParams->Frequency;
|
|
mibReq.Param.Rx2Channel.Datarate = rxParams->Datarate;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetRx1Delay( uint32_t rxDelay )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
mibReq.Type = MIB_RECEIVE_DELAY_1;
|
|
mibReq.Param.ReceiveDelay1 = rxDelay;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetRx2Delay( uint32_t rxDelay )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
mibReq.Type = MIB_RECEIVE_DELAY_2;
|
|
mibReq.Param.ReceiveDelay2 = rxDelay;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetJoinRx1Delay( uint32_t rxDelay )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
mibReq.Type = MIB_JOIN_ACCEPT_DELAY_1;
|
|
mibReq.Param.JoinAcceptDelay1 = rxDelay;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetJoinRx2Delay( uint32_t rxDelay )
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
mibReq.Type = MIB_JOIN_ACCEPT_DELAY_2;
|
|
mibReq.Param.JoinAcceptDelay2 = rxDelay;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetPingPeriodicity( uint8_t *pingPeriodicity )
|
|
{
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
if( pingPeriodicity == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
*pingPeriodicity = LmHandlerParams.PingSlotPeriodicity;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
#else /* LORAMAC_CLASSB_ENABLED == 0 */
|
|
return LORAMAC_HANDLER_ERROR;
|
|
#endif /* LORAMAC_CLASSB_ENABLED */
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetPingPeriodicity( uint8_t pingPeriodicity )
|
|
{
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
/* Not yet joined */
|
|
if( LmHandlerJoinStatus() != LORAMAC_HANDLER_SET )
|
|
{
|
|
LmHandlerParams.PingSlotPeriodicity = pingPeriodicity;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Cannot change Region in running state */
|
|
return LmHandlerPingSlotReq( pingPeriodicity );
|
|
}
|
|
#else /* LORAMAC_CLASSB_ENABLED == 0 */
|
|
return LORAMAC_HANDLER_ERROR;
|
|
#endif /* LORAMAC_CLASSB_ENABLED */
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetBeaconState( BeaconState_t *beaconState )
|
|
{
|
|
#if ( LORAMAC_CLASSB_ENABLED == 1 )
|
|
MibRequestConfirm_t mibReq;
|
|
|
|
if( beaconState == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
mibReq.Type = MIB_BEACON_STATE;
|
|
if( LoRaMacMibGetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
*beaconState = mibReq.Param.BeaconState;
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
#else /* LORAMAC_CLASSB_ENABLED == 0 */
|
|
return LORAMAC_HANDLER_ERROR;
|
|
#endif /* LORAMAC_CLASSB_ENABLED */
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerGetKey( KeyIdentifier_t keyID, uint8_t *key )
|
|
{
|
|
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
|
|
Key_t *keyItem;
|
|
#endif /* LORAWAN_KMS */
|
|
|
|
if( key == NULL )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
|
|
if( SECURE_ELEMENT_SUCCESS != SecureElementGetKeyByID( keyID, &keyItem ) )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
memcpy1( key, keyItem->KeyValue, 16 );
|
|
#else
|
|
if( SECURE_ELEMENT_SUCCESS != SecureElementGetKeyByID( keyID, key ) )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
#endif /* LORAWAN_KMS */
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerSetKey( KeyIdentifier_t keyID, uint8_t *key )
|
|
{
|
|
/* Not yet joined */
|
|
if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET )
|
|
{
|
|
if( keyID == APP_KEY ) /* Specific usage because APP_KEY is used to derive other keys */
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
mibReq.Type = MIB_APP_KEY;
|
|
mibReq.Param.AppKey = key;
|
|
if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
else if( SECURE_ELEMENT_SUCCESS != SecureElementSetKey( keyID, key ) )
|
|
{
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Cannot change Keys in running state */
|
|
return LORAMAC_HANDLER_ERROR;
|
|
}
|
|
|
|
return LORAMAC_HANDLER_SUCCESS;
|
|
}
|
|
|
|
LmHandlerErrorStatus_t LmHandlerNvmDataStore( void )
|
|
{
|
|
#if (defined( CONTEXT_MANAGEMENT_ENABLED ) && ( CONTEXT_MANAGEMENT_ENABLED == 1 ))
|
|
LoRaMacNvmData_t *nvm;
|
|
uint32_t nvm_size;
|
|
LmHandlerErrorStatus_t lmhStatus = LORAMAC_HANDLER_SUCCESS;
|
|
int32_t status = NVM_DATA_OK;
|
|
|
|
lmhStatus = LmHandlerHalt();
|
|
|
|
if( lmhStatus == LORAMAC_HANDLER_SUCCESS )
|
|
{
|
|
status = NvmDataMgmtStoreBegin();
|
|
|
|
if( status == NVM_DATA_NO_UPDATED_DATA )
|
|
{
|
|
lmhStatus = LORAMAC_HANDLER_NVM_DATA_UP_TO_DATE;
|
|
}
|
|
else if( ( status != NVM_DATA_OK ) || ( LmHandlerCallbacks->OnStoreContextRequest == NULL ) )
|
|
{
|
|
lmhStatus = LORAMAC_HANDLER_ERROR;
|
|
}
|
|
else
|
|
{
|
|
MibRequestConfirm_t mibReq;
|
|
mibReq.Type = MIB_NVM_CTXS;
|
|
LoRaMacMibGetRequestConfirm( &mibReq );
|
|
nvm = ( LoRaMacNvmData_t * )mibReq.Param.Contexts;
|
|
nvm_size = ( ( sizeof( LoRaMacNvmData_t ) + 7 ) & ~0x07 );
|
|
LmHandlerCallbacks->OnStoreContextRequest( nvm, nvm_size );
|
|
}
|
|
|
|
if( NvmDataMgmtStoreEnd() != NVM_DATA_OK )
|
|
{
|
|
lmhStatus = LORAMAC_HANDLER_ERROR;
|
|
}
|
|
}
|
|
|
|
if( ( lmhStatus == LORAMAC_HANDLER_SUCCESS ) && ( LmHandlerCallbacks->OnNvmDataChange != NULL ) )
|
|
{
|
|
LmHandlerCallbacks->OnNvmDataChange( LORAMAC_HANDLER_NVM_STORE );
|
|
}
|
|
|
|
return lmhStatus;
|
|
#else
|
|
return LORAMAC_HANDLER_ERROR;
|
|
#endif /* CONTEXT_MANAGEMENT_ENABLED */
|
|
}
|