Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of LoRaWAN_Semtech_stack_v4.1 by
main-api-v3.cpp
- Committer:
- mleksio
- Date:
- 2016-04-22
- Revision:
- 5:cbb921e2a03b
- Parent:
- 1:2be292bd43f9
File content as of revision 5:cbb921e2a03b:
#if 0
/*
 / _____)             _              | |
( (____  _____ ____ _| |_ _____  ____| |__
 \____ \| ___ |    (_   _) ___ |/ ___)  _ \
 _____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
    (C)2013 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 <string.h>
#include <math.h>
#include "mbed.h"
#include "utilities.h"
#include "LoRaMac-api-v3.h"
#include "Comissioning.h"
/*!
 * When set to 1 the application uses the Over-the-Air activation procedure
 * When set to 0 the application uses the Personalization activation procedure
 */
#define OVER_THE_AIR_ACTIVATION                     1
/*!
 * Join requests trials duty cycle.
 */
#define OVER_THE_AIR_ACTIVATION_DUTYCYCLE           10000000  // 10 [s] value in us
/*!
 * 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
/*!
 * LoRaWAN confirmed messages
 */
#define LORAWAN_CONFIRMED_MSG_ON                    false
/*!
 * LoRaWAN Adaptative Data Rate
 *
 * \remark Please note that when ADR is enabled the end-device should be static
 */
#define LORAWAN_ADR_ON                              1
#if defined( USE_BAND_868 )
/*!
 * LoRaWAN ETSI duty cycle control enable/disable
 *
 * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes
 */
#define LORAWAN_DUTYCYCLE_ON                        true
#endif
/*!
 * LoRaWAN application port
 */
#define LORAWAN_APP_PORT                            1
/*!
 * User application data buffer size
 */
#define LORAWAN_APP_DATA_SIZE                       8
#if( OVER_THE_AIR_ACTIVATION != 0 )
static uint8_t DevEui[] = LORAWAN_DEVICE_EUI;
static uint8_t AppEui[] = LORAWAN_APPLICATION_EUI;
static uint8_t AppKey[] = LORAWAN_APPLICATION_KEY;
#else
static uint8_t NwkSKey[] = LORAWAN_NWKSKEY;
static uint8_t AppSKey[] = LORAWAN_APPSKEY;
/*!
 * Device address
 */
static uint32_t DevAddr;
#endif
/*!
 * Indicates if the MAC layer has already joined a network.
 */
static bool IsNetworkJoined = false;
/*!
 * 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 void OnTxNextPacketTimerEvent( void );
static Timeout TxNextPacketTimer;
#if( OVER_THE_AIR_ACTIVATION != 0 )
/*!
 * Defines the join request timer
 */
static void OnJoinReqTimerEvent( void );
static Timeout JoinReqTimer;
#endif
/*!
 * Indicates if a new packet can be sent
 */
static bool TxNextPacket = true;
static bool ScheduleNextTx = false;
static bool DownlinkStatusUpdate = false;
static LoRaMacCallbacks_t LoRaMacCallbacks;
/*!
 * \brief Function executed on duty cycle delayed Tx  timer event
 */
static void OnLed1TimerEvent( void );
static void OnLed2TimerEvent( void );
static Timeout Led1Timer;
static Timeout Led2Timer;
volatile bool Led1StateChanged = false;
volatile bool Led2StateChanged = false;
#define LED1_TIMER_TIMEOUT      25000
#define LED2_TIMER_TIMEOUT      25000
static bool AppLedStateOn = false;
/*!
 * 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;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
/*!
 * Prepares the frame buffer to be sent
 */
