void _init_loramac(semtech_loramac_t *mac, LoRaMacPrimitives_t * primitives, LoRaMacCallback_t *callbacks) { mutex_lock(&mac->lock); DEBUG("[semtech-loramac] initializing loramac\n"); primitives->MacMcpsConfirm = mcps_confirm; primitives->MacMcpsIndication = mcps_indication; primitives->MacMlmeConfirm = mlme_confirm; primitives->MacMlmeIndication = mlme_indication; LoRaMacInitialization(&semtech_loramac_radio_events, primitives, callbacks, LORAMAC_ACTIVE_REGION); #ifdef DISABLE_LORAMAC_DUTYCYCLE LoRaMacTestSetDutyCycleOn(false); #endif mutex_unlock(&mac->lock); semtech_loramac_set_dr(mac, LORAMAC_DEFAULT_DR); semtech_loramac_set_adr(mac, LORAMAC_DEFAULT_ADR); semtech_loramac_set_public_network(mac, LORAMAC_DEFAULT_PUBLIC_NETWORK); semtech_loramac_set_class(mac, LORAMAC_DEFAULT_DEVICE_CLASS); semtech_loramac_set_tx_port(mac, LORAMAC_DEFAULT_TX_PORT); semtech_loramac_set_tx_mode(mac, LORAMAC_DEFAULT_TX_MODE); semtech_loramac_set_system_max_rx_error(mac, LORAMAC_DEFAULT_SYSTEM_MAX_RX_ERROR); semtech_loramac_set_min_rx_symbols(mac, LORAMAC_DEFAULT_MIN_RX_SYMBOLS); mac->link_chk.available = false; #ifdef MODULE_PERIPH_EEPROM _read_loramac_config(mac); #endif }
void LoRaMacSetDutyCycleOn( bool enable ) { LoRaMacTestSetDutyCycleOn( enable ); }
/** * 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; } } } }
/*! * \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 ); }