Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
MinimouseSrc/MacLayer.cpp
- Committer:
- fholin
- Date:
- 2017-12-15
- Revision:
- 0:2325d1d28df3
- Child:
- 1:eda561b01daf
File content as of revision 0:2325d1d28df3:
/* __ __ _ _ | \/ ( _) ( _) | \ / |_ _ __ _ _ __ ___ ___ _ _ ___ ___ | |\/| | | '_ \| | '_ ` _ \ / _ \| | | / __|/ _ \ | | | | | | | | | | | | | | ( _) | |_| \__ \ __/ |_| |_|_|_| |_|_|_| |_| |_|\___/ \__,_|___/\___| Description : LoraWan Mac Layer objets. License : Revised BSD License, see LICENSE.TXT file include in the project Maintainer : Fabien Holin ( SEMTECH) */ #include "MacLayer.h" #include "LoRaMacCrypto.h" #include "LoraWanProcess.h" #include "ApiRtc.h" #include "Define.h" #include "utilities.h" #include "ApiFlash.h" /*************************************************/ /* Constructors */ /*@note have to check init values */ /*************************************************/ LoraWanContainer::LoraWanContainer( PinName interrupt ) :Phy( interrupt ) { FcntUp = 0; Phy.RadioContainerInit( ); StateTimer = TIMERSTATE_SLEEP; FcntDwn = 0; AvailableRxPacketForUser = NOLORARXPACKETAVAILABLE; MacTxFrequency[0] = 868100000; MacTxFrequency[1] = 868300000; MacTxFrequency[2] = 868500000; NbOfActiveChannel = 3; MacTxSf = 7; MacTxPower = 14; MacRx1SfOffset = 0; MacRx2Frequency = 869525000; MacRx2Sf = 9; MacRx1Delay = RX1DELAY; JoinedStatus = 0 ; memcpy( appSKey, LoRaMacAppSKey, 16 ); memcpy( nwkSKey, LoRaMacNwkSKey, 16 ); DevAddr = 0x26011918; }; LoraWanContainer::~LoraWanContainer( ) { }; /***********************************************************************************************/ /* Public Methods */ /***********************************************************************************************/ //@note Partionning Public/private not yet finalized /**********************************************************************/ /* Called During LP.Process */ /**********************************************************************/ void LoraWanContainer::ConfigureRadioAndSend( void ) { GiveNextSf( ); uint8_t ChannelIndex = GiveNextChannel ( );//@note have to be completed Phy.DevAddrIsr = DevAddr ; //@note copy of the mac devaddr in order to filter it in the radio isr routine. Phy.TxFrequency = MacTxFrequency[ChannelIndex]; Phy.TxPower = MacTxPower; Phy.TxSf = MacTxSf; Phy.SetTxConfig( ); Phy.TxPayloadSize = MacPayloadSize; Phy.Send( ); }; void LoraWanContainer::ConfigureRadioForRx1 ( void ) { Phy.RxFrequency = Phy.TxFrequency; Phy.RxSf = Phy.TxSf + MacRx1SfOffset;//@note + sf offset Phy.SetRxConfig( ); }; void LoraWanContainer::ConfigureRadioForRx2 ( void ) { Phy.RxFrequency = MacRx2Frequency; Phy.RxSf = MacRx2Sf; Phy.SetRxConfig( ); }; void LoraWanContainer::ConfigureTimerForRx ( int type ) { int status = OKLORAWAN ; uint32_t tCurrentMillisec; uint32_t tAlarmMillisec; int toffset = 8; // @note created a Define? tCurrentMillisec = RtcGetTimeMs( ); if (type == RX1) { tAlarmMillisec = MacRx1Delay + Phy.TimestampRtcIsr - tCurrentMillisec - toffset ; if ( tAlarmMillisec <= toffset ) {// too late to launch a timer Phy.StateRadioProcess = RADIOSTATE_RX1FINISHED ; } else { SetAlarm( tAlarmMillisec ); } } else { tAlarmMillisec = MacRx1Delay + 1000 + Phy.TimestampRtcIsr - tCurrentMillisec ;// @note Rx2 Dalay is alway RX1DELAY + 1 second if ( tAlarmMillisec <= toffset ) {// too late to launch a timer Phy.StateRadioProcess = RADIOSTATE_IDLE ; } else { SetAlarm( tAlarmMillisec ); } } pcf.printf( " timer will expire in %d ms\n", tAlarmMillisec ); } /****************************/ /* DecodeRxFrame */ /****************************/ int LoraWanContainer::DecodeRxFrame( void ) { int status = OKLORAWAN ; uint32_t micIn ; status += CheckRxPayloadLength ( ); status += ExtractRxMhdr ( ) ; /************************************************************************/ /* Case : the receive packet is a JoinResponse */ /************************************************************************/ if ( MtypeRx == JOINACCEPT ) { LoRaMacJoinDecrypt( &Phy.RxPhyPayload[1], Phy.RxPhyPayloadSize-1, LoRaMacAppKey, &MacRxPayload[1] ); MacRxPayload[0] = Phy.RxPhyPayload[0]; MacRxPayloadSize = Phy.RxPhyPayloadSize - MICSIZE ; memcpy((uint8_t *)&micIn, &MacRxPayload[MacRxPayloadSize], MICSIZE); status += LoRaMacCheckJoinMic( MacRxPayload, MacRxPayloadSize, LoRaMacAppKey, micIn); if ( status == OKLORAWAN) { return JOINACCEPTPACKET; } } else { /************************************************************************/ /* Case : the receive packet is not a JoinResponse */ /************************************************************************/ uint16_t FcntDownTmp = 0; status += ExtractRxFhdr ( &FcntDownTmp) ; if ( status == OKLORAWAN) { MacRxPayloadSize = Phy.RxPhyPayloadSize - MICSIZE ; memcpy((uint8_t *)&micIn, &Phy.RxPhyPayload[MacRxPayloadSize], MICSIZE); status += LoRaMacCheckMic(&Phy.RxPhyPayload[0], MacRxPayloadSize, nwkSKey, DevAddr, FcntDownTmp, micIn ); // @note api discussion see at the end of this file } if ( status == OKLORAWAN) { status = AcceptFcntDwn ( FcntDownTmp ) ; } if ( status == OKLORAWAN) { MacRxPayloadSize = MacRxPayloadSize - FHDROFFSET - FoptsLength ; LoRaMacPayloadDecrypt( &Phy.RxPhyPayload[FHDROFFSET + FoptsLength], MacRxPayloadSize, (FportRx == 0 )?nwkSKey:appSKey, DevAddr, 1, FcntDwn, &MacRxPayload[0] ); pcf.printf( " MtypeRx = %d \n ",MtypeRx ); pcf.printf( " FcntDwn = %d \n ",FcntDwn ); } } if (status != OKLORAWAN ) { return ( NOVALIDRXPACKET ); } else if ( FportRx == 0 ) { return ( NWKRXPACKET ) ; } else { AvailableRxPacketForUser = LORARXPACKETAVAILABLE; //@note in this case fopts should be not equal to zero and so there are also management frame available + user data return ( USERRXPACKET ) ; } } /*********************************/ /* End of Decode Frame */ /*********************************/ /************************************************************************************************/ /* NWK MANAGEMENTS Methods */ /************************************************************************************************/ void LoraWanContainer::ParseManagementPacket( void ) { uint8_t CmdIdentifier; CmdIdentifier = MacRxPayload[0]; switch ( CmdIdentifier ) { case LINK_CHECK_ANS : LinkCheckParser( ); break; case LINK_ADR_REQ : LinkADRParser( ); break; case DUTY_CYCLE_REQ : DutyCycleParser( ); break; case RXPARRAM_SETUP_REQ : RXParamSetupParser( ); break; case DEV_STATUS_REQ : DevStatusParser( ); break; case NEW_CHANNEL_REQ : NewChannelParser( ); break; case RXTIMING_SETUP_REQ : RXTimingSetupParser( ); break; } } void LoraWanContainer::UpdateMacLayer ( void ) { FcntUp++; //@note case Retry not yet manage /*Store Context In ROM */ if (( FcntUp % FLASH_UPDATE_PERIOD ) == 0 ){ SaveInFlash ( ); } switch ( IsFrameToSend ) { case NOFRAME_TOSEND : break; case NWKFRAME_TOSEND : memcpy( &Phy.TxPhyPayload[FHDROFFSET], MacNwkAns, MacNwkAnsSize ); UserPayloadSize = MacNwkAnsSize; fPort = PORTNWK; MType = UNCONFDATAUP; //@note Mtype have to be confirm BuildTxLoraFrame( ); EncryptTxFrame( ); break; case USERACK_TOSEND : break; } } /**********************************************************************/ /* Special Case Join OTA */ /**********************************************************************/ void LoraWanContainer::UpdateJoinProcedure ( void ) { pcf.printf( " receive a Join Response \n"); uint8_t AppNonce[3]; memcpy( AppNonce, &MacRxPayload[1], 6); LoRaMacJoinComputeSKeys(LoRaMacAppKey, AppNonce, DevNonce, nwkSKey, appSKey ); DevAddr = MacRxPayload[7] + ( MacRxPayload[8] << 8 ) + ( MacRxPayload[9] << 16 )+ ( MacRxPayload[10] << 24 ); Phy.DevAddrIsr = DevAddr ; MacRx1SfOffset = ( MacRxPayload[11] & 0x70 ) >> 3 ; MacRx2Sf = ( MacRxPayload[11] & 0x0F ); MacRx1Delay = MacRxPayload[12] ; JoinedStatus = 1; //@note have to manage option byte for channel frequency planned } /**********************************************************************/ /* End Of Called During LP.Process */ /**********************************************************************/ /********************************************************/ /* Called During LP.Join() */ /********************************************************/ void LoraWanContainer::BuildJoinLoraFrame( void ) { DevNonce = randr( 0, 65535 ); MType = JOINREQUEST ; SetMacHeader ( ); for (int i = 0; i <8; i++){ Phy.TxPhyPayload[1+i] = AppEui[7-i]; Phy.TxPhyPayload[9+i] = DevEui[7-i]; } Phy.TxPhyPayload[17] = ( uint8_t )( ( DevNonce & 0x00FF ) ); Phy.TxPhyPayload[18] = ( uint8_t )( ( DevNonce & 0xFF00 ) >> 8 ); MacPayloadSize = 19 ; uint32_t mic ; LoRaMacJoinComputeMic( &Phy.TxPhyPayload[0], MacPayloadSize, LoRaMacAppKey, &mic ); memcpy(&Phy.TxPhyPayload[MacPayloadSize], (uint8_t *)&mic, 4); MacPayloadSize = MacPayloadSize + 4; } /********************************************************/ /* Called During LP.Send () */ /********************************************************/ void LoraWanContainer::BuildTxLoraFrame( void ) { Fctrl = 0; // @todo in V1.0 Adr isn't manage and ack is done by an empty packet Fctrl = ( AckBitForTx << 5 ); AckBitForTx = 0; SetMacHeader( ); SetFrameHeader( ); MacPayloadSize = UserPayloadSize+FHDROFFSET; }; void LoraWanContainer::EncryptTxFrame( void ) { LoRaMacPayloadEncrypt( &Phy.TxPhyPayload[FHDROFFSET], UserPayloadSize, appSKey, DevAddr, UP_LINK, FcntUp, &Phy.TxPhyPayload[FHDROFFSET] ); LoRaMacComputeAndAddMic( &Phy.TxPhyPayload[0], MacPayloadSize, nwkSKey, DevAddr, UP_LINK, FcntUp ); MacPayloadSize = MacPayloadSize + 4; }; /************************************************************************************************/ /* Private Methods */ /************************************************************************************************/ void LoraWanContainer::SetMacHeader( void ) { Phy.TxPhyPayload[0] = ( ( MType & 0x7 ) <<5 ) + ( MajorBits & 0x3 ); }; void LoraWanContainer::SetFrameHeader( ) { Phy.TxPhyPayload[1] = ( uint8_t )( ( DevAddr & 0x000000FF ) ); Phy.TxPhyPayload[2] = ( uint8_t )( ( DevAddr & 0x0000FF00 ) >> 8 ); Phy.TxPhyPayload[3] = ( uint8_t )( ( DevAddr & 0x00FF0000 ) >> 16 ); Phy.TxPhyPayload[4] = ( uint8_t )( ( DevAddr & 0xFF000000 ) >> 24 ); Phy.TxPhyPayload[5] = Fctrl; Phy.TxPhyPayload[6] = ( uint8_t )( ( FcntUp & 0x00FF ) ); Phy.TxPhyPayload[7] = ( uint8_t )( ( FcntUp & 0x00FF00 ) >> 8 ); Phy.TxPhyPayload[8] = fPort; } int LoraWanContainer::CheckRxPayloadLength ( void ) { int status = OKLORAWAN; if ( Phy.RxPhyPayloadSize < MINLORAWANPAYLOADSIZE ) { status = ERRORLORAWAN; return (status); } return (status); } int LoraWanContainer::ExtractRxMhdr ( void ) { int status = OKLORAWAN; MtypeRx = Phy.RxPhyPayload[0] >> 5 ; MajorRx = Phy.RxPhyPayload[0] & 0x3 ; if (( MtypeRx == JOINREQUEST) || ( MtypeRx == UNCONFDATAUP ) || ( MtypeRx == CONFDATAUP) || ( MtypeRx == REJOINREQUEST )) { status = ERRORLORAWAN; } AckBitForTx = ( MtypeRx == CONFDATADOWN ) ? 1 : 0 ; return (status); } int LoraWanContainer::ExtractRxFhdr ( uint16_t *FcntDwnTmp ) { //@note Not yet at all finalized have to initiate action on each field int status = OKLORAWAN; uint32_t DevAddrtmp = 0 ; DevAddrtmp = Phy.RxPhyPayload[1] + ( Phy.RxPhyPayload[2] << 8 ) + ( Phy.RxPhyPayload[3] << 16 )+ ( Phy.RxPhyPayload[4] << 24 ); status = (DevAddrtmp == DevAddr) ? OKLORAWAN : ERRORLORAWAN; FctrlRx = Phy.RxPhyPayload[5] ; *FcntDwnTmp = Phy.RxPhyPayload[6] + ( Phy.RxPhyPayload[7] << 8 ); FoptsLength = FctrlRx & 0x7; memcpy(&Fopts[0], &Phy.RxPhyPayload[8], FoptsLength); FportRx = Phy.RxPhyPayload[8+FoptsLength]; /**************************/ /* manage Fctrl Byte */ /**************************/ return (status); } int LoraWanContainer::AcceptFcntDwn ( uint16_t FcntDwnTmp ) { int status = OKLORAWAN; uint16_t FcntDwnLsb = ( FcntDwn & 0x0000FFFF ); uint16_t FcntDwnMsb = ( FcntDwn & 0xFFFF0000 ) >> 16; #ifdef CHECKFCNTDOWN if ( FcntDwnmtp > FcntDwnLsb ) { FcntDwn = FcntDwnTmp ; } else if ( ( FcntDwnLsb - FcntDwnmtp ) > MAX_FCNT_GAP ) ) { FcntDwn = ( ( FcntDwnMsb + 1 ) << 16 ) + FcntDwnTmp ; } else { status = ERRORLORAWAN ; } #else if ( ( FcntDwnLsb - FcntDwnTmp ) > MAX_FCNT_GAP ) { FcntDwn = ( ( FcntDwnMsb + 1 ) << 16 ) + FcntDwnTmp ; } else { FcntDwn = FcntDwnTmp ; } #endif return ( status ) ; } void LoraWanContainer::GiveNextSf( void ) { switch ( AdrModeSelect ) { case STATICADRMODE : MacTxSf = 7; break; case MOBILELONGRANGEADRMODE: if ( MacTxSf == 12 ) { MacTxSf = 7; } else { MacTxSf = 12; } break; case MOBILELOWPOWERADRMODE: ( MacTxSf == 12 ) ? MacTxSf = 7 : MacTxSf++ ; break; default: MacTxSf = 12; } MacTxSf = ( MacTxSf > 12 ) ? 12 : MacTxSf; MacTxSf = ( MacTxSf < 7 ) ? 7 : MacTxSf; } uint8_t LoraWanContainer::GiveNextChannel( void ) { return ( randr( 0, NbOfActiveChannel - 1 ) ); }; /************************************************************************************************/ /* Private NWK MANAGEMENTS Methods */ /************************************************************************************************/ void LoraWanContainer::LinkCheckParser( void ) { //@NOTE NOT YET IMPLEMENTED } /*****************************************************/ /* Private NWK MANAGEMENTS : LinkADR */ /*****************************************************/ void LoraWanContainer::LinkADRParser( void ) { int status = OKLORAWAN; uint8_t StatusAns = 0x7 ; // initilised for ans answer ok uint8_t temp ; uint16_t temp2 ; /* Valid DataRate And Prepare Ans */ temp = ( ( MacRxPayload[1] & 0xF0 ) >> 4 ); status = isValidDataRate( temp ); (status == OKLORAWAN ) ? MacTxPower = temp : StatusAns &= 0x5 ; /* Valid TxPower And Prepare Ans */ temp = ( MacRxPayload[1] & 0x0F ); status = OKLORAWAN; status = isValidTxPower( temp ); (status == OKLORAWAN ) ? MacTxPower = temp : StatusAns &= 0x5 ; /* Valid DataRate Channel Mask And Prepare Ans */ temp2 = MacRxPayload[2] + ( MacRxPayload[3] << 8 ) ; status = OKLORAWAN; status = isValidChannelMask( temp2 ); (status == OKLORAWAN ) ? MacChMask = temp2 : StatusAns &= 0x6 ; /* Valid Redundancy And Prepare Ans */ temp = MacRxPayload[4]; status = OKLORAWAN; status = isValidNbRep( temp ); (status == OKLORAWAN ) ? MacNbRepUnconfirmedTx = temp : StatusAns &= 0x3 ; /* Prepare Ans*/ MacNwkAns [0] = MacRxPayload[0] ; // copy Cid MacNwkAns [1] = StatusAns ; MacNwkAnsSize = 2 ; IsFrameToSend = NWKFRAME_TOSEND ; } void LoraWanContainer::DutyCycleParser( void ) { //@NOTE NOT YET IMPLEMENTED } /*****************************************************/ /* Private NWK MANAGEMENTS : RXParamSetupParser */ /*****************************************************/ void LoraWanContainer::RXParamSetupParser( void ) { //@note not valid case or error case have been yet implemented int status = OKLORAWAN; uint8_t StatusAns = 0x7 ; // initilised for ans answer ok int temp ; /* Valid Rx1SfOffset And Prepare Ans */ temp = ( MacRxPayload[1] & 0x70 ) >> 3 ; status = isValidRx1SfOffset( temp ); (status == OKLORAWAN ) ? MacRx1SfOffset = temp : StatusAns &= 0x6 ; /* Valid MacRx2Sf And Prepare Ans */ status = OKLORAWAN; temp = ( MacRxPayload[1] & 0x0F ); status = isValidMacRx2Sf( temp ); (status == OKLORAWAN ) ? MacRx2Sf = temp : StatusAns &= 0x5 ; /* Valid MacRx2Frequency And Prepare Ans */ status = OKLORAWAN; temp = ( MacRxPayload[2] ) + ( MacRxPayload[3] << 8 ) + ( MacRxPayload[4] << 16 ); status = isValidMacRx2Frequency( temp ); (status == OKLORAWAN ) ? MacRx2Frequency = temp : StatusAns &= 0x3 ; /* Prepare Ans*/ MacNwkAns [0] = MacRxPayload[0] ; // copy Cid MacNwkAns [1] = StatusAns ; MacNwkAnsSize = 2 ; IsFrameToSend = NWKFRAME_TOSEND ; } void LoraWanContainer::DevStatusParser( void ) { //@NOTE NOT YET IMPLEMENTED } void LoraWanContainer::NewChannelParser( void ) { //@NOTE NOT YET IMPLEMENTED } void LoraWanContainer::RXTimingSetupParser( void ) { //@NOTE NOT YET IMPLEMENTED } uint8_t LoraWanContainer::isValidRx1SfOffset ( uint8_t temp ) { // @note not yet implemented return ( OKLORAWAN ); } uint8_t LoraWanContainer::isValidMacRx2Sf ( uint8_t temp ) { // @note not yet implemented return ( OKLORAWAN ); } uint8_t LoraWanContainer::isValidMacRx2Frequency ( uint32_t temp ) { // @note not yet implemented return ( OKLORAWAN ); } uint8_t LoraWanContainer::isValidDataRate ( uint8_t temp ) { // @note not yet implemented return ( OKLORAWAN ); } uint8_t LoraWanContainer::isValidTxPower ( uint8_t temp ) { // @note not yet implemented return ( OKLORAWAN ); } uint8_t LoraWanContainer::isValidChannelMask ( uint16_t temp ) { // @note not yet implemented return ( OKLORAWAN ); } uint8_t LoraWanContainer::isValidNbRep ( uint8_t temp ) { // @note not yet implemented return ( OKLORAWAN ); } void LoraWanContainer::SaveInFlash ( ) { BackUpFlash.MacTxSf = MacTxSf; BackUpFlash.MacTxPower = MacTxPower; BackUpFlash.MacChMask = MacChMask; BackUpFlash.MacNbRepUnconfirmedTx = MacNbRepUnconfirmedTx; BackUpFlash.MacRx2Frequency = MacRx2Frequency; BackUpFlash.MacRx2Sf = MacRx2Sf; BackUpFlash.MacRx1SfOffset = MacRx1SfOffset; BackUpFlash.NbOfActiveChannel = NbOfActiveChannel; BackUpFlash.MacRx1Delay = MacRx1Delay; BackUpFlash.FcntUp = FcntUp; BackUpFlash.FcntDwn = FcntDwn; BackUpFlash.DevAddr = DevAddr; BackUpFlash.JoinedStatus = JoinedStatus; memcpy( &BackUpFlash.MacTxFrequency[0], &MacTxFrequency[0], 16); memcpy( &BackUpFlash.MacMinMaxSFChannel[0], &MacMinMaxSFChannel[0], 16); memcpy( &BackUpFlash.nwkSKey[0], &nwkSKey[0], 16); memcpy( &BackUpFlash.appSKey[0], &appSKey[0], 16); gFlash.program( &BackUpFlash, USERFLASHADRESS, sizeof(sBackUpFlash) ); } void LoraWanContainer::LoadFromFlash ( ) { gFlash.read((uint8_t *)(&BackUpFlash), USERFLASHADRESS, sizeof(sBackUpFlash)); BackUpFlash.FcntUp += FLASH_UPDATE_PERIOD; //@note automatic increment MacTxSf = BackUpFlash.MacTxSf; MacTxPower = BackUpFlash.MacTxPower; MacChMask = BackUpFlash.MacChMask ; MacNbRepUnconfirmedTx = BackUpFlash.MacNbRepUnconfirmedTx ; MacRx2Frequency = BackUpFlash.MacRx2Frequency ; MacRx2Sf = BackUpFlash.MacRx2Sf ; MacRx1SfOffset = BackUpFlash.MacRx1SfOffset; NbOfActiveChannel = BackUpFlash.NbOfActiveChannel; MacRx1Delay = BackUpFlash.MacRx1Delay ; FcntUp = BackUpFlash.FcntUp ; FcntDwn = BackUpFlash.FcntDwn ; DevAddr = BackUpFlash.DevAddr; JoinedStatus = BackUpFlash.JoinedStatus; memcpy( &MacTxFrequency[0], &BackUpFlash.MacTxFrequency[0], 16); memcpy( &MacMinMaxSFChannel[0], &BackUpFlash.MacMinMaxSFChannel[0], 16); memcpy( &nwkSKey[0], &BackUpFlash.nwkSKey[0], 16); memcpy( &appSKey[0], &BackUpFlash.appSKey[0], 16); gFlash.program( &BackUpFlash, USERFLASHADRESS, sizeof(sBackUpFlash) ); } /**************************************TIMER PART**********************************************************/ /**********************************************************************************************************/ /*@Note Probably to create a new directory or may be an timer Object to be discuss */ /************************************************************************************/ /* Rx1 Timer Isr Routine */ /* Called when Alarm expires */ /************************************************************************************/ void LoraWanContainer::SetAlarm (uint32_t alarmInMs) { TimerLora.attach_us(this, &LoraWanContainer::IsrTimerRx, alarmInMs * 1000); } void LoraWanContainer::IsrTimerRx( void ) { StateTimer = TIMERSTATE_SLEEP; Phy.Radio.Rx(0); //@note No More timeout FW on RX use only timeout impplement in the HW radio }; /****************************************API Crypto ***********************/ uint8_t LoraWanContainer::crypto_verifyMICandDecrypt( uint8_t *frame_header, const uint8_t *encrypted_payload ,uint32_t micIn, uint8_t keySet, uint8_t *decrypted_payload, uint8_t PayloadSize){ uint32_t DevAddrtmp = 0; uint16_t FcntDwnmtp = 0; int status = OKLORAWAN ; if ( keySet == UNICASTKEY) { DevAddrtmp = frame_header[1] + ( frame_header[2] << 8 ) + ( frame_header[3] << 16 )+ ( frame_header[4] << 24 ); FcntDwnmtp = frame_header[6] + ( frame_header[7] << 8 ); status += LoRaMacCheckMic(frame_header, PayloadSize, nwkSKey, DevAddrtmp, FcntDwnmtp, micIn ); //@note note sure that it is better to sen dheader because extract again devaddr fcntdwn fopts etc .... PayloadSize = PayloadSize - FHDROFFSET - FoptsLength ; if ( status == OKLORAWAN) { LoRaMacPayloadDecrypt( &Phy.RxPhyPayload[FHDROFFSET + FoptsLength], MacRxPayloadSize, (FportRx == 0 )?nwkSKey:appSKey, DevAddr, 1, FcntDwn, &MacRxPayload[0] ); } } }