Пример #1
0
void LoRaMacInitNwkIds( uint32_t netID, uint32_t devAddr, uint8_t *nwkSKey, uint8_t *appSKey )
{
    MibRequestConfirm_t mibSet;

    mibSet.Type = MIB_NET_ID;
    mibSet.Param.NetID = netID;

    LoRaMacMibSetRequestConfirm( &mibSet );

    mibSet.Type = MIB_DEV_ADDR;
    mibSet.Param.DevAddr = devAddr;

    LoRaMacMibSetRequestConfirm( &mibSet );

    mibSet.Type = MIB_NWK_SKEY;
    mibSet.Param.NwkSKey = nwkSKey;

    LoRaMacMibSetRequestConfirm( &mibSet );

    mibSet.Type = MIB_APP_SKEY;
    mibSet.Param.AppSKey = appSKey;

    LoRaMacMibSetRequestConfirm( &mibSet );

    mibSet.Type = MIB_NETWORK_JOINED;
    mibSet.Param.IsNetworkJoined = true;

    LoRaMacMibSetRequestConfirm( &mibSet );
}
Пример #2
0
static void _join_abp(semtech_loramac_t *mac)
{
    DEBUG("[semtech-loramac] starting ABP join\n");

    semtech_loramac_set_netid(mac, LORAMAC_DEFAULT_NETID);

    mutex_lock(&mac->lock);
    MibRequestConfirm_t mibReq;
    mibReq.Type = MIB_NETWORK_JOINED;
    mibReq.Param.IsNetworkJoined = false;
    LoRaMacMibSetRequestConfirm(&mibReq);

    mibReq.Type = MIB_DEV_ADDR;
    mibReq.Param.DevAddr = ((uint32_t)mac->devaddr[0] << 24 |
                            (uint32_t)mac->devaddr[1] << 16 |
                            (uint32_t)mac->devaddr[2] << 8 |
                            (uint32_t)mac->devaddr[3]);
    LoRaMacMibSetRequestConfirm(&mibReq);

    mibReq.Type = MIB_NWK_SKEY;
    mibReq.Param.NwkSKey = mac->nwkskey;
    LoRaMacMibSetRequestConfirm(&mibReq);

    mibReq.Type = MIB_APP_SKEY;
    mibReq.Param.AppSKey = mac->appskey;
    LoRaMacMibSetRequestConfirm(&mibReq);

    mibReq.Type = MIB_NETWORK_JOINED;
    mibReq.Param.IsNetworkJoined = true;
    LoRaMacMibSetRequestConfirm(&mibReq);
    mutex_unlock(&mac->lock);
}
Пример #3
0
void LoRaMacSetPublicNetwork( bool enable )
{
    MibRequestConfirm_t mibSet;

    mibSet.Type = MIB_PUBLIC_NETWORK;
    mibSet.Param.EnablePublicNetwork = enable;

    LoRaMacMibSetRequestConfirm( &mibSet );
}
Пример #4
0
void LoRaMacSetChannelsTxPower( int8_t txPower )
{
    MibRequestConfirm_t mibSet;

    mibSet.Type = MIB_CHANNELS_TX_POWER;
    mibSet.Param.ChannelsTxPower = txPower;

    LoRaMacMibSetRequestConfirm( &mibSet );
}
Пример #5
0
void LoRaMacSetJoinAcceptDelay2( uint32_t delay )
{
    MibRequestConfirm_t mibSet;

    mibSet.Type = MIB_JOIN_ACCEPT_DELAY_2;
    mibSet.Param.JoinAcceptDelay2 = delay;

    LoRaMacMibSetRequestConfirm( &mibSet );
}
Пример #6
0
void LoRaMacSetChannelsDatarate( int8_t datarate )
{
    MibRequestConfirm_t mibSet;

    mibSet.Type = MIB_CHANNELS_DATARATE;
    mibSet.Param.ChannelsDatarate = datarate;

    LoRaMacMibSetRequestConfirm( &mibSet );
}
Пример #7
0
void LoRaMacSetMaxRxWindow( uint32_t delay )
{
    MibRequestConfirm_t mibSet;

    mibSet.Type = MIB_MAX_RX_WINDOW_DURATION;
    mibSet.Param.MaxRxWindow = delay;

    LoRaMacMibSetRequestConfirm( &mibSet );
}
Пример #8
0
void LoRaMacSetReceiveDelay2( uint32_t delay )
{
    MibRequestConfirm_t mibSet;

    mibSet.Type = MIB_RECEIVE_DELAY_2;
    mibSet.Param.ReceiveDelay2 = delay;

    LoRaMacMibSetRequestConfirm( &mibSet );
}
Пример #9
0
void LoRaMacSetChannelsMask( uint16_t *mask )
{
    MibRequestConfirm_t mibSet;

    mibSet.Type = MIB_CHANNELS_MASK;
    mibSet.Param.ChannelsMask = mask;

    LoRaMacMibSetRequestConfirm( &mibSet );
}
Пример #10
0
void LoRaMacSetChannelsNbRep( uint8_t nbRep )
{
    MibRequestConfirm_t mibSet;

    mibSet.Type = MIB_CHANNELS_NB_REP;
    mibSet.Param.ChannelNbRep = nbRep;

    LoRaMacMibSetRequestConfirm( &mibSet );
}
Пример #11
0
void LoRaMacSetDeviceClass( DeviceClass_t deviceClass )
{
    MibRequestConfirm_t mibSet;

    mibSet.Type = MIB_DEVICE_CLASS;
    mibSet.Param.Class = deviceClass;

    LoRaMacMibSetRequestConfirm( &mibSet );
}
Пример #12
0
void LoRaMacSetRx2Channel( Rx2ChannelParams_t param )
{
    MibRequestConfirm_t mibSet;

    mibSet.Type = MIB_RX2_CHANNEL;
    mibSet.Param.Rx2Channel = param;

    LoRaMacMibSetRequestConfirm( &mibSet );
}
Пример #13
0
void LoRaMacSetAdrOn( bool enable )
{
    MibRequestConfirm_t mibSet;

    mibSet.Type = MIB_ADR;
    mibSet.Param.AdrEnable = enable;

    LoRaMacMibSetRequestConfirm( &mibSet );
}
Пример #14
0
static void _join_otaa(semtech_loramac_t *mac)
{
    DEBUG("[semtech-loramac] starting OTAA join\n");

    uint8_t dr = semtech_loramac_get_dr(mac);

    mutex_lock(&mac->lock);
    MibRequestConfirm_t mibReq;
    mibReq.Type = MIB_NETWORK_JOINED;
    mibReq.Param.IsNetworkJoined = false;
    LoRaMacMibSetRequestConfirm(&mibReq);

    MlmeReq_t mlmeReq;
    mlmeReq.Type = MLME_JOIN;
    mlmeReq.Req.Join.DevEui = mac->deveui;
    mlmeReq.Req.Join.AppEui = mac->appeui;
    mlmeReq.Req.Join.AppKey = mac->appkey;
    mlmeReq.Req.Join.Datarate = dr;
    mutex_unlock(&mac->lock);
    uint8_t ret = LoRaMacMlmeRequest(&mlmeReq);
    switch(ret) {
        case LORAMAC_STATUS_OK:
            /* Let the MAC do his job */
            return;
        case LORAMAC_STATUS_DUTYCYCLE_RESTRICTED:
        {
            DEBUG("[semtech-loramac] join otaa: duty cycle restricted\n");
            /* Cannot join. */
            msg_t msg;
            msg.type = MSG_TYPE_LORAMAC_JOIN;
            msg.content.value = SEMTECH_LORAMAC_DUTYCYCLE_RESTRICTED;
            msg_send(&msg, semtech_loramac_pid);
            return;
        }
        case LORAMAC_STATUS_BUSY:
        {
            DEBUG("[semtech-loramac] join otaa: mac is busy\n");
            /* Cannot join. */
            msg_t msg;
            msg.type = MSG_TYPE_LORAMAC_JOIN;
            msg.content.value = SEMTECH_LORAMAC_BUSY;
            msg_send(&msg, semtech_loramac_pid);
            return;
        }
        default:
        {
            DEBUG("[semtech-loramac] join otaa: failed with status %d\n", ret);
            /* Cannot join. */
            msg_t msg;
            msg.type = MSG_TYPE_LORAMAC_JOIN;
            msg.content.value = SEMTECH_LORAMAC_JOIN_FAILED;
            msg_send(&msg, semtech_loramac_pid);
            return;
        }
    }
}
Пример #15
0
static inline void _set_uplink_counter(semtech_loramac_t *mac, uint8_t *counter)
{
    uint32_t counter4 = ((uint32_t)counter[0] << 24 |
                         (uint32_t)counter[1] << 16 |
                         (uint32_t)counter[2] << 8 |
                         counter[3]);

    DEBUG("[semtech-loramac] uplink counter: %" PRIu32 " \n", counter4);

    mutex_lock(&mac->lock);
    MibRequestConfirm_t mibReq;
    mibReq.Type = MIB_UPLINK_COUNTER;
    mibReq.Param.UpLinkCounter = counter4;
    LoRaMacMibSetRequestConfirm(&mibReq);
    mutex_unlock(&mac->lock);
}
Пример #16
0
/*!
 * \brief   MCPS-Indication event function
 *
 * \param   [IN] mcpsIndication - Pointer to the indication structure,
 *               containing indication attributes.
 */
