LoRaWAN end device MAC layer for SX1272 and SX1276. Supports LoRaWAN-1.0 and LoRaWAN-1.1

Dependencies:   sx12xx_hal

Dependents:   LoRaWAN-SanJose_Bootcamp LoRaWAN-grove-cayenne LoRaWAN-classC-demo LoRaWAN-grove-cayenne ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LoRaMac1v1.cpp Source File

LoRaMac1v1.cpp

00001 
00002 #include "LoRaMacPrivate.h"
00003 #include "LoRaMacCrypto.h"
00004 
00005 //#define ADR_ACK_LIMIT                               64
00006 //#define ADR_ACK_DELAY                               32
00007 #define LORA_MAC_FRMPAYLOAD_OVERHEAD                13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4)
00008 #define RECEIVE_DELAY1_us                           1000000
00009 #define LORAMAC_MFR_LEN                             4
00010 
00011 /*!
00012  * LoRaMAC Battery level indicator
00013  */
00014 typedef enum eLoRaMacBatteryLevel
00015 {
00016     /*!
00017      * External power source
00018      */
00019     BAT_LEVEL_EXT_SRC                = 0x00,
00020     /*!
00021      * Battery level empty
00022      */
00023     BAT_LEVEL_EMPTY                  = 0x01,
00024     /*!
00025      * Battery level full
00026      */
00027     BAT_LEVEL_FULL                   = 0xFE,
00028     /*!
00029      * Battery level - no measurement available
00030      */
00031     BAT_LEVEL_NO_MEASURE             = 0xFF,
00032 }LoRaMacBatteryLevel_t;
00033 
00034 /*!
00035  * LoRaMac internal state
00036  */
00037 flags_t flags;
00038 
00039 void (*function_pending)(void); // one-shot
00040 
00041 /*!
00042  * Current channel index
00043  */
00044 uint8_t Channel;
00045 
00046 static MlmeIndication_t MlmeIndication;
00047 static MlmeConfirm_t MlmeConfirm;
00048 static McpsIndication_t McpsIndication;
00049 static McpsConfirm_t McpsConfirm;
00050 
00051 uint32_t LoRaMacDevAddr;
00052 uint32_t LoRaMacNetID;
00053 static skey_t keys;
00054 
00055 uint8_t MacCommandsBufferToRepeatIndex;
00056 uint8_t MacCommandsBufferIndex;
00057 uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH];
00058 static uint8_t MacCommandsBufferToRepeat[LORA_MAC_COMMAND_MAX_LENGTH];
00059 
00060 LoRaMacParams_t  LoRaMacParams;
00061 
00062 #ifdef LORAWAN_JOIN_EUI
00063     static const uint8_t *LoRaMacDevEui;
00064     static const uint8_t *LoRaMacJoinEui;
00065     static const uint8_t *RootNwkKey;
00066     static const uint8_t *RootAppKey;
00067     static uint8_t MaxJoinRequestTrials;
00068     static uint8_t JSEncKey[16]; // TODO move to keys
00069     static uint8_t JSIntKey[16]; // TODO move to keys
00070     static uint8_t JoinReqType;
00071     static uint16_t LoRaMacDevNonce;
00072     uint16_t RJcount0;
00073 
00074     static uint32_t FCntUp;
00075     static uint32_t NFCntDown;  /**< set to next expected value */
00076     static uint32_t AFCntDown;  /**< set to next expected value */
00077 #endif /* LORAWAN_JOIN_EUI  */
00078 
00079 static uint16_t ADR_ACK_LIMIT;
00080 static uint16_t ADR_ACK_DELAY;
00081 
00082 DeviceClass_t LoRaMacDeviceClass;
00083 uint8_t tx_buf_len;
00084 const LoRaMacHeader_t * uplinkMHDR = (LoRaMacHeader_t *)&Radio::radio.tx_buf[0];
00085 
00086 static uint32_t RxWindow1Delay_us;
00087 static uint32_t RxWindow2Delay_us;
00088 
00089 LoRaMacHeader_t  last_up_macHdr;
00090 static uint8_t rxFRMPayload[244];
00091 
00092 static const LoRaMacPrimitives_t  *LoRaMacPrimitives;
00093 static const LoRaMacCallback_t *LoRaMacCallbacks;
00094 
00095 /*!
00096  * LoRaMAC frame counter. Each time a packet is received the counter is incremented.
00097  * Only the 16 LSB bits are received
00098  */
00099 static uint16_t ConfFCntDown;
00100 static uint16_t ConfFCntUp;
00101 
00102 static void PrepareRxDoneAbort(LoRaMacEventInfoStatus_t);
00103 
00104 void OnRadioRxTimeout(void);
00105 
00106 LoRaMacStatus_t
00107 AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 )
00108 {
00109     LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
00110     // The maximum buffer length must take MAC commands to re-send into account.
00111     uint8_t bufLen = LORA_MAC_COMMAND_MAX_LENGTH - MacCommandsBufferToRepeatIndex;
00112 
00113     MAC_PRINTF("AddMacCommand(%02x, %02x, %02x)\r\n", cmd, p1, p2);
00114     switch( cmd )
00115     {
00116         case MOTE_MAC_LINK_CHECK_REQ:
00117         case MOTE_MAC_DEVICE_TIME_REQ:
00118             if( MacCommandsBufferIndex < bufLen )
00119             {
00120                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
00121                 // No payload for this command
00122                 status = LORAMAC_STATUS_OK;
00123             }
00124             break;
00125         case MOTE_MAC_LINK_ADR_ANS:
00126             if( MacCommandsBufferIndex < ( bufLen - 1 ) )
00127             {
00128                 MAC_PRINTF("LINK_ADR_ANS %02x ", p1);
00129                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
00130                 // Margin
00131                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
00132                 status = LORAMAC_STATUS_OK;
00133             }
00134             break;
00135         case MOTE_MAC_DUTY_CYCLE_ANS:
00136             if( MacCommandsBufferIndex < bufLen )
00137             {
00138                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
00139                 // No payload for this answer
00140                 status = LORAMAC_STATUS_OK;
00141             }
00142             break;
00143         case MOTE_MAC_RX_PARAM_SETUP_ANS:
00144             if( MacCommandsBufferIndex < ( bufLen - 1 ) )
00145             {
00146                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
00147                 // Status: Datarate ACK, Channel ACK
00148                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
00149                 status = LORAMAC_STATUS_OK;
00150             }
00151             break;
00152         case MOTE_MAC_DEV_STATUS_ANS:
00153             if( MacCommandsBufferIndex < ( bufLen - 2 ) )
00154             {
00155                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
00156                 // 1st byte Battery
00157                 // 2nd byte Margin
00158                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
00159                 MacCommandsBuffer[MacCommandsBufferIndex++] = p2;
00160                 status = LORAMAC_STATUS_OK;
00161             }
00162             break;
00163         case MOTE_MAC_NEW_CHANNEL_ANS:
00164             if( MacCommandsBufferIndex < ( bufLen - 1 ) )
00165             {
00166                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
00167                 // Status: Datarate range OK, Channel frequency OK
00168                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
00169                 status = LORAMAC_STATUS_OK;
00170             }
00171             break;
00172         case MOTE_MAC_RX_TIMING_SETUP_ANS:
00173             if( MacCommandsBufferIndex < bufLen )
00174             {
00175                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
00176                 // No payload for this answer
00177                 status = LORAMAC_STATUS_OK;
00178             }
00179             break;
00180 #ifdef LORAWAN_JOIN_EUI
00181         case MOTE_MAC_REKEY_IND:
00182             if( MacCommandsBufferIndex < bufLen-1 )
00183             {
00184                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
00185                 // minor version:
00186                 if (RootAppKey == NULL)
00187                     MacCommandsBuffer[MacCommandsBufferIndex++] = 0;    // lorawan1v0
00188                 else
00189                     MacCommandsBuffer[MacCommandsBufferIndex++] = 1;    // lorawan1v1
00190 
00191                 status = LORAMAC_STATUS_OK;
00192             }
00193             break;
00194         case MOTE_MAC_REJOIN_PARAM_ANS:
00195             if( MacCommandsBufferIndex < bufLen-1 )
00196             {
00197                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
00198                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
00199                 status = LORAMAC_STATUS_OK;
00200             }
00201             break;
00202 #else
00203         case MOTE_MAC_RESET_IND:
00204             if( MacCommandsBufferIndex < bufLen-1 )
00205             {
00206                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
00207                 // minor version:
00208                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
00209                 status = LORAMAC_STATUS_OK;
00210             }
00211             break;
00212 #endif /* !LORAWAN_JOIN_EUI  */
00213         case MOTE_MAC_MODE_IND:
00214             if( MacCommandsBufferIndex < bufLen-1 )
00215             {
00216                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
00217                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
00218                 status = LORAMAC_STATUS_OK;
00219             }
00220             break;
00221         default:
00222             MAC_PRINTF("unknown-addCmd %02x\r\n", cmd);
00223             return LORAMAC_STATUS_SERVICE_UNKNOWN;
00224     } // ..switch( cmd )
00225 
00226     if( status == LORAMAC_STATUS_OK )
00227     {
00228         flags.MacCommandsInNextTx = true;
00229     }
00230     return status;
00231 } // ..AddMacCommand()
00232 
00233 
00234 LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout )
00235 {
00236     int8_t txPowerIndex = 0;
00237     int8_t txPower = 0;
00238 
00239     txPowerIndex = region_LimitTxPower( LoRaMacParams.ChannelsTxPower  );
00240     txPower = TxPowers[txPowerIndex];
00241 
00242     Radio::SetTxContinuousWave( Channels[Channel].FreqHz, txPower, timeout );
00243 
00244     flags.uplink_in_progress = 1;
00245 
00246     return LORAMAC_STATUS_OK;
00247 }
00248 
00249 __attribute__((weak)) LoRaMacStatus_t
00250 LoRaMacMlmeRequestClassB( const MlmeReq_t *mlmeRequest )
00251 {
00252     return LORAMAC_STATUS_SERVICE_UNKNOWN;
00253 }
00254 
00255 __attribute__((weak)) LoRaMacStatus_t
00256 AddMacCommandClassB( uint8_t cmd, uint8_t p1, uint8_t p2 )
00257 {
00258     return LORAMAC_STATUS_SERVICE_UNKNOWN;
00259 }
00260 
00261 __attribute__((weak)) void
00262 ResetMacParametersClassB()
00263 {
00264 }
00265 
00266 static void ResetMacParameters( void )
00267 {
00268 #ifdef LORAWAN_JOIN_EUI
00269     flags.IsLoRaMacNetworkJoined = 0;
00270     NFCntDown = 0;
00271     AFCntDown = 0;
00272 #endif /* LORAWAN_JOIN_EUI  */
00273 
00274 #ifdef DUTY_ENABLE
00275     DutyInit();
00276 #endif /* DUTY_ENABLE */
00277 
00278     MacCommandsBufferIndex = 0;
00279     MacCommandsBufferToRepeatIndex = 0;
00280 
00281     //IsRxWindowsEnabled = true;
00282 
00283     LoRaMacParams.ChannelsTxPower  = LoRaMacParamsDefaults.ChannelsTxPower ;
00284     LoRaMacParams.ChannelsDatarate  = LoRaMacParamsDefaults.ChannelsDatarate ;
00285 
00286     LoRaMacParams.MaxRxWindow_us  = LoRaMacParamsDefaults.MaxRxWindow_us ;
00287     LoRaMacParams.ReceiveDelay1_us  = LoRaMacParamsDefaults.ReceiveDelay1_us ;
00288     LoRaMacParams.ReceiveDelay2_us  = LoRaMacParamsDefaults.ReceiveDelay2_us ;
00289 #ifdef LORAWAN_JOIN_EUI
00290     LoRaMacParams.JoinAcceptDelay1_us  = LoRaMacParamsDefaults.JoinAcceptDelay1_us ;
00291     LoRaMacParams.JoinAcceptDelay2_us  = LoRaMacParamsDefaults.JoinAcceptDelay2_us ;
00292 #endif /* LORAWAN_JOIN_EUI */
00293 
00294     LoRaMacParams.Rx1DrOffset  = LoRaMacParamsDefaults.Rx1DrOffset ;
00295     LoRaMacParams.NbTrans  = LoRaMacParamsDefaults.NbTrans ;
00296 
00297     LoRaMacParams.Rx2Channel  = LoRaMacParamsDefaults.Rx2Channel ;
00298 
00299     memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask , ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask , sizeof( LoRaMacParams.ChannelsMask  ) );
00300     LoRaMacParams.NbEnabledChannels = LoRaMacParamsDefaults.NbEnabledChannels;
00301 
00302 #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
00303     memcpy( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask , sizeof( LoRaMacParams.ChannelsMask  ) );
00304 #endif
00305 
00306     LoRaMacParams.MaxListenTime = LoRaMacParamsDefaults.MaxListenTime;
00307 
00308 
00309     flags.SrvAckRequested = false;
00310     flags.MacCommandsInNextTx = false;
00311 
00312     // Initialize channel index.
00313     Channel = LORA_MAX_NB_CHANNELS;
00314 
00315     ResetMacParametersClassB();
00316 
00317 } // ..ResetMacParameters()
00318 
00319 static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen )
00320 {
00321     uint16_t maxN = 0;
00322     uint8_t payloadSize;
00323 
00324     // Get the maximum payload length
00325     maxN = MaxPayloadOfDatarate[datarate];
00326 
00327     // Calculate the resulting payload size
00328     payloadSize = ( lenN + fOptsLen );
00329 
00330     // Validation of the application payload size
00331     if( payloadSize <= maxN )
00332     {
00333         return true;
00334     }
00335     return false;
00336 }
00337 
00338 static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut )
00339 {
00340     uint8_t i = 0;
00341     uint8_t cmdCount = 0;
00342 
00343     if( ( cmdBufIn == NULL ) || ( cmdBufOut == NULL ) )
00344     {
00345         return 0;
00346     }
00347 
00348     for( i = 0; i < length; i++ )
00349     {
00350         switch( cmdBufIn[i] )
00351         {
00352             // STICKY
00353             case MOTE_MAC_RX_PARAM_SETUP_ANS:
00354             {
00355                 cmdBufOut[cmdCount++] = cmdBufIn[i++];
00356                 cmdBufOut[cmdCount++] = cmdBufIn[i];
00357                 break;
00358             }
00359             case MOTE_MAC_RX_TIMING_SETUP_ANS:
00360             {
00361                 cmdBufOut[cmdCount++] = cmdBufIn[i];
00362                 break;
00363             }
00364             // NON-STICKY
00365             case MOTE_MAC_DEV_STATUS_ANS:
00366             { // 2 bytes payload
00367                 i += 2;
00368                 break;
00369             }
00370             case MOTE_MAC_MODE_IND:
00371             case MOTE_MAC_LINK_ADR_ANS:
00372             case MOTE_MAC_NEW_CHANNEL_ANS:
00373             { // 1 byte payload
00374                 i++;
00375                 break;
00376             }
00377             case SRV_MAC_ADR_PARAM_SETUP_ANS:
00378             case MOTE_MAC_DUTY_CYCLE_ANS:
00379             case MOTE_MAC_LINK_CHECK_REQ:
00380             { // 0 byte payload
00381                 break;
00382             }
00383             default:
00384                 break;
00385         }
00386     }
00387 
00388     return cmdCount;
00389 } // ..ParseMacCommandsToRepeat()
00390 
00391 LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t  *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
00392 {
00393     uint32_t fcnt_up;
00394     uint16_t i;
00395 #ifdef LORAWAN_JOIN_EUI
00396     uint32_t mic = 0;
00397 #endif /* LORAWAN_JOIN_EUI  */
00398     const void* payload = fBuffer;
00399     uint8_t framePort = fPort;
00400     uint8_t LoRaMacTxPayloadLen = 0;
00401 
00402     tx_buf_len = 0;
00403 
00404     if( fBuffer == NULL )
00405     {
00406         fBufferSize = 0;
00407     }
00408 
00409     LoRaMacTxPayloadLen = fBufferSize;
00410 
00411     Radio::radio.tx_buf[tx_buf_len++] = macHdr->Value ;
00412 
00413     switch( macHdr->Bits.MType  )
00414     {
00415 #ifdef LORAWAN_JOIN_EUI
00416         case FRAME_TYPE_JOIN_REQ:
00417             if (LoRaMacJoinEui == NULL || LoRaMacDevEui == NULL)
00418                 return LORAMAC_STATUS_PARAMETER_INVALID;
00419 
00420             RxWindow1Delay_us = LoRaMacParams.JoinAcceptDelay1_us  - RADIO_WAKEUP_TIME_us;
00421             RxWindow2Delay_us = LoRaMacParams.JoinAcceptDelay2_us  - RADIO_WAKEUP_TIME_us;
00422 
00423             memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacJoinEui, 8 );
00424             tx_buf_len += 8;
00425             memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacDevEui, 8 );
00426             tx_buf_len += 8;
00427 
00428             if (RootAppKey == NULL)
00429                 LoRaMacDevNonce = Radio::Random();  /* lorawan 1.0 */
00430             else {
00431                 LoRaMacDevNonce = eeprom_read(EEPROM_DEVNONCE);
00432                 /* joinReq DevNonce value is never re-used in 1v1 */
00433                 if (eeprom_increment_value(EEPROM_DEVNONCE) < 0)
00434                     return LORAMAC_STATUS_EEPROM_FAIL;
00435             }
00436             MAC_PRINTF("DevNonce:%u ", LoRaMacDevNonce);
00437 
00438             Radio::radio.tx_buf[tx_buf_len++] = LoRaMacDevNonce & 0xFF;
00439             Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
00440 
00441             if (LoRaMacJoinComputeMic(false, Radio::radio.tx_buf, tx_buf_len & 0xFF, RootNwkKey, &mic) < 0)
00442                 return LORAMAC_STATUS_SERVICE_UNKNOWN;
00443 
00444             Radio::radio.tx_buf[tx_buf_len++] = mic & 0xFF;
00445             Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 8 ) & 0xFF;
00446             Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 16 ) & 0xFF;
00447             Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 24 ) & 0xFF;
00448 
00449             break;
00450         case FRAME_TYPE_REJOIN_REQ:
00451             RxWindow1Delay_us = LoRaMacParams.JoinAcceptDelay1_us  - RADIO_WAKEUP_TIME_us;
00452             RxWindow2Delay_us = LoRaMacParams.JoinAcceptDelay2_us  - RADIO_WAKEUP_TIME_us;
00453 
00454             Radio::radio.tx_buf[tx_buf_len++] = JoinReqType;
00455 
00456             tx_buf_len = tx_buf_len;
00457 
00458             if (JoinReqType == 0 || JoinReqType == 2) {
00459                 LoRaMacDevNonce = RJcount0++;
00460                 /* NetID + DevEUI */
00461                 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacNetID ) & 0xFF;
00462                 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacNetID >> 8 ) & 0xFF;
00463                 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacNetID >> 16 ) & 0xFF;
00464 
00465                 memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacDevEui, 8 );
00466                 tx_buf_len += 8;
00467 
00468                 Radio::radio.tx_buf[tx_buf_len++] = LoRaMacDevNonce & 0xFF;
00469                 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
00470 
00471                 if (LoRaMacJoinComputeMic(false, Radio::radio.tx_buf, tx_buf_len & 0xFF, keys.SNwkSIntKey, &mic) < 0)
00472                     return LORAMAC_STATUS_SERVICE_UNKNOWN;
00473 
00474             } else if (JoinReqType == 1) {
00475                 /* JoinEUI + DevEUI */
00476                 LoRaMacDevNonce = eeprom_read(EEPROM_RJCOUNT1);
00477                 if (eeprom_increment_value(EEPROM_RJCOUNT1) < 0)
00478                     return LORAMAC_STATUS_EEPROM_FAIL;
00479 
00480                 memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacJoinEui, 8 );
00481                 tx_buf_len += 8;
00482                 memcpyr( Radio::radio.tx_buf + tx_buf_len, LoRaMacDevEui, 8 );
00483                 tx_buf_len += 8;
00484 
00485                 Radio::radio.tx_buf[tx_buf_len++] = LoRaMacDevNonce & 0xFF;
00486                 Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
00487 
00488                 //print_buf(JSIntKey, 16, "JSIntKey");
00489                 if (LoRaMacJoinComputeMic(false, Radio::radio.tx_buf, tx_buf_len & 0xFF, JSIntKey, &mic) < 0)
00490                     return LORAMAC_STATUS_SERVICE_UNKNOWN;
00491 
00492             }
00493 
00494             Radio::radio.tx_buf[tx_buf_len++] = mic & 0xFF;
00495             Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 8 ) & 0xFF;
00496             Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 16 ) & 0xFF;
00497             Radio::radio.tx_buf[tx_buf_len++] = ( mic >> 24 ) & 0xFF;
00498             MAC_PRINTF("up-rejoin-frame len%u type%u\r\n", tx_buf_len, JoinReqType);
00499             break;
00500 #endif /* LORAWAN_JOIN_EUI  */
00501         case FRAME_TYPE_DATA_CONFIRMED_UP:
00502             //Intentional fallthrough
00503         case FRAME_TYPE_DATA_UNCONFIRMED_UP:
00504 #ifdef LORAWAN_JOIN_EUI
00505             if (!flags.IsLoRaMacNetworkJoined)
00506             {
00507                 return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined yet
00508             }
00509 
00510             if (flags.OptNeg && flags.need_ReKeyConf) {
00511                 /* lorawan1v1 need rekeying confirmation */
00512                 LoRaMacStatus_t s = AddMacCommand(MOTE_MAC_REKEY_IND, 0, 0);
00513                 if (s != LORAMAC_STATUS_OK)
00514                     return s;
00515                 if (McpsIndication.ADR_ACK_CNT > ADR_ACK_DELAY) {
00516                     /* give up sending rekey indication, try joining again */
00517                     flags.IsLoRaMacNetworkJoined = false;
00518                     return LORAMAC_STATUS_NO_NETWORK_JOINED;
00519                 }
00520             }
00521             fcnt_up = FCntUp;
00522 #else
00523             if (flags.need_ResetConf) {
00524                 LoRaMacStatus_t s = AddMacCommand(MOTE_MAC_RESET_IND, flags.OptNeg, 0);
00525                 if (s != LORAMAC_STATUS_OK)
00526                     return s;
00527             }
00528             fcnt_up = eeprom_read(EEPROM_FCNTUP);
00529 #endif /* LORAWAN_JOIN_EUI  */
00530 
00531 
00532             if( ValidatePayloadLength( LoRaMacTxPayloadLen, LoRaMacParams.ChannelsDatarate , MacCommandsBufferIndex ) == false )
00533             {
00534                 MAC_PRINTF("LoRaMacTxPayloadLen%u, FOptsLen%u\r\n", LoRaMacTxPayloadLen, MacCommandsBufferIndex);
00535                 return LORAMAC_STATUS_LENGTH_ERROR;
00536             }
00537 
00538             RxWindow1Delay_us = LoRaMacParams.ReceiveDelay1_us  - RADIO_WAKEUP_TIME_us;
00539             RxWindow2Delay_us = LoRaMacParams.ReceiveDelay2_us  - RADIO_WAKEUP_TIME_us;
00540 
00541             if( flags.SrvAckRequested == true )
00542             {
00543                 flags.SrvAckRequested = false;
00544                 fCtrl->Bits.Ack = 1;
00545             }
00546 
00547             Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr ) & 0xFF;
00548             Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
00549             Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
00550             Radio::radio.tx_buf[tx_buf_len++] = ( LoRaMacDevAddr >> 24 ) & 0xFF;
00551 
00552             Radio::radio.tx_buf[tx_buf_len++] = fCtrl->Value;
00553 
00554             // FCntUp will be inserted in SendFrameOnChannel(), where MIC is inserted also
00555             tx_buf_len += 2;
00556 
00557             ConfFCntUp = 0;
00558             if (flags.OptNeg) {
00559                 if (macHdr->Bits.MType  == FRAME_TYPE_DATA_CONFIRMED_UP) {
00560 #ifdef LORAWAN_JOIN_EUI
00561                     ConfFCntUp = FCntUp;
00562 #else
00563                     ConfFCntUp = eeprom_read(EEPROM_FCNTUP);
00564 #endif /* LORAWAN_JOIN_EUI */
00565                 }
00566             }
00567 
00568             // Copy the MAC commands which must be re-send into the MAC command buffer
00569             memcpy( &MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat, MacCommandsBufferToRepeatIndex );
00570             MacCommandsBufferIndex += MacCommandsBufferToRepeatIndex;
00571 
00572             if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
00573             {
00574                 if( ( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH ) && ( flags.MacCommandsInNextTx == true ) )
00575                 {
00576                     MAC_PRINTF("uplink mac-cmds %u into FOpts at %u ", MacCommandsBufferIndex, tx_buf_len);
00577                     fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
00578                     // Update FCtrl field with new value of OptionsLength
00579                     Radio::radio.tx_buf[0x05] = fCtrl->Value;
00580 
00581                     /* lorawan1v1: encode FOpts using NWkSEncKey */
00582                     if (flags.OptNeg) {
00583                         LoRaMacEncrypt(0, MacCommandsBuffer, MacCommandsBufferIndex, keys.NwkSEncKey, LoRaMacDevAddr, UP_LINK, fcnt_up, Radio::radio.tx_buf + tx_buf_len);
00584                         tx_buf_len += MacCommandsBufferIndex;
00585                     } else {
00586                         for( i = 0; i < MacCommandsBufferIndex; i++ )
00587                         {
00588                             Radio::radio.tx_buf[tx_buf_len++] = MacCommandsBuffer[i];
00589                             MAC_PRINTF("%02x ", MacCommandsBuffer[i]);
00590                         }
00591                         MAC_PRINTF(" fCtrl->Value:%02x\r\n", Radio::radio.tx_buf[0x05]);
00592                     }
00593                 }
00594             }
00595             else
00596             {
00597                 if( ( MacCommandsBufferIndex > 0 ) && ( flags.MacCommandsInNextTx ) )
00598                 {
00599                     MAC_PRINTF("uplink mac-cmds %u port0 ", MacCommandsBufferIndex);
00600                     for (i = 0; i < MacCommandsBufferIndex; i++)
00601                         MAC_PRINTF("%02x ", MacCommandsBuffer[i]);
00602                     MAC_PRINTF("\r\n");
00603                     LoRaMacTxPayloadLen = MacCommandsBufferIndex;
00604                     payload = MacCommandsBuffer;
00605                     framePort = 0;
00606                 }
00607             }
00608             flags.MacCommandsInNextTx = false;
00609             // Store MAC commands which must be re-send in case the device does not receive a downlink anymore
00610             MacCommandsBufferToRepeatIndex = ParseMacCommandsToRepeat( MacCommandsBuffer, MacCommandsBufferIndex, MacCommandsBufferToRepeat );
00611             if( MacCommandsBufferToRepeatIndex > 0 )
00612             {
00613                 flags.MacCommandsInNextTx = true;
00614             }
00615             MacCommandsBufferIndex = 0;
00616 
00617             if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
00618             {
00619                 const uint8_t* keyPtr;
00620                 Radio::radio.tx_buf[tx_buf_len++] = framePort;
00621 
00622                 if( framePort == 0 )
00623                 {
00624                     DEBUG_CRYPT_BUF(keys.NwkSEncKey, 16, "NwkSEncKey", 0);
00625                     keyPtr = keys.NwkSEncKey;
00626                 }
00627                 else
00628                 {
00629                     DEBUG_CRYPT_BUF(keys.AppSKey, 16, "AppSKey", 0);
00630                     keyPtr = keys.AppSKey;
00631                 }
00632                 LoRaMacEncrypt(1, (uint8_t* ) payload, LoRaMacTxPayloadLen, keyPtr, LoRaMacDevAddr, UP_LINK, fcnt_up, Radio::radio.tx_buf + tx_buf_len);
00633             }
00634             tx_buf_len = tx_buf_len + LoRaMacTxPayloadLen;
00635             /* mic cacluation in SendFrameOnChannel() */
00636             break;
00637         case FRAME_TYPE_PROPRIETARY:
00638             if( ( fBuffer != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
00639             {
00640                 memcpy( Radio::radio.tx_buf + tx_buf_len, ( uint8_t* ) fBuffer, LoRaMacTxPayloadLen );
00641                 tx_buf_len = tx_buf_len + LoRaMacTxPayloadLen;
00642             }
00643             break;
00644         default:
00645             return LORAMAC_STATUS_SERVICE_UNKNOWN;
00646     }
00647 
00648     flags.uplink_mtype = macHdr->Bits.MType ;
00649     flags.uplink_in_progress = LoRaMacParams.NbTrans ;
00650 
00651     return LORAMAC_STATUS_OK;
00652 } // ..PrepareFrame()
00653 
00654 LoRaMacStatus_t Send( LoRaMacHeader_t  *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
00655 {
00656     LoRaMacFrameCtrl_t fCtrl;
00657     LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
00658 
00659     fCtrl.Value = 0;
00660     fCtrl.Bits.FOptsLen      = 0;
00661     if( LoRaMacDeviceClass == CLASS_B )
00662     {
00663         fCtrl.Bits.FPending      = 1;
00664     }
00665     else
00666     {
00667         fCtrl.Bits.FPending      = 0;
00668     }
00669     fCtrl.Bits.Ack           = false;
00670     fCtrl.Bits.AdrAckReq     = false;
00671     fCtrl.Bits.Adr           = flags.AdrCtrlOn;
00672 
00673     // Prepare the frame
00674     status = PrepareFrame( macHdr, &fCtrl, fPort, fBuffer, fBufferSize );
00675 
00676     // Validate status
00677     if( status != LORAMAC_STATUS_OK )
00678     {
00679         return status;
00680     }
00681 
00682     // Reset confirm parameters
00683     McpsConfirm.NbRetries = 0;
00684     McpsConfirm.AckReceived = false;
00685 
00686     status = LORAMAC_STATUS_OK;
00687     if (flags.rxing)
00688         function_pending = region_ScheduleTx;
00689     else
00690         region_ScheduleTx( );
00691 
00692     return status;
00693 } // ..Send()
00694 
00695 LoRaMacStatus_t waitingFor;
00696 
00697 LoRaMacStatus_t
00698 LoRaMacMlmeRequest( const MlmeReq_t *mlmeRequest )
00699 {
00700     LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
00701 #ifdef LORAWAN_JOIN_EUI
00702     LoRaMacHeader_t  macHdr;
00703 #endif /* LORAWAN_JOIN_EUI  */
00704 
00705     if( mlmeRequest == NULL )
00706     {
00707         return LORAMAC_STATUS_PARAMETER_INVALID;
00708     }
00709 
00710     if (flags.uplink_in_progress > 0) {
00711         MAC_PRINTF("LoRaMacMlmeRequest() BUSY\r\n");
00712         return waitingFor;
00713     }
00714 
00715     MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_MLMEREQ;
00716     MlmeIndication.MlmeIndication = mlmeRequest->Type;
00717 
00718     waitingFor = LORAMAC_STATUS_WAITING_FOR_TXSTART;
00719 
00720     MAC_PRINTF("LoRaMacMlmeRequest() ");
00721     switch( mlmeRequest->Type )
00722     {
00723 #ifdef LORAWAN_JOIN_EUI
00724         case MLME_JOIN:
00725         {
00726             if( ( mlmeRequest->Req.Join.DevEui == NULL ) ||
00727                 ( mlmeRequest->Req.Join.JoinEui == NULL ) ||
00728                 ( mlmeRequest->Req.Join.NwkKey == NULL ) ||
00729                 ( mlmeRequest->Req.Join.NbTrials == 0 ) )
00730             {
00731                 return LORAMAC_STATUS_PARAMETER_INVALID;
00732             }
00733 
00734             LoRaMacDevEui = mlmeRequest->Req.Join.DevEui;
00735             LoRaMacJoinEui = mlmeRequest->Req.Join.JoinEui;
00736             RootNwkKey = mlmeRequest->Req.Join.NwkKey;
00737             RootAppKey = mlmeRequest->Req.Join.AppKey;
00738             MaxJoinRequestTrials = mlmeRequest->Req.Join.NbTrials;
00739 
00740             /*if (RootAppKey != NULL) {*/
00741                 LoRaMacGenerateJoinKey(0x05, RootNwkKey, LoRaMacDevEui, JSEncKey);
00742                 //print_buf(JSEncKey, 16, "new-JSEncKey");
00743                 LoRaMacGenerateJoinKey(0x06, RootNwkKey, LoRaMacDevEui, JSIntKey);
00744                 //print_buf(JSIntKey, 16, "new-JSIntKey");
00745             /*}*/
00746             JoinReqType = 0xff;
00747 
00748             // Reset variable JoinRequestTrials
00749             MlmeIndication.JoinRequestTrials = 0;
00750 
00751             // Setup header information
00752             macHdr.Value  = 0;
00753             macHdr.Bits.MType  = FRAME_TYPE_JOIN_REQ;
00754 
00755             ResetMacParameters( );
00756 
00757             // Add a +1, since we start to count from 0
00758             LoRaMacParams.ChannelsDatarate  = region_AlternateDatarate( MlmeIndication.JoinRequestTrials + 1 );
00759 
00760             status = Send( &macHdr, 0, NULL, 0 );
00761             break;
00762         }
00763         case MLME_REJOIN_1:
00764             if ( mlmeRequest->Req.Join.JoinEui == NULL )
00765                 return LORAMAC_STATUS_PARAMETER_INVALID;
00766 
00767             LoRaMacJoinEui = mlmeRequest->Req.Join.JoinEui;
00768             JoinReqType = 0x01;
00769             // fall-thru
00770         case MLME_REJOIN_0:
00771         case MLME_REJOIN_2: // Type2 can only be sent via mac-command
00772             if( ( mlmeRequest->Req.Join.DevEui == NULL ) ||
00773                 ( mlmeRequest->Req.Join.NwkKey == NULL ) ||
00774                 ( mlmeRequest->Req.Join.NbTrials == 0 ) )
00775             {
00776                 MAC_PRINTF(" (missing %p %p %d)\n",
00777                     mlmeRequest->Req.Join.DevEui,
00778                     mlmeRequest->Req.Join.NwkKey,
00779                     mlmeRequest->Req.Join.NbTrials
00780                 );
00781                 return LORAMAC_STATUS_PARAMETER_INVALID;
00782             }
00783 
00784             RootNwkKey = mlmeRequest->Req.Join.NwkKey;
00785             LoRaMacDevEui = mlmeRequest->Req.Join.DevEui;
00786             LoRaMacGenerateJoinKey(0x05, RootNwkKey, LoRaMacDevEui, JSEncKey);
00787             LoRaMacGenerateJoinKey(0x06, RootNwkKey, LoRaMacDevEui, JSIntKey);
00788 
00789             RootAppKey = mlmeRequest->Req.Join.AppKey;
00790 
00791             macHdr.Value  = 0;
00792             macHdr.Bits.MType  = FRAME_TYPE_REJOIN_REQ;
00793 
00794             if (mlmeRequest->Type == MLME_REJOIN_0)
00795                 JoinReqType = 0x00;
00796             else if (mlmeRequest->Type == MLME_REJOIN_2)
00797                 JoinReqType = 0x02;
00798 
00799             MaxJoinRequestTrials = mlmeRequest->Req.Join.NbTrials;
00800 
00801             status = Send( &macHdr, 0, NULL, 0 );
00802             break;
00803 #endif /* LORAWAN_JOIN_EUI  */
00804         case MLME_LINK_CHECK:
00805             status = AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 );
00806             break;
00807         case MLME_TIME_REQ:
00808             status = AddMacCommand( MOTE_MAC_DEVICE_TIME_REQ, 0, 0 );
00809             break;
00810         case MLME_TXCW:
00811             status = SetTxContinuousWave( mlmeRequest->Req.TxCw.Timeout );
00812             break;
00813         case MLME_PING_SLOT_INFO:
00814         {
00815             uint8_t value = mlmeRequest->Req.PingSlotInfo.Value;
00816             status = LoRaMacMlmeRequestClassB(mlmeRequest);
00817             if (status == LORAMAC_STATUS_OK)
00818                 status = AddMacCommandClassB( MOTE_MAC_PING_SLOT_INFO_REQ, value, 0 );
00819             break;
00820         }
00821         case MLME_BEACON_ACQUISITION:
00822         case MLME_BEACON_TIMING:
00823             status = LoRaMacMlmeRequestClassB(mlmeRequest);
00824             break;
00825         default:
00826             break;
00827     } // ...switch( mlmeRequest->Type )
00828 
00829     if( status != LORAMAC_STATUS_OK )
00830         MlmeConfirm.MlmeRequest = MLME_NONE;
00831     else
00832     {
00833         MlmeConfirm.MlmeRequest = mlmeRequest->Type;
00834     }
00835 
00836     return status;
00837 } // ..LoRaMacMlmeRequest()
00838 
00839 LoRaMacStatus_t
00840 LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet )
00841 {
00842     LoRaMacStatus_t status = LORAMAC_STATUS_OK;
00843 
00844     switch( mibGet->Type ) {
00845         case MIB_APP_SKEY:
00846             mibGet->Param.key = keys.AppSKey;
00847             break;
00848         case MIB_FNwkSIntKey:
00849             mibGet->Param.key = keys.FNwkSIntKey;
00850             break;
00851         case MIB_SNwkSIntKey:
00852             mibGet->Param.key = keys.SNwkSIntKey;
00853             break;
00854         case MIB_NwkSEncKey:
00855             mibGet->Param.key = keys.NwkSEncKey;
00856             break;
00857         case MIB_NwkSKey:
00858             /* lorawan 1.0 */
00859             mibGet->Param.key = keys.FNwkSIntKey;
00860             break;
00861         case MIB_RX2_CHANNEL:
00862             mibGet->Param.Rx2Channel = LoRaMacParams.Rx2Channel ;
00863             break;
00864         case MIB_DEVICE_CLASS:
00865             mibGet->Param.Class = LoRaMacDeviceClass;
00866             break;
00867         case MIB_ADR:
00868             mibGet->Param.AdrEnable = flags.AdrCtrlOn;
00869             break;
00870         case MIB_DEV_ADDR:
00871             mibGet->Param.DevAddr = LoRaMacDevAddr;
00872             break;
00873         case MIB_PUBLIC_NETWORK:
00874             mibGet->Param.EnablePublicNetwork = flags.PublicNetwork;
00875             break;
00876         case MIB_CHANNELS_MASK:
00877             mibGet->Param.ChannelsMask = LoRaMacParams.ChannelsMask ;
00878             LoRaMacParams.NbEnabledChannels = region_CountNbEnabledChannels();
00879             break;
00880         case MIB_MAX_LISTEN_TIME:
00881             mibGet->Param.MaxListenTime = LoRaMacParams.MaxListenTime;
00882             break;
00883 #ifdef LORAWAN_JOIN_EUI
00884         case MIB_NETWORK_JOINED:
00885             mibGet->Param.IsNetworkJoined = flags.IsLoRaMacNetworkJoined;
00886             break;
00887 #endif /* LORAWAN_JOIN_EUI */
00888     } // ..switch( mibGet->Type )
00889 
00890     return status;
00891 }
00892 
00893 
00894 LoRaMacStatus_t
00895 LoRaMacQueryTxPossible(uint8_t size, LoRaMacTxInfo_t* txInfo)
00896 {
00897     int8_t datarate = LoRaMacParamsDefaults.ChannelsDatarate ;
00898     uint8_t fOptLen = MacCommandsBufferIndex + MacCommandsBufferToRepeatIndex;
00899 
00900     if( txInfo == NULL )
00901     {
00902         return LORAMAC_STATUS_PARAMETER_INVALID;
00903     }
00904 
00905     //AdrNextDr( flags.AdrCtrlOn, false, &datarate );
00906 
00907     txInfo->CurrentPayloadSize = MaxPayloadOfDatarate[datarate];
00908 
00909     if( txInfo->CurrentPayloadSize >= fOptLen )
00910     {
00911         txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize - fOptLen;
00912     }
00913     else
00914     {
00915         return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
00916     }
00917 
00918     if( ValidatePayloadLength( size, datarate, 0 ) == false )
00919     {
00920         return LORAMAC_STATUS_LENGTH_ERROR;
00921     }
00922 
00923     if( ValidatePayloadLength( size, datarate, fOptLen ) == false )
00924     {
00925         return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
00926     }
00927 
00928     return LORAMAC_STATUS_OK;
00929 }
00930 
00931 LoRaMacStatus_t
00932 LoRaMacMcpsRequest( McpsReq_t *mcpsRequest )
00933 {
00934     LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
00935     LoRaMacHeader_t  macHdr;
00936     uint8_t fPort = 0;
00937     void *fBuffer;
00938     uint16_t fBufferSize;
00939     int8_t datarate;
00940     bool readyToSend = false;
00941 
00942     if( mcpsRequest == NULL )
00943     {
00944         return LORAMAC_STATUS_PARAMETER_INVALID;
00945     }
00946     if (flags.uplink_in_progress > 0) {
00947         MAC_PRINTF("LoRaMacMcpsRequest() in_progress BUSY%u\r\n", flags.uplink_in_progress);
00948         return waitingFor;
00949     }
00950     if (ConfFCntUp > 0) {
00951         // unacknowledged confirmed uplink pending, must resend previous uplink
00952         MAC_PRINTF("LoRaMacMcpsRequest() ConfFCntUp%u\r\n", ConfFCntUp);
00953         return LORAMAC_STATUS_BUSY_UPCONF;
00954     }
00955 
00956 #ifdef LORAWAN_JOIN_EUI
00957     if (!flags.IsLoRaMacNetworkJoined)
00958         return LORAMAC_STATUS_NO_NETWORK_JOINED;
00959 #endif /* LORAWAN_JOIN_EUI  */
00960 
00961     macHdr.Value  = 0;
00962     memset ( ( uint8_t* ) &McpsConfirm, 0, sizeof( McpsConfirm ) );
00963     McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_MCPSREQ;
00964     McpsConfirm.McpsRequest = mcpsRequest->Type;
00965 
00966     datarate = mcpsRequest->Req.Datarate;
00967     fBufferSize = mcpsRequest->Req.fBufferSize;
00968     fBuffer = mcpsRequest->Req.fBuffer;
00969     readyToSend = true;
00970 
00971     switch( mcpsRequest->Type )
00972     {
00973         case MCPS_UNCONFIRMED:
00974         {
00975             macHdr.Bits.MType  = FRAME_TYPE_DATA_UNCONFIRMED_UP;
00976             fPort = mcpsRequest->Req.fPort;
00977             break;
00978         }
00979         case MCPS_CONFIRMED:
00980         {
00981             //AckTimeoutRetriesCounter = 1;
00982             //AckTimeoutRetries = mcpsRequest->Req.NbTrials;
00983 
00984             macHdr.Bits.MType  = FRAME_TYPE_DATA_CONFIRMED_UP;
00985             fPort = mcpsRequest->Req.fPort;
00986             break;
00987         }
00988         case MCPS_PROPRIETARY:
00989         {
00990             macHdr.Bits.MType  = FRAME_TYPE_PROPRIETARY;
00991             break;
00992         }
00993         default:
00994             readyToSend = false;
00995             break;
00996     }
00997 
00998     if( readyToSend == true )
00999     {
01000         if( flags.AdrCtrlOn == false )
01001         {
01002             if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == true )
01003             {
01004                 LoRaMacParams.ChannelsDatarate  = datarate;
01005             }
01006             else
01007             {
01008                 return LORAMAC_STATUS_PARAMETER_INVALID;
01009             }
01010         }
01011 
01012         status = Send( &macHdr, fPort, fBuffer, fBufferSize );
01013     }
01014 
01015     return status;
01016 } // ..LoRaMacMcpsRequest()
01017 
01018 __attribute__((weak)) LoRaMacStatus_t
01019 SwitchClassB( DeviceClass_t deviceClass )
01020 {
01021     return LORAMAC_STATUS_DEVICE_OFF;
01022 }
01023 
01024 void
01025 RxWindowSetup( unsigned freq, int8_t datarate, unsigned bandwidth, uint16_t timeout)
01026 {
01027     uint8_t downlinkDatarate = Datarates[datarate];
01028     unsigned bwKHz;
01029 
01030     switch (bandwidth) {
01031         case 0: bwKHz = 125; break;
01032         case 1: bwKHz = 250; break;
01033         case 2: bwKHz = 500; break;
01034         default: bwKHz = 0; /* fail */ break;
01035     }
01036 
01037     MAC_PRINTF(" rxwin-dr%u-sf%u ", datarate, downlinkDatarate);
01038     Radio::SetChannel( freq );
01039 
01040     // Store downlink datarate
01041     McpsIndication.RxDatarate = ( uint8_t ) datarate;
01042 
01043 #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868) || defined(USE_BAND_ARIB_8CH)
01044     if( datarate == DR_7 )
01045     {
01046         Radio::GFSKModemConfig(downlinkDatarate * 1000, 50, 25000);
01047         Radio::GFSKPacketConfig(5, false, true);
01048     }
01049     else
01050     {
01051         Radio::LoRaModemConfig(bwKHz, downlinkDatarate, 1);
01052         Radio::LoRaPacketConfig(8, false, false, true);
01053         Radio::SetLoRaSymbolTimeout(timeout);
01054     }
01055 #elif defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
01056     Radio::LoRaModemConfig(bwKHz, downlinkDatarate, 1);
01057     Radio::LoRaPacketConfig(8, false, false, true);
01058     Radio::SetLoRaSymbolTimeout(timeout);
01059 #endif
01060 
01061     Radio::SetRxMaxPayloadLength(MaxPayloadOfDatarate[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD);
01062 } //..RxWindowSetup()
01063 
01064 LowPowerTimeout RxWindowEvent1;
01065 LowPowerTimeout RxWindowEvent2;
01066 
01067 static void RxWindow2Start( void )
01068 {
01069     /* TODO: join accept rx2 channel unique */
01070     if (LoRaMacDeviceClass == CLASS_C)
01071         Radio::Rx( 0 ); // Continuous mode
01072     else
01073         Radio::Rx( LoRaMacParams.MaxRxWindow_us  );
01074 
01075     McpsIndication.RxSlot = 2;
01076 }
01077 
01078 static void mlme_confirm(LoRaMacEventInfoStatus_t status)
01079 {
01080     MlmeConfirm.Status = status;
01081 
01082     if (MlmeConfirm.MlmeRequest != MLME_NONE) {
01083         if (LoRaMacPrimitives->MacMlmeConfirm != NULL)
01084             LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm );
01085 
01086         MlmeConfirm.MlmeRequest = MLME_NONE;
01087         MlmeIndication.MlmeIndication = MLME_NONE;
01088     }
01089 }
01090 
01091 static void mcps_confirm(LoRaMacEventInfoStatus_t status)
01092 {
01093     McpsConfirm.Status = status;
01094 
01095     if (McpsConfirm.McpsRequest != MCPS_NONE) {
01096         if (LoRaMacPrimitives->MacMcpsConfirm)
01097             LoRaMacPrimitives->MacMcpsConfirm( &McpsConfirm );
01098 
01099         McpsConfirm.McpsRequest = MCPS_NONE;
01100     }
01101 }
01102 
01103 #if defined(LORAWAN_JOIN_EUI)
01104 static struct {
01105     bool forced;
01106     uint8_t dr;
01107     uint8_t type;
01108     uint8_t retries;
01109     uint8_t Period;
01110     LowPowerTimeout event;
01111     struct {
01112         uint8_t MaxTimeN;
01113         uint8_t MaxCountN;
01114         unsigned uplinks_since;
01115         bool enabled;
01116     } type0;
01117 } rejoin;
01118 void _rejoin_retry(void);
01119 
01120 void rejoin_retry()
01121 {
01122     LoRaMacStatus_t status;
01123     LoRaMacHeader_t  macHdr;
01124 
01125     macHdr.Value  = 0;
01126     macHdr.Bits.MType  = FRAME_TYPE_REJOIN_REQ;
01127     LoRaMacParams.ChannelsDatarate  = rejoin.dr;
01128     JoinReqType = rejoin.type;
01129     status = Send( &macHdr, 0, NULL, 0 );
01130     if (status != LORAMAC_STATUS_OK) {
01131         MAC_PRINTF("rejoin-send-failed%d ", status);
01132     }
01133 
01134     MAC_PRINTF("Rejoin%u ", JoinReqType);
01135     if (rejoin.forced) {
01136         if (--rejoin.retries > 0) {
01137             us_timestamp_t period_us = (1 << rejoin.Period) + random_at_most(32000000);
01138             rejoin.event.attach_us(_rejoin_retry, period_us);
01139             MAC_PRINTF("try%u", rejoin.retries);
01140         } else
01141             rejoin.forced = false;
01142     }
01143     MAC_PRINTF("\r\n");
01144 }
01145 
01146 void _rejoin_retry()
01147 {
01148     if (flags.uplink_in_progress > 0) {
01149         function_pending = rejoin_retry;
01150     } else
01151         rejoin_retry();
01152 }
01153 #endif /* LORAWAN_JOIN_EUI  */
01154 
01155 void
01156 finish_uplink(LoRaMacEventInfoStatus_t status)
01157 {
01158     if ((flags.uplink_in_progress > 0 && McpsIndication.RxSlot == 2) || status == LORAMAC_EVENT_INFO_STATUS_OK) {
01159         if ((uplinkMHDR->Bits.MType  == FRAME_TYPE_DATA_CONFIRMED_UP && status == LORAMAC_EVENT_INFO_STATUS_OK) || uplinkMHDR->Bits.MType  != FRAME_TYPE_DATA_CONFIRMED_UP) {
01160             flags.uplink_in_progress--;
01161         }
01162 
01163         if (flags.uplink_in_progress > 0) {
01164             McpsIndication.Status = status;
01165             if (LoRaMacPrimitives->MacMcpsIndication != NULL)
01166                 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
01167 
01168             if (flags.rxing)
01169                 function_pending = region_ScheduleTx;
01170             else {
01171                 region_ScheduleTx( );
01172             }
01173         } else
01174             region_session_start(status);
01175     }
01176 
01177 #ifdef LORAWAN_JOIN_EUI
01178     LoRaMacHeader_t  macHdr;
01179     macHdr.Value  = Radio::radio.tx_buf[0];
01180     if (macHdr.Bits.MType  != FRAME_TYPE_REJOIN_REQ) {
01181         if (rejoin.type0.enabled && --rejoin.type0.uplinks_since == 0) {
01182             rejoin.type0.uplinks_since = 1 << (rejoin.type0.MaxCountN + 4);
01183 
01184             rejoin.type = 0;
01185             rejoin_retry();
01186             return;
01187         }
01188     }
01189 #endif /* LORAWAN_JOIN_EUI  */
01190 
01191     waitingFor = LORAMAC_STATUS_OK;
01192 
01193     if (function_pending != NULL) {
01194         function_pending();
01195         function_pending = NULL;
01196     }
01197 } // ..finish_uplink()
01198 
01199 LowPowerTimeout TxDelayedEvent;
01200 
01201 void OnTxDelayedIsr()
01202 {
01203     flags.OnTxDelayed = true;
01204 }
01205 
01206 static void OnTxDelayedTimerEvent()
01207 {
01208     MAC_PRINTF("OnTxDelayedTimerEvent() ");
01209 #ifdef LORAWAN_JOIN_EUI
01210     LoRaMacHeader_t  macHdr;
01211     LoRaMacFrameCtrl_t fCtrl;
01212 
01213     if (!flags.IsLoRaMacNetworkJoined)
01214     {
01215         // Add a +1, since we start to count from 0
01216         LoRaMacParams.ChannelsDatarate  = region_AlternateDatarate( MlmeIndication.JoinRequestTrials + 1 );
01217 
01218         macHdr.Value  = 0;
01219         macHdr.Bits.MType  = FRAME_TYPE_JOIN_REQ;
01220 
01221         fCtrl.Value = 0;
01222         fCtrl.Bits.Adr = flags.AdrCtrlOn;
01223 
01224         /* In case of join request retransmissions, the stack must prepare
01225          * the frame again, because the network server keeps track of the random
01226          * LoRaMacDevNonce values to prevent reply attacks. */
01227         PrepareFrame( &macHdr, &fCtrl, 0, NULL, 0 );
01228         /* TODO PrepareFrame() != LORAMAC_STATUS_OK */
01229     }
01230 #endif /* LORAWAN_JOIN_EUI  */
01231 
01232     if (flags.rxing)
01233         function_pending = region_ScheduleTx;
01234     else {
01235         region_ScheduleTx( );
01236     }
01237 } // ..OnTxDelayedTimerEvent()
01238 
01239 static void RxWindow2Setup(void)
01240 {
01241     MAC_PRINTF("RxWindow2Setup %uhz dr%u", LoRaMacParams.Rx2Channel .FrequencyHz, LoRaMacParams.Rx2Channel .Datarate);
01242     RxWindowSetup(
01243         LoRaMacParams.Rx2Channel .FrequencyHz,
01244         LoRaMacParams.Rx2Channel .Datarate,
01245         region_GetRxBandwidth( LoRaMacParams.Rx2Channel .Datarate ),
01246         region_GetRxSymbolTimeout( LoRaMacParams.Rx2Channel .Datarate )
01247     );
01248 
01249     waitingFor = LORAMAC_STATUS_WAITING_FOR_RX2;
01250 }
01251 
01252 static void
01253 PrepareRxDoneAbort(LoRaMacEventInfoStatus_t status)
01254 {
01255     MAC_PRINTF("rxAbort ");
01256     if( ( McpsIndication.RxSlot == 1 ) && ( LoRaMacDeviceClass == CLASS_C ) )
01257     {
01258         RxWindow2Setup();
01259         RxWindow2Start();   // start continuous rx2 reception
01260     }
01261 
01262 #ifdef LORAWAN_JOIN_EUI
01263     if (!flags.IsLoRaMacNetworkJoined && LoRaMacJoinEui != NULL && LoRaMacDevEui == NULL)  {
01264         TxDelayedEvent.attach_us(OnTxDelayedIsr, 1000000);
01265         MAC_PRINTF("RxDoneAbort-join-tx-delay");
01266     }
01267 #endif /* LORAWAN_JOIN_EUI  */
01268 
01269 
01270     McpsIndication.Status = status;
01271     if (LoRaMacPrimitives->MacMcpsIndication != NULL)
01272         LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );    // RxAbort
01273 
01274     mcps_confirm(status);  // RXAbort
01275     mlme_confirm(status);
01276 
01277     finish_uplink(status);
01278 
01279     MAC_PRINTF("\r\n");
01280 
01281 } // ..PrepareRxDoneAbort()
01282 
01283 
01284 static LoRaMacStatus_t SwitchClass( DeviceClass_t deviceClass )
01285 {
01286     LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
01287 
01288     switch( LoRaMacDeviceClass )
01289     {
01290         case CLASS_A:
01291         {
01292             MAC_PRINTF("CLASS_A ");
01293             if (deviceClass == CLASS_B)
01294                 status = SwitchClassB(deviceClass);
01295 
01296             if (deviceClass == CLASS_C)
01297             {
01298                 MAC_PRINTF("->C ");
01299                 LoRaMacDeviceClass = deviceClass;
01300                 RxWindow2Setup();
01301                 RxWindow2Start(); // continuous rx2 reception
01302                 if (flags.OptNeg) {
01303                     AddMacCommand(MOTE_MAC_MODE_IND, LoRaMacDeviceClass, 0);
01304                 }
01305 
01306                 status = LORAMAC_STATUS_OK;
01307             }
01308             break;
01309         }
01310         case CLASS_B:
01311         {
01312             MAC_PRINTF("CLASS_B ");
01313             if( deviceClass == CLASS_A )
01314             {
01315                 MAC_PRINTF("->A ");
01316                 LoRaMacDeviceClass = deviceClass;
01317                 status = LORAMAC_STATUS_OK;
01318             }
01319             break;
01320         }
01321         case CLASS_C:
01322         {
01323             MAC_PRINTF("CLASS_C ");
01324             if( deviceClass == CLASS_A )
01325             {
01326                 MAC_PRINTF("->A ");
01327                 LoRaMacDeviceClass = deviceClass;
01328                 if (flags.OptNeg) {
01329                     AddMacCommand(MOTE_MAC_MODE_IND, LoRaMacDeviceClass, 0);
01330                 }
01331 
01332                 // Set the radio into sleep to setup a defined state
01333                 Radio::Sleep();
01334 
01335                 status = LORAMAC_STATUS_OK;
01336             }
01337             break;
01338         }
01339     }
01340 
01341     MAC_PRINTF("\r\n");
01342     return status;
01343 }
01344 
01345 LoRaMacStatus_t
01346 LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet )
01347 {
01348     LoRaMacStatus_t status = LORAMAC_STATUS_OK;
01349 
01350     if (mibSet == NULL)
01351         return LORAMAC_STATUS_PARAMETER_INVALID;
01352 
01353     if (flags.uplink_in_progress > 0)
01354         return waitingFor;
01355 
01356     switch (mibSet->Type) {
01357         case MIB_CHANNELS_MASK:
01358             if( mibSet->Param.ChannelsMask )
01359             {
01360 #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
01361                 bool chanMaskState = true;
01362 
01363 #if defined( USE_BAND_915_HYBRID )
01364                 chanMaskState = ValidateChannelMask( mibSet->Param.ChannelsMask );
01365 #endif
01366                 if( chanMaskState == true )
01367                 {
01368                     if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 2 ) &&
01369                         ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) )
01370                     {
01371                         status = LORAMAC_STATUS_PARAMETER_INVALID;
01372                     }
01373                     else
01374                     {
01375                         memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask ,
01376                                  ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask  ) );
01377                         for ( uint8_t i = 0; i < sizeof( LoRaMacParams.ChannelsMask  ) / 2; i++ )
01378                         {
01379                             // Disable channels which are no longer available
01380                             ChannelsMaskRemaining[i] &= LoRaMacParams.ChannelsMask [i];
01381                         }
01382                     }
01383                 }
01384                 else
01385                 {
01386                     status = LORAMAC_STATUS_PARAMETER_INVALID;
01387                 }
01388 #elif defined( USE_BAND_470 )
01389                 memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask ,
01390                          ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask  ) );
01391 #else
01392                 memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask ,
01393                          ( uint8_t* ) mibSet->Param.ChannelsMask, 2 );
01394 #endif
01395                 LoRaMacParams.NbEnabledChannels = region_CountNbEnabledChannels();
01396             }
01397             else
01398             {
01399                 status = LORAMAC_STATUS_PARAMETER_INVALID;
01400             }
01401             break;
01402 #ifdef LORAWAN_JOIN_EUI
01403         /* values which cannot be set in OTA */
01404         case MIB_NwkSKey:
01405         case MIB_SNwkSIntKey:
01406         case MIB_NwkSEncKey:
01407         case MIB_FNwkSIntKey:
01408         case MIB_APP_SKEY:
01409         case MIB_DEV_ADDR:
01410         case MIB_NETWORK_JOINED:
01411 #endif
01412         case MIB_RX2_CHANNEL:
01413             return LORAMAC_STATUS_PARAMETER_INVALID;
01414         case MIB_DEVICE_CLASS:
01415             status = SwitchClass(mibSet->Param.Class);
01416             break;
01417         case MIB_ADR:
01418             flags.AdrCtrlOn = mibSet->Param.AdrEnable;
01419             break;
01420         case MIB_PUBLIC_NETWORK:
01421             flags.PublicNetwork = mibSet->Param.EnablePublicNetwork;
01422             Radio::SetPublicNetwork( flags.PublicNetwork );
01423             break;
01424         case MIB_MAX_LISTEN_TIME:
01425             LoRaMacParams.MaxListenTime = mibSet->Param.MaxListenTime;
01426             break;
01427 #ifndef LORAWAN_JOIN_EUI
01428         case MIB_SNwkSIntKey:
01429             flags.have_SNwkSIntKey = 1;
01430             memcpy( keys.SNwkSIntKey, mibSet->Param.key, sizeof(keys.SNwkSIntKey) );
01431             if (flags.have_NwkSEncKey) {
01432                 flags.OptNeg = 1;
01433                 flags.need_ResetConf = 1;
01434             }
01435             break;
01436         case MIB_NwkSEncKey:
01437             flags.have_NwkSEncKey = 1;
01438             memcpy( keys.NwkSEncKey, mibSet->Param.key, sizeof(keys.NwkSEncKey) );
01439             if (flags.have_SNwkSIntKey) {
01440                 flags.OptNeg = 1;
01441                 flags.need_ResetConf = 1;
01442             }
01443             break;
01444         case MIB_APP_SKEY:
01445             memcpy( keys.AppSKey, mibSet->Param.key, sizeof( keys.AppSKey ) );
01446             break;
01447         case MIB_FNwkSIntKey:
01448             memcpy( keys.FNwkSIntKey, mibSet->Param.key, sizeof( keys.FNwkSIntKey ) );
01449             break;
01450         case MIB_NwkSKey:
01451             /* lorawan 1.0 ABP */
01452             memcpy( keys.FNwkSIntKey, mibSet->Param.key, sizeof( keys.FNwkSIntKey ) );
01453             memcpy( keys.SNwkSIntKey, mibSet->Param.key, sizeof( keys.SNwkSIntKey) );
01454             memcpy( keys.NwkSEncKey, mibSet->Param.key, sizeof( keys.NwkSEncKey) );
01455             flags.OptNeg = 0;
01456             break;
01457         case MIB_DEV_ADDR:
01458             LoRaMacDevAddr = mibSet->Param.DevAddr;
01459             break;
01460 #endif /* !LORAWAN_JOIN_EUI */
01461     } // ..switch( mibSet->Type )
01462 
01463     return status;
01464 } // ..LoRaMacMibSetRequestConfirm()
01465 
01466 __attribute__((weak)) LoRaMacStatus_t
01467 LoRaMacClassBInitialization( void )
01468 {
01469     return LORAMAC_STATUS_OK;
01470 }
01471 
01472 
01473 static void RxWindow1Start( void )
01474 {      
01475     if (LoRaMacDeviceClass == CLASS_C) {
01476         Radio::Standby();
01477         region_rx1_setup(Channel);
01478     }
01479 
01480     Radio::Rx( LoRaMacParams.MaxRxWindow_us  );
01481 
01482     McpsIndication.RxSlot = 1;
01483 }
01484 
01485 volatile us_timestamp_t tx_done_at;
01486 
01487 static void OnRadioTxDone( )
01488 {
01489     if ((RxWindow1Delay_us < 100000 || RxWindow1Delay_us > 10000000) ||
01490         (RxWindow2Delay_us < 100000 || RxWindow2Delay_us > 10000000))
01491     {
01492         PrepareRxDoneAbort(LORAMAC_EVENT_INFO_BAD_RX_DELAY);
01493         return;
01494     }
01495     // Setup timers
01496     RxWindowEvent1.attach_us(RxWindow1Start, RxWindow1Delay_us);
01497     waitingFor = LORAMAC_STATUS_WAITING_FOR_RX1;
01498     McpsIndication.RxSlot = 0;
01499 
01500     tx_done_at = Radio::irqAt;
01501 
01502     if (LoRaMacDeviceClass != CLASS_C)
01503     {
01504         RxWindowEvent2.attach_us(RxWindow2Start, RxWindow2Delay_us);
01505         region_rx1_setup(Channel);
01506         Radio::Sleep();
01507     }
01508     else
01509     {
01510         RxWindow2Setup();
01511         RxWindow2Start();
01512         // simulate timeout to complete uplink
01513         RxWindowEvent2.attach_us(OnRadioRxTimeout, RxWindow2Delay_us + 256000);
01514     }
01515 
01516     // Store last tx channel
01517     //LastTxChannel = Channel;
01518 #ifdef DUTY_ENABLE
01519     DutyTxDone(at_us);
01520 #endif /* DUTY_ENABLE */
01521 
01522 } // ..OnRadioTxDone()
01523 
01524 static void OnRadioTxTimeout( void )
01525 {
01526     if( LoRaMacDeviceClass != CLASS_C )
01527     {
01528         Radio::Sleep();
01529     }
01530     else
01531     {
01532         RxWindow2Setup();
01533         RxWindow2Start();
01534     }
01535 
01536     finish_uplink(LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT);
01537 
01538     mcps_confirm(LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT);
01539     mlme_confirm(LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT);
01540 } // ..OnRadioTxTimeout()
01541 
01542 __attribute__((weak)) bool
01543 beacon_rx_done_payload(uint16_t size)
01544 {
01545     return false;
01546 }
01547 
01548 static void
01549 print_mtype(uint8_t mt)
01550 {
01551 #ifdef MAC_DEBUG
01552     const char* cp;
01553     switch (mt) {
01554 #ifdef LORAWAN_JOIN_EUI
01555         case FRAME_TYPE_JOIN_REQ: cp = "JOIN_REQ "; break;
01556         case FRAME_TYPE_JOIN_ACCEPT: cp = "JOIN_ACC "; break;
01557         case FRAME_TYPE_REJOIN_REQ: cp = "REJOIN_REQ"; break;
01558 #endif /* LORAWAN_JOIN_EUI */
01559         case FRAME_TYPE_DATA_UNCONFIRMED_UP: cp = "UNCONF_UP"; break;
01560         case FRAME_TYPE_DATA_UNCONFIRMED_DOWN: cp = "UNCONF_DN"; break;
01561         case FRAME_TYPE_DATA_CONFIRMED_UP: cp = "CONF_UP"; break;
01562         case FRAME_TYPE_DATA_CONFIRMED_DOWN: cp = "CONF_DN"; break;
01563         case FRAME_TYPE_PROPRIETARY: cp = "P"; break;
01564         default: return;
01565     }
01566     MAC_PRINTF("MTYPE_%s ", cp);
01567 #endif /* MAC_DEBUG */
01568 }
01569 
01570 /* bool a: true=AFCntDown, false=NFCntDown */
01571 uint32_t get_fcntdwn(bool a)
01572 {
01573 #ifdef LORAWAN_JOIN_EUI
01574     if (a)
01575         return AFCntDown;
01576     else
01577         return NFCntDown;
01578 #else
01579     if (a)
01580         return eeprom_read(EEPROM_AFCNTDWN);
01581     else
01582         return eeprom_read(EEPROM_NFCNTDWN);
01583 #endif
01584 }
01585 
01586 __attribute__((weak)) bool
01587 ProcessMacCommandsClassB(const uint8_t* payload, uint8_t* macIndex)
01588 {
01589     return false;   /* false: not taken */
01590 }
01591 
01592 
01593 static bool ValidateDatarate( int8_t datarate, uint16_t* channelsMask )
01594 {
01595     if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == false )
01596     {
01597         return false;
01598     }
01599     for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
01600     {
01601         for( uint8_t j = 0; j < 16; j++ )
01602         {
01603             if( ( ( channelsMask[k] & ( 1 << j ) ) != 0 ) )
01604             {// Check datarate validity for enabled channels
01605                 if( ValueInRange( datarate, Channels[i + j].DrRange.Fields.Min, Channels[i + j].DrRange.Fields.Max ) == true )
01606                 {
01607                     // At least 1 channel has been found we can return OK.
01608                     return true;
01609                 }
01610             }
01611         }
01612     }
01613     return false;
01614 }
01615 
01616 static bool Rx2FreqInRange( uint32_t freq )
01617 {
01618 #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) || defined (USE_BAND_ARIB_8CH)
01619     if( Radio::CheckRfFrequency( freq ) == true )
01620 #elif defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
01621     if( ( Radio::CheckRfFrequency( freq ) == true ) &&
01622         ( freq >= LORAMAC_FIRST_RX1_CHANNEL ) &&
01623         ( freq <= LORAMAC_LAST_RX1_CHANNEL ) &&
01624         ( ( ( freq - ( uint32_t ) LORAMAC_FIRST_RX1_CHANNEL ) % ( uint32_t ) LORAMAC_STEPWIDTH_RX1_CHANNEL ) == 0 ) )
01625 #endif
01626     {
01627         return true;
01628     }
01629     return false;
01630 }
01631 
01632 __attribute__((weak)) void
01633 deviceTimeClassB(uint32_t secs, uint32_t subsecs)
01634 {
01635 }
01636 
01637 /* return -1 for unknown mac cmd */
01638 static int
01639 ProcessMacCommands(const uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, float snr)
01640 {
01641     uint8_t buf[2];
01642     int ret = 0;
01643 
01644     MACC_PRINTF("ProcessMacCommands(, %u, %u,,) ", macIndex, commandsSize);
01645     while (macIndex < commandsSize)
01646     {
01647         MACC_PRINTF("ProcessMacCommands %u(0x%02x): ", macIndex, payload[macIndex]);
01648         // Decode Frame MAC commands
01649         switch (payload[macIndex++])
01650         {
01651             case SRV_MAC_LINK_CHECK_ANS:
01652                 MACC_PRINTF("LINK_CHECK_ANS ");
01653                 buf[0] = payload[macIndex++];
01654                 buf[1] = payload[macIndex++];
01655                 MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
01656                 MlmeConfirm.fields.link.DemodMargin = buf[0];
01657                 MlmeConfirm.fields.link.NbGateways = buf[1];
01658                 break;
01659             case SRV_MAC_MODE_CONF:
01660                 break;
01661             case SRV_MAC_LINK_ADR_REQ:
01662                 MACC_PRINTF("LINK_ADR_REQ ");
01663                 {
01664                     uint8_t i;
01665                     int8_t txPower = 0;
01666                     uint8_t Redundancy = 0;
01667                     adr_t adr;
01668 
01669                     adr.status = 0x07;
01670                     // Initialize local copy of the channels mask array
01671                     for( i = 0; i < 6; i++ )
01672                     {
01673                         adr.channelsMask[i] = LoRaMacParams.ChannelsMask [i];
01674                     }
01675                     adr.datarate = payload[macIndex++];
01676                     txPower = adr.datarate & 0x0F;
01677                     adr.datarate = ( adr.datarate >> 4 ) & 0x0F;
01678                     MACC_PRINTF("dr%u power%u ", adr.datarate, txPower);
01679 
01680                     if( ( flags.AdrCtrlOn == false ) &&
01681                         ( ( LoRaMacParams.ChannelsDatarate  != adr.datarate ) || ( LoRaMacParams.ChannelsTxPower  != txPower ) ) )
01682                     { // ADR disabled don't handle ADR requests if server tries to change datarate or txpower
01683                         MACC_PRINTF("AdrCtrlOn:%u dr%u != dr%u, %d != %d\r\n", flags.AdrCtrlOn,
01684                             LoRaMacParams.ChannelsDatarate , adr.datarate,
01685                             LoRaMacParams.ChannelsTxPower , txPower
01686                         );
01687                         // Answer the server with fail status
01688                         // Power ACK     = 0
01689                         // Data rate ACK = 0
01690                         // Channel mask  = 0
01691                         AddMacCommand( MOTE_MAC_LINK_ADR_ANS, 0, 0 );
01692                         macIndex += 3;  // Skip over the remaining bytes of the request
01693                         break;
01694                     }
01695                     adr.chMask = ( uint16_t )payload[macIndex++];
01696                     adr.chMask |= ( uint16_t )payload[macIndex++] << 8;
01697 
01698                     Redundancy = payload[macIndex++];
01699                     adr.chMaskCntl = ( Redundancy >> 4 ) & 0x07;
01700                     if ((Redundancy & 0x0f) > 0)
01701                         LoRaMacParams.NbTrans  = Redundancy & 0x0f;
01702 
01703                     MACC_PRINTF("chMask:%04x chMaskCntl:%x nbTrans:%u ", adr.chMask, adr.chMaskCntl, LoRaMacParams.NbTrans );
01704 
01705                     region_adr_request(&adr);
01706 
01707                     if( ValidateDatarate( adr.datarate, adr.channelsMask ) == false )
01708                     {
01709                         MACC_PRINTF("badDr ");
01710                         adr.status &= 0xFD; // Datarate KO
01711                     }
01712 
01713                     //
01714                     // Remark MaxTxPower = 0 and MinTxPower = 5
01715                     //
01716                     if( ValueInRange( txPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) == false )
01717                     {
01718                         MACC_PRINTF("badPower(max:%d given:%d min:%d) ", LORAMAC_MAX_TX_POWER, txPower, LORAMAC_MIN_TX_POWER);
01719                         adr.status &= 0xFB; // TxPower KO
01720                     }
01721                     MACC_PRINTF("status:%x (idx %u) ", adr.status, macIndex);
01722                     if( ( adr.status & 0x07 ) == 0x07 )
01723                     {
01724                         LoRaMacParams.ChannelsDatarate  = adr.datarate;
01725                         LoRaMacParams.ChannelsTxPower  = txPower;
01726 
01727                         memcpy( ( uint8_t* )LoRaMacParams.ChannelsMask , ( uint8_t* )adr.channelsMask, sizeof( LoRaMacParams.ChannelsMask  ) );
01728                         LoRaMacParams.NbEnabledChannels = region_CountNbEnabledChannels();
01729 
01730                     }
01731                     AddMacCommand( MOTE_MAC_LINK_ADR_ANS, adr.status, 0 );
01732                 }
01733                 break;
01734             case SRV_MAC_RX_PARAM_SETUP_REQ:
01735                 {
01736                     uint8_t status = 0x07;
01737                     int8_t datarate = 0;
01738                     int8_t drOffset = 0;
01739                     uint32_t freq = 0;
01740 
01741                     drOffset = ( payload[macIndex] >> 4 ) & 0x07;
01742                     datarate = payload[macIndex] & 0x0F;
01743                     macIndex++;
01744 
01745                     freq =  ( uint32_t )payload[macIndex++];
01746                     freq |= ( uint32_t )payload[macIndex++] << 8;
01747                     freq |= ( uint32_t )payload[macIndex++] << 16;
01748                     freq *= 100;
01749                     MACC_PRINTF("RX_PARAM_SETUP_REQ %uhz drOffset:%u dr%u ", freq, drOffset, datarate);
01750 
01751                     if( Rx2FreqInRange( freq ) == false )
01752                     {
01753                         status &= 0xFE; // Channel frequency KO
01754                     }
01755 
01756                     if( ValueInRange( datarate, LORAMAC_RX_MIN_DATARATE, LORAMAC_RX_MAX_DATARATE ) == false )
01757                     {
01758                         status &= 0xFD; // Datarate KO
01759                     }
01760 #if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
01761                     if( ( ValueInRange( datarate, DR_5, DR_7 ) == true ) ||
01762                         ( datarate > DR_13 ) )
01763                     {
01764                         status &= 0xFD; // Datarate KO
01765                     }
01766 #endif
01767                     if( ValueInRange( drOffset, LORAMAC_MIN_RX1_DR_OFFSET, LORAMAC_MAX_RX1_DR_OFFSET ) == false )
01768                     {
01769                         status &= 0xFB; // Rx1DrOffset range KO
01770                     }
01771 
01772                     MACC_PRINTF("status:0x%02x ", status);
01773                     if( ( status & 0x07 ) == 0x07 )
01774                     {
01775                         LoRaMacParams.Rx2Channel .Datarate = datarate;
01776                         LoRaMacParams.Rx2Channel .FrequencyHz = freq;
01777                         LoRaMacParams.Rx1DrOffset  = drOffset;
01778                     }
01779                     AddMacCommand( MOTE_MAC_RX_PARAM_SETUP_ANS, status, 0 );
01780                 }
01781                 break;
01782             case SRV_MAC_DEV_STATUS_REQ:
01783                 MACC_PRINTF("DEV_STATUS_REQ ");
01784                 {
01785                     uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE;
01786                     if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->GetBatteryLevel != NULL ) )
01787                     {
01788                         batteryLevel = LoRaMacCallbacks->GetBatteryLevel( );
01789                     }
01790                     AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr );
01791                     break;
01792                 }
01793             case SRV_MAC_NEW_CHANNEL_REQ:
01794                 {
01795                     uint8_t status = 0x03;
01796 
01797 #if defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
01798                     status &= 0xFC; // Channel frequency and datarate KO
01799                     macIndex += 5;
01800 #else
01801                     int8_t channelIndex = 0;
01802                     ChannelParams_t chParam;
01803 
01804                     channelIndex = payload[macIndex++];
01805                     chParam.FreqHz = ( uint32_t )payload[macIndex++];
01806                     chParam.FreqHz |= ( uint32_t )payload[macIndex++] << 8;
01807                     chParam.FreqHz |= ( uint32_t )payload[macIndex++] << 16;
01808                     chParam.FreqHz *= 100;
01809                     chParam.DrRange.Value = payload[macIndex++];
01810                     MACC_PRINTF("NEW_CHANNEL_REQ ch%u %uhz drRange:%02x ", channelIndex, chParam.Frequency, chParam.DrRange.Value);
01811 
01812                     if( chParam.FreqHz == 0 )
01813                     {
01814                         if( channelIndex < 3 )
01815                         {
01816                             status &= 0xFC;
01817                         }
01818                         else
01819                         {
01820                             if( LoRaMacChannelRemove( channelIndex ) != LORAMAC_STATUS_OK )
01821                             {
01822                                 status &= 0xFC;
01823                             }
01824                         }
01825                     }
01826                     else
01827                     {
01828                         switch( LoRaMacChannelAdd( channelIndex, chParam ) )
01829                         {
01830                             case LORAMAC_STATUS_OK:
01831                             {
01832                                 MACC_PRINTF("add-ok ");
01833                                 break;
01834                             }
01835                             case LORAMAC_STATUS_FREQUENCY_INVALID:
01836                             {
01837                                 MACC_PRINTF("add-bad-freq ");
01838                                 status &= 0xFE;
01839                                 break;
01840                             }
01841                             case LORAMAC_STATUS_DATARATE_INVALID:
01842                             {
01843                                 MACC_PRINTF("add-bad-dr ");
01844                                 status &= 0xFD;
01845                                 break;
01846                             }
01847                             case LORAMAC_STATUS_FREQ_AND_DR_INVALID:
01848                             {
01849                                 MACC_PRINTF("add-bad-both ");
01850                                 status &= 0xFC;
01851                                 break;
01852                             }
01853                             default:
01854                             {
01855                                 MACC_PRINTF("add-bad-? ");
01856                                 status &= 0xFC;
01857                                 break;
01858                             }
01859                         }
01860                     }
01861 #endif
01862                     MACC_PRINTF("status:%x ", status);
01863                     AddMacCommand( MOTE_MAC_NEW_CHANNEL_ANS, status, 0 );
01864                 }
01865                 break;
01866             case SRV_MAC_ADR_PARAM_SETUP_REQ:
01867                 MACC_PRINTF("ADR_PARAM_SETUP_REQ");
01868                 {
01869                     uint8_t exps = payload[macIndex++] & 0x0F;
01870                     ADR_ACK_LIMIT = 1 << (exps >> 4);
01871                     ADR_ACK_DELAY = 1 << (exps & 0x0f);
01872                 }
01873                 AddMacCommand(SRV_MAC_ADR_PARAM_SETUP_ANS, 0, 0);
01874                 break;
01875             case SRV_MAC_RX_TIMING_SETUP_REQ:
01876                 MACC_PRINTF("RX_TIMING_SETUP_REQ");
01877                 {
01878                     uint8_t delay = payload[macIndex++] & 0x0F;
01879 
01880                     if( delay == 0 )
01881                     {
01882                         delay++;
01883                     }
01884                     LoRaMacParams.ReceiveDelay1_us  = delay * 1e6;
01885                     LoRaMacParams.ReceiveDelay2_us  = LoRaMacParams.ReceiveDelay1_us  + 1e6;
01886                     AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 );
01887                 }
01888                 break;
01889 #ifdef LORAWAN_JOIN_EUI
01890             case SRV_MAC_REKEY_CONF:
01891                 macIndex++; //TODO server_version = payload[macIndex++];
01892                 
01893                 flags.need_ReKeyConf = 0;
01894                 break;
01895             case SRV_MAC_FORCE_REJOIN_REQ:
01896                 {
01897                     uint16_t cmd_payload = payload[macIndex++];
01898                     cmd_payload |= payload[macIndex++] << 8;
01899                     rejoin.type = (cmd_payload >> 4) & 7;
01900                     if (rejoin.type == 2)
01901                         JoinReqType = 2;
01902                     else {
01903                         JoinReqType = 0;
01904                         rejoin.type = 0;
01905                     }
01906 
01907                     rejoin.dr = cmd_payload & 0x0f;
01908                     LoRaMacParams.ChannelsDatarate  = rejoin.dr;
01909                     rejoin.retries = 1 + ((cmd_payload >> 8) & 7);
01910                     MAC_PRINTF("FORCE_REJOIN 0x%04x dr%u type%u tries%u ", cmd_payload, LoRaMacParams.ChannelsDatarate , JoinReqType, rejoin.retries);
01911 
01912                     {
01913                         rejoin.Period = (cmd_payload >> 11) & 7;
01914                         /* first forced-rejoin attempt must be immediate */
01915                         rejoin.event.attach_us(_rejoin_retry, 50000);
01916                         rejoin.forced = true;
01917                     }
01918                 }
01919                 break;
01920             case SRV_MAC_REJOIN_PARAM_REQ:
01921                 {
01922                     uint8_t p = payload[macIndex++];
01923                     rejoin.type0.MaxTimeN = p >> 4;
01924                     rejoin.type0.MaxCountN = p & 0xf;
01925                     rejoin.type0.enabled = true;
01926                     MACC_PRINTF("REJOIN_PARAM MaxTimeN%u MaxCountN%u ", rejoin.type0.MaxTimeN, rejoin.type0.MaxCountN);
01927                     rejoin.type0.uplinks_since = 1 << (rejoin.type0.MaxCountN + 4);
01928                     AddMacCommand(MOTE_MAC_REJOIN_PARAM_ANS, 0, 0);
01929                 }
01930                 break;
01931 #else
01932             case SRV_MAC_RESET_CONF:
01933                 macIndex++; //TODO server_version = payload[macIndex++];
01934                 flags.need_ResetConf = 0;
01935                 break;
01936 #endif /* !LORAWAN_JOIN_EUI  */
01937             case SRV_MAC_DEVICE_TIME_ANS:
01938                 {
01939                     uint32_t subusecs, secs;
01940                     us_timestamp_t us_since_tx_done;
01941                     secs = payload[macIndex++];
01942                     secs += payload[macIndex++] << 8;
01943                     secs += payload[macIndex++] << 16;
01944                     secs += payload[macIndex++] << 24;
01945                     subusecs = payload[macIndex++] * 3906.5;
01946 
01947                     //MAC_PRINTF("secs:%u, subusecs:%u\r\n", secs, subusecs);
01948                     deviceTimeClassB(secs, subusecs);
01949 
01950                     us_since_tx_done = Radio::lpt.read_us() - tx_done_at;
01951                     MlmeConfirm.fields.time.uSeconds += us_since_tx_done;
01952                     while (us_since_tx_done >= 1000000) {
01953                         MlmeConfirm.fields.time.Seconds++;
01954                         us_since_tx_done -= 1000000;
01955                     }
01956                     MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
01957                     MlmeConfirm.fields.time.Seconds = secs;
01958                     MlmeConfirm.fields.time.uSeconds = subusecs;
01959                 }
01960                 break;
01961             default:
01962                 --macIndex;
01963                 if (ProcessMacCommandsClassB(payload, &macIndex)) {
01964                     /* mac command was taken */
01965                     //MACC_PRINTF("B-cont\r\n");
01966                 }
01967 #ifdef DUTY_ENABLE
01968                 else if (ProcessMacCommandsDuty(payload, &macIndex)) {
01969                     /* mac command was taken */
01970                 }
01971 #endif /* DUTY_ENABLE */
01972                 else {
01973                     ret = -1;
01974                     MAC_PRINTF("unknown mac:0x%02x at %u\r\n", payload[macIndex-1], macIndex-1);
01975                 }
01976                 break;
01977         } // ..switch(payload[macIndex++])
01978 
01979         MACC_PRINTF("\r\n");
01980 
01981     } // ..while( macIndex < commandsSize )
01982 
01983     return ret;
01984 } // ..ProcessMacCommands()
01985 
01986 #define MAX_FCNT_GAP        0x4000
01987 /* return: true == send downlink ack */
01988 static int
01989 rx_downlink(uint8_t pktHeaderLen, uint16_t rx_size, int8_t snr)
01990 {
01991     LoRaMacHeader_t  macHdr;
01992     LoRaMacFrameCtrl_t fCtrl;
01993     uint32_t myFCntDwn32, rxFCnt32;
01994     uint8_t rxFPort;
01995     uint16_t rxFCnt16;
01996     uint32_t address;
01997     uint32_t mic, micRx;
01998     uint8_t appPayloadStartIndex = 0;
01999     bool skipIndication = false;
02000     uint8_t frameLen = 0;
02001     bool is_AFCntDown;
02002     block_t block;
02003     const uint8_t* rx_payload = Radio::radio.rx_buf;
02004 
02005     macHdr.Value  = rx_payload[0];
02006 
02007     address = rx_payload[pktHeaderLen++];
02008     address |= ( (uint32_t)rx_payload[pktHeaderLen++] << 8 );
02009     address |= ( (uint32_t)rx_payload[pktHeaderLen++] << 16 );
02010     address |= ( (uint32_t)rx_payload[pktHeaderLen++] << 24 );
02011 
02012     fCtrl.Value = rx_payload[pktHeaderLen++];
02013 
02014     rxFCnt16 = ( uint16_t )rx_payload[pktHeaderLen++];
02015     rxFCnt16 |= ( uint16_t )rx_payload[pktHeaderLen++] << 8;
02016 
02017     is_AFCntDown = false;
02018     if (( ( rx_size - 4 ) - (8 + fCtrl.Bits.FOptsLen) ) > 0) {
02019         appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
02020         rxFPort = rx_payload[appPayloadStartIndex++];
02021         if (flags.OptNeg && rxFPort > 0)
02022             is_AFCntDown = true;
02023     } /* else no payload/fport present */
02024 
02025     myFCntDwn32 = get_fcntdwn(is_AFCntDown);
02026 
02027     McpsIndication.expectedFCntDown = myFCntDwn32;
02028     McpsIndication.receivedFCntDown = rxFCnt16;
02029 
02030     rxFCnt32 = (myFCntDwn32 & 0xffff0000) | rxFCnt16;
02031     DEBUG_MIC_DOWN(" rxFCnt32:%" PRIu32" ", rxFCnt32);
02032 
02033     micRx = ( uint32_t )rx_payload[rx_size - LORAMAC_MFR_LEN];
02034     micRx |= ( ( uint32_t )rx_payload[rx_size - LORAMAC_MFR_LEN + 1] << 8 );
02035     micRx |= ( ( uint32_t )rx_payload[rx_size - LORAMAC_MFR_LEN + 2] << 16 );
02036     micRx |= ( ( uint32_t )rx_payload[rx_size - LORAMAC_MFR_LEN + 3] << 24 );
02037 
02038     block.b.header = 0x49;
02039     if (flags.OptNeg)
02040         block.b.confFCnt = ConfFCntUp;
02041     else
02042         block.b.confFCnt = 0;
02043     block.b.dr = 0;
02044     block.b.ch = 0;
02045     block.b.dir = DOWN_LINK;
02046     block.b.DevAddr = address;
02047     block.b.FCnt = rxFCnt32;
02048     block.b.zero8 = 0;
02049     block.b.lenMsg = rx_size - LORAMAC_MFR_LEN;
02050     mic = LoRaMacComputeMic(&block, rx_payload, keys.SNwkSIntKey);
02051     if (micRx != mic) {
02052         bool ignore_rx = true;
02053         PrepareRxDoneAbort(LORAMAC_EVENT_INFO_STATUS_MIC_FAIL);
02054         MAC_PRINTF("\e[31mmicFail");
02055         if (flags.OptNeg) {
02056             block.b.confFCnt = ConfFCntUp - 1;
02057             mic = LoRaMacComputeMic(&block, rx_payload, keys.SNwkSIntKey);
02058             if (micRx == mic)
02059                 ignore_rx = false;
02060             else {
02061                 block.b.confFCnt = 0;
02062                 mic = LoRaMacComputeMic(&block, rx_payload, keys.SNwkSIntKey);
02063                 if (micRx == mic)
02064                     ignore_rx = false;
02065             }
02066         }
02067         if (ignore_rx) {
02068             MAC_PRINTF("\e[0m\r\n");
02069             return -1;
02070         } else {
02071             McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
02072             if (LoRaMacPrimitives->MacMcpsIndication != NULL)
02073                 LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
02074         }
02075     } else {
02076         /* downlink with good MIC means previous confirmed uplink was receied */
02077         ConfFCntUp = 0;
02078         if (McpsIndication.RxSlot == 1) {   // no need for RX2 with good mic on rx1
02079             RxWindowEvent2.detach();
02080         }
02081     }
02082 
02083     McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
02084     //McpsIndication.Multicast = 0;//multicast;
02085     McpsIndication.FramePending = fCtrl.Bits.FPending;
02086     McpsIndication.Buffer = NULL;
02087     McpsIndication.BufferSize = 0;
02088 
02089     MacCommandsBufferToRepeatIndex = 0;
02090 
02091     if (macHdr.Bits.MType  == FRAME_TYPE_DATA_CONFIRMED_DOWN)
02092     {
02093         flags.SrvAckRequested = true;
02094         McpsIndication.McpsIndication = MCPS_CONFIRMED;
02095 
02096 #ifdef LORAWAN_JOIN_EUI
02097         if (flags.IsLoRaMacNetworkJoined)
02098 #endif /* LORAWAN_JOIN_EUI  */
02099 
02100         if (flags.OptNeg)
02101             ConfFCntDown = rxFCnt16;
02102     }
02103     else
02104     {   // FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
02105         ConfFCntDown = 0;
02106         flags.SrvAckRequested = false;
02107         McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
02108     }
02109 
02110     if (fCtrl.Bits.FOptsLen > 0)
02111     {
02112         // Decode Options field MAC commands
02113         if (flags.OptNeg) {
02114             uint32_t FCnt32;
02115             bool fromStored;
02116             uint8_t macDecrypt[16];
02117             DEBUG_CRYPT_BUF(keys.NwkSEncKey, 16, "NwkSEncKey", 0);
02118             if (appPayloadStartIndex > 0) {
02119                 /* rx header has AFCntDown: not for use with FOpts */
02120                 FCnt32 = get_fcntdwn(false);
02121                 fromStored = true;
02122             } else {
02123                 /* NFCntDown received in rx header */
02124                 FCnt32 = (get_fcntdwn(false) & 0xffff0000) | rxFCnt16;
02125                 fromStored = false;
02126             }
02127             DEBUG_CRYPT("FCnt32:%" PRIu32" ", FCnt32);
02128             DEBUG_CRYPT_BUF(rx_payload+8, fCtrl.Bits.FOptsLen, "FOpts-rx", 0);
02129             LoRaMacEncrypt(0, rx_payload+8, fCtrl.Bits.FOptsLen, keys.NwkSEncKey, LoRaMacDevAddr, DOWN_LINK, FCnt32, macDecrypt);
02130             DEBUG_CRYPT_BUF(macDecrypt, fCtrl.Bits.FOptsLen, "FOpts-decrypt", 0);
02131             if (ProcessMacCommands(macDecrypt, 0, fCtrl.Bits.FOptsLen, snr) < 0) {
02132                 if (fromStored) {
02133                     MAC_PRINTF("fromStored-");
02134                 }
02135                 MAC_PRINTF("FCnt32:%lu ", FCnt32);
02136             }
02137         } else {
02138             MAC_PRINTF("ProcessMacCommands-FOpts ");
02139             ProcessMacCommands( rx_payload, 8, fCtrl.Bits.FOptsLen + 8, snr);
02140         }
02141     }
02142 
02143     if (appPayloadStartIndex > 0)
02144     {
02145         frameLen = ( rx_size - 4 ) - appPayloadStartIndex;
02146 
02147         McpsIndication.Port = rxFPort;
02148 
02149         if (rxFPort == 0)
02150         {
02151             if( ( fCtrl.Bits.FOptsLen == 0 ) /*&& ( multicast == 0 )*/ )
02152             {
02153                 uint8_t macDecrypt[16];
02154                 LoRaMacPayloadDecrypt(rx_payload + appPayloadStartIndex,
02155                                       frameLen,
02156                                       keys.NwkSEncKey,
02157                                       address,
02158                                       DOWN_LINK,
02159                                       rxFCnt32,
02160                                       macDecrypt
02161                 );
02162 
02163                 // Decode frame payload MAC commands
02164                 MAC_PRINTF("ProcessMacCommands-payload ");
02165                 if (ProcessMacCommands( macDecrypt, 0, frameLen, snr) < 0) {
02166                     MAC_PRINTF(" rxFCnt32:%" PRIu32 " ", rxFCnt32);
02167                 }
02168             }
02169             else
02170             {
02171                 skipIndication = true;
02172             }
02173         }
02174         else
02175         {   /* rxFPort > 0 */
02176             MAC_PRINTF("rxFCnt32:%" PRIu32" %08" PRIx32" ", rxFCnt32, address);
02177             MAC_PRINTF("FCntDown%" PRIu32 " ", rxFCnt32);
02178             DEBUG_CRYPT(" addr%" PRIx32" len%u\r\n", address, frameLen);
02179             DEBUG_CRYPT_BUF(rx_payload + appPayloadStartIndex, frameLen, "rxEncd", 0);
02180             DEBUG_CRYPT_BUF(keys.AppSKey, 16, "AppSKey", 0);
02181             LoRaMacPayloadDecrypt(rx_payload + appPayloadStartIndex,
02182                                   frameLen,
02183                                   keys.AppSKey,
02184                                   address,
02185                                   DOWN_LINK,
02186                                   rxFCnt32,
02187                                   rxFRMPayload
02188             );
02189 
02190             if( skipIndication == false )
02191             {
02192                 McpsIndication.Buffer = rxFRMPayload;
02193                 McpsIndication.BufferSize = frameLen;
02194                 McpsIndication.RxData = true;
02195             }
02196         }
02197     } // ..if have payload
02198 
02199     if (!skipIndication)
02200     {
02201         McpsIndication.AckReceived = fCtrl.Bits.Ack;
02202         McpsConfirm.AckReceived = fCtrl.Bits.Ack;
02203 
02204         if (LoRaMacPrimitives->MacMcpsIndication != NULL)
02205             LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );    // RxDone
02206     }
02207 
02208     if (McpsIndication.RxSlot == 1 || McpsIndication.RxSlot == 2)
02209         McpsIndication.ADR_ACK_CNT = 0;
02210 
02211     /* set FCntDwn to next expected value, if last NbTrans */
02212 #ifdef LORAWAN_JOIN_EUI
02213     if (flags.uplink_in_progress <= 1 && last_up_macHdr.Bits.MType  == FRAME_TYPE_DATA_CONFIRMED_UP) {
02214         if (fCtrl.Bits.Ack) {
02215             FCntUp++;
02216         } else {
02217             MAC_PRINTF("\e[31mrx-!ack\e[0m\n");
02218         }
02219     }
02220 
02221     if (is_AFCntDown) {
02222         AFCntDown = rxFCnt32 + 1;
02223     } else {
02224         NFCntDown = rxFCnt32 + 1;
02225     }
02226 #else
02227     /* if last NbTrans confirmed uplink ack'd ok: increment FCntUp */
02228     if (flags.uplink_in_progress <= 1 && fCtrl.Bits.Ack && last_up_macHdr.Bits.MType  == FRAME_TYPE_DATA_CONFIRMED_UP) {
02229         eeprom_increment_value(EEPROM_FCNTUP);  /* TODO handle ee-failure return */
02230     }
02231 
02232     if (is_AFCntDown)
02233         eeprom_write_word(EEPROM_AFCNTDWN, rxFCnt32 + 1);
02234     else
02235         eeprom_write_word(EEPROM_NFCNTDWN, rxFCnt32 + 1);
02236 #endif /* !LORAWAN_JOIN_EUI */
02237 
02238     return 0;
02239 } // ...rx_downlink()
02240 
02241 
02242 #ifdef LORAWAN_JOIN_EUI
02243 typedef union {
02244     struct {
02245         uint8_t mhdr;
02246         unsigned int joinNonce : 24;
02247         unsigned int Home_NetID : 24;
02248         uint32_t DevAddr;
02249         struct {
02250             uint8_t RX2dr       : 4;  // 0,1,2,3
02251             uint8_t RX1DRoffset : 3;  // 4,5,6
02252             uint8_t OptNeg      : 1;  // 7
02253         } DLSettings;
02254         uint8_t RxDelay;
02255     } __attribute__((packed)) fields;
02256     uint8_t octets[13];
02257 } joinAccept_t;
02258 #endif /* LORAWAN_JOIN_EUI  */
02259 
02260 
02261 #define JOIN_ACCEPT_MAX_SIZE        34
02262 static void
02263 //OnRadioRxDone(uint8_t *rx_payload, uint16_t rx_size, int16_t rssi, int8_t snr, us_timestamp_t us_rxDone_at)
02264 OnRadioRxDone(uint8_t rx_size, float rssi, float snr)
02265 {
02266     LoRaMacEventInfoStatus_t status = LORAMAC_EVENT_INFO_STATUS_UNKNOWN_MTYPE;
02267     LoRaMacHeader_t  macHdr;
02268 #ifdef LORAWAN_JOIN_EUI
02269     uint8_t _jaDecrypted[JOIN_ACCEPT_MAX_SIZE];
02270     uint32_t mic, micRx;
02271     const uint8_t* key;
02272     const joinAccept_t* ja;
02273 #endif /* LORAWAN_JOIN_EUI  */
02274     uint8_t pktHeaderLen = 0;
02275 
02276     McpsConfirm.AckReceived = false;
02277     McpsIndication.Rssi = rssi;
02278     McpsIndication.Snr = snr;
02279     McpsIndication.Port = 0;
02280     //McpsIndication.Multicast = 0;
02281     McpsIndication.FramePending = 0;
02282     McpsIndication.Buffer = NULL;
02283     McpsIndication.BufferSize = 0;
02284     McpsIndication.RxData = false;
02285     McpsIndication.AckReceived = false;
02286     McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
02287 
02288     if (MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_SENDING) {
02289         /* when regular downlink is sent in response to rejoin request */
02290         MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
02291     }
02292 
02293     if (LoRaMacDeviceClass != CLASS_C)
02294     {
02295         Radio::Sleep();
02296     }
02297 
02298     MAC_PRINTF("OnRadioRxDone(%u) RxSlot%d ", rx_size, McpsIndication.RxSlot);
02299     if (beacon_rx_done_payload(rx_size))
02300         return;
02301 
02302     macHdr.Value  = Radio::radio.rx_buf[pktHeaderLen++];
02303 
02304     MAC_PRINTF(" rx-");
02305     print_mtype(macHdr.Bits.MType );
02306     switch (macHdr.Bits.MType )
02307     {
02308 #ifdef LORAWAN_JOIN_EUI
02309         case FRAME_TYPE_JOIN_ACCEPT:
02310             /* always permitting join accept because it might be due to rejoin */
02311             if (rx_size >= JOIN_ACCEPT_MAX_SIZE) {
02312                 MAC_PRINTF("joinAccept overSize %u\r\n", rx_size);
02313                 return;
02314             }
02315 
02316             DEBUG_CRYPT_BUF(Radio::radio.rx_buf, rx_size, "rxBuf", 0);
02317             MAC_PRINTF("JoinReqType:%02x ", JoinReqType);
02318             if (JoinReqType == 0xff) {
02319                 DEBUG_CRYPT_BUF(RootNwkKey, 16, "NwkKey", 0);
02320                 key = RootNwkKey;
02321             } else {
02322                 key = JSEncKey;
02323                 DEBUG_CRYPT_BUF(JSEncKey, 16, "JSEncKey", 0);
02324             }
02325             LoRaMacJoinDecrypt( Radio::radio.rx_buf + 1, rx_size - 1, key, &_jaDecrypted[1]);
02326             DEBUG_CRYPT_BUF(_jaDecrypted, rx_size, "macbuf", 0);
02327 
02328             _jaDecrypted[0] = macHdr.Value ;
02329             ja = (joinAccept_t*)_jaDecrypted;
02330             flags.OptNeg = ja->fields.DLSettings.OptNeg;
02331 
02332             if (flags.OptNeg) {
02333                 uint8_t micBuf[40];
02334                 uint8_t* ptr = micBuf;
02335                 if (RootAppKey == NULL) {
02336                     MAC_PRINTF("OptNeg-without-AppKey ");
02337                     PrepareRxDoneAbort(LORAMAC_EVENT_INFO_STATUS_NO_APPKEY);
02338                     return;
02339                 }
02340                 *ptr++ = JoinReqType;
02341                 memcpyr(ptr, LoRaMacJoinEui, 8);
02342                 ptr += 8;
02343                 *ptr++ = LoRaMacDevNonce & 0xff;
02344                 *ptr++ = LoRaMacDevNonce >> 8;
02345                 memcpy(ptr, _jaDecrypted, rx_size - LORAMAC_MFR_LEN);
02346                 ptr += rx_size - LORAMAC_MFR_LEN;
02347                 DEBUG_MIC_BUF_DOWN(JSIntKey, 16, "JSIntKey", ROW_MIC);
02348                 DEBUG_MIC_BUF_DOWN(micBuf, ptr - micBuf, "jaMic-in", ROW_MIC+1);
02349                 if (LoRaMacJoinComputeMic(false, micBuf, ptr - micBuf, JSIntKey, &mic ) < 0) {
02350                     MAC_PRINTF("cryptFail\r\n");
02351                     return;
02352                 }
02353             } else {
02354                 if (LoRaMacJoinComputeMic(false, _jaDecrypted, rx_size - LORAMAC_MFR_LEN, RootNwkKey, &mic ) < 0) {
02355                     MAC_PRINTF("cryptFail\r\n");
02356                     return;
02357                 }
02358             }
02359 
02360             micRx = ( uint32_t )_jaDecrypted[rx_size - LORAMAC_MFR_LEN];
02361             micRx |= ( ( uint32_t )_jaDecrypted[rx_size - LORAMAC_MFR_LEN + 1] << 8 );
02362             micRx |= ( ( uint32_t )_jaDecrypted[rx_size - LORAMAC_MFR_LEN + 2] << 16 );
02363             micRx |= ( ( uint32_t )_jaDecrypted[rx_size - LORAMAC_MFR_LEN + 3] << 24 );
02364 
02365             MAC_PRINTF("JOIN_ACCEPT %u,OptNeg%" PRIu32" ", rx_size, flags.OptNeg);
02366 
02367             if (micRx == mic)
02368             {
02369                 if (McpsIndication.RxSlot == 1) {  // no need for RX2 with good mic on rx1
02370                     RxWindowEvent2.detach();
02371                 }
02372 
02373 #ifdef LORAWAN_ROOT_APPKEY        
02374                 if (flags.OptNeg) {
02375                     MlmeConfirm.fields.join.myJoinNonce = eeprom_read(EEPROM_JOINNONCE);
02376                     MlmeConfirm.fields.join.rxJoinNonce = ja->fields.joinNonce;
02377                     if (MlmeConfirm.fields.join.rxJoinNonce <= MlmeConfirm.fields.join.myJoinNonce) {
02378                         /* replay attack */
02379                         PrepareRxDoneAbort(LORAMAC_EVENT_INFO_STATUS_JOINNONCE);
02380                         return;
02381                     }
02382                     flags.need_ReKeyConf = 1;
02383                     LoRaMacJoinComputeSKeys_1v1( RootNwkKey, RootAppKey, _jaDecrypted+1, LoRaMacJoinEui, LoRaMacDevNonce, &keys);
02384                     eeprom_write_word(EEPROM_JOINNONCE, MlmeConfirm.fields.join.rxJoinNonce);
02385                 } else
02386 #endif /* LORAWAN_ROOT_APPKEY */
02387                     LoRaMacJoinComputeSKeys_1v0( RootNwkKey, _jaDecrypted+1, LoRaMacDevNonce, &keys);
02388 
02389                 DEBUG_CRYPT_BUF(keys.AppSKey , 16, "create-AppSKey", 0);
02390 
02391                 LoRaMacNetID = ja->fields.Home_NetID;
02392                 LoRaMacDevAddr = ja->fields.DevAddr;
02393 
02394                 // DLSettings
02395                 LoRaMacParams.Rx1DrOffset  = ja->fields.DLSettings.RX1DRoffset;
02396                 LoRaMacParams.Rx2Channel .Datarate = ja->fields.DLSettings.RX2dr;
02397 
02398                 // RxDelay
02399                 LoRaMacParams.ReceiveDelay1_us  = (ja->fields.RxDelay & 0x0f) * 1000000;
02400                 if( LoRaMacParams.ReceiveDelay1_us  == 0 )
02401                 {
02402                     LoRaMacParams.ReceiveDelay1_us  = 1000000;
02403                 }
02404                 LoRaMacParams.ReceiveDelay2_us  = LoRaMacParams.ReceiveDelay1_us  + 1000000;
02405                 MAC_PRINTF("rx1droffset:%u, rx2dr%u rxDelays:%" PRIu32" %" PRIu32", devaddr:%08" PRIx32" ",
02406                     LoRaMacParams.Rx1DrOffset ,
02407                     LoRaMacParams.Rx2Channel .Datarate,
02408                     LoRaMacParams.ReceiveDelay1_us ,
02409                     LoRaMacParams.ReceiveDelay2_us ,
02410                     LoRaMacDevAddr
02411                 );
02412 
02413 #if !( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )  // TODO
02414                 //CFList
02415                 if( ( rx_size - 1 ) > 16 )
02416                 {
02417                     ChannelParams_t param;
02418                     param.DrRange.Value = ( LORAMAC_TX_MAX_DATARATE << 4 ) | LORAMAC_TX_MIN_DATARATE;
02419 
02420                     for( uint8_t i = 3, j = 0; i < ( 5 + 3 ); i++, j += 3 )
02421                     {
02422                         param.FreqHz = ( ( uint32_t )_jaDecrypted[13 + j] | ( ( uint32_t )_jaDecrypted[14 + j] << 8 ) | ( ( uint32_t )_jaDecrypted[15 + j] << 16 ) ) * 100;
02423                         if( param.FreqHz != 0 )
02424                         {
02425                             LoRaMacChannelAdd( i, param );
02426                         }
02427                         else
02428                         {
02429                             LoRaMacChannelRemove( i );
02430                         }
02431                     }
02432                 }
02433 #endif
02434                 status = LORAMAC_EVENT_INFO_STATUS_OK;
02435                 flags.IsLoRaMacNetworkJoined = true;
02436                 LoRaMacParams.ChannelsDatarate  = LoRaMacParamsDefaults.ChannelsDatarate ;
02437 
02438                 MAC_PRINTF("JoinReqType%x\r\n", JoinReqType);
02439                 FCntUp = 0;
02440                 NFCntDown = 0;
02441                 AFCntDown = 0;
02442                 ConfFCntDown = 0;
02443                 RJcount0 = 0;
02444                 McpsIndication.ADR_ACK_CNT = 0;
02445 
02446                 rejoin.event.detach();
02447 
02448                 // must always notify application layer
02449                 MlmeConfirm.MlmeRequest = MLME_JOIN;
02450                 region_session_start(LORAMAC_EVENT_INFO_STATUS_OK);
02451             }
02452             else
02453             {   /* join-accept mic fail */
02454                 status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
02455                 MAC_PRINTF("ja-mic-fail rx:%" PRIx32 " calc:%" PRIx32" size:%d\r\n", micRx, mic, rx_size);  
02456                 if (MlmeIndication.MlmeIndication != MLME_NONE) {
02457                     MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;      
02458                     if (LoRaMacPrimitives->MacMlmeIndication != NULL)
02459                         LoRaMacPrimitives->MacMlmeIndication(&MlmeIndication);
02460                 }
02461             }
02462             break;
02463 #endif /* LORAWAN_JOIN_EUI  */
02464         case FRAME_TYPE_DATA_CONFIRMED_DOWN:
02465         case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
02466             if (rx_downlink(pktHeaderLen, rx_size, snr) == 0)
02467                 status = LORAMAC_EVENT_INFO_STATUS_OK;
02468             break;
02469         case FRAME_TYPE_PROPRIETARY:
02470             {
02471                 McpsIndication.McpsIndication = MCPS_PROPRIETARY;
02472                 McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
02473                 McpsIndication.Buffer = Radio::radio.rx_buf;
02474                 McpsIndication.BufferSize = rx_size - pktHeaderLen;
02475 
02476                 if (LoRaMacPrimitives->MacMcpsIndication != NULL)
02477                     LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );    // RxDone
02478                 break;
02479             }
02480         default:
02481             MAC_PRINTF("unknown frame type:%02x\r\n", macHdr.Value );
02482             PrepareRxDoneAbort(LORAMAC_EVENT_INFO_STATUS_UNKNOWN_MTYPE);
02483             break;
02484     } // ..switch( macHdr.Bits.MType )
02485 
02486     if (LoRaMacDeviceClass == CLASS_C) {
02487         if (McpsIndication.RxSlot == 1) {
02488             RxWindow2Setup();
02489             RxWindow2Start();   // immiediately to continuous rx2 reception
02490         } else if (McpsIndication.RxSlot == 2) {
02491             /* stop simulated rx timeout for classC rx2-continuous */
02492             RxWindowEvent2.detach();
02493         }
02494     }
02495 
02496     {
02497         if (flags.uplink_in_progress > 0)
02498             finish_uplink(status);
02499 
02500         mcps_confirm(status);  // RxDone
02501         mlme_confirm(status);
02502     }
02503 
02504     MAC_PRINTF("\r\n");
02505 
02506     flags.rxing = false;
02507 } // ..OnRadioRxDone()
02508 
02509 __attribute__((weak)) bool
02510 beacon_rx_timeout()
02511 {
02512     return false;
02513 }
02514 
02515 void OnRadioRxTimeout( void )
02516 {
02517     MAC_PRINTF("OnRadioRxTimeout()%d ", McpsIndication.RxSlot);
02518 #ifdef LORAWAN_JOIN_EUI
02519     MAC_PRINTF(",%u ", flags.IsLoRaMacNetworkJoined);
02520 #endif /* LORAWAN_JOIN_EUI  */
02521 
02522     if (beacon_rx_timeout())
02523         return;
02524 
02525     if (McpsIndication.RxSlot == 1)
02526         RxWindow2Setup();
02527 
02528     if (LoRaMacDeviceClass != CLASS_C)
02529         Radio::Sleep();
02530 
02531     if (McpsIndication.RxSlot == 2)
02532     {
02533 #ifdef LORAWAN_JOIN_EUI
02534         if (flags.IsLoRaMacNetworkJoined) {
02535 #endif /* LORAWAN_JOIN_EUI  */
02536             if (uplinkMHDR->Bits.MType  == FRAME_TYPE_DATA_UNCONFIRMED_UP) {
02537                 /* sent once, stoping now */
02538                 mcps_confirm(LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT);
02539             }
02540 
02541             mlme_confirm(LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT);
02542 #ifdef LORAWAN_JOIN_EUI
02543         } else {
02544             if (++MlmeIndication.JoinRequestTrials < MaxJoinRequestTrials) {
02545                 TxDelayedEvent.attach_us(OnTxDelayedIsr, 1000000);
02546                 MAC_PRINTF("RxTImeout-join-tx-delay\r\n");
02547                 MAC_PRINTF("join-try%u of%u ", MlmeIndication.JoinRequestTrials, MaxJoinRequestTrials);
02548 
02549                 if (MlmeIndication.MlmeIndication != MLME_NONE) {
02550                     MlmeIndication.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
02551                     if (LoRaMacPrimitives->MacMlmeIndication)
02552                         LoRaMacPrimitives->MacMlmeIndication(&MlmeIndication);
02553                 }
02554             } else {
02555                 mlme_confirm(LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL);
02556             }
02557         }
02558 #endif /* LORAWAN_JOIN_EUI  */
02559 
02560         finish_uplink(LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT);
02561     } // ..if (McpsIndication.RxSlot == 2)
02562 
02563     if (LoRaMacDeviceClass == CLASS_C) {
02564         if (McpsIndication.RxSlot != 2) {
02565             RxWindow2Start();
02566         }
02567     } else
02568         flags.rxing = false;
02569 
02570     MAC_PRINTF("\r\n");
02571 
02572 } // ..OnRadioRxTimeout()
02573 
02574 __attribute__((weak)) void 
02575 on_dio0_top_half(us_timestamp_t dio0_at)
02576 {
02577 }
02578 
02579 static void OnRadioRxError( void )
02580 {
02581     if( LoRaMacDeviceClass != CLASS_C )
02582     {
02583         Radio::Sleep();
02584     }
02585     else
02586     {
02587         RxWindow2Setup();
02588         RxWindow2Start();
02589     }
02590 
02591     if (McpsIndication.RxSlot == 2)
02592     {
02593         flags.uplink_in_progress = 0;  // TODO check
02594         mlme_confirm(LORAMAC_EVENT_INFO_STATUS_RX2_ERROR);
02595         mcps_confirm(LORAMAC_EVENT_INFO_STATUS_RX2_ERROR);
02596     }
02597 } // ..OnRadioRxError
02598 
02599 const RadioEvents_t rev = {
02600     /* Dio0_top_half */     on_dio0_top_half,
02601     /* TxDone_topHalf */    OnRadioTxDone,
02602     /* TxDone_botHalf */    NULL,
02603     /* TxTimeout  */        OnRadioTxTimeout,
02604     /* RxDone  */           OnRadioRxDone,
02605     /* RxTimeout  */        OnRadioRxTimeout,
02606     /* RxError  */          OnRadioRxError,
02607     /* FhssChangeChannel  */NULL,
02608     /* CadDone  */          NULL
02609 };
02610 
02611 LoRaMacStatus_t
02612 LoRaMacInitialization( const LoRaMacPrimitives_t  *primitives, const LoRaMacCallback_t *callbacks )
02613 {
02614     if( primitives == NULL )
02615     {
02616         return LORAMAC_STATUS_PARAMETER_INVALID;
02617     }
02618 
02619     if( ( primitives->MacMcpsConfirm == NULL ) ||
02620         ( primitives->MacMcpsIndication == NULL ) ||
02621         ( primitives->MacMlmeConfirm == NULL ) ||
02622         ( primitives->MacMlmeIndication == NULL ) )
02623     {
02624         return LORAMAC_STATUS_PARAMETER_INVALID;
02625     }
02626 
02627     if (targetCheckLSE() < 0)
02628         return LORAMAC_STATUS_LSE;
02629 
02630     LoRaMacPrimitives = primitives;
02631     LoRaMacCallbacks = callbacks;
02632 
02633     LoRaMacDeviceClass = CLASS_A;
02634 
02635 #ifdef DUTY_ENABLE
02636     DutyInit();
02637 #endif /* DUTY_ENABLE */
02638 
02639     region_mac_init();
02640 
02641     ResetMacParameters( );
02642 
02643     // Initialize Radio driver
02644 
02645     LoRaMacClassBInitialization();
02646     Radio::Init( &rev );
02647 
02648     // Random seed initialization
02649     srand(Radio::Random());
02650 
02651     flags.PublicNetwork = true;
02652     Radio::SetPublicNetwork( flags.PublicNetwork );
02653     Radio::Sleep();
02654 
02655     McpsIndication.RxSlot = -1;
02656     function_pending = NULL;
02657 
02658     McpsConfirm.McpsRequest = MCPS_NONE;
02659 
02660 #ifdef LORAWAN_JOIN_EUI
02661     MaxJoinRequestTrials = 1;
02662 #else
02663     flags.have_SNwkSIntKey = 0;
02664     flags.have_NwkSEncKey = 0;
02665     flags.OptNeg = 0;
02666 #endif /* !LORAWAN_JOIN_EUI  */
02667 
02668     LoRaMacCryptoInit();
02669 
02670     MlmeIndication.MlmeIndication = MLME_NONE;
02671 
02672     ADR_ACK_LIMIT = DEFAULT_ADR_ACK_LIMIT;
02673     ADR_ACK_DELAY = DEFAULT_ADR_ACK_DELAY;
02674 
02675     return LORAMAC_STATUS_OK;
02676 } // ..LoRaMacInitialization()
02677 
02678 void SendFrameOnChannel( uint8_t ch_num )
02679 {
02680     int8_t txPowerIndex = 0;
02681     int8_t txPower = 0;
02682     uint8_t tx_len = tx_buf_len;
02683     uint32_t mic;
02684 
02685     /* TODO: if beacon guard, defer until pingslot 0 */
02686 
02687     last_up_macHdr.Value  = Radio::radio.tx_buf[0];
02688     if (last_up_macHdr.Bits.MType  == FRAME_TYPE_DATA_UNCONFIRMED_UP ||
02689         last_up_macHdr.Bits.MType  == FRAME_TYPE_DATA_CONFIRMED_UP)
02690     {
02691         LoRaMacFrameCtrl_t* fCtrl = (LoRaMacFrameCtrl_t*)&Radio::radio.tx_buf[5];
02692         block_t block;
02693         uint32_t fcnt_up;
02694 #ifdef LORAWAN_JOIN_EUI
02695         fcnt_up = FCntUp;
02696 #else
02697         fcnt_up = eeprom_read(EEPROM_FCNTUP);
02698 #endif /* LORAWAN_JOIN_EUI  */
02699 
02700         fCtrl->Bits.AdrAckReq = false;
02701         if (fCtrl->Bits.Adr) {
02702             if (McpsIndication.ADR_ACK_CNT >= ADR_ACK_LIMIT) {
02703                 if (LoRaMacParamsDefaults.ChannelsDatarate  > LORAMAC_TX_MIN_DATARATE || LoRaMacParams.ChannelsTxPower  > LORAMAC_DEFAULT_TX_POWER || LoRaMacParams.NbEnabledChannels < LoRaMacParamsDefaults.NbEnabledChannels)
02704                     fCtrl->Bits.AdrAckReq = true;
02705 
02706                 if (McpsIndication.ADR_ACK_CNT >= (ADR_ACK_LIMIT + ADR_ACK_DELAY)) {
02707                     /* if tx power less than default: increase tx power, otherwise decrease datarate */
02708                     if (LoRaMacParams.ChannelsTxPower  > LORAMAC_DEFAULT_TX_POWER) {
02709                         LoRaMacParams.ChannelsTxPower --;
02710                     } else if (LoRaMacParams.ChannelsDatarate  > LORAMAC_TX_MIN_DATARATE) {
02711                         LoRaMacParams.ChannelsDatarate --;
02712                         McpsIndication.ADR_ACK_CNT -= ADR_ACK_DELAY;
02713                     } else {
02714                         memcpy(LoRaMacParams.ChannelsMask , LoRaMacParamsDefaults.ChannelsMask , sizeof(LoRaMacParams.ChannelsMask ));
02715                         LoRaMacParams.NbEnabledChannels = LoRaMacParamsDefaults.NbEnabledChannels;
02716                     }
02717                 }
02718             }
02719         } // ..if (fCtrl->Bits.Adr)
02720 
02721         Radio::radio.tx_buf[6] = fcnt_up & 0xFF;
02722         Radio::radio.tx_buf[7] = ( fcnt_up >> 8 ) & 0xFF;
02723 
02724         block.b.header = 0x49;
02725         block.b.confFCnt = 0;
02726         block.b.dr = 0;
02727         block.b.ch = 0;
02728         block.b.dir = UP_LINK;
02729         block.b.DevAddr = LoRaMacDevAddr;
02730         block.b.FCnt = fcnt_up;
02731         block.b.zero8 = 0;
02732         block.b.lenMsg = tx_len;
02733         if (flags.OptNeg) {
02734             uint16_t cmacF, cmacS;
02735             cmacF = LoRaMacComputeMic(&block, Radio::radio.tx_buf, keys.FNwkSIntKey);
02736 
02737             block.b.confFCnt = ConfFCntDown;
02738             block.b.dr = LoRaMacParams.ChannelsDatarate ;
02739             block.b.ch = ch_num;
02740             cmacS = LoRaMacComputeMic(&block, Radio::radio.tx_buf, keys.SNwkSIntKey) & 0xffff;
02741             mic = cmacS | (cmacF << 16);
02742             ConfFCntDown = 0;   /* single use */
02743         } else
02744             mic = LoRaMacComputeMic(&block, Radio::radio.tx_buf, keys.FNwkSIntKey);
02745 
02746         Radio::radio.tx_buf[tx_buf_len + 0] = mic & 0xFF;
02747         Radio::radio.tx_buf[tx_buf_len + 1] = ( mic >> 8 ) & 0xFF;
02748         Radio::radio.tx_buf[tx_buf_len + 2] = ( mic >> 16 ) & 0xFF;
02749         Radio::radio.tx_buf[tx_buf_len + 3] = ( mic >> 24 ) & 0xFF;
02750         tx_len += LORAMAC_MFR_LEN;
02751         MAC_PRINTF("FCntUp%u ", fcnt_up);
02752 
02753 #ifdef LORAWAN_JOIN_EUI
02754         McpsConfirm.UpLinkCounter = FCntUp;
02755 #else
02756         McpsConfirm.UpLinkCounter = eeprom_read(EEPROM_FCNTUP);
02757 #endif /* !LORAWAN_JOIN_EUI  */
02758 
02759         if (flags.uplink_in_progress <= 1)
02760             McpsIndication.ADR_ACK_CNT++;
02761 
02762     } // ..if sending (un)conf
02763 
02764     txPowerIndex = region_LimitTxPower( LoRaMacParams.ChannelsTxPower  );
02765     txPower = TxPowers[txPowerIndex];
02766 
02767     if (MlmeConfirm.MlmeRequest != MLME_NONE) {
02768         MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_SENDING;
02769     }
02770     if (McpsConfirm.McpsRequest != MCPS_NONE) {
02771         McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_SENDING;
02772         McpsConfirm.Datarate = LoRaMacParams.ChannelsDatarate ;
02773         McpsConfirm.TxPower = txPowerIndex;
02774         McpsConfirm.UpLinkFreqHz = Channels[ch_num].FreqHz;
02775     }
02776 
02777     Radio::SetChannel(Channels[ch_num].FreqHz);
02778     if (MlmeIndication.MlmeIndication != MLME_NONE)
02779         MlmeIndication.freqHz = Channels[ch_num].FreqHz;
02780 
02781     region_tx_setup(txPower, tx_len);
02782 
02783     // Store the time on air
02784     //McpsConfirm.TxTimeOnAir = TxTimeOnAir_us;
02785     //MlmeConfirm.TxTimeOnAir = TxTimeOnAir_us;
02786 
02787     // Send now
02788     if (Radio::Send(tx_len, LoRaMacParams.MaxListenTime, REGION_LBT_CHANNEL_FREE_TIME_us, REGION_LBT_RSSI_THRESHOLD_DBM) < 0) {
02789         mcps_confirm(LORAMAC_EVENT_INFO_STATUS_CHANNEL_BUSY);  // SendFrame fail
02790         return;
02791     }
02792     waitingFor = LORAMAC_STATUS_WAITING_FOR_TXDONE;
02793     MAC_PRINTF(" sfoc %u, %" PRIu32"hz\r\n", tx_len, Channels[ch_num].FreqHz);
02794 
02795     /* if this is unconfirmed up, and last NbTrans */
02796     if (last_up_macHdr.Bits.MType  == FRAME_TYPE_DATA_UNCONFIRMED_UP && flags.uplink_in_progress <= 1) {
02797 #ifdef LORAWAN_JOIN_EUI
02798         FCntUp++;
02799 #else
02800         if (eeprom_increment_value(EEPROM_FCNTUP) < 0) {
02801             mcps_confirm(LORAMAC_EVENT_INFO_STATUS_INCR_FAIL);  // SendFrame fail
02802         }
02803 #endif
02804     }
02805 } // ..SendFrameOnChannel()
02806 
02807 uint8_t CountBits( uint16_t mask, uint8_t nbBits )
02808 {
02809     uint8_t nbActiveBits = 0;
02810 
02811     for( uint8_t j = 0; j < nbBits; j++ )
02812     {
02813         if( ( mask & ( 1 << j ) ) == ( 1 << j ) )
02814         {
02815             nbActiveBits++;
02816         }
02817     }
02818     return nbActiveBits;
02819 }
02820 
02821 void LoRaMacPrintStatus()
02822 {
02823 #ifdef MAC_DEBUG
02824     switch (waitingFor) {
02825         case LORAMAC_STATUS_WAITING_FOR_TXSTART: MAC_PRINTF("wait-TXSTART "); break;
02826         case LORAMAC_STATUS_WAITING_FOR_TXDONE:  MAC_PRINTF("wait-TXDONE "); break;
02827         case LORAMAC_STATUS_WAITING_FOR_RX1:     MAC_PRINTF("wait-RX1 "); break;
02828         case LORAMAC_STATUS_WAITING_FOR_RX2:     MAC_PRINTF("wait-RX2 "); break;
02829         default: break;
02830     }
02831     if (flags.uplink_in_progress > 0)
02832         MAC_PRINTF("uplink_in_progress:%u ", flags.uplink_in_progress);
02833     MAC_PRINTF("ConfFCntUp%u\r\n", ConfFCntUp);
02834     MAC_PRINTF("function_pending:%p\r\n", function_pending);
02835     MAC_PRINTF("rx delays:%u, %u, %u, %u\r\n",
02836         RxWindow1Delay_us,
02837         LoRaMacParams.ReceiveDelay1_us ,
02838         RxWindow2Delay_us,
02839         LoRaMacParams.ReceiveDelay2_us 
02840     );
02841     if (flags.uplink_in_progress) {
02842         MAC_PRINTF("since txDone:%u\r\n", Radio::lpt.read_us() - tx_done_at);
02843     }
02844 
02845     MAC_PRINTF("class-");
02846     switch (LoRaMacDeviceClass) {
02847         case CLASS_A:   MAC_PRINTF("A "); break;
02848         case CLASS_B:   MAC_PRINTF("B "); break;
02849         case CLASS_C:   MAC_PRINTF("C "); break;
02850     }
02851     MAC_PRINTF("\r\n");
02852 
02853     //Radio::PrintStatus();
02854 #endif /* MAC_DEBUG */
02855 }
02856 
02857 us_timestamp_t LoRaMacReadTimer()
02858 {
02859     return Radio::lpt.read_us();
02860 }
02861 
02862 int8_t
02863 LoRaMacGetRxSlot()
02864 {
02865     return McpsIndication.RxSlot;
02866 }
02867 
02868 void
02869 LoRaMacUserContext()
02870 {
02871     Radio::service();
02872 
02873     if (flags.OnTxDelayed) {
02874         OnTxDelayedTimerEvent();
02875         flags.OnTxDelayed = false;
02876     }
02877 }
02878