static void PrepareTxFrame( uint8_t port )
{
    switch( port )
    {
    case 1:
        {
            //uint16_t pressure = 0;
            //int16_t altitudeBar = 0;
            //int16_t temperature = 0;
            //uint8_t batteryLevel = 0;
            //pressure = ( uint16_t )( MPL3115ReadPressure( ) / 10 );             // in hPa / 10
            //temperature = ( int16_t )( MPL3115ReadTemperature( ) * 100 );       // in ?C * 100
            //altitudeBar = ( int16_t )( MPL3115ReadAltitude( ) * 10 );           // in m * 10
            //batteryLevel = BoardGetBatteryLevel( );                             // 1 (very low) to 254 (fully charged)
            //AppData[0] = ( SelectorGetValue( ) << 4 ) | AppLedStateOn;
            //AppData[1] = ( pressure >> 8 ) & 0xFF;
            //AppData[2] = pressure & 0xFF;
            //AppData[3] = ( temperature >> 8 ) & 0xFF;
            //AppData[4] = temperature & 0xFF;
            //AppData[5] = ( altitudeBar >> 8 ) & 0xFF;
            //AppData[6] = altitudeBar & 0xFF;
            //AppData[7] = batteryLevel;
        }
        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;
    }
}
static void ProcessRxFrame( LoRaMacEventFlags_t *flags, LoRaMacEventInfo_t *info )
{
    switch( info->RxPort ) // Check Rx port number
    {
    case 1: // The application LED can be controlled on port 1 or 2
    case 2:
        if( info->RxBufferSize == 1 )
        {
            AppLedStateOn = info->RxBuffer[0] & 0x01;
            //Led3StateChanged = true;
        }
        break;
    case 224:
        if( ComplianceTest.Running == false )
        {
            // Check compliance test enable command (i)
            if( ( info->RxBufferSize == 4 ) && 
                ( info->RxBuffer[0] == 0x01 ) &&
                ( info->RxBuffer[1] == 0x01 ) &&
                ( info->RxBuffer[2] == 0x01 ) &&
                ( info->RxBuffer[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;
                
                LoRaMacSetAdrOn( true );
#if defined( USE_BAND_868 )
                LoRaMacTestSetDutyCycleOn( false );
#endif
            }
        }
        else
        {
            ComplianceTest.State = info->RxBuffer[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;
                LoRaMacSetAdrOn( LORAWAN_ADR_ON );
#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 = info->RxBufferSize;
                AppData[0] = 4;
                for( uint8_t i = 1; i < AppDataSize; i++ )
                {
                    AppData[i] = info->RxBuffer[i] + 1;
                }
                break;
            case 5: // (viii)
                LoRaMacLinkCheckReq( );
                break;
            default:
                break;
            }
        }
        break;
    default:
        break;
    }
}
static bool SendFrame( void )
{
    uint8_t sendFrameStatus = 0;
    if( IsTxConfirmed == false )
    {
        sendFrameStatus = LoRaMacSendFrame( AppPort, AppData, AppDataSize );
    }
    else
    {
        sendFrameStatus = LoRaMacSendConfirmedFrame( AppPort, AppData, AppDataSize, 8 );
    }
    switch( sendFrameStatus )
    {
    case 3: // LENGTH_ERROR
        // Send empty frame in order to flush MAC commands
        LoRaMacSendFrame( 0, NULL, 0 );
        return false;
    case 5: // NO_FREE_CHANNEL
        // Try again later
        return true;
    default:
        return false;
    }
}
#if( OVER_THE_AIR_ACTIVATION != 0 )
/*!
 * \brief Function executed on JoinReq Timeout event
 */
static void OnJoinReqTimerEvent( void )
{
    JoinReqTimer.detach();
    TxNextPacket = true;
}
#endif
/*!
 * \brief Function executed on TxNextPacket Timeout event
 */
static void OnTxNextPacketTimerEvent( void )
{
    TxNextPacketTimer.detach();
    TxNextPacket = true;
}
/*!
 * \brief Function executed on Led 1 Timeout event
 */
static void OnLed1TimerEvent( void )
{
    Led1Timer.detach();
    Led1StateChanged = true;
}
/*!
 * \brief Function executed on Led 2 Timeout event
 */
static void OnLed2TimerEvent( void )
{
    Led2Timer.detach();
    Led2StateChanged = true;
}
/*!
 * \brief Function to be executed on MAC layer event
 */
static void OnMacEvent( LoRaMacEventFlags_t *flags, LoRaMacEventInfo_t *info )
{
    if( flags->Bits.JoinAccept == 1 )
    {
#if( OVER_THE_AIR_ACTIVATION != 0 )
        JoinReqTimer.detach();
#endif
        IsNetworkJoined = true;
    }
    else
    {
        if( flags->Bits.Tx == 1 )
        {
        }
        if( flags->Bits.Rx == 1 )
        {
            if( ComplianceTest.Running == true )
            {
                ComplianceTest.DownLinkCounter++;
                if( flags->Bits.LinkCheck == 1 )
                {
                    ComplianceTest.LinkCheck = true;
                    ComplianceTest.DemodMargin = info->DemodMargin;
                    ComplianceTest.NbGateways = info->NbGateways;
                }
            }
            if( flags->Bits.RxData == true )
            {
                ProcessRxFrame( flags, info );
            }
            DownlinkStatusUpdate = true;
            Led2Timer.attach_us(OnLed2TimerEvent, LED2_TIMER_TIMEOUT);
        }
    }
    // Schedule a new transmission
    ScheduleNextTx = true;
}
/**
 * Main application entry point.
 */
int main( void )
{
#if( OVER_THE_AIR_ACTIVATION != 0 )
    uint8_t sendFrameStatus = 0;
#endif
    bool trySendingFrameAgain = false;
#warning HW and RADIO CHIP must be configured!!!!
    //BoardInitMcu( );
    //BoardInitPeriph( );
    //hal_init();
    //radio_init();
    LoRaMacCallbacks.MacEvent = OnMacEvent;
    //LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
    LoRaMacInit( &LoRaMacCallbacks );
    IsNetworkJoined = false;
#if( OVER_THE_AIR_ACTIVATION == 0 )
    // Random seed initialization
    #warning seed initialization must be implemented
    srand1( 1 );
    // Choose a random device address based on Board unique ID
    // NwkAddr rand [0, 33554431]
    DevAddr = randr( 0, 0x01FFFFFF );
    LoRaMacInitNwkIds( LORAWAN_NETWORK_ID, DevAddr, NwkSKey, AppSKey );
    IsNetworkJoined = true;
#else
    // Initialize LoRaMac device unique ID
    //BoardGetUniqueId( DevEui );
#endif
    TxNextPacket = true;
    LoRaMacSetAdrOn( LORAWAN_ADR_ON );
    LoRaMacSetPublicNetwork( LORAWAN_PUBLIC_NETWORK );
#if defined( USE_BAND_868 )
    #warning dutycycleON OFFFFFFFFFFFFF!!!!!!!!!!!!!!!!!!!!!!!
//    LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
    LoRaMacTestSetDutyCycleOn( 0 );
//    LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
#endif
    while( 1 )
    {
        while( IsNetworkJoined == false )
        {
#if( OVER_THE_AIR_ACTIVATION != 0 )
            if( TxNextPacket == true )
            {
                printf("Trial to join network... txnextpacket %i \r\n", TxNextPacket);
                TxNextPacket = false;
                
                sendFrameStatus = LoRaMacJoinReq( DevEui, AppEui, AppKey );
                printf("status = %i\r\n", sendFrameStatus);
                switch( sendFrameStatus )
                {
                case 1: // BUSY
                    break;
                case 0: // OK
                case 2: // NO_NETWORK_JOINED
                case 3: // LENGTH_PORT_ERROR
                case 4: // MAC_CMD_ERROR
                case 6: // DEVICE_OFF
                default:
                    // Relaunch timer for next trial
                    JoinReqTimer.attach_us(OnJoinReqTimerEvent, OVER_THE_AIR_ACTIVATION_DUTYCYCLE);
                    break;
                }
            }
            //TimerLowPowerHandler( );
#endif
        }
        if( Led1StateChanged == true )
        {
            Led1StateChanged = false;
            // Switch LED 1 OFF
            led1 = 0;
        }
        if( Led2StateChanged == true )
        {
            Led2StateChanged = false;
            // Switch LED 2 OFF
            led2 = 0;
        }
        if( DownlinkStatusUpdate == true )
        {
            DownlinkStatusUpdate = false;
            // Switch LED 2 ON for each received downlink
            led2 = 1;
        }
        if( ScheduleNextTx == true )
        {
            ScheduleNextTx = false;
            if( ComplianceTest.Running == true )
            {
                TxNextPacket = true;
            }
            else
            {
                // Schedule next packet transmission
                TxDutyCycleTime = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );
                TxNextPacketTimer.attach_us(OnTxNextPacketTimerEvent, TxDutyCycleTime);
            }
        }
        if( trySendingFrameAgain == true )
        {
            trySendingFrameAgain = SendFrame( );
        }
        if( TxNextPacket == true )
        {
            TxNextPacket = false;
            PrepareTxFrame( AppPort );
            
            // Switch LED 1 ON
            led1 = 1;
            Led1Timer.attach_us(OnLed1TimerEvent, LED1_TIMER_TIMEOUT);
            trySendingFrameAgain = SendFrame( );
        }
        //TimerLowPowerHandler( );
    }
}
#endif
            
    