static void McpsIndication( McpsIndication_t *mcpsIndication )
{
    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( );
    }
    // 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;
            }
            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 )
                    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 )
                    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;

                    AppData[0] = 4;
                    for( uint8_t i = 1; i < MIN( AppDataSize, LORAWAN_APP_DATA_MAX_SIZE ); i++ )
                    {
                        AppData[i] = mcpsIndication->Buffer[i] + 1;
                    }
                    break;
                case 5: // (viii)
                    {
                        MlmeReq_t mlmeReq;
                        mlmeReq.Type = MLME_LINK_CHECK;
                        LoRaMacMlmeRequest( &mlmeReq );
                    }
                    break;
                case 6: // (ix)
                    {
                        MlmeReq_t mlmeReq;

                        // 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 )
                        LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
#endif

                        mlmeReq.Type = MLME_JOIN;

                        mlmeReq.Req.Join.DevEui = DevEui;
                        mlmeReq.Req.Join.AppEui = AppEui;
                        mlmeReq.Req.Join.AppKey = AppKey;
                        mlmeReq.Req.Join.Datarate = LORAWAN_DEFAULT_DATARATE;

                        if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK )
                        {
                            DeviceState = DEVICE_STATE_SLEEP;
                        }
                        else
                        {
                            DeviceState = DEVICE_STATE_CYCLE;
                        }
                    }
                    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] );
                            LoRaMacMlmeRequest( &mlmeReq );
                        }
                        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];
                            LoRaMacMlmeRequest( &mlmeReq );
                        }
                        ComplianceTest.State = 1;
                    }
                    break;
                default:
                    break;
                }
            }
            break;
        default:
            break;
        }
    }

    // Switch LED 2 ON for each received downlink
    GpioWrite( &Led2, 1 );
    TimerStart( &Led2Timer );
}
Пример #17
0
int main( void )
{
    HAL_EnableDBGStopMode();
    LowPowerConfiguration();
    pc.baud(115200);
    // print banner
    pc.printf("\r\n============== DEBUG STARTED ==============\r\n");
    
    /** User button triggers the ultrasonic sensor */ 
    //PinDetect button(PC_13,PullUp);
    //button.attach_asserted(&sensor, &UltraSonic::triggerSample); // callback routine to trigger usonic
    //button.setSampleFrequency();

    LoRaMacPrimitives_t LoRaMacPrimitives;
    LoRaMacCallback_t LoRaMacCallbacks;
    MibRequestConfirm_t mibReq;

    //BoardInitMcu( );
    //BoardInitPeriph( );
    BoardInit( );

    TimerInit( &mainLoopTimeout, onMainLoopTimeoutEvent );
    

    DeviceState = DEVICE_STATE_INIT;

    while( 1 )
    {
       wait(0.5);
        // This is a kind of watchdog on the main loop, if the timer isn't cancelled in x seconds then loop will enter INIT state
       TimerSetValue( &mainLoopTimeout, 3000000 );
       TimerStart( &mainLoopTimeout );


        switch( DeviceState )
        {
            case DEVICE_STATE_INIT:
            {
                  pc.printf("DEVICE_STATE_INIT\r\n");

                LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
                LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
                LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
                LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
                LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks );

                TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent );
                TimerInit( &ultrasonicTimer, OnUltrasonicTimeout );

                mibReq.Type = MIB_ADR;
                mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
                LoRaMacMibSetRequestConfirm( &mibReq ); // MAC information base service to set attributes of LoRaMac layer

                mibReq.Type = MIB_PUBLIC_NETWORK;
                mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;
                LoRaMacMibSetRequestConfirm( &mibReq );
                
                sensor.distanceAvailable = false; // Ensure initialised to false after power up

                DeviceState = DEVICE_STATE_JOIN;
                break;
            }
            case DEVICE_STATE_JOIN:
            {
                  pc.printf("DEVICE_STATE_JOIN\r\n");

#if( OVER_THE_AIR_ACTIVATION != 0 )
                pc.printf("OTA\r\n");
                MlmeReq_t mlmeReq;

                // Initialize LoRaMac device unique ID
                //BoardGetUniqueId( DevEui );
                mlmeReq.Type = MLME_JOIN; // MAC management service types are MLME_JOIN or MLME_LINK_CHECK

                mlmeReq.Req.Join.DevEui = DevEui;
                mlmeReq.Req.Join.AppEui = AppEui;
                mlmeReq.Req.Join.AppKey = AppKey;

                if( NextTx == true )
                {
                    LoRaMacMlmeRequest( &mlmeReq );  // Sends a join request
                }
                // Schedule next packet transmission
                //TxDutyCycleTime = OVER_THE_AIR_ACTIVATION_DUTYCYCLE;
                //DeviceState = DEVICE_STATE_CYCLE;

                DeviceState = DEVICE_STATE_CYCLE;
#else
                pc.printf("ABP\r\n");
                // Choose a random device address if not already defined in Comissioning.h
                if( DevAddr == 0 )
                {
                    // Random seed initialization
                   // srand1( BoardGetRandomSeed( ) );
                    // Choose a random device address
                    DevAddr = randr( 0, 0x01FFFFFF );
                }
                mibReq.Type = MIB_NET_ID;
                mibReq.Param.NetID = LORAWAN_NETWORK_ID;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_DEV_ADDR;
                mibReq.Param.DevAddr = DevAddr;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_NWK_SKEY;
                mibReq.Param.NwkSKey = NwkSKey;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_APP_SKEY;
                mibReq.Param.AppSKey = AppSKey;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_NETWORK_JOINED;
                mibReq.Param.IsNetworkJoined = true;
                LoRaMacMibSetRequestConfirm( &mibReq );

                DeviceState = DEVICE_STATE_SEND;
#endif
                break;
            }
            case DEVICE_STATE_SEND:
            {
                  pc.printf("DEVICE_STATE_SEND\r\n");

                if( NextTx == true )
                {
                    pc.printf("Sending\r\n");
                    PrepareTxFrame( AppPort );
                    NextTx = SendFrame( );
                }
            }   
            case DEVICE_STATE_CYCLE:
            {
                 pc.printf("DEVICE_STATE_CYCLE\r\n");
          
                 pc.printf("SensorState = %d, distanceAvailable = ",SensorState);
                if (sensor.distanceAvailable)
                   pc.printf("true\r\n");
                else
                      pc.printf("false\r\n");

                pc.printf("LoRaMacState = %d\r\n",GetMacStatus());      
                      
                if ((SensorState == SENT) || (SensorState == INIT)) { /** Range and Temperature readings have been sent so we can sleep */
                    TimerStop( &TxNextPacketTimer );
                    // Wait for MAC state to become idle before deep sleeping
                    if (GetMacStatus() == 0) { // Ensure MAC state is idle before sleeping
                        pc.printf("DeepSleep ..zzz.\r\n");
                        TimerStop(&mainLoopTimeout); // cancel main loop guard timeout
                        WakeUp::set(DEEPSLEEP_SECONDS); // Set RTC alarm to wake up from deep sleep
                        LowPowerPrep();
                        deepsleep(); // Deep sleep until wake up alarm from RTC 
                        LowPowerRestore();
                        SensorState = TRIGGERED;
                        /* Trigger ultrasonic sensor and start sensor read failure timer */
                        sensor.triggerSample(); // Get Ultrasonic reading
                        TimerSetValue( &ultrasonicTimer, 2000000 ); // 2s timeout
                        TimerStart( &ultrasonicTimer );
                        DeviceState = DEVICE_STATE_SLEEP; // Cycle in sleep until sensor readings ready
                    }
                    else { // Cycle around until MAC state is idle
                        DeviceState = DEVICE_STATE_CYCLE;
                    }
                }
                else {
                    // Error shouldn't get here
                      pc.printf("Error State!!\r\n");
                    //TimerSetValue( &TxNextPacketTimer, TxDutyCycleTime );
                    //TimerStart( &TxNextPacketTimer );
                    SensorState = INIT;
                    DeviceState = DEVICE_STATE_SLEEP;
                }        

                break;
            }
            case DEVICE_STATE_SLEEP:
            {
                 pc.printf("DEVICE_STATE_SLEEP\r\n");

                // Loop until sensor ready
                if ((SensorState == TRIGGERED) && (sensor.distanceAvailable)) {
                    pc.printf("Xmit Reading..!\r\n");
                    TimerStop( &ultrasonicTimer ); // stop the sensor failure timer
                    SensorState = SENDING;
                    TimerSetValue( &TxNextPacketTimer, 10 ); // Schedule immediate transmission
                    TimerStart( &TxNextPacketTimer );
                }
        
                break;
            }
            default:
            {
                DeviceState = DEVICE_STATE_INIT;
                break;
            }
        }
    }
}
Пример #18
0
/**
 * Main application entry point.
 */
