void LoRaMacInitNwkIds( uint32_t netID, uint32_t devAddr, uint8_t *nwkSKey, uint8_t *appSKey ) { MibRequestConfirm_t mibSet; mibSet.Type = MIB_NET_ID; mibSet.Param.NetID = netID; LoRaMacMibSetRequestConfirm( &mibSet ); mibSet.Type = MIB_DEV_ADDR; mibSet.Param.DevAddr = devAddr; LoRaMacMibSetRequestConfirm( &mibSet ); mibSet.Type = MIB_NWK_SKEY; mibSet.Param.NwkSKey = nwkSKey; LoRaMacMibSetRequestConfirm( &mibSet ); mibSet.Type = MIB_APP_SKEY; mibSet.Param.AppSKey = appSKey; LoRaMacMibSetRequestConfirm( &mibSet ); mibSet.Type = MIB_NETWORK_JOINED; mibSet.Param.IsNetworkJoined = true; LoRaMacMibSetRequestConfirm( &mibSet ); }
static void _join_abp(semtech_loramac_t *mac) { DEBUG("[semtech-loramac] starting ABP join\n"); semtech_loramac_set_netid(mac, LORAMAC_DEFAULT_NETID); mutex_lock(&mac->lock); MibRequestConfirm_t mibReq; mibReq.Type = MIB_NETWORK_JOINED; mibReq.Param.IsNetworkJoined = false; LoRaMacMibSetRequestConfirm(&mibReq); mibReq.Type = MIB_DEV_ADDR; mibReq.Param.DevAddr = ((uint32_t)mac->devaddr[0] << 24 | (uint32_t)mac->devaddr[1] << 16 | (uint32_t)mac->devaddr[2] << 8 | (uint32_t)mac->devaddr[3]); LoRaMacMibSetRequestConfirm(&mibReq); mibReq.Type = MIB_NWK_SKEY; mibReq.Param.NwkSKey = mac->nwkskey; LoRaMacMibSetRequestConfirm(&mibReq); mibReq.Type = MIB_APP_SKEY; mibReq.Param.AppSKey = mac->appskey; LoRaMacMibSetRequestConfirm(&mibReq); mibReq.Type = MIB_NETWORK_JOINED; mibReq.Param.IsNetworkJoined = true; LoRaMacMibSetRequestConfirm(&mibReq); mutex_unlock(&mac->lock); }
void LoRaMacSetPublicNetwork( bool enable ) { MibRequestConfirm_t mibSet; mibSet.Type = MIB_PUBLIC_NETWORK; mibSet.Param.EnablePublicNetwork = enable; LoRaMacMibSetRequestConfirm( &mibSet ); }
void LoRaMacSetChannelsTxPower( int8_t txPower ) { MibRequestConfirm_t mibSet; mibSet.Type = MIB_CHANNELS_TX_POWER; mibSet.Param.ChannelsTxPower = txPower; LoRaMacMibSetRequestConfirm( &mibSet ); }
void LoRaMacSetJoinAcceptDelay2( uint32_t delay ) { MibRequestConfirm_t mibSet; mibSet.Type = MIB_JOIN_ACCEPT_DELAY_2; mibSet.Param.JoinAcceptDelay2 = delay; LoRaMacMibSetRequestConfirm( &mibSet ); }
void LoRaMacSetChannelsDatarate( int8_t datarate ) { MibRequestConfirm_t mibSet; mibSet.Type = MIB_CHANNELS_DATARATE; mibSet.Param.ChannelsDatarate = datarate; LoRaMacMibSetRequestConfirm( &mibSet ); }
void LoRaMacSetMaxRxWindow( uint32_t delay ) { MibRequestConfirm_t mibSet; mibSet.Type = MIB_MAX_RX_WINDOW_DURATION; mibSet.Param.MaxRxWindow = delay; LoRaMacMibSetRequestConfirm( &mibSet ); }
void LoRaMacSetReceiveDelay2( uint32_t delay ) { MibRequestConfirm_t mibSet; mibSet.Type = MIB_RECEIVE_DELAY_2; mibSet.Param.ReceiveDelay2 = delay; LoRaMacMibSetRequestConfirm( &mibSet ); }
void LoRaMacSetChannelsMask( uint16_t *mask ) { MibRequestConfirm_t mibSet; mibSet.Type = MIB_CHANNELS_MASK; mibSet.Param.ChannelsMask = mask; LoRaMacMibSetRequestConfirm( &mibSet ); }
void LoRaMacSetChannelsNbRep( uint8_t nbRep ) { MibRequestConfirm_t mibSet; mibSet.Type = MIB_CHANNELS_NB_REP; mibSet.Param.ChannelNbRep = nbRep; LoRaMacMibSetRequestConfirm( &mibSet ); }
void LoRaMacSetDeviceClass( DeviceClass_t deviceClass ) { MibRequestConfirm_t mibSet; mibSet.Type = MIB_DEVICE_CLASS; mibSet.Param.Class = deviceClass; LoRaMacMibSetRequestConfirm( &mibSet ); }
void LoRaMacSetRx2Channel( Rx2ChannelParams_t param ) { MibRequestConfirm_t mibSet; mibSet.Type = MIB_RX2_CHANNEL; mibSet.Param.Rx2Channel = param; LoRaMacMibSetRequestConfirm( &mibSet ); }
void LoRaMacSetAdrOn( bool enable ) { MibRequestConfirm_t mibSet; mibSet.Type = MIB_ADR; mibSet.Param.AdrEnable = enable; LoRaMacMibSetRequestConfirm( &mibSet ); }
static void _join_otaa(semtech_loramac_t *mac) { DEBUG("[semtech-loramac] starting OTAA join\n"); uint8_t dr = semtech_loramac_get_dr(mac); mutex_lock(&mac->lock); MibRequestConfirm_t mibReq; mibReq.Type = MIB_NETWORK_JOINED; mibReq.Param.IsNetworkJoined = false; LoRaMacMibSetRequestConfirm(&mibReq); MlmeReq_t mlmeReq; mlmeReq.Type = MLME_JOIN; mlmeReq.Req.Join.DevEui = mac->deveui; mlmeReq.Req.Join.AppEui = mac->appeui; mlmeReq.Req.Join.AppKey = mac->appkey; mlmeReq.Req.Join.Datarate = dr; mutex_unlock(&mac->lock); uint8_t ret = LoRaMacMlmeRequest(&mlmeReq); switch(ret) { case LORAMAC_STATUS_OK: /* Let the MAC do his job */ return; case LORAMAC_STATUS_DUTYCYCLE_RESTRICTED: { DEBUG("[semtech-loramac] join otaa: duty cycle restricted\n"); /* Cannot join. */ msg_t msg; msg.type = MSG_TYPE_LORAMAC_JOIN; msg.content.value = SEMTECH_LORAMAC_DUTYCYCLE_RESTRICTED; msg_send(&msg, semtech_loramac_pid); return; } case LORAMAC_STATUS_BUSY: { DEBUG("[semtech-loramac] join otaa: mac is busy\n"); /* Cannot join. */ msg_t msg; msg.type = MSG_TYPE_LORAMAC_JOIN; msg.content.value = SEMTECH_LORAMAC_BUSY; msg_send(&msg, semtech_loramac_pid); return; } default: { DEBUG("[semtech-loramac] join otaa: failed with status %d\n", ret); /* Cannot join. */ msg_t msg; msg.type = MSG_TYPE_LORAMAC_JOIN; msg.content.value = SEMTECH_LORAMAC_JOIN_FAILED; msg_send(&msg, semtech_loramac_pid); return; } } }
static inline void _set_uplink_counter(semtech_loramac_t *mac, uint8_t *counter) { uint32_t counter4 = ((uint32_t)counter[0] << 24 | (uint32_t)counter[1] << 16 | (uint32_t)counter[2] << 8 | counter[3]); DEBUG("[semtech-loramac] uplink counter: %" PRIu32 " \n", counter4); mutex_lock(&mac->lock); MibRequestConfirm_t mibReq; mibReq.Type = MIB_UPLINK_COUNTER; mibReq.Param.UpLinkCounter = counter4; LoRaMacMibSetRequestConfirm(&mibReq); mutex_unlock(&mac->lock); }
/*! * \brief MCPS-Indication event function * * \param [IN] mcpsIndication - Pointer to the indication structure, * containing indication attributes. */ static void McpsIndication( McpsIndication_t *mcpsIndication ) { if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK ) { return; } switch( mcpsIndication->McpsIndication ) { case MCPS_UNCONFIRMED: { break; } case MCPS_CONFIRMED: { break; } case MCPS_PROPRIETARY: { break; } case MCPS_MULTICAST: { break; } default: break; } // Check Multicast // Check Port // Check Datarate // Check FramePending 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( 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; } 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; AppDataSizeBackup = AppDataSize; AppDataSize = 2; ComplianceTest.DownLinkCounter = 0; ComplianceTest.LinkCheck = false; ComplianceTest.DemodMargin = 0; ComplianceTest.NbGateways = 0; ComplianceTest.Running = true; ComplianceTest.State = 1; MibRequestConfirm_t mibReq; mibReq.Type = MIB_ADR; mibReq.Param.AdrEnable = true; LoRaMacMibSetRequestConfirm( &mibReq ); #if defined( REGION_EU868 ) 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 = AppDataSizeBackup; ComplianceTest.DownLinkCounter = 0; ComplianceTest.Running = false; MibRequestConfirm_t mibReq; mibReq.Type = MIB_ADR; mibReq.Param.AdrEnable = LORAWAN_ADR_ON; LoRaMacMibSetRequestConfirm( &mibReq ); #if defined( REGION_EU868 ) 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 < MIN( AppDataSize, LORAWAN_APP_DATA_MAX_SIZE ); 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 = AppDataSizeBackup; ComplianceTest.DownLinkCounter = 0; ComplianceTest.Running = false; MibRequestConfirm_t mibReq; mibReq.Type = MIB_ADR; mibReq.Param.AdrEnable = LORAWAN_ADR_ON; LoRaMacMibSetRequestConfirm( &mibReq ); #if defined( REGION_EU868 ) 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.Datarate = LORAWAN_DEFAULT_DATARATE; if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK ) { DeviceState = DEVICE_STATE_SLEEP; } else { DeviceState = DEVICE_STATE_CYCLE; } } 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; } break; default: break; } } break; default: break; } } // Switch LED 2 ON for each received downlink GpioWrite( &Led2, 1 ); TimerStart( &Led2Timer ); }
int main( void ) { HAL_EnableDBGStopMode(); LowPowerConfiguration(); pc.baud(115200); // print banner pc.printf("\r\n============== DEBUG STARTED ==============\r\n"); /** User button triggers the ultrasonic sensor */ //PinDetect button(PC_13,PullUp); //button.attach_asserted(&sensor, &UltraSonic::triggerSample); // callback routine to trigger usonic //button.setSampleFrequency(); LoRaMacPrimitives_t LoRaMacPrimitives; LoRaMacCallback_t LoRaMacCallbacks; MibRequestConfirm_t mibReq; //BoardInitMcu( ); //BoardInitPeriph( ); BoardInit( ); TimerInit( &mainLoopTimeout, onMainLoopTimeoutEvent ); DeviceState = DEVICE_STATE_INIT; while( 1 ) { wait(0.5); // This is a kind of watchdog on the main loop, if the timer isn't cancelled in x seconds then loop will enter INIT state TimerSetValue( &mainLoopTimeout, 3000000 ); TimerStart( &mainLoopTimeout ); switch( DeviceState ) { case DEVICE_STATE_INIT: { pc.printf("DEVICE_STATE_INIT\r\n"); LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm; LoRaMacPrimitives.MacMcpsIndication = McpsIndication; LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm; LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel; LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks ); TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent ); TimerInit( &ultrasonicTimer, OnUltrasonicTimeout ); mibReq.Type = MIB_ADR; mibReq.Param.AdrEnable = LORAWAN_ADR_ON; LoRaMacMibSetRequestConfirm( &mibReq ); // MAC information base service to set attributes of LoRaMac layer mibReq.Type = MIB_PUBLIC_NETWORK; mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK; LoRaMacMibSetRequestConfirm( &mibReq ); sensor.distanceAvailable = false; // Ensure initialised to false after power up DeviceState = DEVICE_STATE_JOIN; break; } case DEVICE_STATE_JOIN: { pc.printf("DEVICE_STATE_JOIN\r\n"); #if( OVER_THE_AIR_ACTIVATION != 0 ) pc.printf("OTA\r\n"); MlmeReq_t mlmeReq; // Initialize LoRaMac device unique ID //BoardGetUniqueId( DevEui ); mlmeReq.Type = MLME_JOIN; // MAC management service types are MLME_JOIN or MLME_LINK_CHECK mlmeReq.Req.Join.DevEui = DevEui; mlmeReq.Req.Join.AppEui = AppEui; mlmeReq.Req.Join.AppKey = AppKey; if( NextTx == true ) { LoRaMacMlmeRequest( &mlmeReq ); // Sends a join request } // Schedule next packet transmission //TxDutyCycleTime = OVER_THE_AIR_ACTIVATION_DUTYCYCLE; //DeviceState = DEVICE_STATE_CYCLE; DeviceState = DEVICE_STATE_CYCLE; #else pc.printf("ABP\r\n"); // Choose a random device address if not already defined in Comissioning.h if( DevAddr == 0 ) { // Random seed initialization // srand1( BoardGetRandomSeed( ) ); // Choose a random device address DevAddr = randr( 0, 0x01FFFFFF ); } mibReq.Type = MIB_NET_ID; mibReq.Param.NetID = LORAWAN_NETWORK_ID; LoRaMacMibSetRequestConfirm( &mibReq ); mibReq.Type = MIB_DEV_ADDR; mibReq.Param.DevAddr = DevAddr; LoRaMacMibSetRequestConfirm( &mibReq ); mibReq.Type = MIB_NWK_SKEY; mibReq.Param.NwkSKey = NwkSKey; LoRaMacMibSetRequestConfirm( &mibReq ); mibReq.Type = MIB_APP_SKEY; mibReq.Param.AppSKey = AppSKey; LoRaMacMibSetRequestConfirm( &mibReq ); mibReq.Type = MIB_NETWORK_JOINED; mibReq.Param.IsNetworkJoined = true; LoRaMacMibSetRequestConfirm( &mibReq ); DeviceState = DEVICE_STATE_SEND; #endif break; } case DEVICE_STATE_SEND: { pc.printf("DEVICE_STATE_SEND\r\n"); if( NextTx == true ) { pc.printf("Sending\r\n"); PrepareTxFrame( AppPort ); NextTx = SendFrame( ); } } case DEVICE_STATE_CYCLE: { pc.printf("DEVICE_STATE_CYCLE\r\n"); pc.printf("SensorState = %d, distanceAvailable = ",SensorState); if (sensor.distanceAvailable) pc.printf("true\r\n"); else pc.printf("false\r\n"); pc.printf("LoRaMacState = %d\r\n",GetMacStatus()); if ((SensorState == SENT) || (SensorState == INIT)) { /** Range and Temperature readings have been sent so we can sleep */ TimerStop( &TxNextPacketTimer ); // Wait for MAC state to become idle before deep sleeping if (GetMacStatus() == 0) { // Ensure MAC state is idle before sleeping pc.printf("DeepSleep ..zzz.\r\n"); TimerStop(&mainLoopTimeout); // cancel main loop guard timeout WakeUp::set(DEEPSLEEP_SECONDS); // Set RTC alarm to wake up from deep sleep LowPowerPrep(); deepsleep(); // Deep sleep until wake up alarm from RTC LowPowerRestore(); SensorState = TRIGGERED; /* Trigger ultrasonic sensor and start sensor read failure timer */ sensor.triggerSample(); // Get Ultrasonic reading TimerSetValue( &ultrasonicTimer, 2000000 ); // 2s timeout TimerStart( &ultrasonicTimer ); DeviceState = DEVICE_STATE_SLEEP; // Cycle in sleep until sensor readings ready } else { // Cycle around until MAC state is idle DeviceState = DEVICE_STATE_CYCLE; } } else { // Error shouldn't get here pc.printf("Error State!!\r\n"); //TimerSetValue( &TxNextPacketTimer, TxDutyCycleTime ); //TimerStart( &TxNextPacketTimer ); SensorState = INIT; DeviceState = DEVICE_STATE_SLEEP; } break; } case DEVICE_STATE_SLEEP: { pc.printf("DEVICE_STATE_SLEEP\r\n"); // Loop until sensor ready if ((SensorState == TRIGGERED) && (sensor.distanceAvailable)) { pc.printf("Xmit Reading..!\r\n"); TimerStop( &ultrasonicTimer ); // stop the sensor failure timer SensorState = SENDING; TimerSetValue( &TxNextPacketTimer, 10 ); // Schedule immediate transmission TimerStart( &TxNextPacketTimer ); } break; } default: { DeviceState = DEVICE_STATE_INIT; break; } } } }
/** * Main application entry point. */ int main( void ) { LoRaMacPrimitives_t LoRaMacPrimitives; LoRaMacCallback_t LoRaMacCallbacks; MibRequestConfirm_t mibReq; BoardInitMcu( ); BoardInitPeriph( ); DeviceState = DEVICE_STATE_INIT; while( 1 ) { switch( DeviceState ) { case DEVICE_STATE_INIT: { LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm; LoRaMacPrimitives.MacMcpsIndication = McpsIndication; LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm; LoRaMacPrimitives.MacMlmeIndication = MlmeIndication; LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel; LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, ACTIVE_REGION ); 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 ); mibReq.Type = MIB_PUBLIC_NETWORK; mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK; LoRaMacMibSetRequestConfirm( &mibReq ); #if defined( REGION_EU868 ) LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON ); #endif mibReq.Type = MIB_DEVICE_CLASS; mibReq.Param.Class = CLASS_C; LoRaMacMibSetRequestConfirm( &mibReq ); 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.Datarate = LORAWAN_DEFAULT_DATARATE; if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK ) { DeviceState = DEVICE_STATE_SLEEP; } else { DeviceState = DEVICE_STATE_CYCLE; } #else // Choose a random device address if not already defined in Commissioning.h if( DevAddr == 0 ) { // Random seed initialization srand1( BoardGetRandomSeed( ) ); // Choose a random device address DevAddr = randr( 0, 0x01FFFFFF ); } mibReq.Type = MIB_NET_ID; mibReq.Param.NetID = LORAWAN_NETWORK_ID; LoRaMacMibSetRequestConfirm( &mibReq ); mibReq.Type = MIB_DEV_ADDR; mibReq.Param.DevAddr = DevAddr; LoRaMacMibSetRequestConfirm( &mibReq ); mibReq.Type = MIB_NWK_SKEY; mibReq.Param.NwkSKey = NwkSKey; LoRaMacMibSetRequestConfirm( &mibReq ); mibReq.Type = MIB_APP_SKEY; mibReq.Param.AppSKey = AppSKey; LoRaMacMibSetRequestConfirm( &mibReq ); mibReq.Type = MIB_NETWORK_JOINED; mibReq.Param.IsNetworkJoined = true; LoRaMacMibSetRequestConfirm( &mibReq ); DeviceState = DEVICE_STATE_SEND; #endif break; } case DEVICE_STATE_SEND: { if( NextTx == true ) { 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; break; } case DEVICE_STATE_CYCLE: { DeviceState = DEVICE_STATE_SLEEP; // Schedule next packet transmission TimerSetValue( &TxNextPacketTimer, TxDutyCycleTime ); TimerStart( &TxNextPacketTimer ); break; } case DEVICE_STATE_SLEEP: { // Wake up through events TimerLowPowerHandler( ); // Process Radio IRQ Radio.IrqProcess( ); break; } default: { DeviceState = DEVICE_STATE_INIT; break; } } } }