Downlink Issue - After migration from TTN v2 to TTN v3

Hi, We are migrated the end devices from TTN v2 to TTN v3 using Migration tool.

While working in TTN v2,both Uplinks and Downlinks are worked fine.

After migration, Uplinks are working fine in TTN v3. But while giving downlinks, it is not working.

Does anyone have any insights as to why the downlinks aren’t coming through to my node? Or where to look?

Rx1 delay …

Are you using ABP or OTAA?

In Firmware, RX1 delay is 1 sec.
Am using OTAA

Has the device re-joined since migration?

yes. it is rejoined. Automatically Rx1 delay sets as 5 sec in network server

And the device is?

Running which firmware / MAC?

Using which version?

Implementing which version of LoRaWAN?

The device is stm8
The MAC version is MACV.1.0.2

Which firmware?

And which version of it?

Cosmic and version is 2.0

Cosmic make the Arduino style compiler for STM8, are you using LMIC and if so what version?

No. it is not arduino based. IDE’s with cosmic compiler

Either way, Cosmic do the compiler, so you will have compiled some software to do LoRaWAN with it.

Do you still have the source code for this firmware as that should shed light on it

/*!
 * \file      main.c
 *
 * \brief     LoRaMac classA device implementation
 *
 * \copyright Revised BSD License, see section \ref LICENSE.
 *
 * \code
 *                ______                              _
 *               / _____)             _              | |
 *              ( (____  _____ ____ _| |_ _____  ____| |__
 *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
 *               _____) ) ____| | | || |_| ____( (___| | | |
 *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
 *              (C)2013-2017 Semtech
 *
 * \endcode
 *
 * \author    Miguel Luis ( Semtech )
 *
 * \author    Gregory Cristian ( Semtech )
 */

/*! \file classA/ASR6505/main.c */
#include <stdio.h>
#include <string.h>
#include "utilities.h"
#include "board.h"
#include "gpio.h"
#include "LoRaMac.h"
#include "LoRaMacClassD.h"
#include "LoRaMacCrypto.h"
#include "Commissioning.h"

#ifndef ACTIVE_REGION

#warning "No active region defined, LORAMAC_REGION_CN470 will be used as default."

#define ACTIVE_REGION LORAMAC_REGION_IN865

#endif


#ifdef CONFIG_D2D
#define D2D_PREAMBLE_TIME  D2D_PREAMBLE_TIME_DEFAULT
#define D2D_FREQUENCY       503000000
#define D2D_DATARATE        5
#endif

#define LORAWAN_UNCONFIRMED_D2D_MSG 2
#define LORAWAN_CONFIRMED_MSG       1
#define LORAWAN_UNCONFIRMED_MSG     0

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

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

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

/*!
 * LoRaWAN confirmed messages
 */
#define LORAWAN_MSG_TYPE                    LORAWAN_CONFIRMED_MSG

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


#ifdef CONFIG_D2D

typedef enum LmhpRemoteMcastSetupMoteCmd_e
{
    REMOTE_MCAST_SETUP_PKG_VERSION_ANS              = 0x00,
    REMOTE_MCAST_SETUP_MC_GROUP_STATUS_ANS          = 0x01,
    REMOTE_MCAST_SETUP_MC_GROUP_SETUP_ANS           = 0x02,
    REMOTE_MCAST_SETUP_MC_GROUP_DELETE_ANS          = 0x03,
    REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_ANS = 0x04,
    REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_ANS = 0x05
}LmhpRemoteMcastSetupMoteCmd_t;

typedef enum LmhpRemoteMcastSetupSrvCmd_e
{
    REMOTE_MCAST_SETUP_PKG_VERSION_REQ              = 0x00,
    REMOTE_MCAST_SETUP_MC_GROUP_STATUS_REQ          = 0x01,
    REMOTE_MCAST_SETUP_MC_GROUP_SETUP_REQ           = 0x02,
    REMOTE_MCAST_SETUP_MC_GROUP_DELETE_REQ          = 0x03,
    REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_REQ = 0x04,
    REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_REQ = 0x05
}LmhpRemoteMcastSetupSrvCmd_t;

