STM32CubeWL/Middlewares/Third_Party/LoRaWAN/LmHandler/LmHandler.c

2235 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 */
#if (!defined (LORAWAN_DATA_DISTRIB_MGT) || (LORAWAN_DATA_DISTRIB_MGT == 0))
#else /* LORAWAN_DATA_DISTRIB_MGT == 1 */
#include "LmhpPackagesRegistration.h"
#endif /* LORAWAN_DATA_DISTRIB_MGT */
/* 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
.NetworkId = LORAWAN_NETWORK_ID,
.DevAddr = LORAWAN_DEVICE_ADDRESS,
};
#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 ))
/*!
* 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,
.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 ))
/*!
* 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 )
/*!
* 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 */
/*!
* 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 );
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
static bool LmHandlerPackageIsTxPending( void );
#endif /* LORAMAC_VERSION */
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);
/* 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.NvmDataChange = NvmDataMgmtEvent;
LoRaMacCallbacks.MacProcessNotify = LmHandlerCallbacks->OnMacProcess;
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
LmhpComplianceParams.FwVersion.Value = fwVersion;
LmhpComplianceParams.OnTxPeriodicityChanged = LmHandlerCallbacks->OnTxPeriodicityChanged;
LmhpComplianceParams.OnTxFrameCtrlChanged = LmHandlerCallbacks->OnTxFrameCtrlChanged;
LmhpComplianceParams.OnPingSlotPeriodicityChanged = LmHandlerCallbacks->OnPingSlotPeriodicityChanged;
#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 (!defined (LORAWAN_DATA_DISTRIB_MGT) || (LORAWAN_DATA_DISTRIB_MGT == 0))
#else /*LORAWAN_DATA_DISTRIB_MGT == 1*/
if (LmhpPackagesRegistrationInit() != LORAMAC_HANDLER_SUCCESS)
{
return LORAMAC_HANDLER_ERROR;
}
#endif /*LORAWAN_DATA_DISTRIB_MGT*/
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;
UTIL_MEM_cpy_8((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 ))
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;
}
// 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 );
}
mibReq.Type = MIB_DEV_ADDR;
LoRaMacMibGetRequestConfirm( &mibReq );
CommissioningParams.DevAddr = mibReq.Param.DevAddr;
mibReq.Type = MIB_NVM_CTXS;
LoRaMacMibGetRequestConfirm( &mibReq );
LmHandlerParams.ActiveRegion = mibReq.Param.Contexts->MacGroup2.Region;
LmHandlerParams.DefaultClass = mibReq.Param.Contexts->MacGroup2.DeviceClass;
LmHandlerParams.AdrEnable = mibReq.Param.Contexts->MacGroup2.AdrCtrlOn;
}
else
{
mibReq.Type = MIB_NET_ID;
mibReq.Param.NetID = LORAWAN_NETWORK_ID;
LoRaMacMibSetRequestConfirm(&mibReq);
#if ( STATIC_DEVICE_ADDRESS != 1 )
CommissioningParams.DevAddr = LmHandlerCallbacks->GetDevAddr();
#endif /* STATIC_DEVICE_ADDRESS != 1 */
mibReq.Type = MIB_DEV_ADDR;
mibReq.Param.DevAddr = CommissioningParams.DevAddr;
LoRaMacMibSetRequestConfirm(&mibReq);
}
// Read secure-element DEV_EUI and JOIN_EUI values.
mibReq.Type = MIB_DEV_EUI;
LoRaMacMibGetRequestConfirm( &mibReq );
memcpy1( CommissioningParams.DevEui, mibReq.Param.DevEui, 8 );
mibReq.Type = MIB_JOIN_EUI;
LoRaMacMibGetRequestConfirm( &mibReq );
memcpy1( CommissioningParams.JoinEui, mibReq.Param.JoinEui, 8 );
SecureElementPrintKeys();
MW_LOG(TS_OFF, VLEVEL_M, "###### DevAddr: %02X:%02X:%02X:%02X\r\n",
(unsigned)((unsigned char *)(&CommissioningParams.DevAddr))[3],
(unsigned)((unsigned char *)(&CommissioningParams.DevAddr))[2],
(unsigned)((unsigned char *)(&CommissioningParams.DevAddr))[1],
(unsigned)((unsigned char *)(&CommissioningParams.DevAddr))[0]);
#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;
}
#elif (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
if( LmHandlerPackageIsTxPending( ) == true )
{
return true;
}
#endif /* LORAMAC_VERSION */
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( );
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
// Check if a package transmission is pending.
// If it is the case exit function earlier
if( LmHandlerPackageIsTxPending( ) == true )
{
return;
}
// 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;
}
void LmHandlerJoin( ActivationType_t mode, bool forceRejoin )
{
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
#else /* LORAWAN_KMS == 1 */
#if (OVER_THE_AIR_ACTIVATION == 0)
if ( mode == ACTIVATION_TYPE_OTAA )
{
MW_LOG(TS_OFF, VLEVEL_M, "ERROR: OTAA mode not implemented\r\n");
while (1);
}
#endif /* OVER_THE_AIR_ACTIVATION */
#if (ACTIVATION_BY_PERSONALIZATION == 0)
if ( mode == ACTIVATION_TYPE_ABP )
{
MW_LOG(TS_OFF, VLEVEL_M, "ERROR: ABP mode not implemented\r\n");
while (1);
}
#endif /* ACTIVATION_BY_PERSONALIZATION */
#endif /* LORAWAN_KMS */
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_JOIN;
mlmeReq.Req.Join.Datarate = LmHandlerParams.TxDatarate;
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
LoRaMacMlmeRequest( &mlmeReq );
#endif /* LORAMAC_VERSION */
}
else
{
MibRequestConfirm_t mibReq;
mlmeReq.Req.Join.NetworkActivation = ACTIVATION_TYPE_ABP;
JoinParams.Mode = ACTIVATION_TYPE_ABP;
JoinParams.Datarate = LmHandlerParams.TxDatarate;
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 );
/* 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);
#if (defined (LORAWAN_KMS) && (LORAWAN_KMS == 1))
#if ( USE_LRWAN_1_1_X_CRYPTO == 1 )
SecureElementSetObjHandler(F_NWK_S_INT_KEY, KMS_F_NWK_S_INT_KEY_OBJECT_HANDLE);
SecureElementSetObjHandler(S_NWK_S_INT_KEY, KMS_S_NWK_S_INT_KEY_OBJECT_HANDLE);
SecureElementSetObjHandler(NWK_S_ENC_KEY, KMS_NWK_S_ENC_KEY_OBJECT_HANDLE);
#else /* USE_LRWAN_1_1_X_CRYPTO == 0 */
SecureElementSetObjHandler(NWK_S_KEY, KMS_NWK_S_KEY_OBJECT_HANDLE);
#endif /* USE_LRWAN_1_1_X_CRYPTO */
SecureElementSetObjHandler(APP_S_KEY, KMS_APP_S_KEY_OBJECT_HANDLE);
#endif /* LORAWAN_KMS == 1 */
}
LoRaMacStart();
mibReq.Type = MIB_NETWORK_ACTIVATION;
mibReq.Param.NetworkActivation = ACTIVATION_TYPE_ABP;
LoRaMacMibSetRequestConfirm( &mibReq );
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
// Notify upper layer
LmHandlerCallbacks->OnJoinRequest( &JoinParams );
LmHandlerRequestClass(LmHandlerParams.DefaultClass);
#endif
}
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
if ((CtxRestoreDone == false) || (forceRejoin == true))
{
// Starts the join procedure
LoRaMacMlmeRequest( &mlmeReq );
}
DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
#endif /* LORAMAC_VERSION */
}
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( 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 ))
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;
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;
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->FramePending == true) && (deviceClass == CLASS_A))
{
// 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 ))
if ( ( mcpsIndication->FramePending == true ) && ( deviceClass == CLASS_A ) )
{
// 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;
LmHandlerCallbacks->OnTxData( &TxParams );
LmHandlerPackagesNotify( PACKAGE_MLME_CONFIRM, mlmeConfirm );
switch( mlmeConfirm->MlmeRequest )
{
case MLME_JOIN:
{
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_DEV_ADDR;
LoRaMacMibGetRequestConfirm( &mibReq );
CommissioningParams.DevAddr = mibReq.Param.DevAddr;
LmHandlerGetTxDatarate( &JoinParams.Datarate );
if( mlmeConfirm->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
LmHandlerCallbacks->OnJoinRequest( &JoinParams );
if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
{
SecureElementPrintSessionKeys();
}
}
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 ((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_SCHEDULE_UPLINK:
{
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 ))
// The MAC signals that we shall provide an uplink as soon as possible
// Send an empty message
LmHandlerAppData_t appData =
{
.Buffer = NULL,
.BufferSize = 0,
.Port = 0
};
if( LmHandlerPackages[PACKAGE_ID_COMPLIANCE]->IsRunning( ) == false )
{
LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG, true );
}
#elif (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
// The MAC layer signals that we shall provide an uplink as soon as possible
IsUplinkTxPending = true;
#endif /* LORAMAC_VERSION */
}
break;
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;
UTIL_MEM_set_8( 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 (!defined (LORAWAN_DATA_DISTRIB_MGT) || (LORAWAN_DATA_DISTRIB_MGT == 0))
#else /*LORAWAN_DATA_DISTRIB_MGT == 1*/
LmhpPackagesRegister( id, &package );
#endif /*LORAWAN_DATA_DISTRIB_MGT*/
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 ))
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 ))
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;
}
}
}
}
}
#if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000400 ))
static bool LmHandlerPackageIsTxPending( void )
{
for( int8_t i = 0; i < PKG_MAX_NUMBER; i++ )
{
if( LmHandlerPackages[i] != NULL )
{
if( LmHandlerPackages[i]->IsTxPending( ) == true )
{
return true;
}
}
}
return false;
}
#endif /* LORAMAC_VERSION */
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( );
}
}
}
/*
*=============================================================================
* 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;
if (LoRaMacMibGetRequestConfirm(&mibReq) != LORAMAC_STATUS_OK)
{
return LORAMAC_HANDLER_ERROR;
}
UTIL_MEM_cpy_8(devEUI, mibReq.Param.DevEui, SE_EUI_SIZE);
return LORAMAC_HANDLER_SUCCESS;
}
LmHandlerErrorStatus_t LmHandlerSetDevEUI(uint8_t *devEUI)
{
#if ( STATIC_DEVICE_EUI != 1 )
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;
}
#else /* STATIC_DEVICE_EUI == 1 */
return LORAMAC_HANDLER_ERROR;
#endif /* STATIC_DEVICE_EUI */
}
LmHandlerErrorStatus_t LmHandlerGetAppEUI(uint8_t *appEUI)
{
MibRequestConfirm_t mibReq;
if (appEUI == NULL)
{
return LORAMAC_HANDLER_ERROR;
}
mibReq.Type = MIB_JOIN_EUI;
if (LoRaMacMibGetRequestConfirm(&mibReq) != LORAMAC_STATUS_OK)
{
return LORAMAC_HANDLER_ERROR;
}
UTIL_MEM_cpy_8(appEUI, mibReq.Param.JoinEui, SE_EUI_SIZE);
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)
{
#if ( STATIC_DEVICE_ADDRESS != 1 )
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;
}
#else /* STATIC_DEVICE_ADDRESS == 1 */
return LORAMAC_HANDLER_ERROR;
#endif /* STATIC_DEVICE_ADDRESS */
}
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;
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;
}
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 LmHandlerGetNwkKey( uint8_t *nwkKey )
{
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
Key_t *keyItem;
#endif
if (nwkKey == NULL)
{
return LORAMAC_HANDLER_ERROR;
}
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
if (SECURE_ELEMENT_SUCCESS != SecureElementGetKeyByID(NWK_KEY, &keyItem))
{
return LORAMAC_HANDLER_ERROR;
}
UTIL_MEM_cpy_8( nwkKey, keyItem->KeyValue, 16 );
#else
if (SECURE_ELEMENT_SUCCESS != SecureElementGetKeyByID(NWK_KEY, nwkKey))
{
return LORAMAC_HANDLER_ERROR;
}
#endif
return LORAMAC_HANDLER_SUCCESS;
}
LmHandlerErrorStatus_t LmHandlerSetNwkKey( uint8_t *nwkKey )
{
/* Not yet joined */
if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET )
{
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_NWK_KEY;
mibReq.Param.NwkKey = nwkKey;
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 LmHandlerGetAppKey( uint8_t *appKey )
{
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
Key_t *keyItem;
#endif
if (appKey == NULL)
{
return LORAMAC_HANDLER_ERROR;
}
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
if (SECURE_ELEMENT_SUCCESS != SecureElementGetKeyByID(APP_KEY, &keyItem))
{
return LORAMAC_HANDLER_ERROR;
}
UTIL_MEM_cpy_8( appKey, keyItem->KeyValue, 16 );
#else
if (SECURE_ELEMENT_SUCCESS != SecureElementGetKeyByID(APP_KEY, appKey))
{
return LORAMAC_HANDLER_ERROR;
}
#endif
return LORAMAC_HANDLER_SUCCESS;
}
LmHandlerErrorStatus_t LmHandlerSetAppKey( uint8_t *appKey )
{
/* Not yet joined */
if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET )
{
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_APP_KEY;
mibReq.Param.AppKey = appKey;
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 LmHandlerGetNwkSKey( uint8_t *nwkSKey )
{
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
Key_t *keyItem;
#endif
if (nwkSKey == NULL)
{
return LORAMAC_HANDLER_ERROR;
}
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
if (SECURE_ELEMENT_SUCCESS != SecureElementGetKeyByID(NWK_S_KEY, &keyItem))
{
return LORAMAC_HANDLER_ERROR;
}
UTIL_MEM_cpy_8( nwkSKey, keyItem->KeyValue, 16 );
#else
if (SECURE_ELEMENT_SUCCESS != SecureElementGetKeyByID(NWK_S_KEY, nwkSKey))
{
return LORAMAC_HANDLER_ERROR;
}
#endif
return LORAMAC_HANDLER_SUCCESS;
}
LmHandlerErrorStatus_t LmHandlerSetNwkSKey( uint8_t *nwkSKey )
{
/* Not yet joined */
if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET )
{
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_NWK_S_KEY;
mibReq.Param.NwkSKey = nwkSKey;
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 LmHandlerGetAppSKey( uint8_t *appSKey )
{
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
Key_t *keyItem;
#endif
if (appSKey == NULL)
{
return LORAMAC_HANDLER_ERROR;
}
#if (!defined (LORAWAN_KMS) || (LORAWAN_KMS == 0))
if (SECURE_ELEMENT_SUCCESS != SecureElementGetKeyByID(APP_S_KEY, &keyItem))
{
return LORAMAC_HANDLER_ERROR;
}
UTIL_MEM_cpy_8( appSKey, keyItem->KeyValue, 16 );
#else
if (SECURE_ELEMENT_SUCCESS != SecureElementGetKeyByID(APP_S_KEY, appSKey))
{
return LORAMAC_HANDLER_ERROR;
}
#endif
return LORAMAC_HANDLER_SUCCESS;
}
LmHandlerErrorStatus_t LmHandlerSetAppSKey( uint8_t *appSKey )
{
/* Not yet joined */
if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET )
{
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_APP_S_KEY;
mibReq.Param.AppSKey = appSKey;
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 LmHandlerNvmDataStore( void )
{
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 = 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;
}