application layer with: button, LED, pot, tempSense

Dependencies:   mbed SX1272Lib

Fork of LoRaWAN-demo-72-bootcamp by Semtech

Use with sx1272 shield with grove peripherals connected:

D8 D9: ButtonRX TXA3 A4: TempSense
D6 D7:SCL SDA : LEDA1 A2: Pot

Button

Sends to different payloads: short press (under 1 sec)
long press: held down > 1 sec.

serial console keys

115200bps, 8N1
Enter key not used
Keys '0' to '3': cayenne channel number
'0': pot (rotary sensor)
'1': temperature
' 2': digital out
'3': analog out

Revision:
10:52810ecbd83b
Parent:
9:0083afd69815
Child:
11:018e7e28161d
--- a/app/main.cpp	Mon Apr 24 13:31:49 2017 +0000
+++ b/app/main.cpp	Tue Jan 30 22:49:12 2018 +0000
@@ -19,8 +19,6 @@
 #include "LoRaMac.h"
 #include "Commissioning.h"
 #include "SerialDisplay.h"
-#include "DigitDisplay.h"
-#include "ChainableLED.h"
 
 /*!
  * Defines the application data transmission duty cycle. 5s, value in [ms].
@@ -135,94 +133,21 @@
 static uint8_t IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
 
 /*!
- * Defines the application data transmission duty cycle
- */
-static uint32_t TxDutyCycleTime;
-
-/*!
- * Timer to handle the application data transmission duty cycle
- */
-static TimerEvent_t TxNextPacketTimer;
-
-/*!
- * Specifies the state of the application LED
- */
-static bool AppLedStateOn = false;
-volatile bool Led3StateChanged = false;
-/*!
- * Timer to handle the state of LED1
- */
-static TimerEvent_t Led1Timer;
-volatile bool Led1State = false;
-volatile bool Led1StateChanged = false;
-/*!
- * Timer to handle the state of LED2
- */
-static TimerEvent_t Led2Timer;
-volatile bool Led2State = false;
-volatile bool Led2StateChanged = false;
-
-/*!
- * Indicates if a new packet can be sent
- */
-static bool NextTx = true;
-
-/*!
- * Hold the value returned from the Light Sensor
- */
-static float LightValue = 0.0;
-
-/*!
- * Control the 3-color LED 
- * 0: automatic (LED goes brigther as the light decrease, 
- * 1: manual (The LED is controlled by the user)
- */
-static uint8_t LightMode = 0;  // 0: automatic, 1: manual
-
-/*!
- * Ticker to create a PWM for the buzzer
- */
-Ticker BuzzerTimer;
-
-
-/*!
- * Constructor for Buzzer
- */
-DigitalOut Buzzer( A3 );
-
-/*!
- * Constructor for the 3-color LED
- */
-#define NUM_LED 3
-ChainableLED ColorLed( D6, D7, NUM_LED );
-
-/*!
- * Constructor for Light Sensor
- */
-AnalogIn LightSens( A1 ); 
-
-/*!
- * Constructor for 4 Digit 7 semgent display
- */
-DigitDisplay Display( D8, D9 );
-
-/*!
  * Device states
  */
-static enum eDeviceState
-{
-    DEVICE_STATE_INIT,
+static enum eDeviceState {
+    DEVICE_STATE_INIT = 0,
     DEVICE_STATE_JOIN,
+    DEVICE_STATE_JOIN_OK,
     DEVICE_STATE_SEND,
-    DEVICE_STATE_CYCLE,
+    DEVICE_STATE_TRIGGER,
     DEVICE_STATE_SLEEP
-}DeviceState;
+} DeviceState;
 
 /*!
  * LoRaWAN compliance tests support data
  */
-struct ComplianceTest_s
-{
+struct ComplianceTest_s {
     bool Running;
     uint8_t State;
     bool IsTxConfirmed;
@@ -233,36 +158,28 @@
     bool LinkCheck;
     uint8_t DemodMargin;
     uint8_t NbGateways;
-}ComplianceTest;
+} ComplianceTest;
 
 /*
  * SerialDisplay managment variables
  */
 
 /*!
- * Indicates if the MAC layer network join status has changed.
- */
-static bool IsNetworkJoinedStatusUpdate = false;
-
-/*!
  * Strucure containing the Uplink status
  */
-struct sLoRaMacUplinkStatus
-{
+struct sLoRaMacUplinkStatus {
     uint8_t Acked;
     int8_t Datarate;
     uint16_t UplinkCounter;
     uint8_t Port;
     uint8_t *Buffer;
     uint8_t BufferSize;
-}LoRaMacUplinkStatus;
-volatile bool UplinkStatusUpdated = false;
+} LoRaMacUplinkStatus;
 
 /*!
  * Strucure containing the Downlink status
  */
-struct sLoRaMacDownlinkStatus
-{
+struct sLoRaMacDownlinkStatus {
     int16_t Rssi;
     int8_t Snr;
     uint16_t DownlinkCounter;
@@ -270,7 +187,7 @@
     uint8_t Port;
     uint8_t *Buffer;
     uint8_t BufferSize;
-}LoRaMacDownlinkStatus;
+} LoRaMacDownlinkStatus;
 volatile bool DownlinkStatusUpdated = false;
 
 void SerialDisplayRefresh( void )
@@ -301,16 +218,22 @@
     SerialDisplayUpdateDutyCycle( false );
 #endif
     SerialDisplayUpdatePublicNetwork( LORAWAN_PUBLIC_NETWORK );
-    
-    SerialDisplayUpdateLedState( 3, AppLedStateOn );
+
+    //SerialDisplayUpdateLedState( 3, AppLedStateOn );
 }
 