#endif


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

#if( OVER_THE_AIR_ACTIVATION == 0 )

static uint8_t NwkSKey[] = LORAWAN_NWKSKEY;
static uint8_t AppSKey[] = LORAWAN_APPSKEY;
static uint32_t DevAddr = LORAWAN_DEVICE_ADDRESS;

#endif

extern RxConfigParams_t RxWindow1Config;
extern McpsIndication_t McpsIndication;

#ifdef CONFIG_D2D
static uint16_t preambletimtemp = 0;

static ClassDKey_t ClassDMCKeys[] = {
    {LORAWAN_MC_KEY_0},
    {LORAWAN_MC_KEY_1},
    {LORAWAN_MC_KEY_2},
    {LORAWAN_MC_KEY_3}
};

static MulticastParams_t ClassDMCChannels[] = {
{ LORAWAN_MC_ADDR_0, {0},{0},0, NULL  },
{ LORAWAN_MC_ADDR_1, {0},{0},0, NULL  },
{ LORAWAN_MC_ADDR_2, {0},{0},0, NULL  },
{ LORAWAN_MC_ADDR_3, {0},{0},0, NULL  },
};
#endif

uint32_t APP_TX_DUTYCYCLE = 30000;   //28800000 ;            // 8 hours
uint32_t Server_TDC = 0;
uint32_t APP_TX_DUTYCYCLE_RND = 1000;
uint32_t TxDutyCycleTime =  30000;   
/*!
 * Application port
 */
static uint8_t AppPort = LORAWAN_APP_PORT;

/*!
 * User application data size
 */
static uint8_t AppDataSize = 4;
/*!
 * User application data buffer size
 */
#define LORAWAN_APP_DATA_MAX_SIZE                           16

/*!
 * User application data
 */
static uint8_t AppData[LORAWAN_APP_DATA_MAX_SIZE];

/*!
 * Indicates if the node is sending confirmed or unconfirmed messages
 */
static uint8_t TxMsgType = LORAWAN_MSG_TYPE;

/*!
 * Defines the application data transmission duty cycle
 */
//static uint32_t TxDutyCycleTime = APP_TX_DUTYCYCLE;

/*!
 * Timer to handle the application data transmission duty cycle
 */
static TimerEvent_t TxNextPacketTimer;

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

/*!
 * Device states
 */
static enum eDeviceState
{
    DEVICE_STATE_INIT,
    DEVICE_STATE_JOIN,
    DEVICE_STATE_SEND,
    DEVICE_STATE_SEND_MAC,
    DEVICE_STATE_CYCLE,
    DEVICE_STATE_SLEEP
}DeviceState;

/*!
 * \brief   Prepares the payload of the frame
 */
static void PrepareTxFrame( uint8_t port )
{
    AppDataSize = 4;
    AppData[0] = 0x00;
    AppData[1] = 0x01;
    AppData[2] = 0x02;
    AppData[3] = 0x03;
}

/*!
 * \brief   Prepares the payload of the frame
 *
 * \retval  [0: frame could be send, 1: error]
 */
