Files
TencentOS-tiny/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaDemo.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

1185 lines
37 KiB
C

/*!
* \file main.c
*
* \brief LoRaMac classA device implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2017 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*/
/*! \file classA/B-L072Z-LRWAN1/main.c */
#include <stdio.h>
#include "utilities.h"
#include "board.h"
#include "gpio.h"
#include "LoRaMac.h"
#include "Commissioning.h"
#include "NvmCtxMgmt.h"
#define ACTIVE_REGION LORAMAC_REGION_CN470
#ifndef ACTIVE_REGION
#warning "No active region defined, LORAMAC_REGION_EU868 will be used as default."
#define ACTIVE_REGION LORAMAC_REGION_EU868
#endif
/*!
* Defines the application data transmission duty cycle. 5s, value in [ms].
*/
#define APP_TX_DUTYCYCLE 5000
/*!
* Defines a random delay for application data transmission duty cycle. 1s,
* value in [ms].
*/
#define APP_TX_DUTYCYCLE_RND 1000
/*!
* Default datarate
*/
#define LORAWAN_DEFAULT_DATARATE DR_0
/*!
* LoRaWAN confirmed messages
*/
#define LORAWAN_CONFIRMED_MSG_ON false
/*!
* LoRaWAN Adaptive Data Rate
*
* \remark Please note that when ADR is enabled the end-device should be static
*/
#define LORAWAN_ADR_ON 1
#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 )
#include "LoRaMacTest.h"
/*!
* LoRaWAN ETSI duty cycle control enable/disable
*
* \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes
*/
#define LORAWAN_DUTYCYCLE_ON true
#endif
/*!
* LoRaWAN application port
*/
#define LORAWAN_APP_PORT 2
#if( OVER_THE_AIR_ACTIVATION == 0 )
/*!
* Device address
*/
static uint32_t DevAddr = LORAWAN_DEVICE_ADDRESS;
#endif
/*!
* Application port
*/
static uint8_t AppPort = LORAWAN_APP_PORT;
/*!
* User application data size
*/
static uint8_t AppDataSize = 1;
static uint8_t AppDataSizeBackup = 1;
/*!
* User application data buffer size
*/
#define LORAWAN_APP_DATA_MAX_SIZE 242
/*!
* User application data
*/
static uint8_t AppDataBuffer[LORAWAN_APP_DATA_MAX_SIZE];
/*!
* Indicates if the node is sending confirmed or unconfirmed messages
*/
static uint8_t IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
/*!
* Defines the application data transmission duty cycle
*/
static uint32_t TxDutyCycleTime;
/*!
* Timer to handle the application data transmission duty cycle
*/
static TimerEvent_t TxNextPacketTimer;
/*!
* Specifies the state of the application LED
*/
static bool AppLedStateOn = false;
/*!
* Timer to handle the state of LED1
*/
static TimerEvent_t Led1Timer;
/*!
* Timer to handle the state of LED3
*/
static TimerEvent_t Led3Timer;
/*!
* Indicates if a new packet can be sent
*/
static bool NextTx = true;
/*!
* Indicates if LoRaMacProcess call is pending.
*
* \warning If variable is equal to 0 then the MCU can be set in low power mode
*/
static uint8_t IsMacProcessPending = 0;
/*!
* Device states
*/
static enum eDeviceState
{
DEVICE_STATE_RESTORE,
DEVICE_STATE_START,
DEVICE_STATE_JOIN,
DEVICE_STATE_SEND,
DEVICE_STATE_CYCLE,
DEVICE_STATE_SLEEP
}DeviceState;
/*!
* LoRaWAN compliance tests support data
*/
struct ComplianceTest_s
{
bool Running;
uint8_t State;
bool IsTxConfirmed;
uint8_t AppPort;
uint8_t AppDataSize;
uint8_t *AppDataBuffer;
uint16_t DownLinkCounter;
bool LinkCheck;
uint8_t DemodMargin;
uint8_t NbGateways;
}ComplianceTest;
/*!
*
*/
typedef enum
{
LORAMAC_HANDLER_UNCONFIRMED_MSG = 0,
LORAMAC_HANDLER_CONFIRMED_MSG = !LORAMAC_HANDLER_UNCONFIRMED_MSG
}LoRaMacHandlerMsgTypes_t;
/*!
* Application data structure
*/
typedef struct LoRaMacHandlerAppData_s
{
LoRaMacHandlerMsgTypes_t MsgType;
uint8_t Port;
uint8_t BufferSize;
uint8_t *Buffer;
}LoRaMacHandlerAppData_t;
LoRaMacHandlerAppData_t AppData =
{
.MsgType = LORAMAC_HANDLER_UNCONFIRMED_MSG,
.Buffer = NULL,
.BufferSize = 0,
.Port = 0
};
/*!
* LED GPIO pins objects
*/
extern Gpio_t Led1; // Tx
extern Gpio_t Led3; // Rx
extern Gpio_t Led4; // App
/*!
* MAC status strings
*/
const char* MacStatusStrings[] =
{
"OK", // LORAMAC_STATUS_OK
"Busy", // LORAMAC_STATUS_BUSY
"Service unknown", // LORAMAC_STATUS_SERVICE_UNKNOWN
"Parameter invalid", // LORAMAC_STATUS_PARAMETER_INVALID
"Frequency invalid", // LORAMAC_STATUS_FREQUENCY_INVALID
"Datarate invalid", // LORAMAC_STATUS_DATARATE_INVALID
"Frequency or datarate invalid", // LORAMAC_STATUS_FREQ_AND_DR_INVALID
"No network joined", // LORAMAC_STATUS_NO_NETWORK_JOINED
"Length error", // LORAMAC_STATUS_LENGTH_ERROR
"Region not supported", // LORAMAC_STATUS_REGION_NOT_SUPPORTED
"Skipped APP data", // LORAMAC_STATUS_SKIPPED_APP_DATA
"Duty-cycle restricted", // LORAMAC_STATUS_DUTYCYCLE_RESTRICTED
"No channel found", // LORAMAC_STATUS_NO_CHANNEL_FOUND
"No free channel found", // LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND
"Busy beacon reserved time", // LORAMAC_STATUS_BUSY_BEACON_RESERVED_TIME
"Busy ping-slot window time", // LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME
"Busy uplink collision", // LORAMAC_STATUS_BUSY_UPLINK_COLLISION
"Crypto error", // LORAMAC_STATUS_CRYPTO_ERROR
"FCnt handler error", // LORAMAC_STATUS_FCNT_HANDLER_ERROR
"MAC command error", // LORAMAC_STATUS_MAC_COMMAD_ERROR
"ClassB error", // LORAMAC_STATUS_CLASS_B_ERROR
"Confirm queue error", // LORAMAC_STATUS_CONFIRM_QUEUE_ERROR
"Multicast group undefined", // LORAMAC_STATUS_MC_GROUP_UNDEFINED
"Unknown error", // LORAMAC_STATUS_ERROR
};
/*!
* MAC event info status strings.
*/
const char* EventInfoStatusStrings[] =
{
"OK", // LORAMAC_EVENT_INFO_STATUS_OK
"Error", // LORAMAC_EVENT_INFO_STATUS_ERROR
"Tx timeout", // LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT
"Rx 1 timeout", // LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT
"Rx 2 timeout", // LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT
"Rx1 error", // LORAMAC_EVENT_INFO_STATUS_RX1_ERROR
"Rx2 error", // LORAMAC_EVENT_INFO_STATUS_RX2_ERROR
"Join failed", // LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL
"Downlink repeated", // LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED
"Tx DR payload size error", // LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR
"Downlink too many frames loss", // LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS
"Address fail", // LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL
"MIC fail", // LORAMAC_EVENT_INFO_STATUS_MIC_FAIL
"Multicast fail", // LORAMAC_EVENT_INFO_STATUS_MULTICAST_FAIL
"Beacon locked", // LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED
"Beacon lost", // LORAMAC_EVENT_INFO_STATUS_BEACON_LOST
"Beacon not found" // LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND
};
/*!
* Prints the provided buffer in HEX
*
* \param buffer Buffer to be printed
* \param size Buffer size to be printed
*/
void PrintHexBuffer( uint8_t *buffer, uint8_t size )
{
uint8_t newline = 0;
for( uint8_t i = 0; i < size; i++ )
{
if( newline != 0 )
{
printf( "\n" );
newline = 0;
}
printf( "%02X ", buffer[i] );
if( ( ( i + 1 ) % 16 ) == 0 )
{
newline = 1;
}
}
printf( "\n" );
}
/*!
* Executes the network Join request
*/
static void JoinNetwork( void )
{
LoRaMacStatus_t status;
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_JOIN;
mlmeReq.Req.Join.Datarate = LORAWAN_DEFAULT_DATARATE;
// Starts the join procedure
status = LoRaMacMlmeRequest( &mlmeReq );
printf( "\n###### ===== MLME-Request - MLME_JOIN ==== ######\n" );
printf( "STATUS : %s\n", MacStatusStrings[status] );
if( status == LORAMAC_STATUS_OK )
{
printf( "###### ===== JOINING ==== ######\n" );
DeviceState = DEVICE_STATE_SLEEP;
}
else
{
if( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED )
{
printf( "Next Tx in : %lu [ms]\n", mlmeReq.ReqReturn.DutyCycleWaitTime );
}
DeviceState = DEVICE_STATE_CYCLE;
}
}
/*!
* \brief Prepares the payload of the frame
*/
static void PrepareTxFrame( uint8_t port )
{
switch( port )
{
case 2:
{
AppDataSizeBackup = AppDataSize = 1;
AppDataBuffer[0] = AppLedStateOn;
}
break;
case 224:
if( ComplianceTest.LinkCheck == true )
{
ComplianceTest.LinkCheck = false;
AppDataSize = 3;
AppDataBuffer[0] = 5;
AppDataBuffer[1] = ComplianceTest.DemodMargin;
AppDataBuffer[2] = ComplianceTest.NbGateways;
ComplianceTest.State = 1;
}
else
{
switch( ComplianceTest.State )
{
case 4:
ComplianceTest.State = 1;
break;
case 1:
AppDataSize = 2;
AppDataBuffer[0] = ComplianceTest.DownLinkCounter >> 8;
AppDataBuffer[1] = ComplianceTest.DownLinkCounter;
break;
}
}
break;
default:
break;
}
}
/*!
* \brief Prepares the payload of the frame
*
* \retval [0: frame could be send, 1: error]
*/
static bool SendFrame( void )
{
McpsReq_t mcpsReq;
LoRaMacTxInfo_t txInfo;
if( LoRaMacQueryTxPossible( AppDataSize, &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;
mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
}
else
{
if( IsTxConfirmed == false )
{
mcpsReq.Type = MCPS_UNCONFIRMED;
mcpsReq.Req.Unconfirmed.fPort = AppPort;
mcpsReq.Req.Unconfirmed.fBuffer = AppDataBuffer;
mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize;
mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
}
else
{
mcpsReq.Type = MCPS_CONFIRMED;
mcpsReq.Req.Confirmed.fPort = AppPort;
mcpsReq.Req.Confirmed.fBuffer = AppDataBuffer;
mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
mcpsReq.Req.Confirmed.NbTrials = 8;
mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
}
}
// Update global variable
AppData.MsgType = ( mcpsReq.Type == MCPS_CONFIRMED ) ? LORAMAC_HANDLER_CONFIRMED_MSG : LORAMAC_HANDLER_UNCONFIRMED_MSG;
AppData.Port = mcpsReq.Req.Unconfirmed.fPort;
AppData.Buffer = mcpsReq.Req.Unconfirmed.fBuffer;
AppData.BufferSize = mcpsReq.Req.Unconfirmed.fBufferSize;
LoRaMacStatus_t status;
status = LoRaMacMcpsRequest( &mcpsReq );
printf( "\n###### ===== MCPS-Request ==== ######\n" );
printf( "STATUS : %s\n", MacStatusStrings[status] );
if( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED )
{
printf( "Next Tx in : %lu [ms]\n", mcpsReq.ReqReturn.DutyCycleWaitTime );
}
if( status == LORAMAC_STATUS_OK )
{
return false;
}
return true;
}
/*!
* \brief Function executed on TxNextPacket Timeout event
*/
static void OnTxNextPacketTimerEvent( void* context )
{
MibRequestConfirm_t mibReq;
LoRaMacStatus_t status;
TimerStop( &TxNextPacketTimer );
mibReq.Type = MIB_NETWORK_ACTIVATION;
status = LoRaMacMibGetRequestConfirm( &mibReq );
if( status == LORAMAC_STATUS_OK )
{
if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE )
{
// Network not joined yet. Try to join again
JoinNetwork( );
}
else
{
DeviceState = DEVICE_STATE_SEND;
NextTx = true;
}
}
}
/*!
* \brief Function executed on Led 1 Timeout event
*/
static void OnLed1TimerEvent( void* context )
{
TimerStop( &Led1Timer );
// Switch LED 1 OFF
GpioWrite( &Led1, 0 );
}
/*!
* \brief Function executed on Led 3 Timeout event
*/
static void OnLed3TimerEvent( void* context )
{
TimerStop( &Led3Timer );
// Switch LED 3 OFF
GpioWrite( &Led3, 0 );
}
/*!
* \brief MCPS-Confirm event function
*
* \param [IN] mcpsConfirm - Pointer to the confirm structure,
* containing confirm attributes.
*/
static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
{
printf( "\n###### ===== MCPS-Confirm ==== ######\n" );
printf( "STATUS : %s\n", EventInfoStatusStrings[mcpsConfirm->Status] );
if( mcpsConfirm->Status != LORAMAC_EVENT_INFO_STATUS_OK )
{
}
else
{
switch( mcpsConfirm->McpsRequest )
{
case MCPS_UNCONFIRMED:
{
// Check Datarate
// Check TxPower
break;
}
case MCPS_CONFIRMED:
{
// Check Datarate
// Check TxPower
// Check AckReceived
// Check NbTrials
break;
}
case MCPS_PROPRIETARY:
{
break;
}
default:
break;
}
// Switch LED 1 ON
GpioWrite( &Led1, 1 );
TimerStart( &Led1Timer );
}
MibRequestConfirm_t mibGet;
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_DEVICE_CLASS;
LoRaMacMibGetRequestConfirm( &mibReq );
printf( "\n###### ===== UPLINK FRAME %lu ==== ######\n", mcpsConfirm->UpLinkCounter );
printf( "\n" );
printf( "CLASS : %c\n", "ABC"[mibReq.Param.Class] );
printf( "\n" );
printf( "TX PORT : %d\n", AppData.Port );
if( AppData.BufferSize != 0 )
{
printf( "TX DATA : " );
if( AppData.MsgType == LORAMAC_HANDLER_CONFIRMED_MSG )
{
printf( "CONFIRMED - %s\n", ( mcpsConfirm->AckReceived != 0 ) ? "ACK" : "NACK" );
}
else
{
printf( "UNCONFIRMED\n" );
}
PrintHexBuffer( AppData.Buffer, AppData.BufferSize );
}
printf( "\n" );
printf( "DATA RATE : DR_%d\n", mcpsConfirm->Datarate );
mibGet.Type = MIB_CHANNELS;
if( LoRaMacMibGetRequestConfirm( &mibGet ) == LORAMAC_STATUS_OK )
{
printf( "U/L FREQ : %lu\n", mibGet.Param.ChannelList[mcpsConfirm->Channel].Frequency );
}
printf( "TX POWER : %d\n", mcpsConfirm->TxPower );
mibGet.Type = MIB_CHANNELS_MASK;
if( LoRaMacMibGetRequestConfirm( &mibGet ) == LORAMAC_STATUS_OK )
{
printf("CHANNEL MASK: ");
#if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \
defined( REGION_EU868 ) || defined( REGION_IN865 ) || \
defined( REGION_KR920 ) || defined( REGION_EU433 ) || \
defined( REGION_RU864 )
for( uint8_t i = 0; i < 1; i++)
#elif defined( REGION_AU915 ) || defined( REGION_US915 ) || defined( REGION_CN470 )
for( uint8_t i = 0; i < 5; i++)
#else
#error "Please define a region in the compiler options."
#endif
{
printf("%04X ", mibGet.Param.ChannelsMask[i] );
}
printf("\n");
}
printf( "\n" );
}
/*!
* \brief MCPS-Indication event function
*
* \param [IN] mcpsIndication - Pointer to the indication structure,
* containing indication attributes.
*/
static void McpsIndication( McpsIndication_t *mcpsIndication )
{
printf( "\n###### ===== MCPS-Indication ==== ######\n" );
printf( "STATUS : %s\n", EventInfoStatusStrings[mcpsIndication->Status] );
if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
{
return;
}
switch( mcpsIndication->McpsIndication )
{
case MCPS_UNCONFIRMED:
{
break;
}
case MCPS_CONFIRMED:
{
break;
}
case MCPS_PROPRIETARY:
{
break;
}
case MCPS_MULTICAST:
{
break;
}
default:
break;
}
// Check Multicast
// Check Port
// Check Datarate
// Check FramePending
if( mcpsIndication->FramePending == true )
{
// The server signals that it has pending data to be sent.
// We schedule an uplink as soon as possible to flush the server.
OnTxNextPacketTimerEvent( NULL );
}
// Check Buffer
// Check BufferSize
// Check Rssi
// Check Snr
// Check RxSlot
if( ComplianceTest.Running == true )
{
ComplianceTest.DownLinkCounter++;
}
if( mcpsIndication->RxData == true )
{
switch( mcpsIndication->Port )
{
case 1: // The application LED can be controlled on port 1 or 2
case 2:
if( mcpsIndication->BufferSize == 1 )
{
AppLedStateOn = mcpsIndication->Buffer[0] & 0x01;
GpioWrite( &Led4, ( ( AppLedStateOn & 0x01 ) != 0 ) ? 1 : 0 );
}
break;
case 224:
if( ComplianceTest.Running == false )
{
// Check compliance test enable command (i)
if( ( mcpsIndication->BufferSize == 4 ) &&
( mcpsIndication->Buffer[0] == 0x01 ) &&
( mcpsIndication->Buffer[1] == 0x01 ) &&
( mcpsIndication->Buffer[2] == 0x01 ) &&
( mcpsIndication->Buffer[3] == 0x01 ) )
{
IsTxConfirmed = false;
AppPort = 224;
AppDataSizeBackup = AppDataSize;
AppDataSize = 2;
ComplianceTest.DownLinkCounter = 0;
ComplianceTest.LinkCheck = false;
ComplianceTest.DemodMargin = 0;
ComplianceTest.NbGateways = 0;
ComplianceTest.Running = true;
ComplianceTest.State = 1;
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = true;
LoRaMacMibSetRequestConfirm( &mibReq );
#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 )
LoRaMacTestSetDutyCycleOn( false );
#endif
}
}
else
{
ComplianceTest.State = mcpsIndication->Buffer[0];
switch( ComplianceTest.State )
{
case 0: // Check compliance test disable command (ii)
IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
AppPort = LORAWAN_APP_PORT;
AppDataSize = AppDataSizeBackup;
ComplianceTest.DownLinkCounter = 0;
ComplianceTest.Running = false;
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
LoRaMacMibSetRequestConfirm( &mibReq );
#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 )
LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
#endif
break;
case 1: // (iii, iv)
AppDataSize = 2;
break;
case 2: // Enable confirmed messages (v)
IsTxConfirmed = true;
ComplianceTest.State = 1;
break;
case 3: // Disable confirmed messages (vi)
IsTxConfirmed = false;
ComplianceTest.State = 1;
break;
case 4: // (vii)
AppDataSize = mcpsIndication->BufferSize;
AppDataBuffer[0] = 4;
for( uint8_t i = 1; i < MIN( AppDataSize, LORAWAN_APP_DATA_MAX_SIZE ); i++ )
{
AppDataBuffer[i] = mcpsIndication->Buffer[i] + 1;
}
break;
case 5: // (viii)
{
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_LINK_CHECK;
LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq );
printf( "\n###### ===== MLME-Request - MLME_LINK_CHECK ==== ######\n" );
printf( "STATUS : %s\n", MacStatusStrings[status] );
}
break;
case 6: // (ix)
{
// Disable TestMode and revert back to normal operation
IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
AppPort = LORAWAN_APP_PORT;
AppDataSize = AppDataSizeBackup;
ComplianceTest.DownLinkCounter = 0;
ComplianceTest.Running = false;
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
LoRaMacMibSetRequestConfirm( &mibReq );
#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 )
LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
#endif
JoinNetwork( );
}
break;
case 7: // (x)
{
if( mcpsIndication->BufferSize == 3 )
{
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_TXCW;
mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] );
LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq );
printf( "\n###### ===== MLME-Request - MLME_TXCW ==== ######\n" );
printf( "STATUS : %s\n", MacStatusStrings[status] );
}
else if( mcpsIndication->BufferSize == 7 )
{
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_TXCW_1;
mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] );
mlmeReq.Req.TxCw.Frequency = ( uint32_t )( ( mcpsIndication->Buffer[3] << 16 ) | ( mcpsIndication->Buffer[4] << 8 ) | mcpsIndication->Buffer[5] ) * 100;
mlmeReq.Req.TxCw.Power = mcpsIndication->Buffer[6];
LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq );
printf( "\n###### ===== MLME-Request - MLME_TXCW1 ==== ######\n" );
printf( "STATUS : %s\n", MacStatusStrings[status] );
}
ComplianceTest.State = 1;
}
break;
case 8: // Send DeviceTimeReq
{
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_DEVICE_TIME;
LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq );
printf( "\n###### ===== MLME-Request - MLME_DEVICE_TIME ==== ######\n" );
printf( "STATUS : %s\n", MacStatusStrings[status] );
}
break;
default:
break;
}
}
break;
default:
break;
}
}
// Switch LED 3 ON for each received downlink
GpioWrite( &Led3, 1 );
TimerStart( &Led3Timer );
const char *slotStrings[] = { "1", "2", "C", "C Multicast", "B Ping-Slot", "B Multicast Ping-Slot" };
printf( "\n###### ===== DOWNLINK FRAME %lu ==== ######\n", mcpsIndication->DownLinkCounter );
printf( "RX WINDOW : %s\n", slotStrings[mcpsIndication->RxSlot] );
printf( "RX PORT : %d\n", mcpsIndication->Port );
if( mcpsIndication->BufferSize != 0 )
{
printf( "RX DATA : \n" );
PrintHexBuffer( mcpsIndication->Buffer, mcpsIndication->BufferSize );
}
printf( "\n" );
printf( "DATA RATE : DR_%d\n", mcpsIndication->RxDatarate );
printf( "RX RSSI : %d\n", mcpsIndication->Rssi );
printf( "RX SNR : %d\n", mcpsIndication->Snr );
printf( "\n" );
}
/*!
* \brief MLME-Confirm event function
*
* \param [IN] mlmeConfirm - Pointer to the confirm structure,
* containing confirm attributes.
*/
static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm )
{
printf( "\n###### ===== MLME-Confirm ==== ######\n" );
printf( "STATUS : %s\n", EventInfoStatusStrings[mlmeConfirm->Status] );
if( mlmeConfirm->Status != LORAMAC_EVENT_INFO_STATUS_OK )
{
}
switch( mlmeConfirm->MlmeRequest )
{
case MLME_JOIN:
{
if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
{
MibRequestConfirm_t mibGet;
printf( "###### ===== JOINED ==== ######\n" );
printf( "\nOTAA\n\n" );
mibGet.Type = MIB_DEV_ADDR;
LoRaMacMibGetRequestConfirm( &mibGet );
printf( "DevAddr : %08lX\n", mibGet.Param.DevAddr );
printf( "\n\n" );
mibGet.Type = MIB_CHANNELS_DATARATE;
LoRaMacMibGetRequestConfirm( &mibGet );
printf( "DATA RATE : DR_%d\n", mibGet.Param.ChannelsDatarate );
printf( "\n" );
// Status is OK, node has joined the network
DeviceState = DEVICE_STATE_SEND;
}
else
{
// Join was not successful. Try to join again
JoinNetwork( );
}
break;
}
case MLME_LINK_CHECK:
{
if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
{
// Check DemodMargin
// Check NbGateways
if( ComplianceTest.Running == true )
{
ComplianceTest.LinkCheck = true;
ComplianceTest.DemodMargin = mlmeConfirm->DemodMargin;
ComplianceTest.NbGateways = mlmeConfirm->NbGateways;
}
}
break;
}
default:
break;
}
}
/*!
* \brief MLME-Indication event function
*
* \param [IN] mlmeIndication - Pointer to the indication structure.
*/
static void MlmeIndication( MlmeIndication_t *mlmeIndication )
{
if( mlmeIndication->Status != LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED )
{
printf( "\n###### ===== MLME-Indication ==== ######\n" );
printf( "STATUS : %s\n", EventInfoStatusStrings[mlmeIndication->Status] );
}
if( mlmeIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
{
}
switch( mlmeIndication->MlmeIndication )
{
case MLME_SCHEDULE_UPLINK:
{// The MAC signals that we shall provide an uplink as soon as possible
OnTxNextPacketTimerEvent( NULL );
break;
}
default:
break;
}
}
void OnMacProcessNotify( void )
{
IsMacProcessPending = 1;
}
/**
* Main application entry point.
*/
/** 0: Band unknown, 1: LF band, 2: HF band */
extern uint8_t sx1276_band;
int lora_main( void )
{
LoRaMacPrimitives_t macPrimitives;
LoRaMacCallback_t macCallbacks;
MibRequestConfirm_t mibReq;
LoRaMacStatus_t status;
uint8_t devEui[8] = { 0 }; // Automatically filed from secure-element
uint8_t joinEui[8] = { 0 }; // Automatically filed from secure-element
uint8_t sePin[4] = { 0 }; // Automatically filed from secure-element
sx1276_band = 2;
BoardInitMcu( );
BoardInitPeriph( );
macPrimitives.MacMcpsConfirm = McpsConfirm;
macPrimitives.MacMcpsIndication = McpsIndication;
macPrimitives.MacMlmeConfirm = MlmeConfirm;
macPrimitives.MacMlmeIndication = MlmeIndication;
macCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
macCallbacks.GetTemperatureLevel = NULL;
macCallbacks.NvmContextChange = NvmCtxMgmtEvent;
macCallbacks.MacProcessNotify = OnMacProcessNotify;
status = LoRaMacInitialization( &macPrimitives, &macCallbacks, ACTIVE_REGION );
if ( status != LORAMAC_STATUS_OK )
{
printf( "LoRaMac wasn't properly initialized, error: %s", MacStatusStrings[status] );
// Fatal error, endless loop.
while ( 1 )
{
}
}
DeviceState = DEVICE_STATE_RESTORE;
printf( "###### ===== ClassA demo application v1.0.0 ==== ######\n\n" );
while( 1 )
{
// Process Radio IRQ
if( Radio.IrqProcess != NULL )
{
Radio.IrqProcess( );
}
// Processes the LoRaMac events
LoRaMacProcess( );
switch( DeviceState )
{
case DEVICE_STATE_RESTORE:
{
// Try to restore from NVM and query the mac if possible.
if( NvmCtxMgmtRestore( ) == NVMCTXMGMT_STATUS_SUCCESS )
{
printf( "\n###### ===== CTXS RESTORED ==== ######\n\n" );
}
else
{
// Read secure-element DEV_EUI, JOI_EUI and SE_PIN values.
mibReq.Type = MIB_DEV_EUI;
LoRaMacMibGetRequestConfirm( &mibReq );
memcpy1( devEui, mibReq.Param.DevEui, 8 );
mibReq.Type = MIB_JOIN_EUI;
LoRaMacMibGetRequestConfirm( &mibReq );
memcpy1( joinEui, mibReq.Param.JoinEui, 8 );
mibReq.Type = MIB_SE_PIN;
LoRaMacMibGetRequestConfirm( &mibReq );
memcpy1( 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 );
// Choose a random device address if not already defined in Commissioning.h
#if( STATIC_DEVICE_ADDRESS != 1 )
// Random seed initialization
srand1( BoardGetRandomSeed( ) );
// Choose a random device address
DevAddr = randr( 0, 0x01FFFFFF );
#endif
mibReq.Type = MIB_DEV_ADDR;
mibReq.Param.DevAddr = DevAddr;
LoRaMacMibSetRequestConfirm( &mibReq );
#endif // #if( OVER_THE_AIR_ACTIVATION == 0 )
}
DeviceState = DEVICE_STATE_START;
break;
}
case DEVICE_STATE_START:
{
TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent );
TimerInit( &Led1Timer, OnLed1TimerEvent );
TimerSetValue( &Led1Timer, 25 );
TimerInit( &Led3Timer, OnLed3TimerEvent );
TimerSetValue( &Led3Timer, 25 );
mibReq.Type = MIB_PUBLIC_NETWORK;
mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
LoRaMacMibSetRequestConfirm( &mibReq );
#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 )
LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
#endif
mibReq.Type = MIB_SYSTEM_MAX_RX_ERROR;
mibReq.Param.SystemMaxRxError = 20;
LoRaMacMibSetRequestConfirm( &mibReq );
LoRaMacStart( );
mibReq.Type = MIB_NETWORK_ACTIVATION;
status = LoRaMacMibGetRequestConfirm( &mibReq );
if( status == LORAMAC_STATUS_OK )
{
if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE )
{
DeviceState = DEVICE_STATE_JOIN;
}
else
{
DeviceState = DEVICE_STATE_SEND;
NextTx = true;
}
}
break;
}
case DEVICE_STATE_JOIN:
{
mibReq.Type = MIB_DEV_EUI;
LoRaMacMibGetRequestConfirm( &mibReq );
printf( "DevEui : %02X", mibReq.Param.DevEui[0] );
for( int i = 1; i < 8; i++ )
{
printf( "-%02X", mibReq.Param.DevEui[i] );
}
printf( "\n" );
mibReq.Type = MIB_JOIN_EUI;
LoRaMacMibGetRequestConfirm( &mibReq );
printf( "JoinEui : %02X", mibReq.Param.JoinEui[0] );
for( int i = 1; i < 8; i++ )
{
printf( "-%02X", mibReq.Param.JoinEui[i] );
}
printf( "\n" );
mibReq.Type = MIB_SE_PIN;
LoRaMacMibGetRequestConfirm( &mibReq );
printf( "Pin : %02X", mibReq.Param.SePin[0] );
for( int i = 1; i < 4; i++ )
{
printf( "-%02X", mibReq.Param.SePin[i] );
}
printf( "\n\n" );
#if( OVER_THE_AIR_ACTIVATION == 0 )
printf( "###### ===== JOINED ==== ######\n" );
printf( "\nABP\n\n" );
printf( "DevAddr : %08lX\n", DevAddr );
printf( "\n\n" );
mibReq.Type = MIB_NETWORK_ACTIVATION;
mibReq.Param.NetworkActivation = ACTIVATION_TYPE_ABP;
LoRaMacMibSetRequestConfirm( &mibReq );
DeviceState = DEVICE_STATE_SEND;
#else
JoinNetwork( );
#endif
break;
}
case DEVICE_STATE_SEND:
{
if( NextTx == true )
{
PrepareTxFrame( AppPort );
NextTx = SendFrame( );
}
DeviceState = DEVICE_STATE_CYCLE;
break;
}
case DEVICE_STATE_CYCLE:
{
DeviceState = DEVICE_STATE_SLEEP;
if( ComplianceTest.Running == true )
{
// Schedule next packet transmission
TxDutyCycleTime = 5000; // 5000 ms
}
else
{
// Schedule next packet transmission
TxDutyCycleTime = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );
}
// Schedule next packet transmission
TimerSetValue( &TxNextPacketTimer, TxDutyCycleTime );
TimerStart( &TxNextPacketTimer );
break;
}
case DEVICE_STATE_SLEEP:
{
if( NvmCtxMgmtStore( ) == NVMCTXMGMT_STATUS_SUCCESS )
{
printf( "\n###### ===== CTXS STORED ==== ######\n" );
}
CRITICAL_SECTION_BEGIN( );
if( IsMacProcessPending == 1 )
{
// Clear flag and prevent MCU to go into low power modes.
IsMacProcessPending = 0;
}
else
{
// The MCU wakes up through events
BoardLowPowerHandler( );
}
CRITICAL_SECTION_END( );
break;
}
default:
{
DeviceState = DEVICE_STATE_START;
break;
}
}
}
}