for testing STM32L476 Nucleo-64 + Semtech SX1276RF1IAS

Dependencies:   LoRaWAN-demo-76 mbed LoRaWAN-lib SX1276Lib

Fork of LoRaWAN-demo-76 by Semtech

app/main.cpp

Committer:
rukudias
Date:
2017-02-25
Revision:
9:acdb961c138c
Parent:
7:3173f0508a98

File content as of revision 9:acdb961c138c:

/*
 / _____)             _              | |
( (____  _____ ____ _| |_ _____  ____| |__
 \____ \| ___ |    (_   _) ___ |/ ___)  _ \
 _____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
    (C)2015 Semtech

Description: LoRaMac classA device implementation

License: Revised BSD License, see LICENSE.TXT file include in the project

Maintainer: Miguel Luis and Gregory Cristian
*/
#include "mbed.h"
#include "board.h"
#include "radio.h"

#include "LoRaMac.h"
#include "Comissioning.h"

/*!
 * Defines the application data transmission duty cycle. 5s, value in [us].
 */
#define APP_TX_DUTYCYCLE                            5000000

/*!
 * Defines a random delay for application data transmission duty cycle. 1s,
 * value in [us].
 */
#define APP_TX_DUTYCYCLE_RND                        1000000

/*!
 * Default datarate
 */
#define LORAWAN_DEFAULT_DATARATE                    DR_0

/*!
 * LoRaWAN confirmed messages
 */
#define LORAWAN_CONFIRMED_MSG_ON                    true

/*!
 * LoRaWAN Adaptive Data Rate
 *
 * \remark Please note that when ADR is enabled the end-device should be static
 */
#define LORAWAN_ADR_ON                              0

#if defined( USE_BAND_868 )

#include "LoRaMacTest.h"
#include <string>

/*!
 * 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                        false

#define USE_SEMTECH_DEFAULT_CHANNEL_LINEUP          1

#if( USE_SEMTECH_DEFAULT_CHANNEL_LINEUP == 1 ) 

#define LC4                { 867100000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC5                { 867300000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC6                { 867500000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC7                { 867700000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC8                { 867900000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC9                { 868800000, { ( ( DR_7 << 4 ) | DR_7 ) }, 2 }
#define LC10               { 868300000, { ( ( DR_6 << 4 ) | DR_6 ) }, 1 }

#endif

#endif

/*!
 * LoRaWAN application port
 */
#define LORAWAN_APP_PORT                            15

/*!
 * User application data buffer size
 */
#if ( LORAWAN_CONFIRMED_MSG_ON == 1 )
#define LORAWAN_APP_DATA_SIZE                       6

#else
#define LORAWAN_APP_DATA_SIZE                       1

#endif

static uint8_t DevEui[] = LORAWAN_DEVICE_EUI;
static uint8_t AppEui[] = LORAWAN_APPLICATION_EUI;
static uint8_t AppKey[] = LORAWAN_APPLICATION_KEY;

#if( OVER_THE_AIR_ACTIVATION == 0 )

static uint8_t NwkSKey[] = LORAWAN_NWKSKEY;
static uint8_t AppSKey[] = LORAWAN_APPSKEY;

/*!
 * 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 = LORAWAN_APP_DATA_SIZE;

/*!
 * User application data buffer size
 */
#define LORAWAN_APP_DATA_MAX_SIZE                           64

/*!
 * User application data
 */
