/*
 *  Copyright (c) 2016, Intel Corporation
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *  3. Neither the name of the Intel Corporation nor the names of its
 *     contributors may be used to endorse or promote products derived from this
 *     software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

#include "LoRaSDK/Comissioning.h"
#include "LoRaSDK/LoRaMac.h"
#include "LoRaSDK/radio.h"
#include "LoRaSDK/sx1276.h"
#include "LoRaSDK/sx1276-board.h"
#include "LoRaSDK/utilities.h"
#include "LoRaSDK/Region.h"
#include "qm_common.h"
#include "qm_spi.h"
#include "qm_pinmux.h"
#include "qm_interrupt.h"
#include "qm_interrupt_router.h"
#include "qm_isr.h"
#include "clk.h"
#include "qm_pwm.h"
#include <string.h>
#include "power_states.h"
#include "qm_comparator.h"
#include "qm_rtc.h"
#include "vreg.h"
#include "qm_gpio.h"

#include "qm_mailbox.h"
#include "qm_pic_timer.h"
#include "ss_init.h"

/*
 * Define use which Band:
 * 		- #define REGION_AS923
 *      - #define REGION_AU915
 *      - #define REGION_CN470
 *      - #define REGION_CN779
 *      - #define REGION_EU433
 *      - #define REGION_EU868
 *      - #define REGION_KR920
 *      - #define REGION_IN865
 *      - #define REGION_US915
 *      - #define REGION_US915_HYBRID
 *      - #define REGION_CustomAType	//base on EU868
 *      - #define REGION_CustomBType	//base on US915
 */

//#define REGION_EU868
//#define REGION_US915
#define REGION_CustomBType

#if defined(REGION_CustomBType)

//ChannelParams_t        frequency,Rx1Freq,      DataRate(Max|Min)     ,Band index

#define LC0                { 902300000, 0, { ( ( DR_3 << 4 ) | DR_0 ) }, 0 }
#define LC1                { 902500000, 0, { ( ( DR_3 << 4 ) | DR_0 ) }, 0 }
#define LC2                { 902700000, 0, { ( ( DR_3 << 4 ) | DR_0 ) }, 0 }
#define LC3                { 902900000, 0, { ( ( DR_3 << 4 ) | DR_0 ) }, 0 }
#define LC4                { 903100000, 0, { ( ( DR_3 << 4 ) | DR_0 ) }, 0 }
#define LC5                { 903300000, 0, { ( ( DR_3 << 4 ) | DR_0 ) }, 0 }
#define LC6                { 903500000, 0, { ( ( DR_3 << 4 ) | DR_0 ) }, 0 }
#define LC7                { 903700000, 0, { ( ( DR_3 << 4 ) | DR_0 ) }, 0 }

#endif

/* the SPI clock divider is calculated in reference to a 32MHz system clock */
#define SPI_CLOCK_125KHZ_DIV (256)
#define SPI_CLOCK_1MHZ_DIV (32)
#define SPI_CLOCK_DIV SPI_CLOCK_125KHZ_DIV
#define QM_SPI_BMODE QM_SPI_BMODE_0
//#define SPI_Debug
#if defined (SPI_Debug)
#define RegVersionValue 0x12
#endif

//RTC Alarm value
#define ALARM (QM_RTC_ALARM_SECOND(CLK_RTC_DIV_1))// 1 sec

//ID1~3 for made RandomSeed
#define ID1 (0x1FF80050)
#define ID2 (0x1FF80054)
#define ID3 (0x1FF80064)

//Quark Mail-Box settings
qm_mbox_msg_t Mbox_rx_data;
qm_mbox_msg_t Mbox_tx_data;
qm_mbox_ch_t mbox_rx_channel = QM_MBOX_CH_0;
qm_mbox_ch_t mbox_tx_channel = QM_MBOX_CH_1;
qm_mbox_config_t mbox_rx_config;

//timer callback handle
void timer_callback(void *data, uint32_t timer_int);

/* Example callback function */
static void gpio_example_callback(void *, uint32_t);

/*!
 * \brief Function to Init DIO0 IRQ
 */
void Main_IrqInit(void);

/*!
 * \brief MailBox callback Function
 */
void mbox_cb(void *data);


uint32_t Sensor_temperature,Sensor_humidity,Sensor_UV;
static uint32_t counter = 0;
//=====================================================================
//LoRaMac defines
/*!
 * 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
 */
#if defined( REGION_US915 ) || defined( REGION_US915_HYBRID )  || defined( REGION_CustomBType )
#define LORAWAN_DEFAULT_DATARATE                    DR_0
#else
#define LORAWAN_DEFAULT_DATARATE                    DR_5
#endif


/*!
 * 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
 */
