LoRaMAC  4.4.5
Documentation of the API
classA/SKiM881AXL/main.c

LoRaWAN class A application example for the SKiM881AXL.

#include <stdio.h>
#include "utilities.h"
#include "board.h"
#include "gpio.h"
#include "LoRaMac.h"
#include "Commissioning.h"
#include "NvmCtxMgmt.h"
#ifndef ACTIVE_REGION
#warning "No active region defined, LORAMAC_REGION_EU868 will be used as default."
#define ACTIVE_REGION LORAMAC_REGION_EU868
#endif
#define APP_TX_DUTYCYCLE 5000
#define APP_TX_DUTYCYCLE_RND 1000
#define LORAWAN_DEFAULT_DATARATE DR_0
#define LORAWAN_CONFIRMED_MSG_ON false
#define LORAWAN_ADR_ON 1
#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 )
#include "LoRaMacTest.h"
#define LORAWAN_DUTYCYCLE_ON true
#endif
#define LORAWAN_APP_PORT 3
#if( OVER_THE_AIR_ACTIVATION == 0 )
static uint32_t DevAddr = LORAWAN_DEVICE_ADDRESS;
#endif
static uint8_t AppPort = LORAWAN_APP_PORT;
static uint8_t AppDataSize = 4;
static uint8_t AppDataSizeBackup = 4;
#define LORAWAN_APP_DATA_MAX_SIZE 242
static uint8_t AppDataBuffer[LORAWAN_APP_DATA_MAX_SIZE];
static uint8_t IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
static uint32_t TxDutyCycleTime;
static TimerEvent_t TxNextPacketTimer;
static bool AppLedStateOn = false;
static TimerEvent_t Led4Timer;
static TimerEvent_t Led2Timer;
static bool NextTx = true;
static uint8_t IsMacProcessPending = 0;
static enum eDeviceState
{
DEVICE_STATE_RESTORE,
DEVICE_STATE_START,
DEVICE_STATE_JOIN,
DEVICE_STATE_SEND,
DEVICE_STATE_CYCLE,
DEVICE_STATE_SLEEP
}DeviceState;
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;
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
};
extern Gpio_t Led4; // Tx
extern Gpio_t Led2; // Rx
extern Gpio_t Led3; // App
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
};
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
};
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" );
}
static void JoinNetwork( void )
{
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
{
{
printf( "Next Tx in : %lu [ms]\n", mlmeReq.ReqReturn.DutyCycleWaitTime );
}
DeviceState = DEVICE_STATE_CYCLE;
}
}
static void PrepareTxFrame( uint8_t port )
{
switch( port )
{
case 3:
{
uint8_t potiPercentage = 0;
uint16_t vdd = 0;
// Read the current potentiometer setting in percent
potiPercentage = BoardGetPotiLevel( );
// Read the current voltage level
BoardGetBatteryLevel( ); // Updates the value returned by BoardGetBatteryVoltage( ) function.
vdd = BoardGetBatteryVoltage( );
AppDataSizeBackup = AppDataSize = 4;
AppDataBuffer[0] = AppLedStateOn;
AppDataBuffer[1] = potiPercentage;
AppDataBuffer[2] = ( vdd >> 8 ) & 0xFF;
AppDataBuffer[3] = vdd & 0xFF;
}
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;
}
}
static bool SendFrame( void )
{
McpsReq_t mcpsReq;
if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK )
{
// Send empty frame in order to flush MAC commands
mcpsReq.Req.Unconfirmed.fBuffer = NULL;
mcpsReq.Req.Unconfirmed.fBufferSize = 0;
mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
}
else
{
if( IsTxConfirmed == false )
{
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;
status = LoRaMacMcpsRequest( &mcpsReq );
printf( "\n###### ===== MCPS-Request ==== ######\n" );
printf( "STATUS : %s\n", MacStatusStrings[status] );
{
printf( "Next Tx in : %lu [ms]\n", mcpsReq.ReqReturn.DutyCycleWaitTime );
}
if( status == LORAMAC_STATUS_OK )
{
return false;
}
return true;
}
static void OnTxNextPacketTimerEvent( void* context )
{
TimerStop( &TxNextPacketTimer );
status = LoRaMacMibGetRequestConfirm( &mibReq );
if( status == LORAMAC_STATUS_OK )
{
{
// Network not joined yet. Try to join again
JoinNetwork( );
}
else
{
DeviceState = DEVICE_STATE_SEND;
NextTx = true;
}
}
}
static void OnLed4TimerEvent( void* context )
{
TimerStop( &Led4Timer );
// Switch LED 4 OFF
GpioWrite( &Led4, 0 );
}
static void OnLed2TimerEvent( void* context )
{
TimerStop( &Led2Timer );
// Switch LED 2 OFF
GpioWrite( &Led2, 0 );
}
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 )
{
{
// Check Datarate
// Check TxPower
break;
}
{
// Check Datarate
// Check TxPower
// Check AckReceived
// Check NbTrials
break;
}
{
break;
}
default:
break;
}
// Switch LED 4 ON
GpioWrite( &Led4, 1 );
TimerStart( &Led4Timer );
}
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;
{
printf( "U/L FREQ : %lu\n", mibGet.Param.ChannelList[mcpsConfirm->Channel].Frequency );
}
printf( "TX POWER : %d\n", mcpsConfirm->TxPower );
{
printf("CHANNEL MASK: ");
#if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \
defined( REGION_EU868 ) || defined( REGION_IN865 ) || \
defined( REGION_KR920 ) || defined( REGION_RU864 )
for( uint8_t i = 0; i < 1; i++)
#elif defined( REGION_AU915 ) || defined( REGION_US915 )
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" );
}
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 )
{
{
break;
}
{
break;
}
{
break;
}
{
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( &Led3, ( ( 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;
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = true;
#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 )
#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;
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
#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;
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
#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;
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 2 ON for each received downlink
GpioWrite( &Led2, 1 );
TimerStart( &Led2Timer );
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" );
}
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 )
{
printf( "###### ===== JOINED ==== ######\n" );
printf( "\nOTAA\n\n" );
mibGet.Type = MIB_DEV_ADDR;
printf( "DevAddr : %08lX\n", mibGet.Param.DevAddr );
printf( "\n\n" );
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;
}
{
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;
}
}
static void MlmeIndication( MlmeIndication_t *mlmeIndication )
{
{
printf( "\n###### ===== MLME-Indication ==== ######\n" );
printf( "STATUS : %s\n", EventInfoStatusStrings[mlmeIndication->Status] );
}
if( mlmeIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
{
}
switch( mlmeIndication->MlmeIndication )
{
{// The MAC signals that we shall provide an uplink as soon as possible
OnTxNextPacketTimerEvent( NULL );
break;
}
default:
break;
}
}
void OnMacProcessNotify( void )
{
IsMacProcessPending = 1;
}
int main( void )
{
LoRaMacPrimitives_t macPrimitives;
LoRaMacCallback_t macCallbacks;
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
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
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;
memcpy1( devEui, mibReq.Param.DevEui, 8 );
mibReq.Type = MIB_JOIN_EUI;
memcpy1( joinEui, mibReq.Param.JoinEui, 8 );
mibReq.Type = MIB_SE_PIN;
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.Param.AbpLrWanVersion.Value = ABP_ACTIVATION_LRWAN_VERSION;
mibReq.Type = MIB_NET_ID;
mibReq.Param.NetID = LORAWAN_NETWORK_ID;
// 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;
#endif // #if( OVER_THE_AIR_ACTIVATION == 0 )
}
DeviceState = DEVICE_STATE_START;
break;
}
case DEVICE_STATE_START:
{
TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent );
TimerInit( &Led4Timer, OnLed4TimerEvent );
TimerSetValue( &Led4Timer, 25 );
TimerInit( &Led2Timer, OnLed2TimerEvent );
TimerSetValue( &Led2Timer, 25 );
mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 )
LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
#endif
mibReq.Param.SystemMaxRxError = 20;
status = LoRaMacMibGetRequestConfirm( &mibReq );
if( status == LORAMAC_STATUS_OK )
{
{
DeviceState = DEVICE_STATE_JOIN;
}
else
{
DeviceState = DEVICE_STATE_SEND;
NextTx = true;
}
}
break;
}
case DEVICE_STATE_JOIN:
{
mibReq.Type = MIB_DEV_EUI;
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;
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;
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" );
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;
}
}
}
}
MIB_ABP_LORAWAN_VERSION
Definition: LoRaMac.h:1632
MibParam_t::DevEui
uint8_t * DevEui
Definition: LoRaMac.h:1719
MibParam_t::ChannelsDatarate
int8_t ChannelsDatarate
Definition: LoRaMac.h:1971
McpsReq_t::Type
Mcps_t Type
Definition: LoRaMac.h:780
MIB_DEVICE_CLASS
Definition: LoRaMac.h:1303
McpsReq_t::uMcpsParam::Confirmed
McpsReqConfirmed_t Confirmed
Definition: LoRaMac.h:794
LoRaMacMcpsRequest
LoRaMacStatus_t LoRaMacMcpsRequest(McpsReq_t *mcpsRequest)
LoRaMAC MCPS-Request.
LoRaMacStatus_t
LoRaMacStatus_t
Definition: LoRaMac.h:2153
MIB_JOIN_EUI
Definition: LoRaMac.h:1321
MibParam_t::EnablePublicNetwork
bool EnablePublicNetwork
Definition: LoRaMac.h:1881
MCPS_UNCONFIRMED
Definition: LoRaMac.h:652
MIB_CHANNELS
Definition: LoRaMac.h:1487
MCPS_MULTICAST
Definition: LoRaMac.h:660
MlmeConfirm_t::MlmeRequest
Mlme_t MlmeRequest
Definition: LoRaMac.h:1161
LoRaMacPrimitives_t
Definition: LoRaMac.h:2352
MLME_TXCW
Definition: LoRaMac.h:980
MlmeReqJoin_t::Datarate
uint8_t Datarate
Definition: LoRaMac.h:1050
LoRaMacPrimitives_t::MacMcpsIndication
void(* MacMcpsIndication)(McpsIndication_t *McpsIndication)
MCPS-Indication primitive.
Definition: LoRaMac.h:2365
MIB_DEV_ADDR
Definition: LoRaMac.h:1345
MlmeIndication_t
Definition: LoRaMac.h:1197
MIB_ADR
Definition: LoRaMac.h:1333
MibParam_t::ChannelsMask
uint16_t * ChannelsMask
Definition: LoRaMac.h:1917
LoRaMacPrimitives_t::MacMlmeIndication
void(* MacMlmeIndication)(MlmeIndication_t *MlmeIndication)
MLME-Indication primitive.
Definition: LoRaMac.h:2377
LoRaMacPrimitives_t::MacMlmeConfirm
void(* MacMlmeConfirm)(MlmeConfirm_t *MlmeConfirm)
MLME-Confirm primitive.
Definition: LoRaMac.h:2371
ACTIVATION_TYPE_NONE
Definition: LoRaMac.h:170
McpsConfirm_t::Channel
uint32_t Channel
Definition: LoRaMac.h:847
MibParam_t::SePin
uint8_t * SePin
Definition: LoRaMac.h:1731
MIB_DEV_EUI
Definition: LoRaMac.h:1315
McpsIndication_t::Buffer
uint8_t * Buffer
Definition: LoRaMac.h:882
MibParam_t::Class
DeviceClass_t Class
Definition: LoRaMac.h:1707
MibRequestConfirm_t::Type
Mib_t Type
Definition: LoRaMac.h:2126
MibRequestConfirm_t::Param
MibParam_t Param
Definition: LoRaMac.h:2131
MibParam_t::NetworkActivation
ActivationType_t NetworkActivation
Definition: LoRaMac.h:1713
LoRaMacTestSetDutyCycleOn
void LoRaMacTestSetDutyCycleOn(bool enable)
Enabled or disables the duty cycle.
MlmeReq_t
Definition: LoRaMac.h:1113
MibParam_t::JoinEui
uint8_t * JoinEui
Definition: LoRaMac.h:1725
MlmeReq_t::uMlmeParam::Join
MlmeReqJoin_t Join
Definition: LoRaMac.h:1128
MIB_NETWORK_ACTIVATION
Definition: LoRaMac.h:1309
McpsConfirm_t::TxPower
int8_t TxPower
Definition: LoRaMac.h:827
MlmeReq_t::Type
Mlme_t Type
Definition: LoRaMac.h:1118
McpsReqUnconfirmed_t::Datarate
int8_t Datarate
Definition: LoRaMac.h:703
LoRaMacCallback_t::GetBatteryLevel
uint8_t(* GetBatteryLevel)(void)
Measures the battery level.
Definition: LoRaMac.h:2393
McpsConfirm_t::UpLinkCounter
uint32_t UpLinkCounter
Definition: LoRaMac.h:843
LoRaMacTest.h
LoRa MAC layer test function implementation.
LoRaMacCallback_t::MacProcessNotify
void(* MacProcessNotify)(void)
Will be called each time a Radio IRQ is handled by the MAC layer.
Definition: LoRaMac.h:2412
MIB_CHANNELS_MASK
Definition: LoRaMac.h:1517
LoRaMacProcess
void LoRaMacProcess(void)
McpsConfirm_t::McpsRequest
Mcps_t McpsRequest
Definition: LoRaMac.h:815
LORAMAC_EVENT_INFO_STATUS_OK
Definition: LoRaMac.h:513
MibRequestConfirm_t
Definition: LoRaMac.h:2121
McpsConfirm_t::Status
LoRaMacEventInfoStatus_t Status
Definition: LoRaMac.h:819
MLME_JOIN
Definition: LoRaMac.h:956
McpsIndication_t::McpsIndication
Mcps_t McpsIndication
Definition: LoRaMac.h:858
LoRaMacPrimitives_t::MacMcpsConfirm
void(* MacMcpsConfirm)(McpsConfirm_t *McpsConfirm)
MCPS-Confirm primitive.
Definition: LoRaMac.h:2359
McpsIndication_t::FramePending
uint8_t FramePending
Definition: LoRaMac.h:878
McpsConfirm_t::AckReceived
bool AckReceived
Definition: LoRaMac.h:831
LoRaMacCallback_t::GetTemperatureLevel
float(* GetTemperatureLevel)(void)
Measures the temperature level.
Definition: LoRaMac.h:2399
MIB_PUBLIC_NETWORK
Definition: LoRaMac.h:1479
McpsReqUnconfirmed_t::fBuffer
void * fBuffer
Definition: LoRaMac.h:695
MlmeReqTxCw_t::Timeout
uint16_t Timeout
Definition: LoRaMac.h:1061
McpsIndication_t::DownLinkCounter
uint32_t DownLinkCounter
Definition: LoRaMac.h:910
MlmeConfirm_t
Definition: LoRaMac.h:1156
McpsReqConfirmed_t::NbTrials
uint8_t NbTrials
Definition: LoRaMac.h:750
ACTIVATION_TYPE_ABP
Definition: LoRaMac.h:174
LoRaMacCallback_t
Definition: LoRaMac.h:2383
McpsReqUnconfirmed_t::fPort
uint8_t fPort
Definition: LoRaMac.h:691
MibParam_t::DevAddr
uint32_t DevAddr
Definition: LoRaMac.h:1749
McpsIndication_t::Rssi
int16_t Rssi
Definition: LoRaMac.h:894
MIB_SYSTEM_MAX_RX_ERROR
Definition: LoRaMac.h:1597
MCPS_PROPRIETARY
Definition: LoRaMac.h:664
McpsIndication_t::BufferSize
uint8_t BufferSize
Definition: LoRaMac.h:886
MLME_LINK_CHECK
Definition: LoRaMac.h:974
MCPS_CONFIRMED
Definition: LoRaMac.h:656
McpsIndication_t::Snr
int8_t Snr
Definition: LoRaMac.h:898
MLME_DEVICE_TIME
Definition: LoRaMac.h:1005
LoRaMac.h
LoRa MAC layer implementation.
ChannelParams_t::Frequency
uint32_t Frequency
Definition: LoRaMac.h:222
McpsIndication_t::RxData
bool RxData
Definition: LoRaMac.h:890
MibParam_t::ChannelList
ChannelParams_t * ChannelList
Definition: LoRaMac.h:1887
MibParam_t::AdrEnable
bool AdrEnable
Definition: LoRaMac.h:1737
McpsConfirm_t
Definition: LoRaMac.h:810
LoRaMacQueryTxPossible
LoRaMacStatus_t LoRaMacQueryTxPossible(uint8_t size, LoRaMacTxInfo_t *txInfo)
Queries the LoRaMAC if it is possible to send the next frame with a given application data payload si...
McpsReqUnconfirmed_t::fBufferSize
uint16_t fBufferSize
Definition: LoRaMac.h:699
MlmeReq_t::ReqReturn
RequestReturnParam_t ReqReturn
Definition: LoRaMac.h:1150
LORAMAC_STATUS_DUTYCYCLE_RESTRICTED
Definition: LoRaMac.h:2214
LoRaMacMlmeRequest
LoRaMacStatus_t LoRaMacMlmeRequest(MlmeReq_t *mlmeRequest)
LoRaMAC MLME-Request.
MlmeReqTxCw_t::Power
int8_t Power
Definition: LoRaMac.h:1069
LORAMAC_STATUS_OK
Definition: LoRaMac.h:2158
MibParam_t::NetID
uint32_t NetID
Definition: LoRaMac.h:1743
McpsIndication_t::RxDatarate
uint8_t RxDatarate
Definition: LoRaMac.h:874
MlmeReq_t::uMlmeParam::TxCw
MlmeReqTxCw_t TxCw
Definition: LoRaMac.h:1132
MIB_SE_PIN
Definition: LoRaMac.h:1325
MIB_NET_ID
Definition: LoRaMac.h:1339
RequestReturnParam_t::DutyCycleWaitTime
TimerTime_t DutyCycleWaitTime
Definition: LoRaMac.h:677
LoRaMacMibGetRequestConfirm
LoRaMacStatus_t LoRaMacMibGetRequestConfirm(MibRequestConfirm_t *mibGet)
LoRaMAC MIB-Get.
MIB_CHANNELS_DATARATE
Definition: LoRaMac.h:1575
McpsReq_t::uMcpsParam::Unconfirmed
McpsReqUnconfirmed_t Unconfirmed
Definition: LoRaMac.h:790
McpsReq_t
Definition: LoRaMac.h:775
MLME_SCHEDULE_UPLINK
Definition: LoRaMac.h:991
MlmeConfirm_t::DemodMargin
uint8_t DemodMargin
Definition: LoRaMac.h:1174
McpsIndication_t::Port
uint8_t Port
Definition: LoRaMac.h:870
LoRaMacTxInfo_t
Definition: LoRaMac.h:2137
McpsIndication_t
Definition: LoRaMac.h:853
LoRaMacStart
LoRaMacStatus_t LoRaMacStart(void)
Starts LoRaMAC layer.
MlmeConfirm_t::NbGateways
uint8_t NbGateways
Definition: LoRaMac.h:1178
LoRaMacInitialization
LoRaMacStatus_t LoRaMacInitialization(LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks, LoRaMacRegion_t region)
LoRaMAC layer initialization.
MlmeIndication_t::MlmeIndication
Mlme_t MlmeIndication
Definition: LoRaMac.h:1202
LoRaMacMibSetRequestConfirm
LoRaMacStatus_t LoRaMacMibSetRequestConfirm(MibRequestConfirm_t *mibSet)
LoRaMAC MIB-Set.
MLME_TXCW_1
Definition: LoRaMac.h:986
McpsIndication_t::RxSlot
LoRaMacRxSlot_t RxSlot
Definition: LoRaMac.h:902
LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED
Definition: LoRaMac.h:572
MibParam_t::SystemMaxRxError
uint32_t SystemMaxRxError
Definition: LoRaMac.h:1995
LoRaMacCallback_t::NvmContextChange
void(* NvmContextChange)(LoRaMacNvmCtxModule_t module)
Will be called when an attribute has changed in one of the context.
Definition: LoRaMac.h:2405