static uint8_t AppData[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;
Serial pc_debug(USBTX, USBRX);

/*!
 * Indicates if a new packet can be sent
 */
static bool NextTx = true;

int8_t txPower =  LORAMAC_DEFAULT_TX_POWER;
uint32_t upCnt =  0;
uint32_t downCnt =  0;

//#define DR_0                                        0  // SF12 - BW125
//#define DR_1                                        1  // SF11 - BW125
//#define DR_2                                        2  // SF10 - BW125
//#define DR_3                                        3  // SF9  - BW125
//#define DR_4                                        4  // SF8  - BW125
//#define DR_5                                        5  // SF7  - BW125

int8_t sf = LORAWAN_DEFAULT_DATARATE;


/*!
 * Device states
 */
static enum eDevicState
{
    DEVICE_STATE_INIT,
    DEVICE_STATE_JOIN,
    DEVICE_STATE_WAIT_REQUEST,
    DEVICE_STATE_PROCESS_REQUEST,
    DEVICE_STATE_SEND,
    DEVICE_STATE_CYCLE,
    DEVICE_STATE_SLEEP,
    DEVICE_STATE_PROCESS_RESPONSE,
}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;

/*
 * SerialDisplay managment variables
 */

/*!
 * Indicates if the MAC layer network join status has changed.
 */
static bool IsNetworkJoinedStatusUpdate = false;

/*!
 * Strucure containing the Uplink status
 */
struct sLoRaMacUplinkStatus
{
    uint8_t Acked;
    int8_t Datarate;
    uint16_t UplinkCounter;
    uint8_t Port;
    uint8_t *Buffer;
    uint8_t BufferSize;
}LoRaMacUplinkStatus;
volatile bool UplinkStatusUpdated = false;

/*!
 * Strucure containing the Downlink status
 */
struct sLoRaMacDownlinkStatus
{
    int16_t Rssi;
    int8_t Snr;
    uint16_t DownlinkCounter;
    bool RxData;
    uint8_t Port;
    uint8_t *Buffer;
    uint8_t BufferSize;
}LoRaMacDownlinkStatus;
volatile bool DownlinkStatusUpdated = false;

static TimerEvent_t SendTimerEvent;
static void OnSendTimerEvent( void )
{
    pc_debug.printf("OnSendTimerEvent\r\n");
    DeviceState = DEVICE_STATE_PROCESS_REQUEST;
    TimerStop( &SendTimerEvent ); 
}
std::string status_str = "Ok";
void SerialDisplayRefresh( void )
{
    MibRequestConfirm_t mibReq;
    mibReq.Type = MIB_NETWORK_JOINED;
    LoRaMacMibGetRequestConfirm( &mibReq );

}

/*!
 * \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 = sf;

        LoRaMacUplinkStatus.Acked = false;
        LoRaMacUplinkStatus.Port = 0;
        LoRaMacUplinkStatus.Buffer = NULL;
        LoRaMacUplinkStatus.BufferSize = 0;
        pc_debug.printf("SendFrame::LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK\r\n");
    }
    else
    {
        pc_debug.printf("SendFrame::LoRaMacQueryTxPossible MaxPossiblePayload %d\r\n",txInfo.MaxPossiblePayload);
        pc_debug.printf("SendFrame::LoRaMacQueryTxPossible CurrentPayloadSize %d\r\n",txInfo.CurrentPayloadSize);
        LoRaMacUplinkStatus.Acked = false;
        LoRaMacUplinkStatus.Port = AppPort;
        LoRaMacUplinkStatus.Buffer = AppData;
        LoRaMacUplinkStatus.BufferSize = AppDataSize;
        pc_debug.printf("SendFrame::LoRaMacQueryTxPossible( AppDataSize, &txInfo ) == LORAMAC_STATUS_OK\r\n");
         
        if( IsTxConfirmed == false )
        {
            mcpsReq.Type = MCPS_UNCONFIRMED;
            mcpsReq.Req.Unconfirmed.fPort = AppPort;
            mcpsReq.Req.Unconfirmed.fBuffer = AppData;
            mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize;
            mcpsReq.Req.Unconfirmed.Datarate = sf;
        }
        else
        {
            mcpsReq.Type = MCPS_CONFIRMED;
            mcpsReq.Req.Confirmed.fPort = AppPort;
            mcpsReq.Req.Confirmed.fBuffer = AppData;
            mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
            mcpsReq.Req.Confirmed.NbTrials = 8;
            mcpsReq.Req.Confirmed.Datarate = sf;
        }
    }
    
    LoRaMacStatus_t status = LoRaMacMcpsRequest( &mcpsReq );
    
    if( status == LORAMAC_STATUS_OK )
    {
        pc_debug.printf("SendFrame::LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK\r\n");
        return false;
    }
    pc_debug.printf("SendFrame::LoRaMacMcpsRequest( &mcpsReq ) != LORAMAC_STATUS_OK status %d\r\n",status);
    status_str = "Error";
    DeviceState = DEVICE_STATE_PROCESS_RESPONSE;
    return true;
}

/*!
 * \brief Function executed on TxNextPacket Timeout event
 */
static void OnTxNextPacketTimerEvent( void )
{
    pc_debug.printf("OnTxNextPacketTimerEvent::\r\n");
    MibRequestConfirm_t mibReq;
    LoRaMacStatus_t status;

    TimerStop( &TxNextPacketTimer );

    mibReq.Type = MIB_NETWORK_JOINED;
    status = LoRaMacMibGetRequestConfirm( &mibReq );

    if( status == LORAMAC_STATUS_OK )
    {
        pc_debug.printf("OnTxNextPacketTimerEvent:: status == LORAMAC_STATUS_OK\r\n");
        if( mibReq.Param.IsNetworkJoined == true )
        {
            pc_debug.printf("OnTxNextPacketTimerEvent:: mibReq.Param.IsNetworkJoined == true\r\n");
            status_str = "Ok";
            DeviceState = DEVICE_STATE_PROCESS_RESPONSE;
           
        }
        else
        {
            pc_debug.printf("OnTxNextPacketTimerEvent:: mibReq.Param.IsNetworkJoined != true\r\n");
            DeviceState = DEVICE_STATE_JOIN;
        }
    }else{
        pc_debug.printf("OnTxNextPacketTimerEvent status != LORAMAC_STATUS_OK %d\r\n");
        status_str = "Error";
        DeviceState = DEVICE_STATE_PROCESS_RESPONSE;
    }
}

/*!
 * \brief   MCPS-Confirm event function
 *
 * \param   [IN] mcpsConfirm - Pointer to the confirm structure,
 *               containing confirm attributes.
 */
static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
{
    LoRaMacEventInfoStatus_t status_mcps = mcpsConfirm->Status;
    if( status_mcps == LORAMAC_EVENT_INFO_STATUS_OK )
    {
        pc_debug.printf("McpsConfirm:: mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK\r\n");
        switch( mcpsConfirm->McpsRequest )
        {
            case MCPS_UNCONFIRMED:
            {
                // Check Datarate
                // Check TxPower
                break;
            }
            case MCPS_CONFIRMED:
            {
                // Check Datarate
                // Check TxPower
                // Check AckReceived
                // Check NbTrials
                LoRaMacUplinkStatus.Acked = mcpsConfirm->AckReceived;
                break;
            }
            case MCPS_PROPRIETARY:
            {
                break;
            }
            default:
                break;
        }
        LoRaMacUplinkStatus.Datarate = mcpsConfirm->Datarate;
        LoRaMacUplinkStatus.UplinkCounter = mcpsConfirm->UpLinkCounter;
        UplinkStatusUpdated = true;
    }else{
        pc_debug.printf("McpsConfirm:: mcpsConfirm->Status != LORAMAC_EVENT_INFO_STATUS_OK %d\r\n",status_mcps);  
        status_str = "Error";
        DeviceState = DEVICE_STATE_PROCESS_RESPONSE;
    }
}

/*!
 * \brief   MCPS-Indication event function
 *
 * \param   [IN] mcpsIndication - Pointer to the indication structure,
 *               containing indication attributes.
 */
static void McpsIndication( McpsIndication_t *mcpsIndication )
{
    LoRaMacEventInfoStatus_t status_mcps = mcpsIndication->Status;
    if( status_mcps != LORAMAC_EVENT_INFO_STATUS_OK )
    {
        pc_debug.printf("McpsIndication:: mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK %d\r\n",status_mcps);
        status_str = "Error";
        DeviceState = DEVICE_STATE_PROCESS_RESPONSE;
        return;
    }

    pc_debug.printf("McpsIndication:: mcpsIndication->Status == LORAMAC_EVENT_INFO_STATUS_OK\r\n");
    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
    // Check Buffer
    // Check BufferSize
    // Check Rssi
    // Check Snr
    // Check RxSlot
    
    LoRaMacDownlinkStatus.Rssi = mcpsIndication->Rssi;
    if( mcpsIndication->Snr & 0x80 ) // The SNR sign bit is 1
    {
        // Invert and divide by 4
        LoRaMacDownlinkStatus.Snr = ( ( ~mcpsIndication->Snr + 1 ) & 0xFF ) >> 2;
        LoRaMacDownlinkStatus.Snr = -LoRaMacDownlinkStatus.Snr;
    }
    else
    {
        // Divide by 4
        LoRaMacDownlinkStatus.Snr = ( mcpsIndication->Snr & 0xFF ) >> 2;
    }
    LoRaMacDownlinkStatus.DownlinkCounter++;
    LoRaMacDownlinkStatus.RxData = mcpsIndication->RxData;
    LoRaMacDownlinkStatus.Port = mcpsIndication->Port;
    LoRaMacDownlinkStatus.Buffer = mcpsIndication->Buffer;
    LoRaMacDownlinkStatus.BufferSize = mcpsIndication->BufferSize;

    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;
                    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( USE_BAND_868 )
                    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 = LORAWAN_APP_DATA_SIZE;
                    ComplianceTest.DownLinkCounter = 0;
                    ComplianceTest.Running = false;
                    
                    MibRequestConfirm_t mibReq;
                    mibReq.Type = MIB_ADR;
                    mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
                    LoRaMacMibSetRequestConfirm( &mibReq );
#if defined( USE_BAND_868 )
                    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 < AppDataSize; 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;

                        mlmeReq.Type = MLME_JOIN;

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

                        LoRaMacMlmeRequest( &mlmeReq );
                        DeviceState = DEVICE_STATE_SLEEP;
                    }
                    break;
                default:
                    break;
                }
            }
            break;
        default:
            break;
        }
    }
    DownlinkStatusUpdated = true;
    status_str = "Ok";
}