#if defined( REGION_US915 ) || defined( REGION_US915_HYBRID )  || defined( REGION_CustomBType )
#define LORAWAN_ADR_ON                              0
#else
#define LORAWAN_ADR_ON                              1
#endif


#if defined( REGION_EU868 ) || defined( REGION_CustomAType )

#include "LoRaSDK/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

#define USE_SEMTECH_DEFAULT_CHANNEL_LINEUP          0

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

#endif

#endif

#if defined( REGION_CustomAType )
#define LORAWAN_DUTYCYCLE_ON                        true
#define LC0                { 865400000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC1                { 865600000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC2                { 865800000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC3                { 866000000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC4                { 866200000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC5                { 866400000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC6                { 866600000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC7                { 866800000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }

#endif


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

/*!
 * User application data buffer size
 */
#if defined( REGION_EU868 ) || defined( REGION_CustomAType )

#define LORAWAN_APP_DATA_SIZE                       16

#elif defined( REGION_US915 ) || defined( REGION_US915_HYBRID )  || defined( REGION_CustomBType )

#define LORAWAN_APP_DATA_SIZE                       11

#else
#define LORAWAN_APP_DATA_SIZE                       16
#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;

//void rtc_example_callback(void *);

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

/*!
 * Device states
 */
static enum eDeviceState
{
    DEVICE_STATE_INIT,
    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;


//=====================================================================
//functions

uint32_t BoardGetRandomSeed(void)
{
	return (( *(uint32_t*)ID1) ^(*(uint32_t*)ID2) ^(*(uint32_t* )ID3));
}

void BoardGetUniqueId(uint8_t *id)
{
	id[7] = ((*(uint32_t*)ID1) + (*(uint32_t* )ID3)) >> 24;
	id[6] = ((*(uint32_t*)ID1) + (*(uint32_t* )ID3)) >> 16;
	id[5] = ((*(uint32_t*)ID1) + (*(uint32_t* )ID3)) >> 8;
	id[4] = ((*(uint32_t*)ID1) + (*(uint32_t* )ID3)) ;
	id[3] = ((*(uint32_t*)ID2) ) >> 24;
	id[2] = ((*(uint32_t*)ID2) ) >> 16;
	id[1] = ((*(uint32_t*)ID2) ) >> 8;
	id[0] = ((*(uint32_t*)ID2) ) ;
}

//Timer initialization and setting
void TimerInit( void )
{

	/* Variables */
	qm_pwm_config_t  sw_cfg;
	uint32_t lo_cnt = 0x4CCCC; 			  // set the low counter to 0x4CCCC, made it count about 10m second
//	uint32_t lo_cnt = 0x320000;
	uint32_t hi_cnt = 0x00;
	/* Initialise SW timer configuration */
	sw_cfg.lo_count = lo_cnt;
	sw_cfg.hi_count = hi_cnt;
	sw_cfg.mode = QM_PWM_MODE_TIMER_COUNT;
	sw_cfg.mask_interrupt = false;
	sw_cfg.callback = timer_callback;
	sw_cfg.callback_data = NULL;

	/* Enable clocking for the PWM block */
	clk_periph_enable(CLK_PERIPH_PWM_REGISTER | CLK_PERIPH_CLK);
	/* Set the configuration of the Timer */
	qm_pwm_set_config(QM_PWM_0, QM_PWM_ID_0, &sw_cfg);
	qm_pwm_set_config(QM_PWM_0, QM_PWM_ID_1, &sw_cfg);

	/* Register the ISR with the SoC. */
	QM_IR_UNMASK_INT(QM_IRQ_PWM_0_INT);
	QM_IRQ_REQUEST(QM_IRQ_PWM_0_INT, qm_pwm_0_isr_0);

	qm_pwm_set(QM_PWM_0, QM_PWM_ID_0, lo_cnt, hi_cnt);
}

void Timer0Stop (void)
{
	extern bool sw_timer_running;
	sw_timer_running = false;
	qm_pwm_stop(QM_PWM_0, QM_PWM_ID_0);
}


void Timer1Stop (void)
{
	qm_pwm_stop(QM_PWM_0, QM_PWM_ID_1);
}

/*!
 * \brief   Prepares the payload of the frame
 */
static void PrepareTxFrame( uint8_t port )
{
    switch( port )
    {

    case 1:
        {
        	MibRequestConfirm_t mibReq;
        	mibReq.Type = MIB_UPLINK_COUNTER;
        	LoRaMacMibGetRequestConfirm( &mibReq );
        	counter = mibReq.Param.UpLinkCounter;
#if defined( REGION_EU868 ) || defined( REGION_CustomAType )
            AppData[0] = 0x00;
            AppData[1] = Sensor_temperature;
            AppData[2] = Sensor_humidity;
            AppData[3] = Sensor_UV;
            AppData[4] = counter;;
            AppData[5] = 0x05;
            AppData[6] = 0x06;
            AppData[7] = 0xFF;
            AppData[8] = 0xFF;
            AppData[9] = 0xFF;
            AppData[10] =0xFF;
            AppData[11] =0x11;
            AppData[12] =0x12;
            AppData[13] =0x13;
            AppData[14] =0x14;
            AppData[15] =0x15;
#elif defined( REGION_US915 ) || defined( REGION_US915_HYBRID ) || defined( REGION_CustomBType )

            AppData[0] = 0x00;
            AppData[1] = Sensor_temperature;
            AppData[2] = Sensor_humidity;
            AppData[3] = Sensor_UV;
            AppData[4] = counter;
            AppData[5] = 0xFF;
            AppData[6] = 0xFF;
            AppData[7] = 0xFF;
            AppData[8] = 0xFF;
            AppData[9] = 0xFF;
            AppData[10] =0xFF;
#endif
        }
        break;
    case 224:
        if( ComplianceTest.LinkCheck == true )
        {
            ComplianceTest.LinkCheck = false;
            AppDataSize = 3;
            AppData[0] = 5;
            AppData[1] = ComplianceTest.DemodMargin;
            AppData[2] = ComplianceTest.NbGateways;
            ComplianceTest.State = 1;
        }
        else
        {
            switch( ComplianceTest.State )
            {
            case 4:
                ComplianceTest.State = 1;
                break;
            case 1:
                AppDataSize = 2;
                AppData[0] = ComplianceTest.DownLinkCounter >> 8;
                AppData[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 )
{
	//QM_PRINTF(" SendFrame\n");
    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;
        QM_PRINTF(" SendFrame: send empty frame\n");
    }
    else
    {
        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 = LORAWAN_DEFAULT_DATARATE;
        }
        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 = LORAWAN_DEFAULT_DATARATE;
        }
    }

    if( LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK )
    {
        return false;
    }

    return true;
}



/*!
 * \brief Function executed on TxNextPacket Timeout event
 */
static void OnTxNextPacketTimerEvent( void )
{
    MibRequestConfirm_t mibReq;
    LoRaMacStatus_t status;

    Timer1Stop();

    mibReq.Type = MIB_NETWORK_JOINED;
    status = LoRaMacMibGetRequestConfirm( &mibReq );
    //QM_PRINTF("\n [OnTxNextPacketTimerEvent]:State[%d]",status);
    if( status == LORAMAC_STATUS_OK )
    {
    	//QM_PRINTF("\n[OnTxNextPacketTimerEvent]:State OK\n ");
        if( mibReq.Param.IsNetworkJoined == true )
        {
            DeviceState = DEVICE_STATE_SEND;
            NextTx = true;
        }
        else
        {
            DeviceState = DEVICE_STATE_JOIN;
        }
        NextTx = true;
    }
    else
    {
    	//QM_PRINTF("\n State NOT OK ");
    	 DeviceState = DEVICE_STATE_JOIN;
    }
    //QM_PRINTF("\nDeviceState:[%d]\n",DeviceState);
}


/*!
 * \brief   MCPS-Confirm event function
 *
 * \param   [IN] mcpsConfirm - Pointer to the confirm structure,
 *               containing confirm attributes.
 */
static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
{
    if( mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
    {
        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;
        }

    }
    NextTx = true;
}

/*!
 * \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
    // 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:
        case 2:
            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( REGION_EU868 ) || defined( REGION_CustomAType )
                    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( REGION_EU868 ) || defined( REGION_CustomAType )
                    LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
#endif
                    //GpsStart( );
                    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;

                        // Disable TestMode and revert back to normal operation
                        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( REGION_EU868 ) || defined( REGION_CustomAType )
                        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.NbTrials = 3;

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

/*!
 * \brief   MLME-Confirm event function
 *
 * \param   [IN] mlmeConfirm - Pointer to the confirm structure,
 *               containing confirm attributes.
 */
static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm )
{
    switch( mlmeConfirm->MlmeRequest )
    {
        case MLME_JOIN:
        {
            if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
            {
                // Status is OK, node has joined the network
                DeviceState = DEVICE_STATE_SEND;
            }
            else
            {
                // Join was not successful. Try to join again
                DeviceState = DEVICE_STATE_JOIN;
            }
            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;
    }
    NextTx = true;
}

uint8_t spi_read(uint8_t addr)
{
	uint8_t data;
	qm_spi_transfer_t polled_xfer_desc;
	qm_spi_status_t status;
	int ret __attribute__((unused));
	int i;
	static uint8_t tx_buff[2];
	static uint8_t rx_buff[2];
#if defined USE_SPI0
	qm_spi_slave_select(QM_SPI_MST_0, QM_SPI_SS_0);
	qm_spi_get_status(QM_SPI_MST_0, &status);
#else
	qm_spi_slave_select(QM_SPI_MST_1, QM_SPI_SS_0);
	qm_spi_get_status(QM_SPI_MST_1, &status);
#endif

	QM_PRINTF("Status = 0x%x\n", status);
	tx_buff[0]  = addr;//RegVersion , default value :0x12
	tx_buff[1]  = addr;
	/* Set up the sync transfer struct and call a polled transfer. */
	polled_xfer_desc.tx = tx_buff;
	polled_xfer_desc.rx = rx_buff;
	polled_xfer_desc.tx_len = 2;
	polled_xfer_desc.rx_len = 2;
#if defined USE_SPI0
	ret = qm_spi_transfer(QM_SPI_MST_0, &polled_xfer_desc, &status);
#else
	ret = qm_spi_transfer(QM_SPI_MST_1, &polled_xfer_desc, &status);
#endif
	QM_ASSERT(0 == ret);
	clk_sys_udelay(1000000);
	QM_PRINTF("\nspiRead(%d) after..\n",addr);
		for (i = 0; i < 2; i++) {
			QM_PRINTF("tx_buff = 0x%x ", tx_buff[i]);
			QM_PRINTF("rx_buff = 0x%x \n", rx_buff[i]);
		}
		data = rx_buff[0];
	return data;
}

void SPIError(void)
{
	QM_PUTS("\n SPI Error !!\n");
}


static void BoardInitMcu( void )
{//SX1276Init & RTC start.
	qm_spi_config_t spi_cfg;
	SX1276SPIInit(spi_cfg);

	//RTC Start
	/*  Variables */
	qm_rtc_config_t cfg;
	QM_PRINTF("Starting: RTC\n");

	/*  Initialise RTC configuration */
	cfg.init_val = 0;
	cfg.alarm_en = true;
	cfg.alarm_val = ALARM;
	cfg.callback = NULL;
	cfg.callback_data = NULL;
	QM_IRQ_REQUEST(QM_IRQ_RTC_0_INT, qm_rtc_0_isr);

	clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK);
	qm_rtc_set_config(QM_RTC_0, &cfg);
}

static void MailBoxInit( void )
{
	//mboxInit
	Mbox_rx_data.ctrl = 0;
	Mbox_rx_data.data[0] = 0;
	Mbox_rx_data.data[1] = 0;
	Mbox_rx_data.data[2] = 0;
	Mbox_rx_data.data[3] = 0;
	// Configure the mailbox for this channel
	// Register the interrupt handler.
	mbox_rx_config.dest = QM_MBOX_TO_LMT;
	mbox_rx_config.mode = QM_MBOX_INTERRUPT_MODE;
	mbox_rx_config.callback = mbox_cb;
	mbox_rx_config.callback_data = NULL;

	/* Register the interrupt handler. */
	QM_IRQ_REQUEST(QM_IRQ_MAILBOX_0_INT, qm_mailbox_0_isr);

	/* Configure RX channel. */
	qm_mbox_ch_set_config(mbox_rx_channel, &mbox_rx_config);
}


void timer_expired(void *data)//pic timer
{
	QM_PUTS("Timer interrupt triggered");
}

//functions
//=====================================================================

int main(void)
{
	QM_PRINTF("Starting: LoRaMac\n\n");
	bool showNetWorkmessage = true;
	LoRaMacPrimitives_t LoRaMacPrimitives;
//	LoRaMacCallback_t LoRaMacCallbacks;
	MibRequestConfirm_t mibReq;

	/* Start Sensor ARC. */
#if (OVER_THE_AIR_ACTIVATION == 0)
	sensor_activation();
#endif

	BoardInitMcu( );
	MailBoxInit();
	Main_IrqInit( );


#if defined (SPI_Debug)
	while(spi_read(0x42) != RegVersionValue)
	{
		SPIError();
	}
#endif

    DeviceState = DEVICE_STATE_INIT;
	    while( 1 )
	    {
	        switch( DeviceState )
	        {
	            case DEVICE_STATE_INIT:
	            {
	                LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
	                LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
	                LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
	                
#if defined( REGION_EU868 )
                LoRaMacInitialization( &LoRaMacPrimitives, NULL, LORAMAC_REGION_EU868 );
#elif defined( REGION_US915 )
                LoRaMacInitialization( &LoRaMacPrimitives, NULL, LORAMAC_REGION_US915 );
#elif defined( REGION_US915_HYBRID )
                LoRaMacInitialization( &LoRaMacPrimitives, NULL, LORAMAC_REGION_US915_HYBRID );
#elif defined( REGION_CustomAType)
                LoRaMacInitialization( &LoRaMacPrimitives, NULL, LORAMAC_REGION_CustomAType );
                //SettingCustomParameters(LORAMAC_REGION_CustomAType);
#elif defined( REGION_CustomBType)
                LoRaMacInitialization( &LoRaMacPrimitives, NULL, LORAMAC_REGION_CustomBType );
                //SettingCustomParameters(LORAMAC_REGION_CustomBType);
#else
                LoRaMacInitialization( &LoRaMacPrimitives, NULL, LORAMAC_REGION_EU868 );
#endif
					//LoRaMacInitialization( &LoRaMacPrimitives, NULL );
	                QM_PRINTF("\nLoRaMac Initialization finished\n\n");


#if defined (REGION_CustomBType)
	            /*Set Custom parameters*/
	            /*(1)Sync Word*/
	                Radio.SetPublicNetwork(true);//true = 0x34; false = 0x12;
	            /*(2)Preamble Length*/
	                RegionSetCustomPreambleLength(LORAMAC_REGION_CustomBType,8);
	            /*(3)Channels*/
	                /*(3-1)Max Channel*/
	                uint8_t MaxChannel = 72;
	                RegionSetCustomMaxChannel(LORAMAC_REGION_CustomBType,MaxChannel);
	                /*(3-2)Setup Channels*/
                for(uint8_t i=0;i<=MaxChannel;i++)
                {
                	LoRaMacChannelRemove(i);
                }
                LoRaMacChannelAdd( 0, ( ChannelParams_t )LC0 );
                LoRaMacChannelAdd( 1, ( ChannelParams_t )LC1 );
                LoRaMacChannelAdd( 2, ( ChannelParams_t )LC2 );
                LoRaMacChannelAdd( 3, ( ChannelParams_t )LC3 );
                LoRaMacChannelAdd( 4, ( ChannelParams_t )LC4 );
                LoRaMacChannelAdd( 5, ( ChannelParams_t )LC5 );
                LoRaMacChannelAdd( 6, ( ChannelParams_t )LC6 );
                LoRaMacChannelAdd( 7, ( ChannelParams_t )LC7 );

                mibReq.Type = MIB_RX2_CHANNEL;
                mibReq.Param.Rx2Channel = ( Rx2ChannelParams_t ){ 923300000, DR_8 };
                LoRaMacMibSetRequestConfirm( &mibReq );
                /*(4)DutyCycle*/
               // RegionSetCustomDutyCycle(LORAMAC_REGION_CustomAType,DutyCycle);

#endif
	                TimerInit();

	                TxDutyCycleTime = 1000;
	                qm_pwm_set(QM_PWM_0, QM_PWM_ID_1, (TxDutyCycleTime/10)*0x4CCCA, 0x00);

	                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 ) || defined( REGION_CustomAType )
                LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
                /*(1)Sync Word*/
                Radio.SetPublicNetwork(true);//true = 0x34; false = 0x12;
                /*(2)Preamble Length*/
                RegionSetCustomPreambleLength(LORAMAC_REGION_CustomBType,8);
                /*(3)Channels*/
                /*(3-1)Max Channel*/
                uint8_t MaxChannel = 16;
                RegionSetCustomMaxChannel(LORAMAC_REGION_CustomBType,MaxChannel);
                /*(3-2)Setup Channels*/
#if defined( REGION_CustomAType )
                for(uint8_t i=0;i<=MaxChannel;i++)
                {
                	LoRaMacChannelRemove(i);
                }
                LoRaMacChannelAdd( 0, ( ChannelParams_t )LC0 );
                LoRaMacChannelAdd( 1, ( ChannelParams_t )LC1 );
                LoRaMacChannelAdd( 2, ( ChannelParams_t )LC2 );
                LoRaMacChannelAdd( 3, ( ChannelParams_t )LC3 );
                LoRaMacChannelAdd( 4, ( ChannelParams_t )LC4 );
                LoRaMacChannelAdd( 5, ( ChannelParams_t )LC5 );
                LoRaMacChannelAdd( 6, ( ChannelParams_t )LC6 );
                LoRaMacChannelAdd( 7, ( ChannelParams_t )LC7 );

                RegionSetCustomRX2WindowFreq(LORAMAC_REGION_CustomAType,869525000);

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

#if( USE_SEMTECH_DEFAULT_CHANNEL_LINEUP == 1 )
                //if use REGION_EU868, then LC1,LC2,LC3 defined in EU868

                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_DEFAULT_CHANNEL;
                mibReq.Param.Rx2DefaultChannel = ( Rx2ChannelParams_t ){ 869525000, DR_5 };
                LoRaMacMibSetRequestConfirm( &mibReq );

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

#endif
	                DeviceState = DEVICE_STATE_JOIN;
	                break;
	            }
	            case DEVICE_STATE_JOIN:
	            {
	            	LoRaMacDebugMessageOn(true,false);

	#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.NbTrials = 3;

	                if( NextTx == true )
	                {
	                	NextTx = false;
	                	QM_PRINTF("\n Try to Connect to LoRa Network.\n");
	                    LoRaMacMlmeRequest( &mlmeReq );
	                }
	                sensor_activation();
	                DeviceState = DEVICE_STATE_CYCLE;
	#else
	                // 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:
	            {
	            	//QM_PRINTF("\n(Main_while)case:DEVICE_STATE_SEND\n");
	                if( NextTx == true )
	                {

	                	//LoRaMacTestSetDutyCycleOn(false);
	                		//clear irq flags
	                	    QM_PUTS("Clear IRQ Flags.");
	                		Radio.Write(0x12,0xff);
	                		QM_PRINTF(" DEVICE_STATE_SEND: AppPort[%d]\n",AppPort);
	                		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_SLEEP;//Case 1
	                DeviceState = DEVICE_STATE_CYCLE;//Case 2
	                break;
	            }
	            case DEVICE_STATE_CYCLE:
	            {
	                // Schedule next packet transmission
	                // counting 8sec
	            	if(TxDutyCycleTime <= 8000)	//15000=15sec ; 8000=8sec
	            	{
	            		TxDutyCycleTime = 8000;
	            	}

	            	while(QM_PWM[0]->timer[1].controlreg == 1)
	            	{}

	            	qm_pwm_set(QM_PWM_0, QM_PWM_ID_1, ((TxDutyCycleTime/10)*0x4CCCA), 0x00);
	                qm_pwm_start(QM_PWM_0, QM_PWM_ID_1);


	                if(showNetWorkmessage)
	                {
	                mibReq.Type = MIB_APP_SKEY;//MIB_DEV_ADDR//MIB_NWK_SKEY
	                LoRaMacMibGetRequestConfirm( &mibReq );

	                if(mibReq.Param.AppSKey[0] != 0)
	                {QM_PRINTF("\n[DEVICE_STATE_CYCLE] mibReq.Param.AppSKey\n");
	                	for(int i= 0; i< 16 ;i++)
	                	{
	                		if(i==15)
	                		{
	                			QM_PRINTF(" 0x%X",mibReq.Param.AppSKey[i]);
	                		}
	                		else
	                		{
	                			QM_PRINTF(" 0x%X,",mibReq.Param.AppSKey[i]);
	                		}
	                	}
	                	QM_PRINTF("\n");
	                	showNetWorkmessage = false;
	                }
	                }//if(showNetWorkmessage)

	                break;
	            }
	            case DEVICE_STATE_SLEEP:
	            {
	                // Wake up through events
	            	uint16_t sleepTime = 20; // Uint : sec
	            	//while(SX1276.Settings.State != RF_IDLE)
	            	while(Radio.GetStatus() != RF_IDLE)
	            	{}
	            	QM_PUTS("Stop timers.");
	            	Timer1Stop();
	            	Timer0Stop();
	            	Radio.Sleep();
	            	qm_pic_timer_config_t pic_conf;

	            	//Get current UpLink counter number.
	            	mibReq.Type = MIB_UPLINK_COUNTER;
	            	LoRaMacMibGetRequestConfirm( &mibReq );
	            	counter = mibReq.Param.UpLinkCounter;

	            	QM_PUTS("Starting: Power Core example");

	            	/* PIC timer to wake up from C1/C2/C2LP */
	            	pic_conf.mode = QM_PIC_TIMER_MODE_PERIODIC;
	            	pic_conf.int_en = true;
	            	pic_conf.callback = timer_expired;
	            	qm_int_vector_request(QM_X86_PIC_TIMER_INT_VECTOR, qm_pic_timer_0_isr);
	            	qm_pic_timer_set_config(&pic_conf);
	            	qm_pic_timer_set(0x2000000 *sleepTime);		//0x2000000 =1 sec
	            	/* Halt the CPU, PIC TIMER INT will wake me up. */
	            	qm_power_cpu_c2();
	            	NextTx = true;
	            	QM_PUTS("!!Main!Wake up from c2.");
	            	/* Remove PIC timer interrupts. */
	            	pic_conf.int_en = false;
	            	qm_pic_timer_set_config(&pic_conf);

	            	//Set saved UpLink counter number.
	            	LoRaMacSetUplinkCounter(counter);
	            	QM_PRINTF("RTC CCVR [%d] after sleep.\n",QM_RTC[QM_RTC_0]->rtc_ccvr);

	            	//DeviceState = DEVICE_STATE_SEND;
	            	OnTxNextPacketTimerEvent();

	                break;
	            }
	            default:
	            {
	                DeviceState = DEVICE_STATE_INIT;
	                break;
	            }
	        }

	    }
	return 0;
}

void timer_callback(void *data, uint32_t timer_int)
{
	if((timer_int & BIT(QM_PWM_ID_0)))
	{
		extern uint32_t swTimer_0_cnt;
		extern uint32_t swTimer_1_cnt;
		extern uint32_t swTimer_2_cnt;
		extern uint32_t swTimer_3_cnt;
		extern uint32_t swTimer_4_cnt;
		extern uint32_t swTimer_5_cnt;
		extern uint32_t swTimer_6_cnt;
		extern uint32_t swTimer_7_cnt;
		extern bool sw_timer_running;
		extern bool sw_radio_timer_running;
//		uint32_t curr_Time;
		if(swTimer_0_cnt > 0)
		{//TxTimeoutTimer
			swTimer_0_cnt--;
			if (swTimer_0_cnt == 0)
			{
				SX1276.Settings.State = RF_IDLE;//TX Timeout,set LoRa transceiver state to IDLE;
				OnRadioTxTimeout( );
				DeviceState = DEVICE_STATE_CYCLE;
			}
		}
		if(swTimer_1_cnt > 0)
		{//RxTimeoutTimer
			swTimer_1_cnt--;
			if (swTimer_1_cnt == 0)
			{
				SX1276.Settings.State = RF_IDLE;//RX Timeout,set LoRa transceiver state to IDLE;
				OnRadioRxTimeout( );
				DeviceState = DEVICE_STATE_CYCLE;
			}
		}
		if(swTimer_2_cnt > 0)
		{//RxTimeoutSyncWord
			swTimer_2_cnt--;
			if (swTimer_2_cnt == 0)
			{
			//	RxTimeoutSyncWord
				if(SX1276.Settings.Modem == MODEM_FSK)
				{
					SX1276.Settings.FskPacketHandler.PreambleDetected = false;
					SX1276.Settings.FskPacketHandler.SyncWordDetected = false;
					SX1276.Settings.FskPacketHandler.NbBytes = 0;
					SX1276.Settings.FskPacketHandler.Size = 0;
					//Clear Irqs
					Radio.Write(REG_IRQFLAGS1, 	RF_IRQFLAGS1_RSSI |
												RF_IRQFLAGS1_PREAMBLEDETECT |
												RF_IRQFLAGS1_SYNCADDRESSMATCH );
					Radio.Write(REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN );
					if(SX1276.Settings.Fsk.RxContinuous == true)
					{//Continuos mode restart Rx chain
						Radio.Write(REG_RXCONFIG, Radio.Read(REG_RXCONFIG) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK);
						if((sw_radio_timer_running == false) && (sw_timer_running == false))
						{
								sw_radio_timer_running = true;
								/* Enable clocking for the PWM block */
								clk_periph_enable(CLK_PERIPH_PWM_REGISTER | CLK_PERIPH_CLK);
								qm_pwm_start(QM_PWM_0, QM_PWM_ID_0);
						}

					}
				}
			}
		}
		if(swTimer_3_cnt > 0)
		{//MacStateCheckTimer
			swTimer_3_cnt--;
			if (swTimer_3_cnt == 0)
			{
				OnMacStateCheckTimerEvent();
			}
		}
		if(swTimer_4_cnt > 0)
		{//TxDelayedTimer
			swTimer_4_cnt--;
			if (swTimer_4_cnt == 0)
			{
//				curr_Time=QM_RTC[QM_RTC_0]->rtc_ccvr;
//				QM_PRINTF("\n============================\nSW Timer 4 [TxDelayedTimer][%d] fired.\n",curr_Time);
				OnTxDelayedTimerEvent();
			}
		}
		if(swTimer_5_cnt > 0)
		{//RxWindowTimer1
			swTimer_5_cnt--;
			if (swTimer_5_cnt == 0)
			{
//				curr_Time=QM_RTC[QM_RTC_0]->rtc_ccvr;
//				QM_PRINTF("\n============================\nSW Timer 5 [RxWindowTimer1] at rtc:[%d] fired. Call OnRxWindow1TimerEvent. \n",curr_Time);
				OnRxWindow1TimerEvent();
			}
		}
		if(swTimer_6_cnt > 0)
		{//RxWindowTimer2
			swTimer_6_cnt--;
			if (swTimer_6_cnt == 0)
			{
//				curr_Time=QM_RTC[QM_RTC_0]->rtc_ccvr;
//				QM_PRINTF("\n============================\nSW Timer 6 [RxWindowTimer2] at rtc:[%d] fired. Call OnRxWindow2TimerEvent. \n",curr_Time);
				OnRxWindow2TimerEvent();
			}
		}
		if(swTimer_7_cnt > 0)
		{//AckTimeoutTimer
			swTimer_7_cnt--;
			if (swTimer_7_cnt == 0)
			{
//				curr_Time=QM_RTC[QM_RTC_0]->rtc_ccvr;
//				QM_PRINTF("\n============================\nSW Timer 7 [AckTimeoutTimer][%d] fired.\n",curr_Time);
				OnAckTimeoutTimerEvent();
			}
		}
	}
	else if ((timer_int & BIT(QM_PWM_ID_1)))
	{
		QM_PRINTF("\n[Main]HW Timer1 [%d] fired.[%d]\n",QM_RTC[QM_RTC_0]->rtc_ccvr, QM_PWM[QM_PWM_0]->timer[3].loadcount);
		OnTxNextPacketTimerEvent();
	}
	else if ((timer_int & BIT(QM_PWM_ID_2)))
	{

	}
	if (timer_int & BIT(QM_PWM_ID_3))
	{

	}
}

void Main_IrqInit( void )
{
		qm_gpio_port_config_t cfg;
		//qm_gpio_state_t state;
		QM_PUTS("Starting: GPIO\n");
		/* Pin Muxing */
		qm_pmux_pullup_en(SX1276.DIO0, true);		//Setting Pin 20 is Pull up
		qm_pmux_select(SX1276.DIO0, QM_PMUX_FN_0);	//
		qm_pmux_input_en(SX1276.DIO0, true);		//Setting Pin 20 is  Input Pin

		/* Set the GPIO pin muxing. */
		qm_pmux_select(SX1276.ANT_SWITCH_LF_TX , QM_PMUX_FN_0);
		qm_pmux_select(SX1276.ANT_SWITCH_LF_RX , QM_PMUX_FN_0);
		qm_pmux_select(SX1276.ANT_SWITCH_HF_TX , QM_PMUX_FN_0);
		qm_pmux_select(SX1276.ANT_SWITCH_HF_RX , QM_PMUX_FN_0);

		/* Request IRQ and write GPIO port config */
		cfg.direction = BIT(4)|BIT(5)|BIT(6)|BIT(7);
		cfg.int_en = BIT(SX1276.DIO0);			/* Interrupt enabled */
		cfg.int_type = BIT(SX1276.DIO0);      	/* Edge sensitive interrupt */
		cfg.int_polarity = ~BIT(SX1276.DIO0); 	/* falling edge */
		cfg.int_debounce = BIT(SX1276.DIO0);  	/* Debounce enabled */
		cfg.int_bothedge = 0x0;		   		/* Both edge disabled */
		cfg.callback = gpio_example_callback;
		cfg.callback_data = NULL;

		QM_IR_UNMASK_INT(QM_IRQ_GPIO_0_INT);
		QM_IRQ_REQUEST(QM_IRQ_GPIO_0_INT, qm_gpio_0_isr);
		QM_PUTS("GPIO: irq requested\n");

		/* enable pullup on interrupt pin. */
		qm_pmux_pullup_en(SX1276.DIO0, true);
		qm_gpio_set_config(QM_GPIO_0, &cfg);

		/* Write the config. default : TX mode */
		qm_gpio_set_pin(QM_GPIO_0, SX1276.ANT_SWITCH_LF_TX);	//1
		qm_pmux_pullup_en(SX1276.ANT_SWITCH_LF_TX, true);		// PIN_PULL_UP
		qm_gpio_set_pin(QM_GPIO_0, SX1276.ANT_SWITCH_HF_TX);	//1
		qm_pmux_pullup_en(SX1276.ANT_SWITCH_HF_TX, true);		// PIN_PULL_UP

		qm_gpio_clear_pin(QM_GPIO_0, SX1276.ANT_SWITCH_LF_RX);	//0
		qm_pmux_pullup_en(SX1276.ANT_SWITCH_LF_RX, false);		// PIN_PULL_Done
		qm_gpio_clear_pin(QM_GPIO_0, SX1276.ANT_SWITCH_HF_RX);	//0
		qm_pmux_pullup_en(SX1276.ANT_SWITCH_HF_RX, false);		// PIN_PULL_Done
}

void gpio_example_callback(void *data, uint32_t status)
{
	QM_PUTS("GPIO IRQ.");
	Radio.OnDIO0Irq();
}
void mbox_cb(void *mbox)
{
	qm_mbox_ch_t *ch = (qm_mbox_ch_t *)mbox;

	if (0 != qm_mbox_ch_read(*ch, &Mbox_rx_data)) {
		QM_PRINTF("Error: Reading failed on mbox=%d, ctrl=%d.\n",
			       *ch, (int)Mbox_rx_data.ctrl);
	}
	int i;
	for (i = 0; i < 3; i++) {
		QM_PRINTF("\t========== Mbox rx_data.data[%X] ==========\n",Mbox_rx_data.data[i]);
	}
	 Sensor_temperature = Mbox_rx_data.data[0];//Uint :Celsius
	 Sensor_humidity	= Mbox_rx_data.data[1];//Uint :percentage (0~100)
	 Sensor_UV			= Mbox_rx_data.data[2];//Level:0~11

//	mb_got_message[*ch] = true;
}