+uint8_t c_ch;
+
 void SerialRxProcess( void )
 {
-    if( SerialDisplayReadable( ) == true )
-    {
-        switch( SerialDisplayGetChar( ) )
-        {
+    if( SerialDisplayReadable( ) == true ) {
+        char ch = SerialDisplayGetChar();
+        if ( ch >= '0' || ch <= '9') {
+            c_ch = ch - '0';
+            DeviceState = DEVICE_STATE_SEND;
+            return;
+        }
+        switch( ch ) {
             case 'R':
             case 'r':
                 // Refresh Serial screen
@@ -322,66 +245,191 @@
     }
 }
 
+#define LPP_DIGITAL_INPUT       0       // 1 byte
+#define LPP_DIGITAL_OUTPUT      1       // 1 byte
+#define LPP_ANALOG_INPUT        2       // 2 bytes, 0.01 signed
+#define LPP_ANALOG_OUTPUT       3       // 2 bytes, 0.01 signed
+#define LPP_LUMINOSITY          101     // 2 bytes, 1 lux unsigned
+#define LPP_PRESENCE            102     // 1 byte, 1
+#define LPP_TEMPERATURE         103     // 2 bytes, 0.1°C signed
+#define LPP_RELATIVE_HUMIDITY   104     // 1 byte, 0.5% unsigned
+#define LPP_ACCELEROMETER       113     // 2 bytes per axis, 0.001G
+#define LPP_BAROMETRIC_PRESSURE 115     // 2 bytes 0.1 hPa Unsigned
+#define LPP_GYROMETER           134     // 2 bytes per axis, 0.01 °/s
+#define LPP_GPS                 136     // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01m
+
+
+// Data ID + Data Type + Data Size
+#define LPP_DIGITAL_INPUT_SIZE       3
+#define LPP_DIGITAL_OUTPUT_SIZE      3
+#define LPP_ANALOG_INPUT_SIZE        4
+#define LPP_ANALOG_OUTPUT_SIZE       4
+#define LPP_LUMINOSITY_SIZE          4
+#define LPP_PRESENCE_SIZE            3
+#define LPP_TEMPERATURE_SIZE         4
+#define LPP_RELATIVE_HUMIDITY_SIZE   3
+#define LPP_ACCELEROMETER_SIZE       8
+#define LPP_BAROMETRIC_PRESSURE_SIZE 4
+#define LPP_GYROMETER_SIZE           8
+#define LPP_GPS_SIZE                 11
+
+#define CAYENNE_CH_DOUT     2
+#define CAYENNE_CH_AOUT     3
+#define CAYENNE_CH_TEMP     0
+#define CAYENNE_CH_POT      1
+AnalogIn a1(A1);
+AnalogIn a2(A2);
+AnalogIn a3(A3);
+AnalogIn a4(A4);
+
+const unsigned R0 = 100000;
+const unsigned B = 4275;
+
+volatile TimerTime_t buttonStartAt;
+DigitalIn d8(D8);
+DigitalOut extLed(D15);
+PwmOut pwm(PB_11);
+volatile int cayenne_ack_ch;
 /*!
  * \brief   Prepares the payload of the frame
  */
 static void PrepareTxFrame( uint8_t port )
 {
-    switch( port )
-    {
-    case 10:
-        {  
-            uint32_t tempValue = ( uint32_t )( LightValue * 1000000.0 );
-            AppData[0] = LightMode;
-            AppData[1] = ( ( tempValue & 0xFF000000 ) >> 24 ) & 0xFF;
-            AppData[2] = ( ( tempValue & 0x00FF0000 ) >> 16 ) & 0xFF;
-            AppData[3] = ( ( tempValue & 0x0000FF00 ) >> 8 ) & 0xFF;
-            AppData[4] = ( tempValue & 0x000000FF );
+    uint16_t u16, rot;
+    float t, f, R;
+
+    if (c_ch != 0xff) {
+        AppDataSize = 0;
+        AppData[AppDataSize++] = c_ch;
+        switch (c_ch) {
+            case CAYENNE_CH_TEMP:
+                AppData[AppDataSize++] = LPP_TEMPERATURE;
+                u16 = a3.read_u16();
+                R = 65535 / u16 - 1.0;
+                R = R0 * R;
+                t = 1.0/(log(R/R0)/B+1/298.15)-273.15;
+                u16 = t * 10;  // 0.1C per bit
+                AppData[AppDataSize++] = u16 >> 8;
+                AppData[AppDataSize++] = u16;
+                break;
+            case CAYENNE_CH_POT:
+                AppData[AppDataSize++] = LPP_ANALOG_INPUT;
+                u16 = a1.read_u16();    // pot (rotary angle)
+                f = u16 / 198.6;    // scale 65535/3.3 to 0.01v per bit
+                rot = (uint16_t) f;
+                AppData[AppDataSize++] = rot >> 8;
+                AppData[AppDataSize++] = rot;
+                break;
+            case CAYENNE_CH_DOUT:
+                AppData[AppDataSize++] = LPP_DIGITAL_OUTPUT;
+                AppData[AppDataSize++] = extLed.read();
+                break;
+            case CAYENNE_CH_AOUT:
+                AppData[AppDataSize++] = LPP_ANALOG_OUTPUT;
+                u16 = pwm.read() * 100;
+                AppData[AppDataSize++] = u16 >> 8;
+                AppData[AppDataSize++] = u16;
+                break;
         }
-        break;
-    case 15:
-        {
-            AppData[0] = AppLedStateOn;
-            if( IsTxConfirmed == true )
-            {
-                AppData[1] = LoRaMacDownlinkStatus.DownlinkCounter >> 8;
-                AppData[2] = LoRaMacDownlinkStatus.DownlinkCounter;
-                AppData[3] = LoRaMacDownlinkStatus.Rssi >> 8;
-                AppData[4] = LoRaMacDownlinkStatus.Rssi;
-                AppData[5] = LoRaMacDownlinkStatus.Snr;
-            }
+        return;
+    } else if (cayenne_ack_ch != -1) {
+        switch (cayenne_ack_ch) {
+            case CAYENNE_CH_DOUT:
+                AppData[AppDataSize++] = LPP_DIGITAL_OUTPUT;
+                AppData[AppDataSize++] = extLed.read();
+                break;
+            case CAYENNE_CH_AOUT:
+                AppData[AppDataSize++] = LPP_ANALOG_OUTPUT;
+                u16 = pwm.read() * 100;
+                AppData[AppDataSize++] = u16 >> 8;
+                AppData[AppDataSize++] = u16;
+                break;
         }
-        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:
+        cayenne_ack_ch = -1;
+    }
+
+    while (d8.read() == 1) {
+        TimerTime_t duration = TimerGetCurrentTime() - buttonStartAt;
+        vt.SetCursorPos( 41, 1 );
+        if (duration > 1000) {
+            AppDataSize = 0;
+            AppData[AppDataSize++] = CAYENNE_CH_DOUT;
+            AppData[AppDataSize++] = LPP_DIGITAL_OUTPUT;
+            AppData[AppDataSize++] = extLed.read();
+            vt.printf("send outputs           ", duration);
+            return;
+        } else
+            vt.printf("dur %u           ", duration);
+    }
+
+    switch( port ) {
+        case LORAWAN_APP_PORT:
+            AppDataSize = 0;
+            AppData[AppDataSize++] = CAYENNE_CH_TEMP;
+            AppData[AppDataSize++] = LPP_TEMPERATURE;
+            u16 = a3.read_u16();
+            R = 65535 / u16 - 1.0;
+            R = R0 * R;
+            t = 1.0/(log(R/R0)/B+1/298.15)-273.15;
+            u16 = t * 10;  // 0.1C per bit
+            AppData[AppDataSize++] = u16 >> 8;
+            AppData[AppDataSize++] = u16;
+            AppData[AppDataSize++] = CAYENNE_CH_POT;
+            AppData[AppDataSize++] = LPP_ANALOG_INPUT;
+            u16 = a1.read_u16();    // pot (rotary angle)
+            f = u16 / 198.6;    // scale 65535/3.3 to 0.01v per bit
+            rot = (uint16_t) f;
+            AppData[AppDataSize++] = rot >> 8;
+            AppData[AppDataSize++] = rot;
+
+            AppData[AppDataSize++] = CAYENNE_CH_DOUT;
+            AppData[AppDataSize++] = LPP_DIGITAL_OUTPUT;
+            AppData[AppDataSize++] = extLed.read();
+            vt.SetCursorPos( 41, 1 );
+            vt.printf("u16:%u, f:%f, rot:%u t:%.1f\e[K", u16, f, rot, t);
+            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;
-                break;
-            case 1:
-                AppDataSize = 2;
-                AppData[0] = ComplianceTest.DownLinkCounter >> 8;
-                AppData[1] = ComplianceTest.DownLinkCounter;
-                break;
+            } 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;
+            break;
+        default:
+            break;
     }
 }
 
+void LoRaMacStatus_toString(LoRaMacStatus_t s, char* out)
+{
+    switch (s) {
+        case LORAMAC_STATUS_PARAMETER_INVALID:
+            strcpy(out, "PARAMTER_INVALID");
+            break;
+        case LORAMAC_STATUS_BUSY:
+            strcpy(out, "BUSY");
+            break;
+        default:
+            sprintf(out, "<%u>", s);
+            break;
+    }
+}
+
+volatile unsigned sendCnt = 0;
 /*!
  * \brief   Prepares the payload of the frame
  *
@@ -389,11 +437,12 @@
  */
 static bool SendFrame( void )
 {
+    char str[48];
+    LoRaMacStatus_t status;
     McpsReq_t mcpsReq;
     LoRaMacTxInfo_t txInfo;
 
-    if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK )
-    {
+    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;
@@ -405,25 +454,20 @@
         LoRaMacUplinkStatus.Buffer = NULL;
         LoRaMacUplinkStatus.BufferSize = 0;
         SerialDisplayUpdateFrameType( false );
-    }
-    else
-    {
+    } else {
         LoRaMacUplinkStatus.Acked = false;
         LoRaMacUplinkStatus.Port = AppPort;
         LoRaMacUplinkStatus.Buffer = AppData;
         LoRaMacUplinkStatus.BufferSize = AppDataSize;
         SerialDisplayUpdateFrameType( IsTxConfirmed );
 
-        if( IsTxConfirmed == false )
-        {
+        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
-        {
+        } else {
             mcpsReq.Type = MCPS_CONFIRMED;
             mcpsReq.Req.Confirmed.fPort = AppPort;
             mcpsReq.Req.Confirmed.fBuffer = AppData;
@@ -433,69 +477,69 @@
         }
     }
 
-    if( LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK )
-    {
+    sendCnt++;
+    status = LoRaMacMcpsRequest( &mcpsReq );
+    if (status == LORAMAC_STATUS_OK) {
+        vt.SetCursorPos( 44, 1 );
+        vt.printf("%u sendFrame() OK\e[K", sendCnt);
+        SerialDisplayUpdateUplink(
+            LoRaMacUplinkStatus.Acked,
+            LoRaMacUplinkStatus.Datarate,
+            LoRaMacUplinkStatus.UplinkCounter,
+            LoRaMacUplinkStatus.Port,
+            LoRaMacUplinkStatus.Buffer,
+            LoRaMacUplinkStatus.BufferSize
+        );
         return false;
     }
+    LoRaMacStatus_toString(status, str);
+    vt.SetCursorPos( 44, 1 );
+    vt.printf("%u sendFrame() %s\e[K", sendCnt, str);
     return true;
 }
 
-/*!
- * \brief Function executed on TxNextPacket Timeout event
- */
-static void OnTxNextPacketTimerEvent( void )
+void LoRaMacEventInfoStatus_toString(LoRaMacEventInfoStatus_t s, char* out)
 {
-    MibRequestConfirm_t mibReq;
-    LoRaMacStatus_t status;
-
-    TimerStop( &TxNextPacketTimer );
-
-    mibReq.Type = MIB_NETWORK_JOINED;
-    status = LoRaMacMibGetRequestConfirm( &mibReq );
-
-    if( status == LORAMAC_STATUS_OK )
-    {
-        if( mibReq.Param.IsNetworkJoined == true )
-        {
-            DeviceState = DEVICE_STATE_SEND;
-            NextTx = true;
-        }
-        else
-        {
-            DeviceState = DEVICE_STATE_JOIN;
-        }
-    }
-}
+    switch (s) {
+        case LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL:
+            strcpy(out, "JOIN_FAIL");
+            break;
+        case LORAMAC_EVENT_INFO_STATUS_ERROR:
+            strcpy(out, "ERROR");
+            break;
+        case LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT:
+            strcpy(out, "RX2_TIMEOUT");
+            break;
+        case LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL:
+            strcpy(out, "ADDRESS_FAIL");
+            break;
+        case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS:
+            strcpy(out, "FRAMES_LOSS");
+            break;
+        case LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED:
+            strcpy(out, "DOWNLINK_REPEATED");
+            break; // confirmed downlink retry?
+        case LORAMAC_EVENT_INFO_STATUS_MIC_FAIL:
+            strcpy(out, "MIC_FAIL");
+            break;
+        case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT:
+            strcpy(out, "TX_TIMEOUT");
+            break;
+        case LORAMAC_EVENT_INFO_STATUS_RX1_ERROR:
+            strcpy(out, "RX1_ERROR");
+            break;
+        case LORAMAC_EVENT_INFO_STATUS_RX2_ERROR:
+            strcpy(out, "RX2_ERROR");
+            break;
+        case LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR:
+            strcpy(out, "SIZE");
+            break;
 
-/*!
- * \brief Function executed on Led 1 Timeout event
- */
-static void OnLed1TimerEvent( void )
-{
-    TimerStop( &Led1Timer );
-    // Switch LED 1 OFF
-    Led1State = false;
-    Led1StateChanged = true;
-}
 
-/*!
- * \brief Function executed on Led 2 Timeout event
- */
-static void OnLed2TimerEvent( void )
-{
-    TimerStop( &Led2Timer );
-    // Switch LED 2 OFF
-    Led2State = false;
-    Led2StateChanged = true;
-}
-
-/*!
- * \brief Function executed on Buzzer Timeout event
- */
-static void OnBuzzerTimerEvent( void )
-{
-    Buzzer = 0;
-    BuzzerTimer.detach( );
+        default:
+            sprintf(out, "<%d>", s);
+            break;
+    }
 }
 
 /*!
@@ -506,18 +550,14 @@
  */
 static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
 {
-    if( mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
-    {
-        switch( mcpsConfirm->McpsRequest )
-        {
-            case MCPS_UNCONFIRMED:
-            {
+    if( mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) {
+        switch( mcpsConfirm->McpsRequest ) {
+            case MCPS_UNCONFIRMED: {
                 // Check Datarate
                 // Check TxPower
                 break;
             }
-            case MCPS_CONFIRMED:
-            {
+            case MCPS_CONFIRMED: {
                 // Check Datarate
                 // Check TxPower
                 // Check AckReceived
@@ -525,8 +565,7 @@
                 LoRaMacUplinkStatus.Acked = mcpsConfirm->AckReceived;
                 break;
             }
-            case MCPS_PROPRIETARY:
-            {
+            case MCPS_PROPRIETARY: {
                 break;
             }
             default:
@@ -534,17 +573,18 @@
         }
         LoRaMacUplinkStatus.Datarate = mcpsConfirm->Datarate;
         LoRaMacUplinkStatus.UplinkCounter = mcpsConfirm->UpLinkCounter;
+    } else {
+        char str[48];
+        LoRaMacEventInfoStatus_toString(mcpsConfirm->Status, str);
+        vt.SetCursorPos( 44, 1 );
+        vt.printf("mcpsConf %s", str);
 
-        // Switch LED 1 ON
-        Led1State = true;
-        Led1StateChanged = true;
-        TimerStart( &Led1Timer );
+    }
 
-        UplinkStatusUpdated = true;
-    }
-    NextTx = true;
+    DeviceState = DEVICE_STATE_TRIGGER;
 }
 
+
 /*!
  * \brief   MCPS-Indication event function
  *
@@ -553,27 +593,25 @@
  */
 static void McpsIndication( McpsIndication_t *mcpsIndication )
 {
-    if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
-    {
+    if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK ) {
+        char str[48];
+        LoRaMacEventInfoStatus_toString(mcpsIndication->Status, str);
+        vt.SetCursorPos( 44, 1 );
+        vt.printf("mcpsInd %s", str);
         return;
     }
 
-    switch( mcpsIndication->McpsIndication )
-    {
-        case MCPS_UNCONFIRMED:
-        {
+    switch( mcpsIndication->McpsIndication ) {
+        case MCPS_UNCONFIRMED: {
             break;
         }
-        case MCPS_CONFIRMED:
-        {
+        case MCPS_CONFIRMED: {
             break;
         }
-        case MCPS_PROPRIETARY:
-        {
+        case MCPS_PROPRIETARY: {
             break;
         }
-        case MCPS_MULTICAST:
-        {
+        case MCPS_MULTICAST: {
             break;
         }
         default:
@@ -590,14 +628,11 @@
     // Check Snr
     // Check RxSlot
     LoRaMacDownlinkStatus.Rssi = mcpsIndication->Rssi;
-    if( mcpsIndication->Snr & 0x80 ) // The SNR sign bit is 1
-    {
+    if( mcpsIndication->Snr & 0x80 ) { // The SNR sign bit is 1
         // Invert and divide by 4
         LoRaMacDownlinkStatus.Snr = ( ( ~mcpsIndication->Snr + 1 ) & 0xFF ) >> 2;
         LoRaMacDownlinkStatus.Snr = -LoRaMacDownlinkStatus.Snr;
-    }
-    else
-    {
+    } else {
         // Divide by 4
         LoRaMacDownlinkStatus.Snr = ( mcpsIndication->Snr & 0xFF ) >> 2;
     }
@@ -607,185 +642,167 @@
     LoRaMacDownlinkStatus.Buffer = mcpsIndication->Buffer;
     LoRaMacDownlinkStatus.BufferSize = mcpsIndication->BufferSize;
 
-    if( ComplianceTest.Running == true )
-    {
+    if( ComplianceTest.Running == true ) {
         ComplianceTest.DownLinkCounter++;
     }
 
-    if( mcpsIndication->RxData == true )
-    {
-        switch( mcpsIndication->Port )
-        {
-        case 1: // The application LED can be controlled on port 1 or 2
-        case 2:
-            if( mcpsIndication->BufferSize == 1 )
-            {
-                AppLedStateOn = mcpsIndication->Buffer[0] & 0x01;
-                Led3StateChanged = true;
-            }
-            break;
-        case 10: 
-            Display.write( 0, mcpsIndication->Buffer[0] );
-            Display.write( 1, mcpsIndication->Buffer[1] );
-            Display.write( 2, mcpsIndication->Buffer[2] );
-            Display.write( 3, mcpsIndication->Buffer[3] ); 
-            break;
-        case 20:
-            LightMode = mcpsIndication->Buffer[0];
-            if( LightMode )
-            {
-                ColorLed.setColorRGB( 0, mcpsIndication->Buffer[1], mcpsIndication->Buffer[2], mcpsIndication->Buffer[3] );
+    if( mcpsIndication->RxData == true ) {
+        unsigned n;
+        for (n = 0; n < mcpsIndication->BufferSize; n += 4) {
+            uint16_t val = mcpsIndication->Buffer[n+1] << 8;
+            val += mcpsIndication->Buffer[n+2];
+            cayenne_ack_ch = mcpsIndication->Buffer[n];
+            switch (mcpsIndication->Buffer[n]) {
+                case CAYENNE_CH_DOUT:
+                    extLed.write(val);
+                    break;
+                case CAYENNE_CH_AOUT:
+                    pwm.write(val / 100.0);
+                    break;
+                default:
+                    break;
             }
-            break;
-        case 30:
-            BuzzerTimer.attach_us( &OnBuzzerTimerEvent, 200000 );
-            Buzzer = 1;
-            break;
-        case 224:
-            if( ComplianceTest.Running == false )
-            {
-                // Check compliance test enable command (i)
-                if( ( mcpsIndication->BufferSize == 4 ) &&
-                    ( mcpsIndication->Buffer[0] == 0x01 ) &&
-                    ( mcpsIndication->Buffer[1] == 0x01 ) &&
-                    ( mcpsIndication->Buffer[2] == 0x01 ) &&
-                    ( mcpsIndication->Buffer[3] == 0x01 ) )
-                {
-                    IsTxConfirmed = false;
-                    AppPort = 224;
-                    AppDataSize = 2;
-                    ComplianceTest.DownLinkCounter = 0;
-                    ComplianceTest.LinkCheck = false;
-                    ComplianceTest.DemodMargin = 0;
-                    ComplianceTest.NbGateways = 0;
-                    ComplianceTest.Running = true;
-                    ComplianceTest.State = 1;
+        }
 
-                    MibRequestConfirm_t mibReq;
-                    mibReq.Type = MIB_ADR;
-                    mibReq.Param.AdrEnable = true;
-                    LoRaMacMibSetRequestConfirm( &mibReq );
-
-#if defined( USE_BAND_868 )
-                    LoRaMacTestSetDutyCycleOn( false );
-#endif
+        switch( mcpsIndication->Port ) {
+            case 1: // The application LED can be controlled on port 1 or 2
+            case 2:
+                if( mcpsIndication->BufferSize == 1 ) {
+                    //AppLedStateOn = mcpsIndication->Buffer[0] & 0x01;
+                    //Led3StateChanged = true;
                 }
-            }
-            else
-            {
-                ComplianceTest.State = mcpsIndication->Buffer[0];
-                switch( ComplianceTest.State )
-                {
-                case 0: // Check compliance test disable command (ii)
-                    IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
-                    AppPort = LORAWAN_APP_PORT;
-                    AppDataSize = LORAWAN_APP_DATA_SIZE;
-                    ComplianceTest.DownLinkCounter = 0;
-                    ComplianceTest.Running = false;
-
-                    MibRequestConfirm_t mibReq;
-                    mibReq.Type = MIB_ADR;
-                    mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
-                    LoRaMacMibSetRequestConfirm( &mibReq );
-#if defined( USE_BAND_868 )
-                    LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
-#endif
-                    break;
-                case 1: // (iii, iv)
-                    AppDataSize = 2;
-                    break;
-                case 2: // Enable confirmed messages (v)
-                    IsTxConfirmed = true;
-                    ComplianceTest.State = 1;
-                    break;
-                case 3:  // Disable confirmed messages (vi)
-                    IsTxConfirmed = false;
-                    ComplianceTest.State = 1;
-                    break;
-                case 4: // (vii)
-                    AppDataSize = mcpsIndication->BufferSize;
-
-                    AppData[0] = 4;
-                    for( uint8_t i = 1; i < AppDataSize; i++ )
-                    {
-                        AppData[i] = mcpsIndication->Buffer[i] + 1;
-                    }
-                    break;
-                case 5: // (viii)
-                    {
-                        MlmeReq_t mlmeReq;
-                        mlmeReq.Type = MLME_LINK_CHECK;
-                        LoRaMacMlmeRequest( &mlmeReq );
-                    }
-                    break;
-                case 6: // (ix)
-                    {
-                        MlmeReq_t mlmeReq;
-
-                        // Disable TestMode and revert back to normal operation
-                        IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
-                        AppPort = LORAWAN_APP_PORT;
-                        AppDataSize = LORAWAN_APP_DATA_SIZE;
+                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.Running = false;
+                        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 = LORAWAN_ADR_ON;
+                        mibReq.Param.AdrEnable = true;
                         LoRaMacMibSetRequestConfirm( &mibReq );
+
 #if defined( USE_BAND_868 )
-                        LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
+                        LoRaMacTestSetDutyCycleOn( false );
+#endif
+                    }
+                } else {
+                    ComplianceTest.State = mcpsIndication->Buffer[0];
+                    switch( ComplianceTest.State ) {
+                        case 0: // Check compliance test disable command (ii)
+                            IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;
+                            AppPort = LORAWAN_APP_PORT;
+                            AppDataSize = LORAWAN_APP_DATA_SIZE;
+                            ComplianceTest.DownLinkCounter = 0;
+                            ComplianceTest.Running = false;
+
+                            MibRequestConfirm_t mibReq;
+                            mibReq.Type = MIB_ADR;
+                            mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
+                            LoRaMacMibSetRequestConfirm( &mibReq );
+#if defined( USE_BAND_868 )
+                            LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
+#endif
+                            break;
+                        case 1: // (iii, iv)
+                            AppDataSize = 2;
+                            break;
+                        case 2: // Enable confirmed messages (v)
+                            IsTxConfirmed = true;
+                            ComplianceTest.State = 1;
+                            break;
+                        case 3:  // Disable confirmed messages (vi)
+                            IsTxConfirmed = false;
+                            ComplianceTest.State = 1;
+                            break;
+                        case 4: // (vii)
+                            AppDataSize = mcpsIndication->BufferSize;
+
+                            AppData[0] = 4;
+                            for( uint8_t i = 1; i < AppDataSize; i++ ) {
+                                AppData[i] = mcpsIndication->Buffer[i] + 1;
+                            }
+                            break;
+                        case 5: { // (viii)
+                            MlmeReq_t mlmeReq;
+                            mlmeReq.Type = MLME_LINK_CHECK;
+                            LoRaMacMlmeRequest( &mlmeReq );
+                        }
+                        break;
+                        case 6: { // (ix)
+                            MlmeReq_t mlmeReq;
+
+                            // 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( USE_BAND_868 )
+                            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;
+                            mlmeReq.Type = MLME_JOIN;
 
-                        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] );
+                            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;
                         }
-                        else if( mcpsIndication->BufferSize == 7 )
-                        {
-                            MlmeReq_t mlmeReq;
-                            mlmeReq.Type = MLME_TXCW_1;
-                            mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] );
-                            mlmeReq.Req.TxCw.Frequency = ( uint32_t )( ( mcpsIndication->Buffer[3] << 16 ) | ( mcpsIndication->Buffer[4] << 8 ) | mcpsIndication->Buffer[5] ) * 100;
-                            mlmeReq.Req.TxCw.Power = mcpsIndication->Buffer[6];
-                            LoRaMacMlmeRequest( &mlmeReq );
+                        break;
+                        case 7: { // (x)
+                            if( mcpsIndication->BufferSize == 3 ) {
+                                MlmeReq_t mlmeReq;
+                                mlmeReq.Type = MLME_TXCW;
+                                mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] );
+                                LoRaMacMlmeRequest( &mlmeReq );
+                            } else if( mcpsIndication->BufferSize == 7 ) {
+                                MlmeReq_t mlmeReq;
+                                mlmeReq.Type = MLME_TXCW_1;
+                                mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] );
+                                mlmeReq.Req.TxCw.Frequency = ( uint32_t )( ( mcpsIndication->Buffer[3] << 16 ) | ( mcpsIndication->Buffer[4] << 8 ) | mcpsIndication->Buffer[5] ) * 100;
+                                mlmeReq.Req.TxCw.Power = mcpsIndication->Buffer[6];
+                                LoRaMacMlmeRequest( &mlmeReq );
+                            }
+                            ComplianceTest.State = 1;
                         }
-                        ComplianceTest.State = 1;
+                        break;
+                        default:
+                            break;
                     }
-                    break;
-                default:
-                    break;
                 }
-            }
-            break;
-        default:
-            break;
+                break;
+            default:
+                break;
         }
     }
 
-    // Switch LED 2 ON for each received downlink
-    Led2State = true;
-    Led2StateChanged = true;
-    TimerStart( &Led2Timer );
     DownlinkStatusUpdated = true;
 }
 
+
+
 /*!
  * \brief   MLME-Confirm event function
  *
@@ -794,31 +811,31 @@
  */
 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
-                IsNetworkJoinedStatusUpdate = true;
-                DeviceState = DEVICE_STATE_SEND;
-            }
-            else
-            {
+    vt.SetCursorPos( 45, 1 );
+    vt.printf("MlmeConfirm() ");
+    switch( mlmeConfirm->MlmeRequest ) {
+        case MLME_JOIN: {
+            vt.printf("MLME_JOIN ");
+            if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) {
+                vt.printf("OK");
+                DeviceState = DEVICE_STATE_JOIN_OK;
+                extLed = 0;
+            } else {
+                char str[48];
+                LoRaMacEventInfoStatus_toString(mlmeConfirm->Status, str);
+                vt.printf(str);
                 // 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 )
-            {
+        case MLME_LINK_CHECK: {
+            vt.printf("MLME_LINK_CHECK");
+            if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) {
+                vt.printf("OK");
                 // Check DemodMargin
                 // Check NbGateways
-                if( ComplianceTest.Running == true )
-                {
+                if( ComplianceTest.Running == true ) {
                     ComplianceTest.LinkCheck = true;
                     ComplianceTest.DemodMargin = mlmeConfirm->DemodMargin;
                     ComplianceTest.NbGateways = mlmeConfirm->NbGateways;
@@ -827,27 +844,38 @@
             break;
         }
         default:
+            vt.printf("<%d>", mlmeConfirm->MlmeRequest);
             break;
     }
-    NextTx = true;
-    UplinkStatusUpdated = true;
+    vt.printf("\e[K");
+}
+
+void foo()
+{
+    vt.SetCursorPos( 43, 1 );
+    vt.printf("%u d9:%u (%04x %04x %04x %04x)\e[K", DeviceState, d8.read(), a1.read_u16(), a2.read_u16(), a3.read_u16(), a4.read_u16());
 }
 
+const LoRaMacPrimitives_t LoRaMacPrimitives = {
+    McpsConfirm,
+    McpsIndication,
+    MlmeConfirm
+
+};
+const LoRaMacCallback_t LoRaMacCallbacks = {
+    BoardGetBatteryLevel
+};
+
 /**
  * Main application entry point.
  */
 int main( void )
 {
-    LoRaMacPrimitives_t LoRaMacPrimitives;
-    LoRaMacCallback_t LoRaMacCallbacks;
     MibRequestConfirm_t mibReq;
 
     BoardInit( );
     SerialDisplayInit( );
 
-    LightMode = 0;      // 0: manual,   1: automatic
-    Buzzer = 0;         // 0: OFF,      1: ON
-
     SerialDisplayUpdateEui( 5, DevEui );
     SerialDisplayUpdateEui( 6, AppEui );
     SerialDisplayUpdateKey( 7, AppKey );
@@ -861,61 +889,24 @@
 
     DeviceState = DEVICE_STATE_INIT;
 
-    while( 1 )
-    {
+    while( 1 ) {
+        foo();
         SerialRxProcess( );
-        if( IsNetworkJoinedStatusUpdate == true )
-        {
-            IsNetworkJoinedStatusUpdate = false;
-            mibReq.Type = MIB_NETWORK_JOINED;
-            LoRaMacMibGetRequestConfirm( &mibReq );
-            SerialDisplayUpdateNetworkIsJoined( mibReq.Param.IsNetworkJoined );
-        }
-        if( Led1StateChanged == true )
-        {
-            Led1StateChanged = false;
-            SerialDisplayUpdateLedState( 1, Led1State );
-        }
-        if( Led2StateChanged == true )
-        {
-            Led2StateChanged = false;
-            SerialDisplayUpdateLedState( 2, Led2State );
-        }
-        if( Led3StateChanged == true )
-        {
-            Led3StateChanged = false;
-            SerialDisplayUpdateLedState( 3, AppLedStateOn );
-        }
-        if( UplinkStatusUpdated == true )
-        {
-            UplinkStatusUpdated = false;
-            SerialDisplayUpdateUplink( LoRaMacUplinkStatus.Acked, LoRaMacUplinkStatus.Datarate, LoRaMacUplinkStatus.UplinkCounter, LoRaMacUplinkStatus.Port, LoRaMacUplinkStatus.Buffer, LoRaMacUplinkStatus.BufferSize );
-        }
-        if( DownlinkStatusUpdated == true )
-        {
+
+        if( DownlinkStatusUpdated == true ) {
             DownlinkStatusUpdated = false;
-            SerialDisplayUpdateLedState( 2, Led2State );
             SerialDisplayUpdateDownlink( LoRaMacDownlinkStatus.RxData, LoRaMacDownlinkStatus.Rssi, LoRaMacDownlinkStatus.Snr, LoRaMacDownlinkStatus.DownlinkCounter, LoRaMacDownlinkStatus.Port, LoRaMacDownlinkStatus.Buffer, LoRaMacDownlinkStatus.BufferSize );
         }
-        
-        switch( DeviceState )
-        {
-            case DEVICE_STATE_INIT:
-            {
-                LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
-                LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
-                LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
-                LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
+
+        switch( DeviceState ) {
+            case DEVICE_STATE_INIT: {
+                pwm.period(1.0 / 60);
+                cayenne_ack_ch = -1;
+                c_ch = 0xff;
+                d8.mode(PullDown);
+
                 LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks );
 
-                TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent );
-
-                TimerInit( &Led1Timer, OnLed1TimerEvent );
-                TimerSetValue( &Led1Timer, 25 );
-
-                TimerInit( &Led2Timer, OnLed2TimerEvent );
-                TimerSetValue( &Led2Timer, 25 );
-
                 mibReq.Type = MIB_ADR;
                 mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
                 LoRaMacMibSetRequestConfirm( &mibReq );
@@ -938,11 +929,15 @@
                 LoRaMacChannelAdd( 9, ( ChannelParams_t )LC10 );
 
                 mibReq.Type = MIB_RX2_DEFAULT_CHANNEL;
-                mibReq.Param.Rx2DefaultChannel = ( Rx2ChannelParams_t ){ 869525000, DR_3 };
+                mibReq.Param.Rx2DefaultChannel = ( Rx2ChannelParams_t ) {
+                    869525000, DR_3
+                };
                 LoRaMacMibSetRequestConfirm( &mibReq );
 
                 mibReq.Type = MIB_RX2_CHANNEL;
-                mibReq.Param.Rx2Channel = ( Rx2ChannelParams_t ){ 869525000, DR_3 };
+                mibReq.Param.Rx2Channel = ( Rx2ChannelParams_t ) {
+                    869525000, DR_3
+                };
                 LoRaMacMibSetRequestConfirm( &mibReq );
 #endif
 
@@ -956,22 +951,27 @@
                 DeviceState = DEVICE_STATE_JOIN;
                 break;
             }
-            case DEVICE_STATE_JOIN:
-            {
+            case DEVICE_STATE_JOIN: {
 #if( OVER_THE_AIR_ACTIVATION != 0 )
+                LoRaMacStatus_t s;
                 MlmeReq_t mlmeReq;
-
                 mlmeReq.Type = MLME_JOIN;
 
                 mlmeReq.Req.Join.DevEui = DevEui;
                 mlmeReq.Req.Join.AppEui = AppEui;
                 mlmeReq.Req.Join.AppKey = AppKey;
 
-                if( NextTx == true )
-                {
-                    LoRaMacMlmeRequest( &mlmeReq );
-                }
-                DeviceState = DEVICE_STATE_SLEEP;
+                s = LoRaMacMlmeRequest( &mlmeReq );
+                if (s != LORAMAC_STATUS_OK) {
+                    char str[48];
+                    LoRaMacStatus_toString(s, str);
+                    vt.SetCursorPos( 44, 1 );
+                    vt.printf("mlmeReq join %s\e[K", str);
+                    return -1;                    
+                } else
+                    DeviceState = DEVICE_STATE_SLEEP;
+
+                extLed = 1;
 #else
                 mibReq.Type = MIB_NET_ID;
                 mibReq.Param.NetID = LORAWAN_NETWORK_ID;
@@ -992,64 +992,54 @@
                 mibReq.Type = MIB_NETWORK_JOINED;
                 mibReq.Param.IsNetworkJoined = true;
                 LoRaMacMibSetRequestConfirm( &mibReq );
-
                 DeviceState = DEVICE_STATE_SEND;
 #endif
-                IsNetworkJoinedStatusUpdate = true;
                 break;
             }
-            case DEVICE_STATE_SEND:
-            {
-                if( NextTx == true )
-                {
-                    SerialDisplayUpdateUplinkAcked( false );
-                    SerialDisplayUpdateDonwlinkRxData( false );
-                    PrepareTxFrame( AppPort );
+            case DEVICE_STATE_JOIN_OK:
+                MibRequestConfirm_t mibReq;
+                mibReq.Type = MIB_NETWORK_JOINED;
+                LoRaMacMibGetRequestConfirm( &mibReq );
+                SerialDisplayUpdateNetworkIsJoined( mibReq.Param.IsNetworkJoined );
+                mibReq.Type = MIB_DEV_ADDR;
+                LoRaMacMibGetRequestConfirm( &mibReq );
+                SerialDisplayUpdateDevAddr(mibReq.Param.DevAddr);
+                mibReq.Type = MIB_NWK_SKEY;
+                LoRaMacMibGetRequestConfirm( &mibReq );
+                SerialDisplayUpdateKey( 12, mibReq.Param.NwkSKey );
+                mibReq.Type = MIB_APP_SKEY;
+                LoRaMacMibGetRequestConfirm( &mibReq );
+                SerialDisplayUpdateKey( 13,  mibReq.Param.AppSKey );
+                //SerialDisplayUpdateNwkId( uint8_t id );
+                DeviceState = DEVICE_STATE_TRIGGER;
+                break;
+            case DEVICE_STATE_SEND: {
+                SerialDisplayUpdateUplinkAcked( false );
+                SerialDisplayUpdateDonwlinkRxData( false );
+                PrepareTxFrame( AppPort );
 
-                    NextTx = SendFrame( );
-                }
-                if( ComplianceTest.Running == true )
-                {
-                    // Schedule next packet transmission
-                    TxDutyCycleTime = 5000; // 5000 ms
-                }
-                else
-                {
-                    // Schedule next packet transmission
-                    TxDutyCycleTime = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );
-                }
-                DeviceState = DEVICE_STATE_CYCLE;
+                SendFrame( );
+
+                DeviceState = DEVICE_STATE_SLEEP;
                 break;
             }
-            case DEVICE_STATE_CYCLE:
-            {
-                DeviceState = DEVICE_STATE_SLEEP;
-
-                // Schedule next packet transmission
-                TimerSetValue( &TxNextPacketTimer, TxDutyCycleTime );
-                TimerStart( &TxNextPacketTimer );
-                break;
-            }
-            case DEVICE_STATE_SLEEP:
-            {
+            case DEVICE_STATE_SLEEP: {
                 // Wake up through events
                 break;
             }
-            default:
-            {
+            case DEVICE_STATE_TRIGGER:
+                if (d8.read() == 1) {
+                    c_ch = 0xff;
+                    DeviceState = DEVICE_STATE_SEND;
+                    buttonStartAt = TimerGetCurrentTime();
+                }
+                break;
+            default: {
                 DeviceState = DEVICE_STATE_INIT;
                 break;
             }
-            
+
         }
 
-        // Read light sensor
-        LightValue = ( 1 - ( LightSens.read( ) * 1.65 ) );
-
-        // Set automatic RGB from light sensor
-        if( LightMode == 0 )
-        {
-            ColorLed.setColorRGB( 0, ( uint8_t )( 255 * LightValue ), ( uint8_t )( 255 * LightValue ), ( uint8_t )( 255 * LightValue ) );
-        }
     }
 }