/*!
 * \brief   MLME-Confirm event function
 *
 * \param   [IN] mlmeConfirm - Pointer to the confirm structure,
 *               containing confirm attributes.
 */
static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm )
{   
    LoRaMacEventInfoStatus_t status_mlme = mlmeConfirm->Status;
    if( status_mlme == LORAMAC_EVENT_INFO_STATUS_OK )
    {
        pc_debug.printf("MlmeConfirm:: mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK\r\n");
        switch( mlmeConfirm->MlmeRequest )
        {      
            case MLME_JOIN:
            {
                // Status is OK, node has joined the network
                IsNetworkJoinedStatusUpdate = true;
                DeviceState = DEVICE_STATE_SEND;
                NextTx = true;
                break;
            }
            case MLME_LINK_CHECK:
            {
                // Check DemodMargin
                // Check NbGateways
                if( ComplianceTest.Running == true )
                {
                    ComplianceTest.LinkCheck = true;
                    ComplianceTest.DemodMargin = mlmeConfirm->DemodMargin;
                    ComplianceTest.NbGateways = mlmeConfirm->NbGateways;
                }
                break;
            }
            default:
                break;
        }
    }else{
        pc_debug.printf("MlmeConfirm:: mlmeConfirm->Status != LORAMAC_EVENT_INFO_STATUS_OK %d\r\n",status_mlme);
        status_str = "Error";
        DeviceState = DEVICE_STATE_PROCESS_RESPONSE;
    }
    UplinkStatusUpdated = true;
}