static bool SendFrame( void )
{
    McpsReq_t mcpsReq;
    LoRaMacTxInfo_t txInfo;

    if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK )
    {
        // Send empty frame in order to flush MAC commands
        mcpsReq.Type = MCPS_UNCONFIRMED;
        mcpsReq.Req.Unconfirmed.fBuffer = NULL;
        mcpsReq.Req.Unconfirmed.fBufferSize = 0;
        mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
    }
    else
    {
        if( TxMsgType == LORAWAN_UNCONFIRMED_MSG
        #ifdef CONFIG_D2D
           || TxMsgType == LORAWAN_UNCONFIRMED_D2D_MSG 
        #endif             
        )
        {
            #ifdef CONFIG_D2D
            if(TxMsgType == LORAWAN_UNCONFIRMED_D2D_MSG)
            {
                mcpsReq.Type = MCPS_UNCONFIRMED_D2D;
            }
            else
            #endif
            {
                mcpsReq.Type = MCPS_UNCONFIRMED;
            }
            mcpsReq.Req.Unconfirmed.fPort = AppPort;
            mcpsReq.Req.Unconfirmed.fBuffer = AppData;
            mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize;
            mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
        }
        else
        {
            mcpsReq.Type = MCPS_CONFIRMED;
            mcpsReq.Req.Confirmed.fPort = AppPort;
            mcpsReq.Req.Confirmed.fBuffer = AppData;
            mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
            mcpsReq.Req.Confirmed.NbTrials = 8;
            mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
        }
    }

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


#ifdef CONFIG_D2D

bool lwan_multicast_add(void * multicastInfo )
{
    uint8_t i;
    MibRequestConfirm_t mibset;
    uint32_t address = ((MulticastParams_t *)multicastInfo)->Address;
    
    for(i = 0; i < CLASSD_GROUP_ID_NUM; i++){
        if( address == ClassDMCChannels[i].Address){
            return false;
        }
    }      
    
    for(i = 0; i < CLASSD_GROUP_ID_NUM; i++){
        
        if(ClassDMCChannels[i].Address == 0){

            memcpy(&ClassDMCChannels[i], multicastInfo, sizeof(MulticastParams_t));

            mibset.Type = MIB_MULTICAST_CHANNEL;
            mibset.Param.MulticastList = &ClassDMCChannels[i];
            if (LoRaMacMibSetRequestConfirm(&mibset) !=  LORAMAC_STATUS_OK) {
                return false;
            }
            return true;
        }
    }    

    return false;
}

bool lwan_multicast_del(uint32_t address)
{
    uint8_t i;
    MibRequestConfirm_t mibset;
    
    for(i = 0; i < CLASSD_GROUP_ID_NUM; i++){
        if( address == ClassDMCChannels[i].Address){
           
            ClassDMCChannels[i].Address = 0;
            mibset.Type = MIB_MULTICAST_CHANNEL_DEL;
            mibset.Param.MulticastList = &ClassDMCChannels[i];
            if (LoRaMacMibSetRequestConfirm(&mibset) !=  LORAMAC_STATUS_OK) {
                return false;
            } else {
                return true;
            }
        }
    }     

    return false;
}

