Files
TencentOS-tiny/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandler.c
supowang 595cd6f0d2 fix lorawan class A demo for RHF76_052DM board
LoRaMac-node-4.4.4 demo
2020-06-02 16:06:58 +08:00

1012 lines
29 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.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2018 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "utilities.h"
#include "timer.h"
#include "Commissioning.h"
#include "NvmCtxMgmt.h"
#include "LmHandler.h"
#include "LmhPackage.h"
#include "LmhpCompliance.h"
#include "LmhpClockSync.h"
#include "LmhpRemoteMcastSetup.h"
#include "LmhpFragmentation.h"
#ifndef ACTIVE_REGION
#warning "No active region defined, LORAMAC_REGION_EU868 will be used as default."
#define ACTIVE_REGION LORAMAC_REGION_EU868
#endif
#include "LoRaMacTest.h"
static CommissioningParams_t CommissioningParams =
{
.IsOtaaActivation = OVER_THE_AIR_ACTIVATION,
.DevEui = { 0 }, // Automatically filed from secure-element
.JoinEui = { 0 }, // Automatically filed from secure-element
.SePin = { 0 }, // Automatically filed from secure-element
.NetworkId = LORAWAN_NETWORK_ID,
.DevAddr = LORAWAN_DEVICE_ADDRESS,
};
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,
.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
};
static LoRaMAcHandlerBeaconParams_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 }
}
}
};
/*!
* Indicates if a switch to Class B operation is pending or not.
*
* TODO: Create a new structure to store the current handler states/status
* and add the below variable to it.
*/
static bool IsClassBSwitchPending = false;
/*!
* \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.
*/
static void McpsIndication( McpsIndication_t *mcpsIndication );
/*!
* \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.
*/
static void MlmeIndication( MlmeIndication_t *mlmeIndication );
/*!
* Requests network server time update
*
* \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET
*/
static LmHandlerErrorStatus_t LmHandlerDeviceTimeReq( void );
/*!
* Starts the beacon search
*
* \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET
*/
static LmHandlerErrorStatus_t LmHandlerBeaconReq( void );
/*
*=============================================================================
* PACKAGES HANDLING
*=============================================================================
*/
typedef enum PackageNotifyTypes_e
{
PACKAGE_MCPS_CONFIRM,
PACKAGE_MCPS_INDICATION,
PACKAGE_MLME_CONFIRM,
PACKAGE_MLME_INDICATION,
}PackageNotifyTypes_t;
/*!
* 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 );
static void LmHandlerPackagesProcess( void );
LmHandlerErrorStatus_t LmHandlerInit( LmHandlerCallbacks_t *handlerCallbacks,
LmHandlerParams_t *handlerParams )
{
//
MibRequestConfirm_t mibReq;
LmHandlerParams = handlerParams;
LmHandlerCallbacks = handlerCallbacks;
LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
LoRaMacPrimitives.MacMlmeIndication = MlmeIndication;
LoRaMacCallbacks.GetBatteryLevel = LmHandlerCallbacks->GetBatteryLevel;
LoRaMacCallbacks.GetTemperatureLevel = LmHandlerCallbacks->GetTemperature;
LoRaMacCallbacks.NvmContextChange = NvmCtxMgmtEvent;
LoRaMacCallbacks.MacProcessNotify = LmHandlerCallbacks->OnMacProcess;
IsClassBSwitchPending = false;
if( LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LmHandlerParams->Region ) != LORAMAC_STATUS_OK )
{
return LORAMAC_HANDLER_ERROR;
}
// Try to restore from NVM and query the mac if possible.
if( NvmCtxMgmtRestore( ) == NVMCTXMGMT_STATUS_SUCCESS )
{
LmHandlerCallbacks->OnNvmContextChange( LORAMAC_HANDLER_NVM_RESTORE );
}
else
{
// Read secure-element DEV_EUI, JOI_EUI and SE_PIN 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 );
mibReq.Type = MIB_SE_PIN;
LoRaMacMibGetRequestConfirm( &mibReq );
memcpy1( CommissioningParams.SePin, mibReq.Param.SePin, 4 );
#if( OVER_THE_AIR_ACTIVATION == 0 )
// 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 );
mibReq.Type = MIB_NET_ID;
mibReq.Param.NetID = LORAWAN_NETWORK_ID;
LoRaMacMibSetRequestConfirm( &mibReq );
#if( STATIC_DEVICE_ADDRESS != 1 )
// Random seed initialization
srand1( LmHandlerCallbacks->GetRandomSeed( ) );
// Choose a random device address
CommissioningParams.DevAddr = randr( 0, 0x01FFFFFF );
#endif
mibReq.Type = MIB_DEV_ADDR;
mibReq.Param.DevAddr = CommissioningParams.DevAddr;
LoRaMacMibSetRequestConfirm( &mibReq );
#endif // #if( OVER_THE_AIR_ACTIVATION == 0 )
}
mibReq.Type = MIB_PUBLIC_NETWORK;
mibReq.Param.EnablePublicNetwork = LmHandlerParams->PublicNetworkEnable;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = LmHandlerParams->AdrEnable;
LoRaMacMibSetRequestConfirm( &mibReq );
LoRaMacTestSetDutyCycleOn( LmHandlerParams->DutyCycleEnabled );
LoRaMacStart( );
mibReq.Type = MIB_NETWORK_ACTIVATION;
if( LoRaMacMibGetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
{
if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE )
{
LmHandlerCallbacks->OnNetworkParametersChange( &CommissioningParams );
}
}
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( );
return true;
}
if( LmHandlerPackages[PACKAGE_ID_COMPLIANCE]->IsRunning( ) == true )
{
return true;
}
return false;
}
void LmHandlerProcess( void )
{
// Process Radio IRQ
if( Radio.IrqProcess != NULL )
{
Radio.IrqProcess( );
}
// Processes the LoRaMac events
LoRaMacProcess( );
// Call all packages process functions
LmHandlerPackagesProcess( );
if( NvmCtxMgmtStore( ) == NVMCTXMGMT_STATUS_SUCCESS )
{
LmHandlerCallbacks->OnNvmContextChange( LORAMAC_HANDLER_NVM_STORE );
}
}
/*!
* Join a LoRa Network in classA
*
* \Note if the device is ABP, this is a pass through function
*
* \param [IN] isOtaa Indicates which activation mode must be used
*/
static void LmHandlerJoinRequest( bool isOtaa )
{
if( isOtaa == true )
{
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_JOIN;
mlmeReq.Req.Join.Datarate = LmHandlerParams->TxDatarate;
// Update commissioning parameters activation type variable.
CommissioningParams.IsOtaaActivation = true;
// Starts the OTAA join procedure
LmHandlerCallbacks->OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime );
}
else
{
MibRequestConfirm_t mibReq;
LmHandlerJoinParams_t joinParams =
{
.CommissioningParams = &CommissioningParams,
.Datarate = LmHandlerParams->TxDatarate,
.Status = LORAMAC_HANDLER_SUCCESS
};
mibReq.Type = MIB_NETWORK_ACTIVATION;
mibReq.Param.NetworkActivation = ACTIVATION_TYPE_ABP;
LoRaMacMibSetRequestConfirm( &mibReq );
// Notify upper layer
LmHandlerCallbacks->OnJoinRequest( &joinParams );
}
}
void LmHandlerJoin( void )
{
LmHandlerJoinRequest( CommissioningParams.IsOtaaActivation );
}
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 )
{
LoRaMacStatus_t status;
McpsReq_t mcpsReq;
LoRaMacTxInfo_t txInfo;
if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET )
{
// The network isn't joined, try again.
LmHandlerJoinRequest( CommissioningParams.IsOtaaActivation );
return LORAMAC_HANDLER_ERROR;
}
if( ( LmHandlerPackages[PACKAGE_ID_COMPLIANCE]->IsRunning( ) == true ) && ( appData->Port != LmHandlerPackages[PACKAGE_ID_COMPLIANCE]->Port ) && ( appData->Port != 0 ) )
{
return LORAMAC_HANDLER_ERROR;
}
mcpsReq.Req.Unconfirmed.Datarate = LmHandlerParams->TxDatarate;
if( LoRaMacQueryTxPossible( appData->BufferSize, &txInfo ) != LORAMAC_STATUS_OK )
{
// Send empty frame in order to flush MAC commands
TxParams.MsgType = LORAMAC_HANDLER_UNCONFIRMED_MSG;
mcpsReq.Type = MCPS_UNCONFIRMED;
mcpsReq.Req.Unconfirmed.fBuffer = NULL;
mcpsReq.Req.Unconfirmed.fBufferSize = 0;
}
else
{
TxParams.MsgType = isTxConfirmed;
mcpsReq.Req.Unconfirmed.fPort = appData->Port;
mcpsReq.Req.Unconfirmed.fBufferSize = appData->BufferSize;
mcpsReq.Req.Unconfirmed.fBuffer = appData->Buffer;
if( isTxConfirmed == LORAMAC_HANDLER_UNCONFIRMED_MSG )
{
mcpsReq.Type = MCPS_UNCONFIRMED;
}
else
{
mcpsReq.Type = MCPS_CONFIRMED;
mcpsReq.Req.Confirmed.NbTrials = 8;
}
}
TxParams.AppData = *appData;
TxParams.Datarate = LmHandlerParams->TxDatarate;
status = LoRaMacMcpsRequest( &mcpsReq );
LmHandlerCallbacks->OnMacMcpsRequest( status, &mcpsReq, mcpsReq.ReqReturn.DutyCycleWaitTime );
if( status == LORAMAC_STATUS_OK )
{
return LORAMAC_HANDLER_SUCCESS;
}
else
{
return LORAMAC_HANDLER_ERROR;
}
}
static LmHandlerErrorStatus_t LmHandlerDeviceTimeReq( void )
{
LoRaMacStatus_t status;
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_DEVICE_TIME;
status = LoRaMacMlmeRequest( &mlmeReq );
LmHandlerCallbacks->OnMacMlmeRequest( status, &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime );
if( status == LORAMAC_STATUS_OK )
{
return LORAMAC_HANDLER_SUCCESS;
}
else
{
return LORAMAC_HANDLER_ERROR;
}
}
static LmHandlerErrorStatus_t LmHandlerBeaconReq( void )
{
LoRaMacStatus_t status;
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_BEACON_ACQUISITION;
status = LoRaMacMlmeRequest( &mlmeReq );
LmHandlerCallbacks->OnMacMlmeRequest( status, &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime );
if( status == LORAMAC_STATUS_OK )
{
return LORAMAC_HANDLER_SUCCESS;
}
else
{
return LORAMAC_HANDLER_ERROR;
}
}
LmHandlerErrorStatus_t LmHandlerPingSlotReq( uint8_t periodicity )
{
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 );
LmHandlerCallbacks->OnMacMlmeRequest( status, &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime );
if( status == LORAMAC_STATUS_OK )
{
// Send an empty message
LmHandlerAppData_t appData =
{
.Buffer = NULL,
.BufferSize = 0,
.Port = 0
};
return LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG );
}
else
{
return LORAMAC_HANDLER_ERROR;
}
}
LmHandlerErrorStatus_t LmHandlerRequestClass( DeviceClass_t newClass )
{
MibRequestConfirm_t mibReq;
DeviceClass_t currentClass;
LmHandlerErrorStatus_t errorStatus = LORAMAC_HANDLER_SUCCESS;
mibReq.Type = MIB_DEVICE_CLASS;
LoRaMacMibGetRequestConfirm( &mibReq );
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 = CLASS_A;
if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
{
// Switch is instantaneous
LmHandlerCallbacks->OnClassChange( CLASS_A );
}
else
{
errorStatus = LORAMAC_HANDLER_ERROR;
}
}
}
break;
case CLASS_B:
{
if( currentClass != CLASS_A )
{
errorStatus = LORAMAC_HANDLER_ERROR;
}
// Beacon must first be acquired
errorStatus = LmHandlerDeviceTimeReq( );
IsClassBSwitchPending = true;
}
break;
case CLASS_C:
{
if( currentClass != CLASS_A )
{
errorStatus = LORAMAC_HANDLER_ERROR;
}
// Switch is instantaneous
mibReq.Param.Class = CLASS_C;
if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
{
LmHandlerCallbacks->OnClassChange( CLASS_C );
}
else
{
errorStatus = LORAMAC_HANDLER_ERROR;
}
}
break;
default:
break;
}
}
return errorStatus;
}
DeviceClass_t LmHandlerGetCurrentClass( void )
{
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_DEVICE_CLASS;
LoRaMacMibGetRequestConfirm( &mibReq );
return mibReq.Param.Class;
}
int8_t LmHandlerGetCurrentDatarate( void )
{
MibRequestConfirm_t mibGet;
mibGet.Type = MIB_CHANNELS_DATARATE;
LoRaMacMibGetRequestConfirm( &mibGet );
return mibGet.Param.ChannelsDatarate;
}
LoRaMacRegion_t LmHandlerGetActiveRegion( void )
{
return LmHandlerParams->Region;
}
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 )
{
LmHandlerAppData_t appData;
RxParams.IsMcpsIndication = 1;
RxParams.Status = mcpsIndication->Status;
if( RxParams.Status != LORAMAC_EVENT_INFO_STATUS_OK )
{
return;
}
RxParams.Datarate = mcpsIndication->RxDatarate;
RxParams.Rssi = mcpsIndication->Rssi;
RxParams.Snr = mcpsIndication->Snr;
RxParams.DownlinkCounter = mcpsIndication->DownLinkCounter;
RxParams.RxSlot = mcpsIndication->RxSlot;
appData.Port = mcpsIndication->Port;
appData.BufferSize = mcpsIndication->BufferSize;
appData.Buffer = mcpsIndication->Buffer;
LmHandlerCallbacks->OnRxData( &appData, &RxParams );
if( mcpsIndication->DeviceTimeAnsReceived == true )
{
#if( LMH_SYS_TIME_UPDATE_NEW_API == 1 )
// Provide fix values. DeviceTimeAns is accurate
LmHandlerCallbacks->OnSysTimeUpdate( true, 0 );
#else
LmHandlerCallbacks->OnSysTimeUpdate( );
#endif
}
// Call packages RxProcess function
LmHandlerPackagesNotify( PACKAGE_MCPS_INDICATION, mcpsIndication );
if( ( mcpsIndication->FramePending == true ) && ( LmHandlerGetCurrentClass( ) == 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 );
}
}
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 );
JoinParams.CommissioningParams->DevAddr = mibReq.Param.DevAddr;
JoinParams.Datarate = LmHandlerGetCurrentDatarate( );
if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
{
// Status is OK, node has joined the network
JoinParams.Status = LORAMAC_HANDLER_SUCCESS;
}
else
{
// Join was not successful. Try to join again
JoinParams.Status = LORAMAC_HANDLER_ERROR;
}
// Notify upper layer
LmHandlerCallbacks->OnJoinRequest( &JoinParams );
}
break;
case MLME_LINK_CHECK:
{
// Check DemodMargin
// Check NbGateways
}
break;
case MLME_DEVICE_TIME:
{
if( IsClassBSwitchPending == true )
{
LmHandlerBeaconReq( );
}
}
break;
case MLME_BEACON_ACQUISITION:
{
if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
{
// Beacon has been acquired
// Request server for ping slot
LmHandlerPingSlotReq( 0 );
}
else
{
// Beacon not acquired
// Request Device Time again.
LmHandlerDeviceTimeReq( );
}
}
break;
case MLME_PING_SLOT_INFO:
{
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
LmHandlerCallbacks->OnClassChange( CLASS_B );
IsClassBSwitchPending = false;
}
else
{
LmHandlerPingSlotReq( 0 );
}
}
break;
default:
break;
}
}
static void MlmeIndication( MlmeIndication_t *mlmeIndication )
{
RxParams.IsMcpsIndication = 0;
RxParams.Status = mlmeIndication->Status;
if( RxParams.Status != LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED )
{
LmHandlerCallbacks->OnRxData( NULL, &RxParams );
}
// Call packages RxProcess function
LmHandlerPackagesNotify( PACKAGE_MLME_INDICATION, mlmeIndication );
switch( mlmeIndication->MlmeIndication )
{
case MLME_SCHEDULE_UPLINK:
{// 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 );
}
}
break;
case MLME_BEACON_LOST:
{
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 );
LmHandlerCallbacks->OnClassChange( CLASS_A );
LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams );
LmHandlerDeviceTimeReq( );
}
break;
case MLME_BEACON:
{
if( mlmeIndication->Status == LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED )
{
BeaconParams.State = LORAMAC_HANDLER_BEACON_RX;
BeaconParams.Info = mlmeIndication->BeaconInfo;
LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams );
}
else
{
BeaconParams.State = LORAMAC_HANDLER_BEACON_NRX;
BeaconParams.Info = mlmeIndication->BeaconInfo;
LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams );
}
break;
}
default:
break;
}
}
/*
*=============================================================================
* PACKAGES HANDLING
*=============================================================================
*/
LmHandlerErrorStatus_t LmHandlerPackageRegister( uint8_t id, void *params )
{
LmhPackage_t *package = NULL;
switch( id )
{
case PACKAGE_ID_COMPLIANCE:
{
package = LmphCompliancePackageFactory( );
break;
}
case PACKAGE_ID_CLOCK_SYNC:
{
package = LmphClockSyncPackageFactory( );
break;
}
case PACKAGE_ID_REMOTE_MCAST_SETUP:
{
package = LmhpRemoteMcastSetupPackageFactory( );
break;
}
case PACKAGE_ID_FRAGMENTATION:
{
package = LmhpFragmentationPackageFactory( );
break;
}
}
if( package != NULL )
{
LmHandlerPackages[id] = package;
LmHandlerPackages[id]->OnMacMcpsRequest = LmHandlerCallbacks->OnMacMcpsRequest;
LmHandlerPackages[id]->OnMacMlmeRequest = LmHandlerCallbacks->OnMacMlmeRequest;
LmHandlerPackages[id]->OnJoinRequest = LmHandlerJoinRequest;
LmHandlerPackages[id]->OnSendRequest = LmHandlerSend;
LmHandlerPackages[id]->OnDeviceTimeRequest = LmHandlerDeviceTimeReq;
LmHandlerPackages[id]->OnSysTimeUpdate = LmHandlerCallbacks->OnSysTimeUpdate;
LmHandlerPackages[id]->Init( params, LmHandlerParams->DataBuffer, LmHandlerParams->DataBufferMaxSize );
return LORAMAC_HANDLER_SUCCESS;
}
else
{
return LORAMAC_HANDLER_ERROR;
}
}
bool LmHandlerPackageIsInitialized( uint8_t id )
{
if( LmHandlerPackages[id]->IsInitialized != NULL )
{
return LmHandlerPackages[id]->IsInitialized( );
}
else
{
return false;
}
}
bool LmHandlerPackageIsRunning( uint8_t id )
{
if( LmHandlerPackages[id]->IsRunning != NULL )
{
return LmHandlerPackages[id]->IsRunning( );
}
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( params );
}
break;
}
case PACKAGE_MCPS_INDICATION:
{
if( ( LmHandlerPackages[i]->OnMcpsIndicationProcess != NULL ) &&
( LmHandlerPackages[i]->Port == ( ( McpsIndication_t* )params )->Port ) )
{
LmHandlerPackages[i]->OnMcpsIndicationProcess( params );
}
break;
}
case PACKAGE_MLME_CONFIRM:
{
if( LmHandlerPackages[i]->OnMlmeConfirmProcess != NULL )
{
LmHandlerPackages[i]->OnMlmeConfirmProcess( params );
}
break;
}
case PACKAGE_MLME_INDICATION:
{
if( LmHandlerPackages[i]->OnMlmeIndicationProcess != NULL )
{
LmHandlerPackages[i]->OnMlmeIndicationProcess( params );
}
break;
}
}
}
}
}
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( );
}
}
}