/**
 * Main application entry point.
 */
int main( void )
{
    LoRaMacPrimitives_t LoRaMacPrimitives;
    LoRaMacCallback_t LoRaMacCallbacks;
    MibRequestConfirm_t mibReq;

    BoardInit( );
    
    TimerInit( &SendTimerEvent, OnSendTimerEvent );
    TimerSetValue( &SendTimerEvent, 60000000 );//us
    
    
    pc_debug.baud(115200);
    pc_debug.printf("Start\r\n");  
      
#if( OVER_THE_AIR_ACTIVATION == 0 )

#endif

    DeviceState = DEVICE_STATE_INIT;
    
    while( 1 )
    {
        if( IsNetworkJoinedStatusUpdate == true )
        {
            IsNetworkJoinedStatusUpdate = false;
            mibReq.Type = MIB_NETWORK_JOINED;
            LoRaMacMibGetRequestConfirm( &mibReq );
            pc_debug.printf("mibReq.Param.IsNetworkJoined %d\r\n",mibReq.Param.IsNetworkJoined);
        }
        if( UplinkStatusUpdated == true )
        {
            UplinkStatusUpdated = false;
            pc_debug.printf("UplinkStatusUpdated == true\r\n");
            upCnt = LoRaMacUplinkStatus.UplinkCounter;
        }
        if( DownlinkStatusUpdated == true )
        {
            DownlinkStatusUpdated = false;
            pc_debug.printf("DownlinkStatusUpdated == true\r\n");
            downCnt = LoRaMacDownlinkStatus.DownlinkCounter;
        }
        
        switch( DeviceState )
        {
            case DEVICE_STATE_INIT:
            {
                pc_debug.printf("DEVICE_STATE_INIT\r\n");
                
                LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
                LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
                LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
                LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
                
                LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks );

                TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent );

                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 );
//                #defined( USE_BAND_868 )  
//                #define TX_POWER_20_DBM                             0
//                #define TX_POWER_14_DBM                             1
//                #define TX_POWER_11_DBM                             2
//                #define TX_POWER_08_DBM                             3
//                #define TX_POWER_05_DBM                             4
//                #define TX_POWER_02_DBM                             5
                
                mibReq.Type = MIB_CHANNELS_TX_POWER;
                mibReq.Param.ChannelsTxPower = txPower;
                LoRaMacMibSetRequestConfirm( &mibReq );
                

#if defined( USE_BAND_868 )
                LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
#if( USE_SEMTECH_DEFAULT_CHANNEL_LINEUP == 1 ) 
                LoRaMacChannelAdd( 3, ( ChannelParams_t )LC4 );
                LoRaMacChannelAdd( 4, ( ChannelParams_t )LC5 );
                LoRaMacChannelAdd( 5, ( ChannelParams_t )LC6 );
                LoRaMacChannelAdd( 6, ( ChannelParams_t )LC7 );
                LoRaMacChannelAdd( 7, ( ChannelParams_t )LC8 );
                LoRaMacChannelAdd( 8, ( ChannelParams_t )LC9 );
                LoRaMacChannelAdd( 9, ( ChannelParams_t )LC10 );

                mibReq.Type = MIB_RX2_CHANNEL;
                mibReq.Param.Rx2Channel = ( Rx2ChannelParams_t ){ 869525000, DR_3 };
                LoRaMacMibSetRequestConfirm( &mibReq );
#endif

#endif
                mibReq.Type = MIB_UPLINK_COUNTER;
                mibReq.Param.UpLinkCounter = upCnt;
                LoRaMacMibSetRequestConfirm( &mibReq );
                
                mibReq.Type = MIB_DOWNLINK_COUNTER;
                mibReq.Param.DownLinkCounter = downCnt;
                LoRaMacMibSetRequestConfirm( &mibReq );
                
                
                LoRaMacDownlinkStatus.DownlinkCounter = downCnt;
                DeviceState = DEVICE_STATE_JOIN;
                break;
            }
            case DEVICE_STATE_JOIN:
            {
                pc_debug.printf("DEVICE_STATE_JOIN\r\n");
#if( OVER_THE_AIR_ACTIVATION != 0 )
                MlmeReq_t mlmeReq;

                mlmeReq.Type = MLME_JOIN;

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

                if( NextTx == true )
                {
                    LoRaMacMlmeRequest( &mlmeReq );
                }
                DeviceState = DEVICE_STATE_SLEEP;
#else
                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_WAIT_REQUEST;
#endif
                IsNetworkJoinedStatusUpdate = true;
                TimerStart( &SendTimerEvent );
                break;
            }
            case DEVICE_STATE_WAIT_REQUEST:
            {
                break;
            }
            case DEVICE_STATE_PROCESS_REQUEST:
            {
                std::string send_data = "Test!";
                pc_debug.printf("DEVICE_STATE_PROCESS_REQUEST %s\r\n",send_data.c_str());
               
                int pos = 0;
                for(;pos < send_data.size();pos++){
                    AppData[pos] = send_data.at(pos);
                }
                AppData[pos] = '\0';
                AppDataSize = pos;
                AppPort = 10;
                DeviceState = DEVICE_STATE_SEND;
                break;
            }
            case DEVICE_STATE_SEND:
            {
                pc_debug.printf("DEVICE_STATE_SEND\r\n");
                if( NextTx == true )
                {
                    NextTx = SendFrame( );
                }
                
                TxDutyCycleTime = 5000000; //us
                DeviceState = DEVICE_STATE_CYCLE;
                break;
            }
            case DEVICE_STATE_CYCLE:
            {
                pc_debug.printf("DEVICE_STATE_CYCLE\r\n");
                DeviceState = DEVICE_STATE_SLEEP;

                // Schedule next packet transmission
                TimerSetValue( &TxNextPacketTimer, TxDutyCycleTime );
                TimerStart( &TxNextPacketTimer );
                break;
            }
            case DEVICE_STATE_SLEEP:
            {
                // Wake up through events
                break;
            }
            case DEVICE_STATE_PROCESS_RESPONSE:
            {

                pc_debug.printf("DEVICE_STATE_PROCESS_RESPONSE\r\n");
                pc_debug.printf("rssi %d snr %d %s \r\n",LoRaMacDownlinkStatus.Rssi,LoRaMacDownlinkStatus.Snr,status_str.c_str());
                DeviceState = DEVICE_STATE_WAIT_REQUEST;
                NextTx = true;
                TimerStart( &SendTimerEvent );
                break;
            }
            default:
            {
                DeviceState = DEVICE_STATE_INIT;
                break;
            }
        }
    }
}