void on_remote_mcastgroup_setup(uint8_t * buffer, uint16_t size)
{
    uint8_t cmdIndex = 0;
    uint8_t dataBufferIndex = 0;


    while( cmdIndex < size)
    {
        switch( buffer[cmdIndex++] )
        {
            case REMOTE_MCAST_SETUP_PKG_VERSION_REQ:
            {
                AppData[dataBufferIndex++] = REMOTE_MCAST_SETUP_PKG_VERSION_ANS;
                AppData[dataBufferIndex++] = REMOTE_MCAST_SETUP_ID;
                AppData[dataBufferIndex++] = REMOTE_MCAST_SETUP_VERSION;

                printf("\r\n====REMOTE_MCAST_SETUP_PKG_VERSION_REQ.====\r\n");
                break;
            }
            case REMOTE_MCAST_SETUP_MC_GROUP_STATUS_REQ:
            {
                uint8_t i;  
                uint32_t addr;                
                uint8_t reqGroupMask;                
                uint8_t nbGroup = 0;
                uint8_t ansGroupMask = 0;
                uint8_t statusIndex = 0;
                uint8_t status = 0;

                AppData[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_STATUS_ANS;
                statusIndex = dataBufferIndex;
                AppData[dataBufferIndex++] = status;//init

                reqGroupMask = buffer[cmdIndex++] & 0x0F;


                for (i = 0; i < CLASSD_GROUP_ID_NUM; i++) {
                    if (ClassDMCChannels[i].Address) {
                        nbGroup++;
                        if (reqGroupMask & (1 << i))
                        {
                            ansGroupMask |= (1 << i);
                            addr = ClassDMCChannels[i].Address;
                            AppData[dataBufferIndex++] = i;
                            AppData[dataBufferIndex++] = ((uint8_t)(addr & 0xFF));
                            AppData[dataBufferIndex++] = ((uint8_t)(addr >> 8 & 0xFF));
                            AppData[dataBufferIndex++] = ((uint8_t)(addr >> 16 & 0xFF));
                            AppData[dataBufferIndex++] = ((uint8_t)(addr >> 24 & 0xFF));
                        }
                    }
                }

                status = ansGroupMask;
                status |= ((nbGroup << 4) & 0xF0);
                AppData[statusIndex] = status;//update
                printf("\r\n====REMOTE_MCAST_SETUP_MC_GROUP_STATUS_REQ,reqGroupMask=%d,status=%d.====\r\n",reqGroupMask,status);
                break;
            }
            case REMOTE_MCAST_SETUP_MC_GROUP_SETUP_REQ:
            {
                const uint8_t genappkey[]=LORAWAN_GENAPP_KEY;
                uint8_t idError = 0x01; // One bit value
                uint8_t id = buffer[cmdIndex++];
                uint32_t address = 0;
                bool enable_mcaddr = false;
                
                address = ClassDMCChannels[id].Address;                
                if(id < CLASSD_GROUP_ID_NUM)
                {
                    ClassDMCChannels[id].Address =  ( buffer[cmdIndex++] << 0  ) & 0x000000FF;
                    ClassDMCChannels[id].Address += ( buffer[cmdIndex++] << 8  ) & 0x0000FF00;
                    ClassDMCChannels[id].Address += ( ((uint32_t)buffer[cmdIndex++]) << 16 ) & 0x00FF0000;
                    ClassDMCChannels[id].Address += ( ((uint32_t)buffer[cmdIndex++]) << 24 ) & 0xFF000000;

                    LoRaMacDecryptMCastKey(genappkey,&buffer[cmdIndex],ClassDMCKeys[id].key);

                    cmdIndex += 16;
                    //discard McFCountMin
                    //McFCountMin = ( mcpsIndication->Buffer[cmdIndex++] << 0  ) & 0x000000FF;
                    //McFCountMin += ( mcpsIndication->Buffer[cmdIndex++] << 8  ) & 0x0000FF00;
                    //McFCountMin += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000;
                    //McFCountMin += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000;
                    //discard McFCountMax
                    //McFCountMax =  ( mcpsIndication->Buffer[cmdIndex++] << 0  ) & 0x000000FF;
                    //McFCountMax += ( mcpsIndication->Buffer[cmdIndex++] << 8  ) & 0x0000FF00;
                    //McFCountMax += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000;
                    //McFCountMax += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000;

                    LoRaMacD2DMcastComputeSKeys(ClassDMCKeys[id].key,ClassDMCChannels[id].Address,ClassDMCChannels[id].AppSKey,ClassDMCChannels[id].NwkSKey);
                    

                    if(address == 0){
                        MibRequestConfirm_t mibset;
                    
                        mibset.Type = MIB_MULTICAST_CHANNEL;
                        mibset.Param.MulticastList = &ClassDMCChannels[id];
                        if (LoRaMacMibSetRequestConfirm(&mibset) ==  LORAMAC_STATUS_OK) {
                            enable_mcaddr = true;
                        }                          
                    }else{
                        printf("WARNING!!!overwrite previous mcast group:%08x\r\n",(unsigned int)address);
                        enable_mcaddr = true;
                    }
                    
                    if( enable_mcaddr == true )
                    {
                        idError = 0x00;
                        printf("setup mcast group :%08x\r\n",(unsigned int)address);
                    }
                }

                AppData[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_SETUP_ANS;
                AppData[dataBufferIndex++] = ( idError << 2 ) | id;

                printf("\r\n====REMOTE_MCAST_SETUP_MC_GROUP_SETUP_REQ====\r\n");
                break;
            }
            case REMOTE_MCAST_SETUP_MC_GROUP_DELETE_REQ:
            {
                uint8_t status = 0x00;
                uint8_t id = buffer[cmdIndex++] & 0x03;
                uint32_t address = 0;
                
                status = id;
                address = ClassDMCChannels[id].Address;
                AppData[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_DELETE_ANS;
                
                if(address == 0 || lwan_multicast_del( address ) != true )
                {
                    status |= 0x04; // McGroupUndefined bit set
                }
                else
                {
                    printf("delete mcast group :%08x\r\n",(unsigned int)address);
                }

                AppData[dataBufferIndex++] = status;
                printf("\r\n====REMOTE_MCAST_SETUP_MC_GROUP_DELETE_REQ,GroupId=%d,status=%d.====\r\n",id,status);
                break;
            }
            case REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_REQ://not support yet
            case REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_REQ://not support yet
            default:
            {
                printf("mcast command not support \r\n");
                break;
            }
        }
    }

    if( dataBufferIndex != 0 )
    {
        // Answer commands
        printf("\r\n====RemoteMcAns:Size=%d,0x%02X%02X====\r\n",dataBufferIndex,AppData[0],AppData[1]);

        TxMsgType = LORAWAN_CONFIRMED_MSG;
        AppPort = REMOTE_MCAST_SETUP_PORT;
        AppDataSize = dataBufferIndex;
        DeviceState = DEVICE_STATE_SEND;
    }    
}



void lwan_classd_mcchannel_setup(void)
{
    uint32_t i ;  
    MibRequestConfirm_t mibset;
    
    mibset.Type = MIB_MULTICAST_CHANNEL;  

    for( i = 0;i<sizeof(ClassDMCChannels)/sizeof(MulticastParams_t);i++){
        if(ClassDMCChannels[i].Address){
            LoRaMacD2DMcastComputeSKeys(ClassDMCKeys[i].key,ClassDMCChannels[i].Address,ClassDMCChannels[i].AppSKey,ClassDMCChannels[i].NwkSKey);
            
            mibset.Param.MulticastList = &ClassDMCChannels[i];
            if (LoRaMacMibSetRequestConfirm(&mibset) !=  LORAMAC_STATUS_OK) {
                break;
            }
        }
    }    
}
#endif


/*!
 * \brief Function executed on TxNextPacket Timeout event
 */
static void OnTxNextPacketTimerEvent( void )
{
    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
        {
            // Network not joined yet. Try to join again
            MlmeReq_t mlmeReq;
            mlmeReq.Type = MLME_JOIN;
            mlmeReq.Req.Join.DevEui = DevEui;
            mlmeReq.Req.Join.AppEui = AppEui;
            mlmeReq.Req.Join.AppKey = AppKey;
			mlmeReq.Req.Join.NbTrials = 48;
            mlmeReq.Req.Join.Datarate = LORAWAN_DEFAULT_DATARATE;

            if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK )
            {
                DeviceState = DEVICE_STATE_SLEEP;
            }
            else
            {
                DeviceState = DEVICE_STATE_CYCLE;
            }
        }
    }
}

/*!
 * \brief   MCPS-Confirm event function
 *
 * \param   [IN] mcpsConfirm - Pointer to the confirm structure,
 *               containing confirm attributes.
 */
static void mcps_confirm( McpsConfirm_t *mcpsConfirm )
{
    if( mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
    {
        switch( mcpsConfirm->McpsRequest )
        {
            case MCPS_UNCONFIRMED:
            {
                // Check Datarate
                // Check TxPower
                break;
            }
            case MCPS_CONFIRMED:
            {
                // Check Datarate
                // Check TxPower
                // Check AckReceived
                // Check NbTrials
                break;
            }
            case MCPS_PROPRIETARY:
            {
                break;
            }
            default:
                break;
        }
    }
    NextTx = true;
}

/*!
 * \brief   MCPS-Indication event function
 *
 * \param   [IN] mcpsIndication - Pointer to the indication structure,
 *               containing indication attributes.
 */
static void mcps_indication( McpsIndication_t *mcpsIndication )
{
	int i=0;
    if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
    {
        return;
    }

    printf( "receive data: rssi = %d, snr = %d, datarate = %d\r\n", mcpsIndication->Rssi, (int)mcpsIndication->Snr,
                 (int)mcpsIndication->RxDatarate);
    switch( mcpsIndication->McpsIndication )
    {
        case MCPS_UNCONFIRMED:
        {
            break;
        }
        case MCPS_CONFIRMED:
        {
            break;
        }
        case MCPS_PROPRIETARY:
        {
            break;
        }
        case MCPS_MULTICAST:
        {
            break;
        }
        default:
            break;
    }

    // Check Multicast
    // Check Port
    // Check Datarate
    // Check FramePending
    if( mcpsIndication->FramePending == true )
    {
        // The server signals that it has pending data to be sent.
        // We schedule an uplink as soon as possible to flush the server.
        OnTxNextPacketTimerEvent( );
    }
    // Check Buffer
    // Check BufferSize
    // Check Rssi
    // Check Snr
    // Check RxSlot
    if( mcpsIndication->RxData == true )
    {
        switch(mcpsIndication->Port)
        {
            #ifdef CONFIG_D2D
            case REMOTE_MCAST_SETUP_PORT:{
                on_remote_mcastgroup_setup(mcpsIndication->Buffer, mcpsIndication->BufferSize);
                break;                
            }
            #endif
            default:
                break;
        }
    }
		if(mcpsIndication->BufferSize) {
			printf("Received: ");
			for(i=0; i<mcpsIndication->BufferSize; i++) {
				printf("%x ", (void *)mcpsIndication->Buffer[i]);
				//Receive_Buff_Size = (mcpsIndication->BufferSize);
				//Receive_Buffer = mcpsIndication->Buffer[0];
			}
			printf("\r\n");
			Server_TDC = mcpsIndication->Buffer[0]<<8 | mcpsIndication->Buffer[1];
							
				if(Server_TDC != 0)
				{
					APP_TX_DUTYCYCLE = Server_TDC * 60000;
				}
			}
}

/*!
 * \brief   MLME-Confirm event function
 *
 * \param   [IN] mlmeConfirm - Pointer to the confirm structure,
 *               containing confirm attributes.
 */
static void mlme_confirm( MlmeConfirm_t *mlmeConfirm )
{
    switch( mlmeConfirm->MlmeRequest )
    {
        case MLME_JOIN:
        {
            if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
            {
                #ifdef CONFIG_D2D
                MlmeReq_t mlmeReq;
                MibRequestConfirm_t mibReq;
                uint16_t preambletime = D2D_PREAMBLE_TIME;
                #endif
                
                printf("joined\r\n");
                // Status is OK, node has joined the network
                DeviceState = DEVICE_STATE_SEND;

                #ifdef CONFIG_D2D
                mibReq.Type = MIB_RXD_CHANNEL;
                mibReq.Param.RxDChannel.Frequency = D2D_FREQUENCY;
                mibReq.Param.RxDChannel.Datarate = D2D_DATARATE;
                LoRaMacMibSetRequestConfirm(&mibReq);

                if(preambletime != D2D_PREAMBLE_TIME_DEFAULT)
                {
                    mlmeReq.Type = MLME_PREAMBLE_INFO;
                    mlmeReq.Req.PreambleInfo.Period.Value = D2D_PREAMBLE_TIME/100-1;
                    preambletimtemp = (D2D_PREAMBLE_TIME / 100 ) * 100;            
                }
                else
                {
                    mlmeReq.Type = MLME_DEVICE_TIME;
                }

                if (LoRaMacMlmeRequest(&mlmeReq) == LORAMAC_STATUS_OK)
                {
                    DeviceState = DEVICE_STATE_SEND_MAC;
                }
                else
                {
                    DeviceState = DEVICE_STATE_CYCLE;
                }
                #endif                
            }
            else
            {
                MlmeReq_t mlmeReq;
                
                printf("join failed\r\n");
                // Join was not successful. Try to join again
                mlmeReq.Type = MLME_JOIN;
                mlmeReq.Req.Join.DevEui = DevEui;
                mlmeReq.Req.Join.AppEui = AppEui;
                mlmeReq.Req.Join.AppKey = AppKey;
				mlmeReq.Req.Join.NbTrials = 48;
                mlmeReq.Req.Join.Datarate = LORAWAN_DEFAULT_DATARATE;

                if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK )
                {
                    DeviceState = DEVICE_STATE_SLEEP;
                }
                else
                {
                    DeviceState = DEVICE_STATE_CYCLE;
                }
            }
            break;
        }
        case MLME_LINK_CHECK:
        {
            if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
            {
                // Check DemodMargin
                // Check NbGateways
            }
            break;
        }
        #ifdef CONFIG_D2D        
        case MLME_DEVICE_TIME:
        {
            MibRequestConfirm_t mibReq;
            
            if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
            {
                mibReq.Type = MIB_DEVICE_CLASS;
                mibReq.Param.Class = CLASS_D;
                LoRaMacMibSetRequestConfirm(&mibReq);
            }
            break;
        }         
        case MLME_PREAMBLE_INFO: {
            MibRequestConfirm_t mibReq;

            if ( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) {
                if(preambletimtemp){
                    mibReq.Type = MIB_PREAMBLE_TIME;
                    mibReq.Param.PreambleTime = preambletimtemp;
                    LoRaMacMibSetRequestConfirm(&mibReq);

                    mibReq.Type = MIB_DEVICE_CLASS;
                    mibReq.Param.Class = CLASS_D;
                    LoRaMacMibSetRequestConfirm(&mibReq);
                }
            }
            else
            {
                mibReq.Type = MIB_DEVICE_CLASS;
                mibReq.Param.Class = CLASS_A;
                LoRaMacMibSetRequestConfirm(&mibReq);
            }
            preambletimtemp = 0;            
            break;
        }        
        #endif            
        default:
            break;
    }
    NextTx = true;
}

/*!
 * \brief   MLME-Indication event function
 *
 * \param   [IN] mlmeIndication - Pointer to the indication structure.
 */
static void mlme_indication( MlmeIndication_t *mlmeIndication )
{
    switch( mlmeIndication->MlmeIndication )
    {
        case MLME_SCHEDULE_UPLINK:
        {// The MAC signals that we shall provide an uplink as soon as possible
            OnTxNextPacketTimerEvent( );
            break;
        }
        default:
            break;
    }
}

static void lwan_dev_params_update( void )
{
    MibRequestConfirm_t mibReq;
    uint16_t channelsMaskTemp[6];
    channelsMaskTemp[0] = 0x00FF;
    channelsMaskTemp[1] = 0x0000;
    channelsMaskTemp[2] = 0x0000;
    channelsMaskTemp[3] = 0x0000;
    channelsMaskTemp[4] = 0x0000;
    channelsMaskTemp[5] = 0x0000;

    mibReq.Type = MIB_CHANNELS_DEFAULT_MASK;
    mibReq.Param.ChannelsDefaultMask = channelsMaskTemp;
    LoRaMacMibSetRequestConfirm(&mibReq);
    mibReq.Type = MIB_CHANNELS_MASK;
    mibReq.Param.ChannelsMask = channelsMaskTemp;
    LoRaMacMibSetRequestConfirm(&mibReq);
}



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

    BoardInitMcu( );
    BoardInitPeriph( );

    DeviceState = DEVICE_STATE_INIT;

    printf("ClassA app start\r\n");
    while( 1 )
    {
        switch( DeviceState )
        {
            case DEVICE_STATE_INIT:
            {
                LoRaMacPrimitives.MacMcpsConfirm = mcps_confirm;
                LoRaMacPrimitives.MacMcpsIndication = mcps_indication;
                LoRaMacPrimitives.MacMlmeConfirm = mlme_confirm;
                LoRaMacPrimitives.MacMlmeIndication = mlme_indication;
                LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
                LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, ACTIVE_REGION );

                TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent );

                #ifdef CONFIG_D2D
                lwan_classd_mcchannel_setup();
                #endif                  
                
                mibReq.Type = MIB_ADR;
                mibReq.Param.AdrEnable = LORAWAN_ADR_ON;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_PUBLIC_NETWORK;
                mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;
                LoRaMacMibSetRequestConfirm( &mibReq );
                
                lwan_dev_params_update();
                
                DeviceState = DEVICE_STATE_JOIN;
                break;
            }
            case DEVICE_STATE_JOIN:
            {
#if( OVER_THE_AIR_ACTIVATION != 0 )
                MlmeReq_t mlmeReq;

                // Initialize LoRaMac device unique ID
                //BoardGetUniqueId( DevEui );

                mlmeReq.Type = MLME_JOIN;

                mlmeReq.Req.Join.DevEui = DevEui;
                mlmeReq.Req.Join.AppEui = AppEui;
                mlmeReq.Req.Join.AppKey = AppKey;
                mlmeReq.Req.Join.NbTrials = 48;
                mlmeReq.Req.Join.Datarate = LORAWAN_DEFAULT_DATARATE;

                if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK )
                {
                    DeviceState = DEVICE_STATE_SLEEP;
                }
                else
                {
                    DeviceState = DEVICE_STATE_CYCLE;
                }
#else

                mibReq.Type = MIB_NET_ID;
                mibReq.Param.NetID = LORAWAN_NETWORK_ID;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_DEV_ADDR;
                mibReq.Param.DevAddr = DevAddr;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_NWK_SKEY;
                mibReq.Param.NwkSKey = NwkSKey;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_APP_SKEY;
                mibReq.Param.AppSKey = AppSKey;
                LoRaMacMibSetRequestConfirm( &mibReq );

                mibReq.Type = MIB_NETWORK_JOINED;
                mibReq.Param.IsNetworkJoined = true;
                LoRaMacMibSetRequestConfirm( &mibReq );

                DeviceState = DEVICE_STATE_SEND;
#endif
                break;
            }
            case DEVICE_STATE_SEND:
            {
                if( NextTx == true )
                {
                    PrepareTxFrame( AppPort );

                    NextTx = SendFrame( );
                }
                
                // Schedule next packet transmission
                TxDutyCycleTime = APP_TX_DUTYCYCLE + randr( 0, APP_TX_DUTYCYCLE_RND );
                DeviceState = DEVICE_STATE_CYCLE;
                break;
            }
            case DEVICE_STATE_SEND_MAC: {
                if (NextTx == true) {
                    AppDataSize = 0;
                    NextTx = 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:
            {
                #ifdef CONFIG_D2D
                if(LoRaMacClassDISCADDetecting() == false)
                #endif              
                {
                    // Wake up through events
                    TimerLowPowerHandler( );
                }
                // Process Radio IRQ
                Radio.IrqProcess( );
                break;
            }
            default:
            {
                DeviceState = DEVICE_STATE_INIT;
                break;
            }
        }
    }
}

By using ST Visual Develop software

Would be nice if a, you told me the version as requested and b, you’d used the code </> tool to format all that.

The version details will be in the included files but it’s clear it’s a 3+ year old version

If you can look at the LoRaMac.h file to get the version maybe we can figure what MAC commands it is supporting.

Capture

Lorawan Specification version is V1.0.2

The unnecessary screen shot shows the Mac header bit definition, not the version number …

Hi, version is 3.1

There are so many bug fixes since 3.1 it’s hard to know what to list!

Suffice to say, 3.2 fixed issues with decrypting MAC commands …

And the specs were still being written for 1.0 so I doubt it is v1.0.2