int main( void )
{
    LoRaMacPrimitives_t LoRaMacPrimitives;
    LoRaMacCallback_t LoRaMacCallbacks;
    MibRequestConfirm_t mibReq;

    BoardInitMcu( );
    BoardInitPeriph( );

    DeviceState = DEVICE_STATE_INIT;

    while( 1 )
    {
        switch( DeviceState )
        {
            case DEVICE_STATE_INIT:
            {
                LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
                LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
                LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
                LoRaMacPrimitives.MacMlmeIndication = MlmeIndication;
                LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
                LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, ACTIVE_REGION );

                TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent );

                TimerInit( &Led1Timer, OnLed1TimerEvent );
                TimerSetValue( &Led1Timer, 25 );

                TimerInit( &Led2Timer, OnLed2TimerEvent );
                TimerSetValue( &Led2Timer, 25 );

                mibReq.Type = MIB_ADR;
                mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_PUBLIC_NETWORK;
                mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;
                LoRaMacMibSetRequestConfirm( &mibReq );

#if defined( REGION_EU868 )
                LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
#endif
                mibReq.Type = MIB_DEVICE_CLASS;
                mibReq.Param.Class = CLASS_C;
                LoRaMacMibSetRequestConfirm( &mibReq );

                DeviceState = DEVICE_STATE_JOIN;
                break;
            }
            case DEVICE_STATE_JOIN:
            {
#if( OVER_THE_AIR_ACTIVATION != 0 )
                MlmeReq_t mlmeReq;

                // Initialize LoRaMac device unique ID
                BoardGetUniqueId( DevEui );

                mlmeReq.Type = MLME_JOIN;

                mlmeReq.Req.Join.DevEui = DevEui;
                mlmeReq.Req.Join.AppEui = AppEui;
                mlmeReq.Req.Join.AppKey = AppKey;
                mlmeReq.Req.Join.Datarate = LORAWAN_DEFAULT_DATARATE;

                if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK )
                {
                    DeviceState = DEVICE_STATE_SLEEP;
                }
                else
                {
                    DeviceState = DEVICE_STATE_CYCLE;
                }
#else
                // Choose a random device address if not already defined in Commissioning.h
                if( DevAddr == 0 )
                {
                    // Random seed initialization
                    srand1( BoardGetRandomSeed( ) );

                    // Choose a random device address
                    DevAddr = randr( 0, 0x01FFFFFF );
                }

                mibReq.Type = MIB_NET_ID;
                mibReq.Param.NetID = LORAWAN_NETWORK_ID;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_DEV_ADDR;
                mibReq.Param.DevAddr = DevAddr;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_NWK_SKEY;
                mibReq.Param.NwkSKey = NwkSKey;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_APP_SKEY;
                mibReq.Param.AppSKey = AppSKey;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_NETWORK_JOINED;
                mibReq.Param.IsNetworkJoined = true;
                LoRaMacMibSetRequestConfirm( &mibReq );

                DeviceState = DEVICE_STATE_SEND;
#endif
                break;
            }
            case DEVICE_STATE_SEND:
            {
                if( NextTx == true )
                {
                    PrepareTxFrame( AppPort );

                    NextTx = SendFrame( );
                }
                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 );
                }
                DeviceState = DEVICE_STATE_CYCLE;
                break;
            }
            case DEVICE_STATE_CYCLE:
            {
                DeviceState = DEVICE_STATE_SLEEP;

                // Schedule next packet transmission
                TimerSetValue( &TxNextPacketTimer, TxDutyCycleTime );
                TimerStart( &TxNextPacketTimer );
                break;
            }
            case DEVICE_STATE_SLEEP:
            {
                // Wake up through events
                TimerLowPowerHandler( );
                // Process Radio IRQ
                Radio.IrqProcess( );
                break;
            }
            default:
            {
                DeviceState = DEVICE_STATE_INIT;
                break;
            }
        }
    }
}