Source code for the SX126xDVK1xAS Dev Kit. This example code has only been tested on the Nucleo L476RG

Dependencies:   mbed DmTftLibrary SX126xLib

Revision:
0:e5420f1a8a1a
Child:
1:b96176a4ccb8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Demo/DemoApplication.cpp	Tue Sep 05 08:15:37 2017 +0000
@@ -0,0 +1,1445 @@
+/*
+  ______                              _
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2016 Semtech
+
+Description: PingPong, PER demo implementation.
+
+Maintainer: Gregory Cristian & Gilbert Menth
+*/
+
+#include "mbed.h"
+#include "radio.h"
+#include "sx126x-hal.h"
+#include "Eeprom.h"
+#include "DemoApplication.h"
+
+/*!
+ * \brief Defines the local payload buffer size
+ */
+#define BUFFER_SIZE                     255
+
+/*!
+ * \brief Defines the size of the token defining message type in the payload
+ *        cf. above.
+ */
+#define PINGPONG_SIZE                   4
+#define PER_SIZE                        3
+
+/*!
+ * \brief Define time used in PingPong demo to synch with cycle
+ * RX_TIMEOUT_MARGIN is the free time between each cycle (time reserve)
+ */
+#define RX_TIMEOUT_MARGIN               150  // ms
+#define RX_TX_TRANSITION_WAIT           5    // ms
+
+
+/*!
+ * \brief Define the possible message type for the Ping-Pong and PER apps
+ */
+const uint8_t PingMsg[] = "PING";
+const uint8_t PongMsg[] = "PONG";
+const uint8_t PerMsg[]  = "PER";
+
+/*!
+ * \brief Buffer and its size
+ */
+uint8_t BufferSize = BUFFER_SIZE;
+uint8_t Buffer[BUFFER_SIZE];
+
+/*!
+ * \brief Function to be executed on Radio Tx Done event
+ */
+void OnTxDone( void );
+
+/*!
+ * \brief Function to be executed on Radio Rx Done event
+ */
+void OnRxDone( void );
+
+/*!
+ * \brief Function executed on Radio Tx Timeout event
+ */
+void OnTxTimeout( void );
+
+/*!
+ * \brief Function executed on Radio Rx Timeout event
+ */
+void OnRxTimeout( void );
+
+/*!
+ * \brief Function executed on Radio Rx Error event
+ */
+void OnRxError( IrqErrorCode_t );
+
+/*!
+ * \brief Function executed on Radio CAD Done event
+ */
+void OnCadDone( bool channelActivityDetected );
+
+/*!
+ * \brief All the callbacks are stored in a structure
+ */
+RadioCallbacks_t RadioEvents =
+{
+    &OnTxDone,        // txDone
+    &OnRxDone,        // rxDone
+    NULL,             // rxPreambleDetect
+    NULL,             // rxSyncWordDone
+    NULL,             // rxHeaderDone
+    &OnTxTimeout,     // txTimeout
+    &OnRxTimeout,     // rxTimeout
+    &OnRxError,       // rxError
+    &OnCadDone,       // cadDone
+};
+
+// SPI
+// mosi, miso, sclk, nss, dio0, dio1, dio2, dio3, rst, deviceSel, antSwPower, callbacks...
+SX126xHal Radio( D11, D12, D13, D7, D3, D5, NC, NC, A0, A2, D8, &RadioEvents );
+
+/*!
+ * \brief Tx LED toggling on transmition success
+ */
+DigitalOut TX_LED( A4 );
+
+/*!
+ * \brief Rx LED toggling on reception success
+ */
+DigitalOut RX_LED( A5 );
+
+/*!
+ * \brief Mask of IRQs
+ */
+uint16_t IrqMask = 0x0000;
+
+/*!
+ * \brief Locals parameters and status for radio API
+ * NEED TO BE OPTIMIZED, COPY OF STUCTURE ALREADY EXISTING
+ */
+PacketParams_t PacketParams;
+PacketStatus_t PacketStatus;
+ModulationParams_t ModulationParams;
+
+/*!
+ * \brief Flag to indicate if the demo is already running
+ */
+static bool DemoRunning = false;
+
+/*!
+ * \brief Frequency Error (only LSB)
+ */
+static double FreErrorLsb = 0.0;
+
+/*!
+ * \brief Flag holding the current internal state of the demo application
+ */
+static uint8_t DemoInternalState = APP_IDLE;
+
+/*!
+ * \brief Ticker for master to synch Tx frames. Flags for PER and PingPong demo
+ * for Synch TX in cycle.
+ */
+Ticker SendNextPacket;
+static bool SendNext = false;
+
+/*!
+ * \brief Hold last Rx packet number to compute PER in PER and PingPong demo
+ */
+static uint32_t PacketRxSequence = 0;
+static uint32_t PacketRxSequencePrev = 0;
+
+void LedBlink( void );
+void InitializeDemoParameters( uint8_t modulation );
+uint16_t GetTimeOnAir( uint8_t modulation );
+void SendNextPacketEvent( void );
+
+// **************************     RF Test Demo    ******************************
+// *                                                                           *
+// *                                                                           *
+// *                                                                           *
+// *****************************************************************************
+
+uint8_t RunDemoSleepMode( void )
+{
+    SleepParams_t SleepParam;
+    
+    if( Eeprom.EepromData.DemoSettings.HoldDemo == true )
+    {
+        return 0;
+    }
+
+    if( DemoRunning == false )
+    {
+        DemoRunning = true;
+        InitializeDemoParameters( PACKET_TYPE_LORA );
+        TX_LED = 0;
+        RX_LED = 0;
+
+        SleepParam.Fields.WakeUpRTC = 0;       //!< Get out of sleep mode if wakeup signal received from RTC
+        SleepParam.Fields.Reset = 0;           //!< 
+        SleepParam.Fields.WarmStart = 1;       //!< 
+        Radio.SetSleep( SleepParam );
+    }
+    else
+    {
+        LedBlink( );
+    }
+    return 0;
+}
+
+uint8_t RunDemoStandbyRcMode( void )
+{
+    if( Eeprom.EepromData.DemoSettings.HoldDemo == true )
+    {
+        return 0;
+    }
+
+    if( DemoRunning == false )
+    {
+        DemoRunning = true;
+        InitializeDemoParameters( PACKET_TYPE_LORA );
+        TX_LED = 0;
+        RX_LED = 0;
+        Radio.SetRegulatorMode( ( RadioRegulatorMode_t )Eeprom.EepromData.DemoSettings.RadioPowerMode );
+        Radio.SetStandby( STDBY_RC );
+        DemoRunning = true;
+    }
+    else
+    {
+        LedBlink( );
+    }
+    return 0;
+}
+
+uint8_t RunDemoStandbyXoscMode( void )
+{
+    if( Eeprom.EepromData.DemoSettings.HoldDemo == true )
+    {
+        return 0;
+    }
+    if( DemoRunning == false )
+    {
+        DemoRunning = true;
+        InitializeDemoParameters( PACKET_TYPE_LORA );
+        TX_LED = 0;
+        RX_LED = 0;
+        Radio.SetRegulatorMode( ( RadioRegulatorMode_t )Eeprom.EepromData.DemoSettings.RadioPowerMode );
+        Radio.SetStandby( STDBY_XOSC );
+        DemoRunning = true;
+    }
+    else
+    {
+        LedBlink( );
+    }
+    return 0;
+}
+
+uint8_t RunDemoTxCw( void )
+{
+    if( Eeprom.EepromData.DemoSettings.HoldDemo == true )
+    {
+        return 0;
+    }
+
+    if( DemoRunning == false )
+    {
+        DemoRunning = true;
+        InitializeDemoParameters( PACKET_TYPE_LORA );
+        TX_LED = 0;
+        RX_LED = 0;
+        Radio.SetStandby( STDBY_RC );
+        Radio.SetRegulatorMode( ( RadioRegulatorMode_t )Eeprom.EepromData.DemoSettings.RadioPowerMode );
+        Radio.SetRfFrequency( Eeprom.EepromData.DemoSettings.Frequency );
+        Radio.SetTxParams( Eeprom.EepromData.DemoSettings.TxPower, RADIO_RAMP_40_US );
+        Radio.SetTxContinuousWave( );
+        DemoRunning = true;
+    }
+    else
+    {
+        LedBlink( );
+    }
+    return 0;
+}
+
+uint8_t RunDemoTxContinuousModulation( void )
+{
+    uint8_t localPayloadSize = 250;
+    uint8_t i = 0;
+
+    if( Eeprom.EepromData.DemoSettings.HoldDemo == true )
+    {
+        return 0;
+    }
+
+    Radio.ProcessIrqs( );
+
+    if( DemoRunning == false )
+    {
+        DemoRunning = true;
+        InitializeDemoParameters( Eeprom.EepromData.DemoSettings.ModulationType );
+        Radio.SetTxParams( Eeprom.EepromData.DemoSettings.TxPower, RADIO_RAMP_3400_US );
+        TX_LED = 0;
+        RX_LED = 0;
+        IrqMask = IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT;
+        Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+        for( i = 0; i < localPayloadSize; i++ )
+        {
+            Buffer[i] = ( uint8_t )rand( );
+        }
+        Radio.SendPayload( Buffer, localPayloadSize, 0xFFFFFF );
+        DemoInternalState = APP_IDLE;
+    }
+    else
+    {
+        switch( DemoInternalState )
+        {
+            case APP_RX:
+                break;
+
+            case APP_TX:
+                DemoInternalState = APP_IDLE;
+                LedBlink( );
+                // Send the next frame
+                IrqMask = IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT;
+                Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+
+                Radio.SendPayload( Buffer, localPayloadSize, 0xFFFFFF );
+                // we prepare next payload during transmission
+                for( i = 0; i < localPayloadSize; i++ )
+                {
+                    Buffer[i] = ( uint8_t )rand( );
+                }
+                break;
+
+            case APP_RX_TIMEOUT:
+                DemoInternalState = APP_IDLE;
+                break;
+
+            case APP_RX_ERROR:
+                DemoInternalState = APP_IDLE;
+                break;
+
+            case APP_TX_TIMEOUT:
+                DemoInternalState = APP_IDLE; 
+                break;
+
+            case APP_IDLE:
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    return 0;
+}
+
+uint8_t RunDemoRxContinuous( void )
+{
+    uint8_t refreshDisplay = 0;
+
+    if( Eeprom.EepromData.DemoSettings.HoldDemo == true )
+    {
+        return 0;
+    }
+
+    if( DemoRunning == false )
+    {
+        DemoRunning = true;
+
+        printf( "Start RunDemoRxContinuous\n\r" );
+
+        TX_LED = 0;
+        RX_LED = 0;
+
+        Eeprom.EepromData.DemoSettings.CntPacketTx    = 0;
+        Eeprom.EepromData.DemoSettings.CntPacketRxOK  = 0;
+        Eeprom.EepromData.DemoSettings.CntPacketRxKO  = 0;
+
+        InitializeDemoParameters( Eeprom.EepromData.DemoSettings.ModulationType );
+
+        // set preamble to max size to avoid filtering of the receiver on preamble lenght
+        if( Eeprom.EepromData.DemoSettings.ModulationType == PACKET_TYPE_LORA )
+        {
+            PacketParams.Params.LoRa.PreambleLength      = 0xFFFF;
+            PacketParams.Params.LoRa.HeaderType          = ( RadioLoRaPacketLengthsMode_t )Eeprom.EepromData.DemoSettings.PacketParam2;
+            PacketParams.Params.LoRa.PayloadLength       =                                 Eeprom.EepromData.DemoSettings.PacketParam3;
+            PacketParams.Params.LoRa.CrcMode             = ( RadioLoRaCrcModes_t )         Eeprom.EepromData.DemoSettings.PacketParam4;
+            PacketParams.Params.LoRa.InvertIQ            = ( RadioLoRaIQModes_t )          Eeprom.EepromData.DemoSettings.PacketParam5;
+            Radio.SetPacketParams( &PacketParams );
+        }
+
+        IrqMask = IRQ_RX_DONE | IRQ_CRC_ERROR | IRQ_RX_TX_TIMEOUT;
+        Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+        // Rx Continuous
+        if( Eeprom.EepromData.DemoSettings.BoostedRx == false )
+        {
+            Radio.SetRx( 0xFFFFFF );
+        }
+        else
+        {
+            Radio.SetRxBoosted( 0xFFFFFF );
+        }
+        DemoInternalState = APP_IDLE;
+
+    }
+
+    if( Eeprom.EepromData.DemoSettings.MaxNumPacket > 0 ) // != Infinite
+    {
+        if( ( Eeprom.EepromData.DemoSettings.CntPacketRxOK + \
+              Eeprom.EepromData.DemoSettings.CntPacketRxKO ) >= \
+            Eeprom.EepromData.DemoSettings.MaxNumPacket )
+        {
+            RX_LED = 0;
+            TX_LED = 0;
+            DemoInternalState = APP_IDLE;
+            Radio.SetStandby( STDBY_RC );
+            SendNextPacket.detach( );
+            Eeprom.EepromData.DemoSettings.HoldDemo = true;
+            refreshDisplay = 1;
+        }
+    }
+
+    Radio.ProcessIrqs( );
+
+    switch( DemoInternalState )
+    {
+        case APP_TX:
+            break;
+
+        case APP_RX:
+            RX_LED = !RX_LED;
+            Radio.GetPayload( Buffer, &BufferSize, BUFFER_SIZE );
+            Radio.GetPacketStatus( &PacketStatus );
+            if( Eeprom.EepromData.DemoSettings.ModulationType == PACKET_TYPE_LORA )
+            {
+                Eeprom.EepromData.DemoSettings.RssiValue    = PacketStatus.Params.LoRa.RssiPkt;
+                Eeprom.EepromData.DemoSettings.SnrValue     = PacketStatus.Params.LoRa.SnrPkt;
+                if( ( PacketStatus.Params.LoRa.FreqError & 0x00080000 ) == 0x00080000 )
+                {
+                    PacketStatus.Params.LoRa.FreqError = 0xFFFFF - PacketStatus.Params.LoRa.FreqError;
+                }
+                Eeprom.EepromData.DemoSettings.FreqErrorEst = ( double )PacketStatus.Params.LoRa.FreqError * FreErrorLsb;
+            }
+            else // Eeprom.EepromData.DemoSettings.ModulationType == PACKET_TYPE_GFSK
+            {
+                Eeprom.EepromData.DemoSettings.RssiValue = PacketStatus.Params.Gfsk.RssiAvg;
+                Eeprom.EepromData.DemoSettings.SnrValue = 0;
+            }
+
+            DemoInternalState = APP_IDLE;
+            Eeprom.EepromData.DemoSettings.CntPacketRxOK ++;
+            refreshDisplay = 1;
+            break;
+
+        case APP_RX_ERROR:
+        case APP_RX_TIMEOUT:
+            Eeprom.EepromData.DemoSettings.CntPacketRxKO ++;
+            DemoInternalState = PER_RX_START;
+            refreshDisplay = 1;
+            break;
+
+        case APP_TX_TIMEOUT:
+            break;
+
+        case APP_IDLE:
+            break;
+
+        default:
+            break;
+    }
+    return refreshDisplay;
+}
+
+// *************************       PER Demo       ******************************
+// *                                                                           *
+// *                                                                           *
+// *                                                                           *
+// *****************************************************************************
+uint8_t RunDemoApplicationPer( void )
+{
+    uint8_t i = 0;
+    uint8_t refreshDisplay = 0;
+
+    if( Eeprom.EepromData.DemoSettings.HoldDemo == true )
+    {
+        return 0;
+    }
+
+    if( DemoRunning == false )
+    {
+        DemoRunning = true;
+
+        printf( "Start RunDemoApplicationPer\n\r" );
+
+        TX_LED = 0;
+        RX_LED = 0;
+
+        Eeprom.EepromData.DemoSettings.CntPacketTx    = 0;
+        Eeprom.EepromData.DemoSettings.CntPacketRxOK  = 0;
+        Eeprom.EepromData.DemoSettings.CntPacketRxKO  = 0;
+        Eeprom.EepromData.DemoSettings.RxTimeOutCount = 0;
+
+        InitializeDemoParameters( Eeprom.EepromData.DemoSettings.ModulationType );
+
+        Eeprom.EepromData.DemoSettings.InterPacketDelay = GetTimeOnAir( Eeprom.EepromData.DemoSettings.ModulationType ) + RX_TX_TRANSITION_WAIT;
+
+        if( Eeprom.EepromData.DemoSettings.Entity == MASTER )
+        {
+            SendNextPacket.attach_us( &SendNextPacketEvent, ( uint32_t )( ( Eeprom.EepromData.DemoSettings.InterPacketDelay + RX_TIMEOUT_MARGIN ) * 1000 ) );
+            DemoInternalState = APP_TX;
+        }
+        else
+        {
+            IrqMask = /*0xFFFF; IRQ_HEADER_VALID |*/ IRQ_RX_DONE | IRQ_CRC_ERROR | IRQ_RX_TX_TIMEOUT;
+            Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+            // Rx Single without timeout for the start
+            if( Eeprom.EepromData.DemoSettings.BoostedRx == false )
+            {
+                Radio.SetRx( 0x0000 );
+            }
+            else
+            {
+                Radio.SetRxBoosted( 0x0000 );
+            }
+            DemoInternalState = APP_IDLE;
+        }
+    }
+
+    Radio.ProcessIrqs( );
+
+    if( Eeprom.EepromData.DemoSettings.MaxNumPacket > 0 ) // != Infinite
+    {
+        if( ( Eeprom.EepromData.DemoSettings.CntPacketRxOK + \
+              Eeprom.EepromData.DemoSettings.CntPacketRxKO + \
+              Eeprom.EepromData.DemoSettings.RxTimeOutCount) >= \
+            Eeprom.EepromData.DemoSettings.MaxNumPacket )
+        {
+            RX_LED = 0;
+            TX_LED = 0;
+            DemoInternalState = APP_IDLE;
+            Radio.SetStandby( STDBY_RC );
+            SendNextPacket.detach( );
+            Eeprom.EepromData.DemoSettings.HoldDemo = true;
+            refreshDisplay = 1;
+        }
+    }
+
+    switch( DemoInternalState )
+    {
+        case PER_TX_START:
+            Eeprom.EepromData.DemoSettings.CntPacketTx++;
+            DemoInternalState = APP_IDLE;
+
+            Buffer[0] = 0x00;
+            Buffer[1] = ( Eeprom.EepromData.DemoSettings.CntPacketTx >> 24 ) & 0xFF;
+            Buffer[2] = ( Eeprom.EepromData.DemoSettings.CntPacketTx >> 16 ) & 0xFF;
+            Buffer[3] = ( Eeprom.EepromData.DemoSettings.CntPacketTx >> 8 )  & 0xFF;
+            Buffer[4] = Eeprom.EepromData.DemoSettings.CntPacketTx & 0xFF;
+            Buffer[5] = PerMsg[0];
+            Buffer[6] = PerMsg[1];
+            Buffer[7] = PerMsg[2];
+            for( i = 8; i < Eeprom.EepromData.DemoSettings.PayloadLength; i++ )
+            {
+                Buffer[i] = i;
+            }
+            TX_LED = !TX_LED;
+            IrqMask = 0xFFFF; //IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT;
+            Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+            Radio.SendPayload( Buffer, Eeprom.EepromData.DemoSettings.PayloadLength, ( Eeprom.EepromData.DemoSettings.InterPacketDelay ) << 6 );
+            break;
+
+        case PER_RX_START:
+            IrqMask = /*0xFFFF;*/ IRQ_RX_DONE | IRQ_CRC_ERROR | IRQ_RX_TX_TIMEOUT;
+            Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+            if( Eeprom.EepromData.DemoSettings.BoostedRx == false )
+            {
+                Radio.SetRx( ( Eeprom.EepromData.DemoSettings.InterPacketDelay + RX_TIMEOUT_MARGIN ) << 6 );
+            }
+            else
+            {
+                Radio.SetRxBoosted( ( Eeprom.EepromData.DemoSettings.InterPacketDelay + RX_TIMEOUT_MARGIN ) << 6 );
+            }
+            DemoInternalState = APP_IDLE;
+            break;
+
+        case APP_TX:
+            if( SendNext == true )
+            {
+                SendNext = false;
+                if( Eeprom.EepromData.DemoSettings.MaxNumPacket == 0 )
+                {
+                    DemoInternalState = PER_TX_START;  // Infinite -> send next
+                    refreshDisplay = 1;
+                }
+                else if( Eeprom.EepromData.DemoSettings.CntPacketTx < \
+                         Eeprom.EepromData.DemoSettings.MaxNumPacket )
+                {
+                    DemoInternalState = PER_TX_START;  // MaxNumPacket not sent
+                    refreshDisplay = 1;
+                }
+                else    // MaxNumPacket sent -> end of demo
+                {
+                    RX_LED = 0;
+                    TX_LED = 0;
+                    DemoInternalState = APP_IDLE;
+                    Radio.SetStandby( STDBY_RC );
+                    SendNextPacket.detach( );
+                    Eeprom.EepromData.DemoSettings.HoldDemo = true;
+                    refreshDisplay = 1;
+                }
+            }
+            break;
+
+        case APP_RX:
+            RX_LED = !RX_LED;
+            Radio.GetPayload( Buffer, &BufferSize, BUFFER_SIZE );
+            Radio.GetPacketStatus( &PacketStatus );
+            if( Eeprom.EepromData.DemoSettings.ModulationType == PACKET_TYPE_LORA )
+            {
+                Eeprom.EepromData.DemoSettings.RssiValue    = PacketStatus.Params.LoRa.RssiPkt;
+                Eeprom.EepromData.DemoSettings.SnrValue     = PacketStatus.Params.LoRa.SnrPkt;
+                if( ( PacketStatus.Params.LoRa.FreqError & 0x00080000 ) == 0x00080000 )
+                {
+                    PacketStatus.Params.LoRa.FreqError = 0xFFFFF - PacketStatus.Params.LoRa.FreqError;
+                }
+                Eeprom.EepromData.DemoSettings.FreqErrorEst = ( double )PacketStatus.Params.LoRa.FreqError * FreErrorLsb;
+            }
+            else // Eeprom.EepromData.DemoSettings.ModulationType == PACKET_TYPE_GFSK
+            {
+                Eeprom.EepromData.DemoSettings.RssiValue = PacketStatus.Params.Gfsk.RssiAvg;
+                Eeprom.EepromData.DemoSettings.SnrValue = 0;
+                if( ( PacketStatus.Params.Gfsk.FreqError & 0x00000800 ) == 0x00000800 )
+                {
+                    PacketStatus.Params.Gfsk.FreqError = 0x00000FFF - PacketStatus.Params.Gfsk.FreqError;
+                }
+                PacketStatus.Params.LoRa.FreqError = PacketStatus.Params.LoRa.FreqError / 2048;
+                Eeprom.EepromData.DemoSettings.FreqErrorEst = ( ( double )PacketStatus.Params.Gfsk.FreqError / 2048.0 );
+            }
+
+            DemoInternalState = PER_RX_START;
+            if( ( BufferSize >= PER_SIZE ) && ( strncmp( ( const char* )( Buffer + 5 ), ( const char* )PerMsg, PER_SIZE ) == 0 ) )
+            {
+                ComputePerPayload( Buffer, BufferSize );
+                refreshDisplay = 1;
+            }
+            else
+            {
+                Eeprom.EepromData.DemoSettings.RxTimeOutCount++;
+            }
+            break;
+
+        case APP_RX_ERROR:
+        case APP_RX_TIMEOUT:
+            Eeprom.EepromData.DemoSettings.RxTimeOutCount++;
+            DemoInternalState = PER_RX_START;
+            refreshDisplay = 1;
+            break;
+
+        case APP_TX_TIMEOUT:
+            printf( "Failure: timeout in Tx is shorter than the packet time on air\n\r" );
+            DemoInternalState = APP_IDLE;
+            Eeprom.EepromData.DemoSettings.HoldDemo = true;
+            refreshDisplay = 1;
+            break;
+
+        case APP_IDLE: // do nothing
+            /*
+            val = Radio.GetSysErrors( );
+            if( val.Value != 0x0000 )
+            {
+                printf(" Dev Error = 0x%04x \n\r", val.Value );
+            }
+            */
+            break;
+
+        default:
+            break;
+    }
+    return refreshDisplay;
+}
+
+void ComputePerPayload( uint8_t *buffer, uint8_t bufferSize )
+{
+    uint32_t i = 0;
+
+    Eeprom.EepromData.DemoSettings.CntPacketRxOK++;
+    PacketRxSequence = ( ( uint32_t )buffer[1] << 24 ) | \
+                       ( ( uint32_t )buffer[2] << 16 ) | \
+                       ( ( uint32_t )buffer[3] << 8 )  | \
+                                     buffer[4];
+
+    if( ( PacketRxSequence <= PacketRxSequencePrev ) || \
+        ( PacketRxSequencePrev == 0xFFFFFFFF ) )
+    {
+        // Sequence went back => resynchronization
+        // Don't count missed packets this time
+        i = 0;
+    }
+    else
+    {
+        // Determine number of missed packets
+        i = PacketRxSequence - PacketRxSequencePrev - 1;
+    }
+    // Be ready for the next
+    PacketRxSequencePrev = PacketRxSequence;
+    // increment 'missed' counter for the RX session
+    Eeprom.EepromData.DemoSettings.CntPacketRxKO += i;
+    Eeprom.EepromData.DemoSettings.RxTimeOutCount = 0;
+}
+
+// ************************     Ping Pong Demo     *****************************
+// *                                                                           *
+// *                                                                           *
+// *                                                                           *
+// *****************************************************************************
+uint8_t RunDemoApplicationPingPong( void )
+{
+    uint8_t i = 0;
+    uint8_t refreshDisplay = 0;
+
+    if( Eeprom.EepromData.DemoSettings.HoldDemo == true )
+    {
+        return 0;   // quit without refresh display
+    }
+
+    if( DemoRunning == false )
+    {
+        DemoRunning = true;
+        TX_LED = 0;
+        RX_LED = 0;
+        Eeprom.EepromData.DemoSettings.CntPacketTx        = 0;
+        Eeprom.EepromData.DemoSettings.CntPacketRxOK      = 0;
+        Eeprom.EepromData.DemoSettings.CntPacketRxOKSlave = 0;
+        Eeprom.EepromData.DemoSettings.CntPacketRxKO      = 0;
+        Eeprom.EepromData.DemoSettings.CntPacketRxKOSlave = 0;
+        Eeprom.EepromData.DemoSettings.RxTimeOutCount     = 0;
+
+        InitializeDemoParameters( Eeprom.EepromData.DemoSettings.ModulationType );
+
+        Eeprom.EepromData.DemoSettings.InterPacketDelay = GetTimeOnAir( Eeprom.EepromData.DemoSettings.ModulationType ) + RX_TX_TRANSITION_WAIT;
+
+        printf( "Start RunDemoApplicationPingPong.\n\r" );
+
+        if( Eeprom.EepromData.DemoSettings.Entity == MASTER )
+        {
+            DemoInternalState = SEND_PING_MSG;
+            uint32_t temp = ( Eeprom.EepromData.DemoSettings.InterPacketDelay << 1 ) + RX_TIMEOUT_MARGIN;
+            float val = ( float )temp / ( float )( 1000.0 );
+            SendNextPacket.attach( &SendNextPacketEvent, val );
+        }
+        else
+        {
+            IrqMask = IRQ_RX_DONE | IRQ_CRC_ERROR | IRQ_RX_TX_TIMEOUT;
+            Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+            // Rx Single without timeout for the start
+            RX_LED = !RX_LED;
+            
+            if( Eeprom.EepromData.DemoSettings.BoostedRx == false )
+            {
+                Radio.SetRx( 0x0000 );
+            }
+            else
+            {
+                Radio.SetRxBoosted( 0x0000 );
+            }
+            DemoInternalState = APP_IDLE;
+        }
+    }
+
+    Radio.ProcessIrqs( );
+
+    if( Eeprom.EepromData.DemoSettings.Entity == MASTER )
+    {
+        switch( DemoInternalState )
+        {
+            case SEND_PING_MSG:
+                if( ( Eeprom.EepromData.DemoSettings.MaxNumPacket != 0 ) \
+                    && ( Eeprom.EepromData.DemoSettings.CntPacketTx >= Eeprom.EepromData.DemoSettings.MaxNumPacket ) )
+                {
+                    SendNextPacket.detach( );
+                    SendNext = false;
+                    RX_LED = 0;
+                    TX_LED = 0;
+                    DemoInternalState = APP_IDLE;
+                    Radio.SetStandby( STDBY_RC );
+                    Eeprom.EepromData.DemoSettings.HoldDemo = true;
+                    refreshDisplay = 1;
+                }
+                else
+                {
+                    if( SendNext == true )
+                    {
+                        SendNext = false;
+                        Radio.SetStandby( STDBY_RC );
+                        DemoInternalState = APP_IDLE;
+                        Eeprom.EepromData.DemoSettings.CntPacketTx++;
+                        // Send the next PING frame
+                        Buffer[0] = ( Eeprom.EepromData.DemoSettings.CntPacketTx >> 24 ) & 0xFF;
+                        Buffer[1] = ( Eeprom.EepromData.DemoSettings.CntPacketTx >> 16 ) & 0xFF;
+                        Buffer[2] = ( Eeprom.EepromData.DemoSettings.CntPacketTx >> 8 )  & 0xFF;
+                        Buffer[3] = ( Eeprom.EepromData.DemoSettings.CntPacketTx & 0xFF );
+                        Buffer[4] = PingMsg[0];
+                        Buffer[5] = PingMsg[1];
+                        Buffer[6] = PingMsg[2];
+                        Buffer[7] = PingMsg[3];
+                        for( i = 8; i < Eeprom.EepromData.DemoSettings.PayloadLength; i++ )
+                        {
+                            Buffer[i] = i;
+                        }
+                        TX_LED = !TX_LED;
+                        IrqMask = IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT;
+                        Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+                        Radio.SendPayload( Buffer, Eeprom.EepromData.DemoSettings.PayloadLength, \
+                                           Eeprom.EepromData.DemoSettings.InterPacketDelay << 6 );
+                    }
+                }
+                break;
+
+            case APP_TX:
+                DemoInternalState = APP_IDLE;
+                TX_LED = !TX_LED;
+                RX_LED = !RX_LED;
+                IrqMask = IRQ_RX_DONE | IRQ_CRC_ERROR | IRQ_RX_TX_TIMEOUT;
+                Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+
+                if( Eeprom.EepromData.DemoSettings.BoostedRx == false )
+                {
+                    Radio.SetRx( ( ( Eeprom.EepromData.DemoSettings.InterPacketDelay << 1 ) + RX_TIMEOUT_MARGIN ) << 6 );
+                }
+                else
+                {
+                    Radio.SetRxBoosted( ( ( Eeprom.EepromData.DemoSettings.InterPacketDelay << 1 ) + RX_TIMEOUT_MARGIN ) << 6 );
+                }
+                break;
+
+            case APP_RX:
+                RX_LED = !RX_LED;
+                Radio.GetPayload( Buffer, &BufferSize, BUFFER_SIZE );
+                Radio.GetPacketStatus( &PacketStatus );
+                if( Eeprom.EepromData.ModulationParams.PacketType == PACKET_TYPE_LORA )
+                {
+                    Eeprom.EepromData.DemoSettings.RssiValue = PacketStatus.Params.LoRa.RssiPkt;
+                    Eeprom.EepromData.DemoSettings.SnrValue = PacketStatus.Params.LoRa.SnrPkt;
+                }
+                else // Eeprom.EepromData.ModulationParams.PacketType == PACKET_TYPE_GFSK
+                {
+                    Eeprom.EepromData.DemoSettings.RssiValue = PacketStatus.Params.Gfsk.RssiAvg;
+                    Eeprom.EepromData.DemoSettings.SnrValue = 0;
+                }
+
+                if( ( BufferSize >= PINGPONG_SIZE ) && ( strncmp( ( const char* )( Buffer + 8 ), ( const char* )PongMsg, PINGPONG_SIZE ) == 0 ) )
+                {
+                    ComputePingPongPayload( Buffer, BufferSize );
+                }
+                else
+                {
+                    Eeprom.EepromData.DemoSettings.CntPacketRxKO++;
+                }
+                DemoInternalState = SEND_PING_MSG;
+                refreshDisplay = 1;
+                break;
+
+            case APP_RX_TIMEOUT:
+            case APP_RX_ERROR:
+                RX_LED = !RX_LED;
+                Eeprom.EepromData.DemoSettings.CntPacketRxKO++;
+                DemoInternalState = SEND_PING_MSG;
+                refreshDisplay = 1;
+                break;
+
+            case APP_TX_TIMEOUT:
+                printf( "Failure: timeout in Tx is shorter than the packet time on air\n\r" );
+                DemoInternalState = APP_IDLE;
+                Eeprom.EepromData.DemoSettings.HoldDemo = true;
+                refreshDisplay = 1;
+                break;
+
+            case APP_IDLE: // do nothing
+                break;
+
+            default:
+                break;
+        }
+    }
+    else // SLAVE
+    {
+        switch( DemoInternalState )
+        {
+            case SEND_PONG_MSG:
+                wait_ms( RX_TX_TRANSITION_WAIT );
+
+                DemoInternalState = APP_IDLE;
+                // Send the next PING frame
+                Buffer[0]  = ( Eeprom.EepromData.DemoSettings.CntPacketTx >> 24 ) & 0xFF;
+                Buffer[1]  = ( Eeprom.EepromData.DemoSettings.CntPacketTx >> 16 ) & 0xFF;
+                Buffer[2]  = ( Eeprom.EepromData.DemoSettings.CntPacketTx >>  8 ) & 0xFF;
+                Buffer[3]  = ( Eeprom.EepromData.DemoSettings.CntPacketTx & 0xFF );
+                Buffer[4]  = ( ( Eeprom.EepromData.DemoSettings.CntPacketRxKO + \
+                                 Eeprom.EepromData.DemoSettings.RxTimeOutCount ) >> 24 ) & 0xFF;
+                Buffer[5]  = ( ( Eeprom.EepromData.DemoSettings.CntPacketRxKO + \
+                                 Eeprom.EepromData.DemoSettings.RxTimeOutCount ) >> 16 ) & 0xFF;
+                Buffer[6]  = ( ( Eeprom.EepromData.DemoSettings.CntPacketRxKO + \
+                                 Eeprom.EepromData.DemoSettings.RxTimeOutCount ) >> 8 ) & 0xFF;
+                Buffer[7]  = ( ( Eeprom.EepromData.DemoSettings.CntPacketRxKO + \
+                                 Eeprom.EepromData.DemoSettings.RxTimeOutCount ) & 0xFF );
+                Buffer[8]  = PongMsg[0];
+                Buffer[9]  = PongMsg[1];
+                Buffer[10] = PongMsg[2];
+                Buffer[11] = PongMsg[3];
+                for( i = 12; i < Eeprom.EepromData.DemoSettings.PayloadLength; i++ )
+                {
+                    Buffer[i] = i;
+                }
+                TX_LED = !TX_LED;
+                IrqMask = IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT;
+                Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+                Radio.SendPayload( Buffer, Eeprom.EepromData.DemoSettings.PayloadLength, \
+                                   ( Eeprom.EepromData.DemoSettings.InterPacketDelay ) << 6 );
+                break;
+
+            case APP_TX:
+                if( ( Eeprom.EepromData.DemoSettings.MaxNumPacket != 0 ) \
+                    && ( ( Eeprom.EepromData.DemoSettings.CntPacketRxOK + Eeprom.EepromData.DemoSettings.CntPacketRxKO + \
+                           Eeprom.EepromData.DemoSettings.RxTimeOutCount ) >= Eeprom.EepromData.DemoSettings.MaxNumPacket ) )
+                {
+                    SendNextPacket.detach( ); 
+                    SendNext = false;
+                    RX_LED = 0;
+                    TX_LED = 0;
+                    DemoInternalState = APP_IDLE;
+                    Radio.SetStandby( STDBY_RC );
+                    Eeprom.EepromData.DemoSettings.HoldDemo = true;
+                    refreshDisplay = 1;
+                }
+                else
+                {
+                    DemoInternalState = APP_IDLE;
+                    TX_LED = !TX_LED;
+                    RX_LED = !RX_LED;
+                    IrqMask = IRQ_RX_DONE | IRQ_CRC_ERROR | IRQ_RX_TX_TIMEOUT;
+                    Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+                    if( Eeprom.EepromData.DemoSettings.BoostedRx == false )
+                    {
+                        Radio.SetRx( ( ( Eeprom.EepromData.DemoSettings.InterPacketDelay << 1 ) + RX_TIMEOUT_MARGIN ) << 6 );
+                    }
+                    else
+                    {
+                        Radio.SetRxBoosted( ( ( Eeprom.EepromData.DemoSettings.InterPacketDelay << 1 ) + RX_TIMEOUT_MARGIN) << 6 );
+                    }
+                    refreshDisplay = 1;
+                }
+                break;
+
+            case APP_RX:
+                DemoInternalState = APP_IDLE;
+                RX_LED = !RX_LED;
+                Radio.GetPayload( Buffer, &BufferSize, BUFFER_SIZE );
+                Radio.GetPacketStatus( &PacketStatus );
+                if( Eeprom.EepromData.ModulationParams.PacketType == PACKET_TYPE_LORA )
+                {
+                    Eeprom.EepromData.DemoSettings.RssiValue = PacketStatus.Params.LoRa.RssiPkt;
+                    Eeprom.EepromData.DemoSettings.SnrValue = PacketStatus.Params.LoRa.SnrPkt;
+                }
+                else // Eeprom.EepromData.ModulationParams.PacketType == PACKET_TYPE_GFSK
+                {
+                    Eeprom.EepromData.DemoSettings.RssiValue = PacketStatus.Params.Gfsk.RssiAvg;
+                    Eeprom.EepromData.DemoSettings.SnrValue = 0;
+                }
+
+                if( ( BufferSize >= PINGPONG_SIZE ) && ( strncmp( ( const char* )( Buffer + 4 ), ( const char* )PingMsg, PINGPONG_SIZE ) == 0 ) )
+                {
+                    ComputePingPongPayload( Buffer, BufferSize );
+                    DemoInternalState = SEND_PONG_MSG;
+                }
+                else
+                {
+                    Eeprom.EepromData.DemoSettings.CntPacketRxKO++;
+                    RX_LED = !RX_LED;
+                    IrqMask = IRQ_RX_DONE | IRQ_CRC_ERROR | IRQ_RX_TX_TIMEOUT;
+                    Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+                    if( Eeprom.EepromData.DemoSettings.BoostedRx == false )
+                    {
+                        Radio.SetRx( ( Eeprom.EepromData.DemoSettings.InterPacketDelay ) << 6 );
+                    }
+                    else
+                    {
+                        Radio.SetRxBoosted( ( Eeprom.EepromData.DemoSettings.InterPacketDelay ) << 6 );
+                    }
+                    refreshDisplay = 1;
+                }
+                break;
+
+            case APP_RX_TIMEOUT:
+            case APP_RX_ERROR:
+                DemoInternalState = APP_IDLE;
+                Eeprom.EepromData.DemoSettings.RxTimeOutCount++;
+                IrqMask = IRQ_RX_DONE | IRQ_CRC_ERROR | IRQ_RX_TX_TIMEOUT;
+                Radio.SetDioIrqParams( IrqMask, IrqMask, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
+                if( Eeprom.EepromData.DemoSettings.BoostedRx == false )
+                {
+                    Radio.SetRx( ( Eeprom.EepromData.DemoSettings.InterPacketDelay ) << 6 );
+                }
+                else
+                {
+                    Radio.SetRxBoosted( ( Eeprom.EepromData.DemoSettings.InterPacketDelay ) << 6 );
+                }
+                refreshDisplay = 1;
+                break;
+
+            case APP_TX_TIMEOUT:
+                printf( "Failure: timeout in Tx is shorter than the packet time on air\n\r" );
+                DemoInternalState = APP_IDLE;
+                Eeprom.EepromData.DemoSettings.HoldDemo = true;
+                refreshDisplay = 1;
+                break;
+
+            case APP_IDLE: // do nothing
+                break;
+
+            default:
+                break;
+        }
+    }
+    return refreshDisplay;
+}
+
+void ComputePingPongPayload( uint8_t *buffer, uint8_t bufferSize )
+{
+    uint32_t i = 0;
+
+    PacketRxSequence = ( ( uint32_t )buffer[0] << 24 ) | \
+                       ( ( uint32_t )buffer[1] << 16 ) | \
+                       ( ( uint32_t )buffer[2] << 8 )  | \
+                                     buffer[3];
+
+    if( Eeprom.EepromData.DemoSettings.Entity == MASTER )
+    {
+        Eeprom.EepromData.DemoSettings.CntPacketRxKOSlave = 
+                       ( ( uint32_t )buffer[4] << 24 ) | \
+                       ( ( uint32_t )buffer[5] << 16 ) | \
+                       ( ( uint32_t )buffer[6] << 8 )  | \
+                                     buffer[7];
+        if( PacketRxSequence > Eeprom.EepromData.DemoSettings.CntPacketRxKOSlave )
+        {
+            Eeprom.EepromData.DemoSettings.CntPacketRxOKSlave = PacketRxSequence - \
+                Eeprom.EepromData.DemoSettings.CntPacketRxKOSlave;
+        }
+        else
+        {
+            Eeprom.EepromData.DemoSettings.CntPacketRxOKSlave = 0;
+        }
+        
+        if( PacketRxSequence == Eeprom.EepromData.DemoSettings.CntPacketTx )
+        {
+            Eeprom.EepromData.DemoSettings.CntPacketRxOK += 1;
+        }
+        else
+        {
+            Eeprom.EepromData.DemoSettings.CntPacketRxKO += 1;
+        }
+    }
+    else
+    {
+        Eeprom.EepromData.DemoSettings.CntPacketRxOK += 1;
+        if( ( PacketRxSequence <= PacketRxSequencePrev ) || \
+            ( PacketRxSequencePrev == 0 ) )
+        {
+            // Sequence went back => resynchronization
+            // Don't count missed packets this time
+            i = 0;
+        }
+        else
+        {
+            // Determine number of missed packets
+            i = PacketRxSequence - PacketRxSequencePrev - 1;
+        }
+        // Be ready for the next
+        PacketRxSequencePrev = PacketRxSequence;
+        Eeprom.EepromData.DemoSettings.CntPacketTx = PacketRxSequence;
+        // increment 'missed' counter for the RX session
+        Eeprom.EepromData.DemoSettings.CntPacketRxKO += i;
+        Eeprom.EepromData.DemoSettings.RxTimeOutCount = 0;
+    }
+}
+
+// ************************        Utils            ****************************
+// *                                                                           *
+// *                                                                           *
+// *                                                                           *
+// *****************************************************************************
+
+uint8_t GetConnectedDevice( void )
+{
+    return( Radio.GetDeviceType( ) );
+}
+
+void InitDemoApplication( void )
+{
+    RX_LED = 1;
+    TX_LED = 1;
+
+    Radio.Init( );
+
+    // Can also be set in LDO mode but consume more power
+    Radio.SetRegulatorMode( ( RadioRegulatorMode_t )Eeprom.EepromData.DemoSettings.RadioPowerMode );
+    Radio.SetStandby( STDBY_RC );
+
+    memset( &Buffer, 0x00, BufferSize );
+    
+    RX_LED = 0;
+    TX_LED = 0;
+
+    PacketRxSequence = 0;
+    PacketRxSequencePrev = 0;
+    Eeprom.EepromData.DemoSettings.CntPacketTx    = 0;
+    Eeprom.EepromData.DemoSettings.CntPacketRxOK  = 0;
+    Eeprom.EepromData.DemoSettings.CntPacketRxKO  = 0;
+    Eeprom.EepromData.DemoSettings.RxTimeOutCount = 0;
+}
+
+void StopDemoApplication( void )
+{
+    if( DemoRunning == true )
+    {
+        Radio.CheckDeviceReady( );
+
+        RX_LED = 0;
+        TX_LED = 0;
+        DemoRunning = false;
+        SendNext = false;
+        PacketRxSequence = 0;
+        PacketRxSequencePrev = 0;
+        Eeprom.EepromData.DemoSettings.CntPacketTx    = 0;
+        Eeprom.EepromData.DemoSettings.CntPacketRxOK  = 0;
+        Eeprom.EepromData.DemoSettings.CntPacketRxKO  = 0;
+        Eeprom.EepromData.DemoSettings.RxTimeOutCount = 0;
+        
+        DemoInternalState = APP_IDLE;
+        Radio.SetStandby( STDBY_RC );
+        Radio.ClearIrqStatus( IRQ_RADIO_ALL );
+        SendNextPacket.detach( ); 
+    }
+}
+
+/*
+ * Function still being implemented >>> To be completed 
+ * WARNING: Computation is in float and his really slow
+ * LongInterLeaving vs LegacyInterLeaving has no influence on TimeOnAir.
+ */
+uint16_t GetTimeOnAir( uint8_t modulation )
+{
+    uint16_t result = 2000;
+    uint8_t LowDatarateOptimize = 0;
+
+    if( modulation == PACKET_TYPE_LORA )
+    {
+        volatile double loraBw = 0.0;
+        volatile double FreqErrorUnits = 0.0;
+        
+        switch( Eeprom.EepromData.ModulationParams.Params.LoRa.Bandwidth )
+        {
+            case LORA_BW_500:
+                loraBw = 500e3;
+                break;
+
+            case LORA_BW_250:
+                loraBw = 250e3;
+                break;
+
+            case LORA_BW_125:
+                loraBw = 125e3;
+                break;
+
+            case LORA_BW_062:
+                loraBw = 62e3;
+                break;
+
+            case LORA_BW_041:
+                loraBw = 41e3;
+                break;
+
+            case LORA_BW_031:
+                loraBw = 31e3;
+                break;
+
+            case LORA_BW_020:
+                loraBw = 20e3;
+                break;
+
+            case LORA_BW_015:
+                loraBw = 15e3;
+                break;
+
+            case LORA_BW_010:
+                loraBw = 10e3;
+                break;
+
+            case LORA_BW_007:
+                loraBw = 7e3;
+                break;
+
+            default:
+                loraBw = 7e3;
+                break;
+        }
+
+        /* Used to compute the freq Error */
+        FreqErrorUnits = FREQ_ERR;
+        FreErrorLsb = FreqErrorUnits * ( ( double )loraBw / 1000 ) / 500;
+
+        float ts = 1 << Eeprom.EepromData.ModulationParams.Params.LoRa.SpreadingFactor; // time for one symbol in ms
+              ts = (float)ts / (float)loraBw;
+              ts = ts * 1000; // from seconds to miliseconds
+
+        float tPreamble = ( Eeprom.EepromData.PacketParams.Params.LoRa.PreambleLength + 4.25 + ( ( Eeprom.EepromData.ModulationParams.Params.LoRa.SpreadingFactor > 6 ) ? 2 : 0 )) * ts; // time of preamble
+
+        switch( Eeprom.EepromData.ModulationParams.Params.LoRa.Bandwidth )
+        {
+            case LORA_BW_500:
+                break;
+
+            case LORA_BW_250:
+                if( Eeprom.EepromData.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF12 )
+                {
+                    LowDatarateOptimize = 1;
+                }
+                break;
+
+            case LORA_BW_125:
+                if( Eeprom.EepromData.ModulationParams.Params.LoRa.SpreadingFactor >= LORA_SF11 )
+                {
+                    LowDatarateOptimize = 1;
+                }
+                break;
+
+            case LORA_BW_062:
+                if( Eeprom.EepromData.ModulationParams.Params.LoRa.SpreadingFactor >= LORA_SF10 )
+                {
+                    LowDatarateOptimize = 1;
+                }
+                break;
+
+            case LORA_BW_041:
+            case LORA_BW_031:
+                if( Eeprom.EepromData.ModulationParams.Params.LoRa.SpreadingFactor >= LORA_SF9 )
+                {
+                    LowDatarateOptimize = 1;
+                }
+                break;
+
+            case LORA_BW_020:
+            case LORA_BW_015:
+                if( Eeprom.EepromData.ModulationParams.Params.LoRa.SpreadingFactor >= LORA_SF8 )
+                {
+                    LowDatarateOptimize = 1;
+                }
+                break;
+
+            case LORA_BW_010:
+            case LORA_BW_007:
+                if( Eeprom.EepromData.ModulationParams.Params.LoRa.SpreadingFactor >= LORA_SF7 )
+                {
+                    LowDatarateOptimize = 1;
+                }
+                break;
+        }
+
+        float nData = ceil( ( float )( ( 8 * Eeprom.EepromData.PacketParams.Params.LoRa.PayloadLength +                                           \
+                       16 * ( ( Eeprom.EepromData.PacketParams.Params.LoRa.CrcMode == LORA_CRC_OFF ) ? 0 : 1 ) +                \
+                       ( ( Eeprom.EepromData.PacketParams.Params.LoRa.HeaderType == LORA_PACKET_VARIABLE_LENGTH ) ? 20 : 0 ) -  \
+                       ( 4 * Eeprom.EepromData.ModulationParams.Params.LoRa.SpreadingFactor ) + 8 -                             \
+                       ( 8 *( ( Eeprom.EepromData.ModulationParams.Params.LoRa.SpreadingFactor > 6 ) ? 1 : 0 ) ) ) / 4 ) );
+
+               nData = ceil( ( float )nData / ( ( float )( Eeprom.EepromData.ModulationParams.Params.LoRa.SpreadingFactor - \
+                              ( LowDatarateOptimize * 2 ) ) ) * ( ( Eeprom.EepromData.ModulationParams.Params.LoRa.CodingRate % 4 ) + 4 ) );
+
+        float tPayload = nData * ts;
+
+        float tHeader = 8 * ts;
+        // Time on air [ms]
+        float ToA = ceil( tPreamble + tPayload + tHeader );
+
+        result = ( uint16_t )ToA + ( ( uint16_t )ToA >> 1 );   // Set some margin
+    }
+    else if( modulation == PACKET_TYPE_GFSK )
+    {
+        uint16_t packetBitCount = Eeprom.EepromData.PacketParams.Params.Gfsk.PreambleLength;
+
+        packetBitCount += ( Eeprom.EepromData.PacketParams.Params.Gfsk.SyncWordLength + 1 );
+        packetBitCount += Eeprom.EepromData.PacketParams.Params.Gfsk.PayloadLength + 3;
+        packetBitCount *= 8;
+        // 1500 = 1000 * 1.5 : 1000 for translate s in ms and 1.5 is some margin
+        result = ( uint16_t )( ceil( 1500 * ( float )packetBitCount / Eeprom.EepromData.ModulationParams.Params.Gfsk.BitRate ) );
+    }
+    return result;
+}
+
+void InitializeDemoParameters( uint8_t modulation )
+{
+    Radio.SetStandby( STDBY_RC );
+
+    Radio.SetRegulatorMode( ( RadioRegulatorMode_t )Eeprom.EepromData.DemoSettings.RadioPowerMode );
+
+    printf("> InitializeDemoParameters\n\r");
+    if( modulation == PACKET_TYPE_LORA )
+    {
+        printf("set param LORA for demo\n\r");
+        ModulationParams.PacketType = PACKET_TYPE_LORA;
+        PacketParams.PacketType     = PACKET_TYPE_LORA;
+
+        ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t ) Eeprom.EepromData.DemoSettings.ModulationParam1;
+        ModulationParams.Params.LoRa.Bandwidth       = ( RadioLoRaBandwidths_t )       Eeprom.EepromData.DemoSettings.ModulationParam2;
+        ModulationParams.Params.LoRa.CodingRate      = ( RadioLoRaCodingRates_t )      Eeprom.EepromData.DemoSettings.ModulationParam3;
+
+        PacketParams.Params.LoRa.PreambleLength      =                                 Eeprom.EepromData.DemoSettings.PacketParam1;
+        PacketParams.Params.LoRa.HeaderType          = ( RadioLoRaPacketLengthsMode_t )Eeprom.EepromData.DemoSettings.PacketParam2;
+        PacketParams.Params.LoRa.PayloadLength       =                                 Eeprom.EepromData.DemoSettings.PacketParam3;
+        PacketParams.Params.LoRa.CrcMode             = ( RadioLoRaCrcModes_t )         Eeprom.EepromData.DemoSettings.PacketParam4;
+        PacketParams.Params.LoRa.InvertIQ            = ( RadioLoRaIQModes_t )          Eeprom.EepromData.DemoSettings.PacketParam5;
+
+        Eeprom.EepromData.DemoSettings.PayloadLength = PacketParams.Params.LoRa.PayloadLength;
+    }
+    else// if( modulation == PACKET_TYPE_GFSK )
+    {
+        printf("set param GFSK for demo\n\r");
+        ModulationParams.PacketType = PACKET_TYPE_GFSK;
+        PacketParams.PacketType     = PACKET_TYPE_GFSK;
+
+        ModulationParams.Params.Gfsk.BitRate           =                             Eeprom.EepromData.DemoSettings.ModulationParam1;
+        ModulationParams.Params.Gfsk.Fdev              =                             Eeprom.EepromData.DemoSettings.ModulationParam2;
+        ModulationParams.Params.Gfsk.ModulationShaping = ( RadioModShapings_t )      Eeprom.EepromData.DemoSettings.ModulationParam3;
+        ModulationParams.Params.Gfsk.Bandwidth         = ( RadioRxBandwidth_t )      Eeprom.EepromData.DemoSettings.ModulationParam4;
+        PacketParams.Params.Gfsk.PreambleLength        =                             Eeprom.EepromData.DemoSettings.PacketParam1;
+        PacketParams.Params.Gfsk.PreambleMinDetect     = ( RadioPreambleDetection_t )Eeprom.EepromData.DemoSettings.PacketParam2;
+        PacketParams.Params.Gfsk.SyncWordLength        =                             Eeprom.EepromData.DemoSettings.PacketParam3;
+        PacketParams.Params.Gfsk.AddrComp              = ( RadioAddressComp_t )      Eeprom.EepromData.DemoSettings.PacketParam4;
+        PacketParams.Params.Gfsk.HeaderType            = ( RadioPacketLengthModes_t )Eeprom.EepromData.DemoSettings.PacketParam5;
+        PacketParams.Params.Gfsk.PayloadLength         =                             Eeprom.EepromData.DemoSettings.PacketParam6;
+
+        PacketParams.Params.Gfsk.CrcLength             = ( RadioCrcTypes_t )         Eeprom.EepromData.DemoSettings.PacketParam7;
+        PacketParams.Params.Gfsk.DcFree                = ( RadioDcFree_t )           Eeprom.EepromData.DemoSettings.PacketParam8;
+
+        Eeprom.EepromData.DemoSettings.PayloadLength = PacketParams.Params.Gfsk.PayloadLength;
+    }
+
+    Radio.SetStandby( STDBY_RC );
+    Radio.ClearIrqStatus( IRQ_RADIO_ALL );
+    Radio.SetPacketType( ModulationParams.PacketType );
+    Radio.SetModulationParams( &ModulationParams );
+    Radio.SetPacketParams( &PacketParams );
+
+    Radio.SetRfFrequency( Eeprom.EepromData.DemoSettings.Frequency );
+    Radio.SetBufferBaseAddresses( 0x00, 0x00 );
+    
+    
+    Radio.SetTxParams( Eeprom.EepromData.DemoSettings.TxPower, RADIO_RAMP_40_US );
+
+    // only used in GFSK
+    Radio.SetSyncWord( ( uint8_t[] ){ 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 } );
+    Radio.SetWhiteningSeed( 0x01FF );
+
+    RX_LED = 0;
+    TX_LED = 0;
+}
+
+/*!
+ * \brief Callback of ticker PerSendNextPacket
+ */
+void SendNextPacketEvent( void )
+{
+    SendNext = true;
+}
+
+void LedBlink( void )
+{
+    if( ( TX_LED == 0 ) && ( RX_LED == 0 ) )
+    {
+        TX_LED = 1;
+    }
+    else if( ( TX_LED == 1 ) && ( RX_LED == 0 ) )
+    {
+        RX_LED = 1;
+    }
+    else if( ( TX_LED == 1 ) && ( RX_LED == 1 ) )
+    {
+        TX_LED = 0;
+    }
+    else
+    {
+        RX_LED = 0;
+    }
+}
+
+// ************************     Radio Callbacks     ****************************
+// *                                                                           *
+// * These functions are called through function pointer by the Radio low      *
+// * level drivers                                                             *
+// *                                                                           *
+// *****************************************************************************
+void OnTxDone( void )
+{
+    DemoInternalState = APP_TX;
+}
+
+void OnRxDone( void )
+{
+    DemoInternalState = APP_RX;
+}
+
+void OnTxTimeout( void )
+{
+    DemoInternalState = APP_TX_TIMEOUT;
+}
+
+void OnRxTimeout( void )
+{
+    DemoInternalState = APP_RX_TIMEOUT;
+}
+
+void OnRxError( IrqErrorCode_t errorCode )
+{
+    DemoInternalState = APP_RX_ERROR;
+    
+    if( errorCode == IRQ_HEADER_ERROR_CODE )
+    {
+#ifdef ADV_DEBUG
+        printf( ">> IRQ_HEADER_ERROR_CODE\n\r" );
+#endif
+    }
+    else if( errorCode == IRQ_SYNCWORD_ERROR_CODE )
+    {
+#ifdef ADV_DEBUG
+        printf( ">> IRQ_SYNCWORD_ERROR_CODE\n\r" );
+#endif
+    }
+    else if( errorCode == IRQ_CRC_ERROR_CODE )
+    {
+#ifdef ADV_DEBUG
+        printf( ">> IRQ_CRC_ERROR_CODE\n\r" );
+#endif
+    }
+    else
+    {
+#ifdef ADV_DEBUG
+        printf( "unknown error\n\r" );
+#endif
+    }
+    Radio.GetPacketStatus( &PacketStatus );
+}
+
+void OnCadDone( bool channelActivityDetected )
+{
+    if( channelActivityDetected == true )
+    {
+        DemoInternalState = CAD_DONE_CHANNEL_DETECTED;
+    }
+    else
+    {
+        DemoInternalState = CAD_DONE;
+    }
+}