Implement a secure ICS protocol targeting LoRa Node151 microcontroller for controlling irrigation.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4925 lines
163 KiB

  1. /*!
  2. * \file LoRaMac.c
  3. *
  4. * \brief LoRa MAC layer implementation
  5. *
  6. * \copyright Revised BSD License, see section \ref LICENSE.
  7. *
  8. * \code
  9. * ______ _
  10. * / _____) _ | |
  11. * ( (____ _____ ____ _| |_ _____ ____| |__
  12. * \____ \| ___ | (_ _) ___ |/ ___) _ \
  13. * _____) ) ____| | | || |_| ____( (___| | | |
  14. * (______/|_____)_|_|_| \__)_____)\____)_| |_|
  15. * (C)2013-2017 Semtech
  16. *
  17. * ___ _____ _ ___ _ _____ ___ ___ ___ ___
  18. * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
  19. * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
  20. * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
  21. * embedded.connectivity.solutions===============
  22. *
  23. * \endcode
  24. *
  25. * \author Miguel Luis ( Semtech )
  26. *
  27. * \author Gregory Cristian ( Semtech )
  28. *
  29. * \author Daniel Jaeckle ( STACKFORCE )
  30. *
  31. * \author Johannes Bruder ( STACKFORCE )
  32. */
  33. #include "utilities.h"
  34. #include "region/Region.h"
  35. #include "LoRaMacClassB.h"
  36. #include "LoRaMacCrypto.h"
  37. #include "secure-element.h"
  38. #include "LoRaMacTest.h"
  39. #include "LoRaMacTypes.h"
  40. #include "LoRaMacConfirmQueue.h"
  41. #include "LoRaMacHeaderTypes.h"
  42. #include "LoRaMacMessageTypes.h"
  43. #include "LoRaMacParser.h"
  44. #include "LoRaMacCommands.h"
  45. #include "LoRaMacAdr.h"
  46. #include "LoRaMacSerializer.h"
  47. #include "radio.h"
  48. #include "LoRaMac.h"
  49. #ifndef LORAMAC_VERSION
  50. /*!
  51. * LoRaWAN version definition.
  52. */
  53. #define LORAMAC_VERSION 0x01000400
  54. #endif
  55. /*!
  56. * Maximum PHY layer payload size
  57. */
  58. #define LORAMAC_PHY_MAXPAYLOAD 255
  59. /*!
  60. * Maximum length of the fOpts field
  61. */
  62. #define LORA_MAC_COMMAND_MAX_FOPTS_LENGTH 15
  63. /*!
  64. * LoRaMac duty cycle for the back-off procedure during the first hour.
  65. */
  66. #define BACKOFF_DC_1_HOUR 100
  67. /*!
  68. * LoRaMac duty cycle for the back-off procedure during the next 10 hours.
  69. */
  70. #define BACKOFF_DC_10_HOURS 1000
  71. /*!
  72. * LoRaMac duty cycle for the back-off procedure during the next 24 hours.
  73. */
  74. #define BACKOFF_DC_24_HOURS 10000
  75. /*!
  76. * Maximum value for the ADR ack counter
  77. */
  78. #define ADR_ACK_COUNTER_MAX 0xFFFFFFFF
  79. /*!
  80. * LoRaMac internal states
  81. */
  82. enum eLoRaMacState
  83. {
  84. LORAMAC_IDLE = 0x00000000,
  85. LORAMAC_STOPPED = 0x00000001,
  86. LORAMAC_TX_RUNNING = 0x00000002,
  87. LORAMAC_RX = 0x00000004,
  88. LORAMAC_ACK_RETRY = 0x00000010,
  89. LORAMAC_TX_DELAYED = 0x00000020,
  90. LORAMAC_TX_CONFIG = 0x00000040,
  91. LORAMAC_RX_ABORT = 0x00000080,
  92. };
  93. /*
  94. * Request permission state
  95. */
  96. typedef enum eLoRaMacRequestHandling
  97. {
  98. LORAMAC_REQUEST_HANDLING_OFF = 0,
  99. LORAMAC_REQUEST_HANDLING_ON = !LORAMAC_REQUEST_HANDLING_OFF
  100. }LoRaMacRequestHandling_t;
  101. typedef struct sLoRaMacCtx
  102. {
  103. /*
  104. * Length of packet in PktBuffer
  105. */
  106. uint16_t PktBufferLen;
  107. /*
  108. * Buffer containing the data to be sent or received.
  109. */
  110. uint8_t PktBuffer[LORAMAC_PHY_MAXPAYLOAD];
  111. /*!
  112. * Current processed transmit message
  113. */
  114. LoRaMacMessage_t TxMsg;
  115. /*!
  116. * Buffer containing the data received by the application.
  117. */
  118. uint8_t AppData[LORAMAC_PHY_MAXPAYLOAD];
  119. /*
  120. * Size of buffer containing the application data.
  121. */
  122. uint8_t AppDataSize;
  123. /*
  124. * Buffer containing the upper layer data.
  125. */
  126. uint8_t RxPayload[LORAMAC_PHY_MAXPAYLOAD];
  127. SysTime_t LastTxSysTime;
  128. /*
  129. * LoRaMac internal state
  130. */
  131. uint32_t MacState;
  132. /*
  133. * LoRaMac upper layer event functions
  134. */
  135. LoRaMacPrimitives_t* MacPrimitives;
  136. /*
  137. * LoRaMac upper layer callback functions
  138. */
  139. LoRaMacCallback_t* MacCallbacks;
  140. /*
  141. * Radio events function pointer
  142. */
  143. RadioEvents_t RadioEvents;
  144. /*
  145. * LoRaMac duty cycle delayed Tx timer
  146. */
  147. TimerEvent_t TxDelayedTimer;
  148. /*
  149. * LoRaMac reception windows timers
  150. */
  151. TimerEvent_t RxWindowTimer1;
  152. TimerEvent_t RxWindowTimer2;
  153. /*
  154. * LoRaMac reception windows delay
  155. * \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME
  156. * join frame : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME
  157. */
  158. uint32_t RxWindow1Delay;
  159. uint32_t RxWindow2Delay;
  160. /*
  161. * LoRaMac Rx windows configuration
  162. */
  163. RxConfigParams_t RxWindow1Config;
  164. RxConfigParams_t RxWindow2Config;
  165. RxConfigParams_t RxWindowCConfig;
  166. /*
  167. * Limit of uplinks without any donwlink response before the ADRACKReq bit will be set.
  168. */
  169. uint16_t AdrAckLimit;
  170. /*
  171. * Limit of uplinks without any donwlink response after a the first frame with set ADRACKReq bit
  172. * before the trying to regain the connectivity.
  173. */
  174. uint16_t AdrAckDelay;
  175. /*
  176. * Acknowledge timeout timer. Used for packet retransmissions.
  177. */
  178. TimerEvent_t RetransmitTimeoutTimer;
  179. /*
  180. * Uplink messages repetitions counter
  181. */
  182. uint8_t ChannelsNbTransCounter;
  183. /*
  184. * Indicates if the AckTimeout timer has expired or not
  185. */
  186. bool RetransmitTimeoutRetry;
  187. /*
  188. * If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates
  189. * if the nodes needs to manage the server acknowledgement.
  190. */
  191. bool NodeAckRequested;
  192. /*
  193. * Current channel index
  194. */
  195. uint8_t Channel;
  196. /*
  197. * Last transmission time on air
  198. */
  199. TimerTime_t TxTimeOnAir;
  200. /*
  201. * Structure to hold an MCPS indication data.
  202. */
  203. McpsIndication_t McpsIndication;
  204. /*
  205. * Structure to hold MCPS confirm data.
  206. */
  207. McpsConfirm_t McpsConfirm;
  208. /*
  209. * Structure to hold MLME confirm data.
  210. */
  211. MlmeConfirm_t MlmeConfirm;
  212. /*
  213. * Structure to hold MLME indication data.
  214. */
  215. MlmeIndication_t MlmeIndication;
  216. /*
  217. * Holds the current rx window slot
  218. */
  219. LoRaMacRxSlot_t RxSlot;
  220. /*
  221. * LoRaMac tx/rx operation state
  222. */
  223. LoRaMacFlags_t MacFlags;
  224. /*
  225. * Data structure indicating if a request is allowed or not.
  226. */
  227. LoRaMacRequestHandling_t AllowRequests;
  228. /*
  229. * Duty cycle wait time
  230. */
  231. TimerTime_t DutyCycleWaitTime;
  232. /*
  233. * Start time of the response timeout
  234. */
  235. TimerTime_t ResponseTimeoutStartTime;
  236. /*
  237. * Buffer containing the MAC layer commands
  238. */
  239. uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH];
  240. }LoRaMacCtx_t;
  241. /*
  242. * Module context.
  243. */
  244. static LoRaMacCtx_t MacCtx;
  245. static LoRaMacNvmData_t Nvm;
  246. static Band_t RegionBands[REGION_NVM_MAX_NB_BANDS];
  247. /*!
  248. * Defines the LoRaMac radio events status
  249. */
  250. typedef union uLoRaMacRadioEvents
  251. {
  252. uint32_t Value;
  253. struct sEvents
  254. {
  255. uint32_t RxTimeout : 1;
  256. uint32_t RxError : 1;
  257. uint32_t TxTimeout : 1;
  258. uint32_t RxDone : 1;
  259. uint32_t TxDone : 1;
  260. }Events;
  261. }LoRaMacRadioEvents_t;
  262. /*!
  263. * LoRaMac radio events status
  264. */
  265. LoRaMacRadioEvents_t LoRaMacRadioEvents = { .Value = 0 };
  266. /*!
  267. * \brief Function to be executed on Radio Tx Done event
  268. */
  269. static void OnRadioTxDone( void );
  270. /*!
  271. * \brief This function prepares the MAC to abort the execution of function
  272. * OnRadioRxDone in case of a reception error.
  273. */
  274. static void PrepareRxDoneAbort( void );
  275. /*!
  276. * \brief Function to be executed on Radio Rx Done event
  277. */
  278. static void OnRadioRxDone( uint8_t* payload, uint16_t size, int16_t rssi, int8_t snr );
  279. /*!
  280. * \brief Function executed on Radio Tx Timeout event
  281. */
  282. static void OnRadioTxTimeout( void );
  283. /*!
  284. * \brief Function executed on Radio Rx error event
  285. */
  286. static void OnRadioRxError( void );
  287. /*!
  288. * \brief Function executed on Radio Rx Timeout event
  289. */
  290. static void OnRadioRxTimeout( void );
  291. /*!
  292. * \brief Function executed on duty cycle delayed Tx timer event
  293. */
  294. static void OnTxDelayedTimerEvent( void* context );
  295. /*!
  296. * \brief Function executed on first Rx window timer event
  297. */
  298. static void OnRxWindow1TimerEvent( void* context );
  299. /*!
  300. * \brief Function executed on second Rx window timer event
  301. */
  302. static void OnRxWindow2TimerEvent( void* context );
  303. /*!
  304. * \brief Function executed on AckTimeout timer event
  305. */
  306. static void OnRetransmitTimeoutTimerEvent( void* context );
  307. /*!
  308. * \brief Configures the events to trigger an MLME-Indication with
  309. * a MLME type of MLME_SCHEDULE_UPLINK.
  310. */
  311. static void SetMlmeScheduleUplinkIndication( void );
  312. /*!
  313. * Computes next 32 bit downlink counter value and determines the frame counter ID.
  314. *
  315. * \param[IN] addrID - Address identifier
  316. * \param[IN] fType - Frame type
  317. * \param[IN] macMsg - Data message object, holding the current 16 bit transmitted frame counter
  318. * \param[IN] lrWanVersion - LoRaWAN version
  319. * \param[OUT] fCntID - Frame counter identifier
  320. * \param[OUT] currentDown - Current downlink counter value
  321. *
  322. * \retval - Status of the operation
  323. */
  324. static LoRaMacCryptoStatus_t GetFCntDown( AddressIdentifier_t addrID, FType_t fType, LoRaMacMessageData_t* macMsg, Version_t lrWanVersion,
  325. FCntIdentifier_t* fCntID, uint32_t* currentDown );
  326. /*!
  327. * \brief Switches the device class
  328. *
  329. * \param [IN] deviceClass Device class to switch to
  330. */
  331. static LoRaMacStatus_t SwitchClass( DeviceClass_t deviceClass );
  332. /*!
  333. * \brief Gets the maximum application payload length in the absence of the optional FOpt field.
  334. *
  335. * \param [IN] datarate Current datarate
  336. *
  337. * \retval Max length
  338. */
  339. static uint8_t GetMaxAppPayloadWithoutFOptsLength( int8_t datarate );
  340. /*!
  341. * \brief Validates if the payload fits into the frame, taking the datarate
  342. * into account.
  343. *
  344. * \details Refer to chapter 4.3.2 of the LoRaWAN specification, v1.0
  345. *
  346. * \param lenN Length of the application payload. The length depends on the
  347. * datarate and is region specific
  348. *
  349. * \param datarate Current datarate
  350. *
  351. * \param fOptsLen Length of the fOpts field
  352. *
  353. * \retval [false: payload does not fit into the frame, true: payload fits into
  354. * the frame]
  355. */
  356. static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen );
  357. /*!
  358. * \brief Decodes MAC commands in the fOpts field and in the payload
  359. *
  360. * \param [IN] payload A pointer to the payload
  361. * \param [IN] macIndex The index of the payload where the MAC commands start
  362. * \param [IN] commandsSize The size of the MAC commands
  363. * \param [IN] snr The SNR value of the frame
  364. * \param [IN] rxSlot The RX slot where the frame was received
  365. */
  366. static void ProcessMacCommands( uint8_t* payload, uint8_t macIndex, uint8_t commandsSize, int8_t snr, LoRaMacRxSlot_t rxSlot );
  367. /*!
  368. * \brief LoRaMAC layer generic send frame
  369. *
  370. * \param [IN] macHdr MAC header field
  371. * \param [IN] fPort MAC payload port
  372. * \param [IN] fBuffer MAC data buffer to be sent
  373. * \param [IN] fBufferSize MAC data buffer size
  374. * \retval status Status of the operation.
  375. */
  376. LoRaMacStatus_t Send( LoRaMacHeader_t* macHdr, uint8_t fPort, void* fBuffer, uint16_t fBufferSize );
  377. /*!
  378. * \brief LoRaMAC layer send join/rejoin request
  379. *
  380. * \param [IN] joinReqType Type of join-request or rejoin
  381. *
  382. * \retval status Status of the operation.
  383. */
  384. LoRaMacStatus_t SendReJoinReq( JoinReqIdentifier_t joinReqType );
  385. /*!
  386. * \brief LoRaMAC layer frame buffer initialization
  387. *
  388. * \param [IN] macHdr MAC header field
  389. * \param [IN] fCtrl MAC frame control field
  390. * \param [IN] fOpts MAC commands buffer
  391. * \param [IN] fPort MAC payload port
  392. * \param [IN] fBuffer MAC data buffer to be sent
  393. * \param [IN] fBufferSize MAC data buffer size
  394. * \retval status Status of the operation.
  395. */
  396. LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t* macHdr, LoRaMacFrameCtrl_t* fCtrl, uint8_t fPort, void* fBuffer, uint16_t fBufferSize );
  397. /*
  398. * \brief Schedules the frame according to the duty cycle
  399. *
  400. * \param [IN] allowDelayedTx When set to true, the a frame will be delayed,
  401. * the duty cycle restriction is active
  402. * \retval Status of the operation
  403. */
  404. static LoRaMacStatus_t ScheduleTx( bool allowDelayedTx );
  405. /*
  406. * \brief Secures the current processed frame ( TxMsg )
  407. * \param[IN] txDr Data rate used for the transmission
  408. * \param[IN] txCh Index of the channel used for the transmission
  409. * \retval status Status of the operation
  410. */
  411. static LoRaMacStatus_t SecureFrame( uint8_t txDr, uint8_t txCh );
  412. /*
  413. * \brief Calculates the aggregated back off time.
  414. */
  415. static void CalculateBackOff( void );
  416. /*
  417. * \brief Function to remove pending MAC commands
  418. *
  419. * \param [IN] rxSlot The RX slot on which the frame was received
  420. * \param [IN] fCtrl The frame control field of the received frame
  421. * \param [IN] request The request type
  422. */
  423. static void RemoveMacCommands( LoRaMacRxSlot_t rxSlot, LoRaMacFrameCtrl_t fCtrl, Mcps_t request );
  424. /*!
  425. * \brief LoRaMAC layer prepared frame buffer transmission with channel specification
  426. *
  427. * \remark PrepareFrame must be called at least once before calling this
  428. * function.
  429. *
  430. * \param [IN] channel Channel to transmit on
  431. * \retval status Status of the operation.
  432. */
  433. LoRaMacStatus_t SendFrameOnChannel( uint8_t channel );
  434. /*!
  435. * \brief Sets the radio in continuous transmission mode
  436. *
  437. * \remark Uses the radio parameters set on the previous transmission.
  438. *
  439. * \param [IN] timeout Time in seconds while the radio is kept in continuous wave mode
  440. * \param [IN] frequency RF frequency to be set.
  441. * \param [IN] power RF output power to be set.
  442. * \retval status Status of the operation.
  443. */
  444. LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout, uint32_t frequency, uint8_t power );
  445. /*!
  446. * \brief Resets MAC specific parameters to default
  447. */
  448. static void ResetMacParameters( void );
  449. /*!
  450. * \brief Initializes and opens the reception window
  451. *
  452. * \param [IN] rxTimer Window timer to be topped.
  453. * \param [IN] rxConfig Window parameters to be setup
  454. */
  455. static void RxWindowSetup( TimerEvent_t* rxTimer, RxConfigParams_t* rxConfig );
  456. /*!
  457. * \brief Opens up a continuous RX C window. This is used for
  458. * class c devices.
  459. */
  460. static void OpenContinuousRxCWindow( void );
  461. /*!
  462. * \brief Returns a pointer to the internal contexts structure.
  463. *
  464. * \retval void Points to a structure containing all contexts
  465. */
  466. static LoRaMacNvmData_t* GetNvmData( void );
  467. /*!
  468. * \brief Restoring of internal module contexts
  469. *
  470. * \details This function allows to restore module contexts by a given pointer.
  471. *
  472. *
  473. * \retval LoRaMacStatus_t Status of the operation. Possible returns are:
  474. * returns are:
  475. * \ref LORAMAC_STATUS_OK,
  476. * \ref LORAMAC_STATUS_PARAMETER_INVALID,
  477. */
  478. static LoRaMacStatus_t RestoreNvmData( LoRaMacNvmData_t* contexts );
  479. /*!
  480. * \brief Determines the frame type
  481. *
  482. * \param [IN] macMsg Data message object
  483. *
  484. * \param [OUT] fType Frame type
  485. *
  486. * \retval LoRaMacStatus_t Status of the operation. Possible returns are:
  487. * returns are:
  488. * \ref LORAMAC_STATUS_OK,
  489. * \ref LORAMAC_STATUS_PARAMETER_INVALID,
  490. */
  491. LoRaMacStatus_t DetermineFrameType( LoRaMacMessageData_t* macMsg, FType_t* fType );
  492. /*!
  493. * \brief Verifies, if the retransmission counter has reached the limit
  494. *
  495. * \param [IN] counter Current retransmission counter
  496. * \param [IN] limit Retransmission counter limit
  497. *
  498. * \retval Returns true if the number of retransmissions have reached the limit.
  499. */
  500. static bool CheckRetrans( uint8_t counter, uint8_t limit );
  501. /*!
  502. * \brief Checks if the retransmission should be stopped in case of a unconfirmed uplink
  503. *
  504. * \retval Returns true if it should be stopped.
  505. */
  506. static bool CheckRetransUnconfirmedUplink( void );
  507. /*!
  508. * \brief Checks if the retransmission should be stopped in case of a confirmed uplink
  509. *
  510. * \retval Returns true it should be stopped.
  511. */
  512. static bool CheckRetransConfirmedUplink( void );
  513. /*!
  514. * \brief Increases the ADR ack counter. Takes the maximum
  515. * value into account.
  516. *
  517. * \param [IN] counter Current counter value.
  518. *
  519. * \retval Returns the next counter value.
  520. */
  521. static uint32_t IncreaseAdrAckCounter( uint32_t counter );
  522. /*!
  523. * \brief Stops the uplink retransmission
  524. *
  525. * \retval Returns true if successful.
  526. */
  527. static bool StopRetransmission( void );
  528. /*!
  529. * \brief Calls the callback to indicate that a context changed
  530. */
  531. static void CallNvmDataChangeCallback( uint16_t notifyFlags );
  532. /*!
  533. * \brief Verifies if a request is pending currently
  534. *
  535. * \retval 1: Request pending, 0: request not pending
  536. */
  537. static uint8_t IsRequestPending( void );
  538. /*!
  539. * \brief Enabled the possibility to perform requests
  540. *
  541. * \param [IN] requestState Request permission state
  542. */
  543. static void LoRaMacEnableRequests( LoRaMacRequestHandling_t requestState );
  544. /*!
  545. * \brief This function verifies if a RX abort occurred
  546. */
  547. static void LoRaMacCheckForRxAbort( void );
  548. /*!
  549. * \brief This function verifies if a beacon acquisition MLME
  550. * request was pending
  551. *
  552. * \retval 1: Request pending, 0: no request pending
  553. */
  554. static uint8_t LoRaMacCheckForBeaconAcquisition( void );
  555. /*!
  556. * \brief Returns true, if the device must apply the minium datarate
  557. *
  558. * \param [IN] adr ADR status bit
  559. *
  560. * \param [IN] activation Activation type of the device
  561. *
  562. * \param [IN] datarateChanged Set to true, if the datarate was changed
  563. * with the LinkAdrReq.
  564. */
  565. static bool CheckForMinimumAbpDatarate( bool adr, ActivationType_t activation, bool datarateChanged );
  566. /*!
  567. * \brief This function handles join request
  568. */
  569. static void LoRaMacHandleMlmeRequest( void );
  570. /*!
  571. * \brief This function handles mcps request
  572. */
  573. static void LoRaMacHandleMcpsRequest( void );
  574. /*!
  575. * \brief This function handles callback events for requests
  576. */
  577. static void LoRaMacHandleRequestEvents( void );
  578. /*!
  579. * \brief This function handles callback events for indications
  580. */
  581. static void LoRaMacHandleIndicationEvents( void );
  582. /*!
  583. * \brief This function handles callback events for NVM updates
  584. *
  585. * \param [IN] nvmData Data structure containing NVM data.
  586. */
  587. static void LoRaMacHandleNvm( LoRaMacNvmData_t* nvmData );
  588. /*!
  589. * \brief This function verifies if the response timeout has been elapsed. If
  590. * this is the case, the status of Nvm.MacGroup1.SrvAckRequested will be
  591. * reset.
  592. *
  593. * \param [IN] timeoutInMs Timeout [ms] to be compared.
  594. *
  595. * \param [IN] startTimeInMs Start time [ms] used as a base. If set to 0,
  596. * no comparison will be done.
  597. *
  598. * \retval true: Response timeout has been elapsed, false: Response timeout
  599. * has not been elapsed or startTimeInMs is 0.
  600. */
  601. static bool LoRaMacHandleResponseTimeout( TimerTime_t timeoutInMs, TimerTime_t startTimeInMs );
  602. /*!
  603. * Structure used to store the radio Tx event data
  604. */
  605. struct
  606. {
  607. TimerTime_t CurTime;
  608. }TxDoneParams;
  609. /*!
  610. * Structure used to store the radio Rx event data
  611. */
  612. struct
  613. {
  614. TimerTime_t LastRxDone;
  615. uint8_t *Payload;
  616. uint16_t Size;
  617. int16_t Rssi;
  618. int8_t Snr;
  619. }RxDoneParams;
  620. static void OnRadioTxDone( void )
  621. {
  622. TxDoneParams.CurTime = TimerGetCurrentTime( );
  623. MacCtx.LastTxSysTime = SysTimeGet( );
  624. LoRaMacRadioEvents.Events.TxDone = 1;
  625. if( ( MacCtx.MacCallbacks != NULL ) && ( MacCtx.MacCallbacks->MacProcessNotify != NULL ) )
  626. {
  627. MacCtx.MacCallbacks->MacProcessNotify( );
  628. }
  629. }
  630. static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
  631. {
  632. RxDoneParams.LastRxDone = TimerGetCurrentTime( );
  633. RxDoneParams.Payload = payload;
  634. RxDoneParams.Size = size;
  635. RxDoneParams.Rssi = rssi;
  636. RxDoneParams.Snr = snr;
  637. LoRaMacRadioEvents.Events.RxDone = 1;
  638. if( ( MacCtx.MacCallbacks != NULL ) && ( MacCtx.MacCallbacks->MacProcessNotify != NULL ) )
  639. {
  640. MacCtx.MacCallbacks->MacProcessNotify( );
  641. }
  642. }
  643. static void OnRadioTxTimeout( void )
  644. {
  645. LoRaMacRadioEvents.Events.TxTimeout = 1;
  646. if( ( MacCtx.MacCallbacks != NULL ) && ( MacCtx.MacCallbacks->MacProcessNotify != NULL ) )
  647. {
  648. MacCtx.MacCallbacks->MacProcessNotify( );
  649. }
  650. }
  651. static void OnRadioRxError( void )
  652. {
  653. LoRaMacRadioEvents.Events.RxError = 1;
  654. if( ( MacCtx.MacCallbacks != NULL ) && ( MacCtx.MacCallbacks->MacProcessNotify != NULL ) )
  655. {
  656. MacCtx.MacCallbacks->MacProcessNotify( );
  657. }
  658. }
  659. static void OnRadioRxTimeout( void )
  660. {
  661. LoRaMacRadioEvents.Events.RxTimeout = 1;
  662. if( ( MacCtx.MacCallbacks != NULL ) && ( MacCtx.MacCallbacks->MacProcessNotify != NULL ) )
  663. {
  664. MacCtx.MacCallbacks->MacProcessNotify( );
  665. }
  666. }
  667. static void UpdateRxSlotIdleState( void )
  668. {
  669. if( Nvm.MacGroup2.DeviceClass != CLASS_C )
  670. {
  671. MacCtx.RxSlot = RX_SLOT_NONE;
  672. }
  673. else
  674. {
  675. MacCtx.RxSlot = RX_SLOT_WIN_CLASS_C;
  676. }
  677. }
  678. static void ProcessRadioTxDone( void )
  679. {
  680. GetPhyParams_t getPhy;
  681. PhyParam_t phyParam;
  682. SetBandTxDoneParams_t txDone;
  683. if( Nvm.MacGroup2.DeviceClass != CLASS_C )
  684. {
  685. Radio.Sleep( );
  686. }
  687. // Setup timers
  688. TimerSetValue( &MacCtx.RxWindowTimer1, MacCtx.RxWindow1Delay );
  689. TimerStart( &MacCtx.RxWindowTimer1 );
  690. TimerSetValue( &MacCtx.RxWindowTimer2, MacCtx.RxWindow2Delay );
  691. TimerStart( &MacCtx.RxWindowTimer2 );
  692. if( MacCtx.NodeAckRequested == true )
  693. {
  694. getPhy.Attribute = PHY_RETRANSMIT_TIMEOUT;
  695. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  696. TimerSetValue( &MacCtx.RetransmitTimeoutTimer, MacCtx.RxWindow2Delay + phyParam.Value );
  697. TimerStart( &MacCtx.RetransmitTimeoutTimer );
  698. }
  699. else
  700. {
  701. // Transmission successful, setup status directly
  702. MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
  703. }
  704. // Update Aggregated last tx done time
  705. Nvm.MacGroup1.LastTxDoneTime = TxDoneParams.CurTime;
  706. // Update last tx done time for the current channel
  707. txDone.Channel = MacCtx.Channel;
  708. txDone.LastTxDoneTime = TxDoneParams.CurTime;
  709. txDone.ElapsedTimeSinceStartUp = SysTimeSub( SysTimeGetMcuTime( ), Nvm.MacGroup2.InitializationTime );
  710. txDone.LastTxAirTime = MacCtx.TxTimeOnAir;
  711. txDone.Joined = true;
  712. if( Nvm.MacGroup2.NetworkActivation == ACTIVATION_TYPE_NONE )
  713. {
  714. txDone.Joined = false;
  715. }
  716. RegionSetBandTxDone( Nvm.MacGroup2.Region, &txDone );
  717. }
  718. static void PrepareRxDoneAbort( void )
  719. {
  720. MacCtx.MacState |= LORAMAC_RX_ABORT;
  721. if( MacCtx.NodeAckRequested == true )
  722. {
  723. OnRetransmitTimeoutTimerEvent( NULL );
  724. }
  725. MacCtx.MacFlags.Bits.McpsInd = 1;
  726. MacCtx.MacFlags.Bits.MacDone = 1;
  727. UpdateRxSlotIdleState( );
  728. }
  729. static void ProcessRadioRxDone( void )
  730. {
  731. LoRaMacHeader_t macHdr;
  732. ApplyCFListParams_t applyCFList;
  733. GetPhyParams_t getPhy;
  734. PhyParam_t phyParam;
  735. LoRaMacCryptoStatus_t macCryptoStatus = LORAMAC_CRYPTO_ERROR;
  736. LoRaMacMessageData_t macMsgData;
  737. LoRaMacMessageJoinAccept_t macMsgJoinAccept;
  738. uint8_t *payload = RxDoneParams.Payload;
  739. uint16_t size = RxDoneParams.Size;
  740. int16_t rssi = RxDoneParams.Rssi;
  741. int8_t snr = RxDoneParams.Snr;
  742. uint8_t pktHeaderLen = 0;
  743. uint32_t downLinkCounter = 0;
  744. uint32_t address = Nvm.MacGroup2.DevAddr;
  745. uint8_t multicast = 0;
  746. AddressIdentifier_t addrID = UNICAST_DEV_ADDR;
  747. FCntIdentifier_t fCntID;
  748. MacCtx.McpsConfirm.AckReceived = false;
  749. MacCtx.McpsIndication.Rssi = rssi;
  750. MacCtx.McpsIndication.Snr = snr;
  751. MacCtx.McpsIndication.RxSlot = MacCtx.RxSlot;
  752. MacCtx.McpsIndication.Port = 0;
  753. MacCtx.McpsIndication.Multicast = 0;
  754. MacCtx.McpsIndication.FramePending = 0;
  755. MacCtx.McpsIndication.Buffer = NULL;
  756. MacCtx.McpsIndication.BufferSize = 0;
  757. MacCtx.McpsIndication.RxData = false;
  758. MacCtx.McpsIndication.AckReceived = false;
  759. MacCtx.McpsIndication.DownLinkCounter = 0;
  760. MacCtx.McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
  761. MacCtx.McpsIndication.DevAddress = 0;
  762. MacCtx.McpsIndication.DeviceTimeAnsReceived = false;
  763. MacCtx.McpsIndication.ResponseTimeout = 0;
  764. Radio.Sleep( );
  765. if( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_1 )
  766. {
  767. TimerStop( &MacCtx.RxWindowTimer2 );
  768. }
  769. // This function must be called even if we are not in class b mode yet.
  770. if( LoRaMacClassBRxBeacon( payload, size ) == true )
  771. {
  772. MacCtx.MlmeIndication.BeaconInfo.Rssi = rssi;
  773. MacCtx.MlmeIndication.BeaconInfo.Snr = snr;
  774. return;
  775. }
  776. // Check if we expect a ping or a multicast slot.
  777. if( Nvm.MacGroup2.DeviceClass == CLASS_B )
  778. {
  779. if( LoRaMacClassBIsPingExpected( ) == true )
  780. {
  781. LoRaMacClassBSetPingSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
  782. LoRaMacClassBPingSlotTimerEvent( NULL );
  783. MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_B_PING_SLOT;
  784. }
  785. else if( LoRaMacClassBIsMulticastExpected( ) == true )
  786. {
  787. LoRaMacClassBSetMulticastSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
  788. LoRaMacClassBMulticastSlotTimerEvent( NULL );
  789. MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_B_MULTICAST_SLOT;
  790. }
  791. }
  792. macHdr.Value = payload[pktHeaderLen++];
  793. switch( macHdr.Bits.MType )
  794. {
  795. case FRAME_TYPE_JOIN_ACCEPT:
  796. // Check if the received frame size is valid
  797. if( size < LORAMAC_JOIN_ACCEPT_FRAME_MIN_SIZE )
  798. {
  799. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  800. PrepareRxDoneAbort( );
  801. return;
  802. }
  803. macMsgJoinAccept.Buffer = payload;
  804. macMsgJoinAccept.BufSize = size;
  805. // Abort in case if the device isn't joined yet and no rejoin request is ongoing.
  806. if( Nvm.MacGroup2.NetworkActivation != ACTIVATION_TYPE_NONE )
  807. {
  808. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  809. PrepareRxDoneAbort( );
  810. return;
  811. }
  812. macCryptoStatus = LoRaMacCryptoHandleJoinAccept( JOIN_REQ, SecureElementGetJoinEui( ), &macMsgJoinAccept );
  813. if( LORAMAC_CRYPTO_SUCCESS == macCryptoStatus )
  814. {
  815. // Network ID
  816. Nvm.MacGroup2.NetID = ( uint32_t ) macMsgJoinAccept.NetID[0];
  817. Nvm.MacGroup2.NetID |= ( ( uint32_t ) macMsgJoinAccept.NetID[1] << 8 );
  818. Nvm.MacGroup2.NetID |= ( ( uint32_t ) macMsgJoinAccept.NetID[2] << 16 );
  819. // Device Address
  820. Nvm.MacGroup2.DevAddr = macMsgJoinAccept.DevAddr;
  821. // DLSettings
  822. Nvm.MacGroup2.MacParams.Rx1DrOffset = macMsgJoinAccept.DLSettings.Bits.RX1DRoffset;
  823. Nvm.MacGroup2.MacParams.Rx2Channel.Datarate = macMsgJoinAccept.DLSettings.Bits.RX2DataRate;
  824. Nvm.MacGroup2.MacParams.RxCChannel.Datarate = macMsgJoinAccept.DLSettings.Bits.RX2DataRate;
  825. // RxDelay
  826. Nvm.MacGroup2.MacParams.ReceiveDelay1 = macMsgJoinAccept.RxDelay;
  827. if( Nvm.MacGroup2.MacParams.ReceiveDelay1 == 0 )
  828. {
  829. Nvm.MacGroup2.MacParams.ReceiveDelay1 = 1;
  830. }
  831. Nvm.MacGroup2.MacParams.ReceiveDelay1 *= 1000;
  832. Nvm.MacGroup2.MacParams.ReceiveDelay2 = Nvm.MacGroup2.MacParams.ReceiveDelay1 + 1000;
  833. Nvm.MacGroup2.Version.Fields.Minor = 0;
  834. // Apply CF list
  835. applyCFList.Payload = macMsgJoinAccept.CFList;
  836. // Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC
  837. applyCFList.Size = size - 17;
  838. // Apply the last tx channel
  839. applyCFList.JoinChannel = MacCtx.Channel;
  840. RegionApplyCFList( Nvm.MacGroup2.Region, &applyCFList );
  841. Nvm.MacGroup2.NetworkActivation = ACTIVATION_TYPE_OTAA;
  842. // MLME handling
  843. if( LoRaMacConfirmQueueIsCmdActive( MLME_JOIN ) == true )
  844. {
  845. LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_JOIN );
  846. }
  847. }
  848. else
  849. {
  850. // MLME handling
  851. if( LoRaMacConfirmQueueIsCmdActive( MLME_JOIN ) == true )
  852. {
  853. LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL, MLME_JOIN );
  854. }
  855. }
  856. break;
  857. case FRAME_TYPE_DATA_CONFIRMED_DOWN:
  858. MacCtx.McpsIndication.McpsIndication = MCPS_CONFIRMED;
  859. // Intentional fall through
  860. case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
  861. // Check if the received payload size is valid
  862. getPhy.UplinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
  863. getPhy.Datarate = MacCtx.McpsIndication.RxDatarate;
  864. getPhy.Attribute = PHY_MAX_PAYLOAD;
  865. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  866. if( ( MAX( 0, ( int16_t )( ( int16_t ) size - ( int16_t ) LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE ) ) > ( int16_t )phyParam.Value ) ||
  867. ( size < LORAMAC_FRAME_PAYLOAD_MIN_SIZE ) )
  868. {
  869. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  870. PrepareRxDoneAbort( );
  871. return;
  872. }
  873. macMsgData.Buffer = payload;
  874. macMsgData.BufSize = size;
  875. macMsgData.FRMPayload = MacCtx.RxPayload;
  876. macMsgData.FRMPayloadSize = LORAMAC_PHY_MAXPAYLOAD;
  877. if( LORAMAC_PARSER_SUCCESS != LoRaMacParserData( &macMsgData ) )
  878. {
  879. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  880. PrepareRxDoneAbort( );
  881. return;
  882. }
  883. // Handle Class B
  884. // Check if we expect a ping or a multicast slot.
  885. if( Nvm.MacGroup2.DeviceClass == CLASS_B )
  886. {
  887. if( LoRaMacClassBIsPingExpected( ) == true )
  888. {
  889. LoRaMacClassBSetPingSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
  890. LoRaMacClassBPingSlotTimerEvent( NULL );
  891. MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_B_PING_SLOT;
  892. LoRaMacClassBSetFPendingBit( macMsgData.FHDR.DevAddr, ( uint8_t ) macMsgData.FHDR.FCtrl.Bits.FPending );
  893. }
  894. else if( LoRaMacClassBIsMulticastExpected( ) == true )
  895. {
  896. LoRaMacClassBSetMulticastSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
  897. LoRaMacClassBMulticastSlotTimerEvent( NULL );
  898. MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_B_MULTICAST_SLOT;
  899. LoRaMacClassBSetFPendingBit( macMsgData.FHDR.DevAddr, ( uint8_t ) macMsgData.FHDR.FCtrl.Bits.FPending );
  900. }
  901. }
  902. // Store device address
  903. MacCtx.McpsIndication.DevAddress = macMsgData.FHDR.DevAddr;
  904. FType_t fType;
  905. if( LORAMAC_STATUS_OK != DetermineFrameType( &macMsgData, &fType ) )
  906. {
  907. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  908. PrepareRxDoneAbort( );
  909. return;
  910. }
  911. //Check if it is a multicast message
  912. multicast = 0;
  913. downLinkCounter = 0;
  914. for( uint8_t i = 0; i < LORAMAC_MAX_MC_CTX; i++ )
  915. {
  916. if( ( Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.Address == macMsgData.FHDR.DevAddr ) &&
  917. ( Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.IsEnabled == true ) )
  918. {
  919. multicast = 1;
  920. addrID = Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.GroupID;
  921. downLinkCounter = *( Nvm.MacGroup2.MulticastChannelList[i].DownLinkCounter );
  922. address = Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.Address;
  923. if( Nvm.MacGroup2.DeviceClass == CLASS_C )
  924. {
  925. MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_C_MULTICAST;
  926. }
  927. break;
  928. }
  929. }
  930. // Filter messages according to multicast downlink exceptions
  931. if( ( multicast == 1 ) && ( ( fType != FRAME_TYPE_D ) ||
  932. ( macMsgData.FHDR.FCtrl.Bits.Ack != 0 ) ||
  933. ( macMsgData.FHDR.FCtrl.Bits.AdrAckReq != 0 ) ) )
  934. {
  935. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  936. PrepareRxDoneAbort( );
  937. return;
  938. }
  939. // Get downlink frame counter value
  940. macCryptoStatus = GetFCntDown( addrID, fType, &macMsgData, Nvm.MacGroup2.Version, &fCntID, &downLinkCounter );
  941. if( macCryptoStatus != LORAMAC_CRYPTO_SUCCESS )
  942. {
  943. if( macCryptoStatus == LORAMAC_CRYPTO_FAIL_FCNT_DUPLICATED )
  944. {
  945. // Catch the case of repeated downlink frame counter
  946. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
  947. }
  948. else
  949. {
  950. // Other errors
  951. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  952. }
  953. MacCtx.McpsIndication.DownLinkCounter = downLinkCounter;
  954. PrepareRxDoneAbort( );
  955. return;
  956. }
  957. macCryptoStatus = LoRaMacCryptoUnsecureMessage( addrID, address, fCntID, downLinkCounter, &macMsgData );
  958. if( macCryptoStatus != LORAMAC_CRYPTO_SUCCESS )
  959. {
  960. if( macCryptoStatus == LORAMAC_CRYPTO_FAIL_ADDRESS )
  961. {
  962. // We are not the destination of this frame.
  963. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
  964. }
  965. else
  966. {
  967. // MIC calculation fail
  968. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
  969. }
  970. PrepareRxDoneAbort( );
  971. return;
  972. }
  973. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
  974. MacCtx.McpsIndication.Multicast = multicast;
  975. MacCtx.McpsIndication.FramePending = macMsgData.FHDR.FCtrl.Bits.FPending;
  976. MacCtx.McpsIndication.Buffer = NULL;
  977. MacCtx.McpsIndication.BufferSize = 0;
  978. MacCtx.McpsIndication.DownLinkCounter = downLinkCounter;
  979. MacCtx.McpsIndication.AckReceived = macMsgData.FHDR.FCtrl.Bits.Ack;
  980. MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
  981. MacCtx.McpsConfirm.AckReceived = macMsgData.FHDR.FCtrl.Bits.Ack;
  982. // Reset ADR ACK Counter only, when RX1 or RX2 slot
  983. if( ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_1 ) ||
  984. ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_2 ) )
  985. {
  986. Nvm.MacGroup1.AdrAckCounter = 0;
  987. Nvm.MacGroup2.DownlinkReceived = true;
  988. }
  989. // MCPS Indication and ack requested handling
  990. if( multicast == 1 )
  991. {
  992. MacCtx.McpsIndication.McpsIndication = MCPS_MULTICAST;
  993. }
  994. else
  995. {
  996. if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN )
  997. {
  998. Nvm.MacGroup1.SrvAckRequested = true;
  999. if( Nvm.MacGroup2.Version.Fields.Minor == 0 )
  1000. {
  1001. Nvm.MacGroup1.LastRxMic = macMsgData.MIC;
  1002. }
  1003. MacCtx.McpsIndication.McpsIndication = MCPS_CONFIRMED;
  1004. // Handle response timeout for class c and class b downlinks
  1005. if( ( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_1 ) &&
  1006. ( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_2 ) )
  1007. {
  1008. // Calculate timeout
  1009. MacCtx.McpsIndication.ResponseTimeout = REGION_COMMON_CLASS_B_C_RESP_TIMEOUT;
  1010. MacCtx.ResponseTimeoutStartTime = RxDoneParams.LastRxDone;
  1011. }
  1012. }
  1013. else
  1014. {
  1015. Nvm.MacGroup1.SrvAckRequested = false;
  1016. MacCtx.McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
  1017. }
  1018. }
  1019. RemoveMacCommands( MacCtx.McpsIndication.RxSlot, macMsgData.FHDR.FCtrl, MacCtx.McpsConfirm.McpsRequest );
  1020. switch( fType )
  1021. {
  1022. case FRAME_TYPE_A:
  1023. { /* +----------+------+-------+--------------+
  1024. * | FOptsLen | Fopt | FPort | FRMPayload |
  1025. * +----------+------+-------+--------------+
  1026. * | > 0 | X | > 0 | X |
  1027. * +----------+------+-------+--------------+
  1028. */
  1029. // Decode MAC commands in FOpts field
  1030. ProcessMacCommands( macMsgData.FHDR.FOpts, 0, macMsgData.FHDR.FCtrl.Bits.FOptsLen, snr, MacCtx.McpsIndication.RxSlot );
  1031. MacCtx.McpsIndication.Port = macMsgData.FPort;
  1032. MacCtx.McpsIndication.Buffer = macMsgData.FRMPayload;
  1033. MacCtx.McpsIndication.BufferSize = macMsgData.FRMPayloadSize;
  1034. MacCtx.McpsIndication.RxData = true;
  1035. break;
  1036. }
  1037. case FRAME_TYPE_B:
  1038. { /* +----------+------+-------+--------------+
  1039. * | FOptsLen | Fopt | FPort | FRMPayload |
  1040. * +----------+------+-------+--------------+
  1041. * | > 0 | X | - | - |
  1042. * +----------+------+-------+--------------+
  1043. */
  1044. // Decode MAC commands in FOpts field
  1045. ProcessMacCommands( macMsgData.FHDR.FOpts, 0, macMsgData.FHDR.FCtrl.Bits.FOptsLen, snr, MacCtx.McpsIndication.RxSlot );
  1046. MacCtx.McpsIndication.Port = macMsgData.FPort;
  1047. break;
  1048. }
  1049. case FRAME_TYPE_C:
  1050. { /* +----------+------+-------+--------------+
  1051. * | FOptsLen | Fopt | FPort | FRMPayload |
  1052. * +----------+------+-------+--------------+
  1053. * | = 0 | - | = 0 | MAC commands |
  1054. * +----------+------+-------+--------------+
  1055. */
  1056. // Decode MAC commands in FRMPayload
  1057. ProcessMacCommands( macMsgData.FRMPayload, 0, macMsgData.FRMPayloadSize, snr, MacCtx.McpsIndication.RxSlot );
  1058. MacCtx.McpsIndication.Port = macMsgData.FPort;
  1059. break;
  1060. }
  1061. case FRAME_TYPE_D:
  1062. { /* +----------+------+-------+--------------+
  1063. * | FOptsLen | Fopt | FPort | FRMPayload |
  1064. * +----------+------+-------+--------------+
  1065. * | = 0 | - | > 0 | X |
  1066. * +----------+------+-------+--------------+
  1067. */
  1068. // No MAC commands just application payload
  1069. MacCtx.McpsIndication.Port = macMsgData.FPort;
  1070. MacCtx.McpsIndication.Buffer = macMsgData.FRMPayload;
  1071. MacCtx.McpsIndication.BufferSize = macMsgData.FRMPayloadSize;
  1072. MacCtx.McpsIndication.RxData = true;
  1073. break;
  1074. }
  1075. default:
  1076. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  1077. PrepareRxDoneAbort( );
  1078. break;
  1079. }
  1080. if( ( macMsgData.FPort == LORAMAC_CERT_FPORT ) && ( Nvm.MacGroup2.IsCertPortOn == false ) )
  1081. { // Do not notify the upper layer of data reception on FPort LORAMAC_CERT_FPORT if the port
  1082. // handling is disabled.
  1083. MacCtx.McpsIndication.Port = macMsgData.FPort;
  1084. MacCtx.McpsIndication.Buffer = NULL;
  1085. MacCtx.McpsIndication.BufferSize = 0;
  1086. MacCtx.McpsIndication.RxData = false;
  1087. }
  1088. // Provide always an indication, skip the callback to the user application,
  1089. // in case of a confirmed downlink retransmission.
  1090. MacCtx.MacFlags.Bits.McpsInd = 1;
  1091. break;
  1092. case FRAME_TYPE_PROPRIETARY:
  1093. memcpy1( MacCtx.RxPayload, &payload[pktHeaderLen], size - pktHeaderLen );
  1094. MacCtx.McpsIndication.McpsIndication = MCPS_PROPRIETARY;
  1095. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
  1096. MacCtx.McpsIndication.Buffer = MacCtx.RxPayload;
  1097. MacCtx.McpsIndication.BufferSize = size - pktHeaderLen;
  1098. MacCtx.MacFlags.Bits.McpsInd = 1;
  1099. break;
  1100. default:
  1101. MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  1102. PrepareRxDoneAbort( );
  1103. break;
  1104. }
  1105. // Verify if we need to disable the RetransmitTimeoutTimer
  1106. // Only aplies if downlink is received on Rx1 or Rx2 windows.
  1107. if( ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_1 ) ||
  1108. ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_2 ) )
  1109. {
  1110. if( MacCtx.NodeAckRequested == true )
  1111. {
  1112. if( MacCtx.McpsConfirm.AckReceived == true )
  1113. {
  1114. OnRetransmitTimeoutTimerEvent( NULL );
  1115. }
  1116. }
  1117. }
  1118. if( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_CLASS_C )
  1119. {
  1120. MacCtx.MacFlags.Bits.MacDone = 1;
  1121. }
  1122. UpdateRxSlotIdleState( );
  1123. }
  1124. static void ProcessRadioTxTimeout( void )
  1125. {
  1126. if( Nvm.MacGroup2.DeviceClass != CLASS_C )
  1127. {
  1128. Radio.Sleep( );
  1129. }
  1130. UpdateRxSlotIdleState( );
  1131. MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
  1132. LoRaMacConfirmQueueSetStatusCmn( LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT );
  1133. if( MacCtx.NodeAckRequested == true )
  1134. {
  1135. MacCtx.RetransmitTimeoutRetry = true;
  1136. }
  1137. MacCtx.MacFlags.Bits.MacDone = 1;
  1138. }
  1139. static void HandleRadioRxErrorTimeout( LoRaMacEventInfoStatus_t rx1EventInfoStatus, LoRaMacEventInfoStatus_t rx2EventInfoStatus )
  1140. {
  1141. bool classBRx = false;
  1142. if( Nvm.MacGroup2.DeviceClass != CLASS_C )
  1143. {
  1144. Radio.Sleep( );
  1145. }
  1146. if( LoRaMacClassBIsBeaconExpected( ) == true )
  1147. {
  1148. LoRaMacClassBSetBeaconState( BEACON_STATE_TIMEOUT );
  1149. LoRaMacClassBBeaconTimerEvent( NULL );
  1150. classBRx = true;
  1151. }
  1152. if( Nvm.MacGroup2.DeviceClass == CLASS_B )
  1153. {
  1154. if( LoRaMacClassBIsPingExpected( ) == true )
  1155. {
  1156. LoRaMacClassBSetPingSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
  1157. LoRaMacClassBPingSlotTimerEvent( NULL );
  1158. classBRx = true;
  1159. }
  1160. if( LoRaMacClassBIsMulticastExpected( ) == true )
  1161. {
  1162. LoRaMacClassBSetMulticastSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
  1163. LoRaMacClassBMulticastSlotTimerEvent( NULL );
  1164. classBRx = true;
  1165. }
  1166. }
  1167. if( classBRx == false )
  1168. {
  1169. if( MacCtx.RxSlot == RX_SLOT_WIN_1 )
  1170. {
  1171. if( MacCtx.NodeAckRequested == true )
  1172. {
  1173. MacCtx.McpsConfirm.Status = rx1EventInfoStatus;
  1174. }
  1175. LoRaMacConfirmQueueSetStatusCmn( rx1EventInfoStatus );
  1176. if( TimerGetElapsedTime( Nvm.MacGroup1.LastTxDoneTime ) >= MacCtx.RxWindow2Delay )
  1177. {
  1178. TimerStop( &MacCtx.RxWindowTimer2 );
  1179. MacCtx.MacFlags.Bits.MacDone = 1;
  1180. }
  1181. }
  1182. else
  1183. {
  1184. if( MacCtx.NodeAckRequested == true )
  1185. {
  1186. MacCtx.McpsConfirm.Status = rx2EventInfoStatus;
  1187. }
  1188. LoRaMacConfirmQueueSetStatusCmn( rx2EventInfoStatus );
  1189. MacCtx.MacFlags.Bits.MacDone = 1;
  1190. }
  1191. }
  1192. UpdateRxSlotIdleState( );
  1193. }
  1194. static void ProcessRadioRxError( void )
  1195. {
  1196. HandleRadioRxErrorTimeout( LORAMAC_EVENT_INFO_STATUS_RX1_ERROR, LORAMAC_EVENT_INFO_STATUS_RX2_ERROR );
  1197. }
  1198. static void ProcessRadioRxTimeout( void )
  1199. {
  1200. HandleRadioRxErrorTimeout( LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT, LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT );
  1201. }
  1202. static void LoRaMacHandleIrqEvents( void )
  1203. {
  1204. LoRaMacRadioEvents_t events;
  1205. CRITICAL_SECTION_BEGIN( );
  1206. events = LoRaMacRadioEvents;
  1207. LoRaMacRadioEvents.Value = 0;
  1208. CRITICAL_SECTION_END( );
  1209. if( events.Value != 0 )
  1210. {
  1211. if( events.Events.TxDone == 1 )
  1212. {
  1213. ProcessRadioTxDone( );
  1214. }
  1215. if( events.Events.RxDone == 1 )
  1216. {
  1217. ProcessRadioRxDone( );
  1218. }
  1219. if( events.Events.TxTimeout == 1 )
  1220. {
  1221. ProcessRadioTxTimeout( );
  1222. }
  1223. if( events.Events.RxError == 1 )
  1224. {
  1225. ProcessRadioRxError( );
  1226. }
  1227. if( events.Events.RxTimeout == 1 )
  1228. {
  1229. ProcessRadioRxTimeout( );
  1230. }
  1231. }
  1232. }
  1233. bool LoRaMacIsBusy( void )
  1234. {
  1235. if( ( MacCtx.MacState == LORAMAC_IDLE ) &&
  1236. ( MacCtx.AllowRequests == LORAMAC_REQUEST_HANDLING_ON ) )
  1237. {
  1238. return false;
  1239. }
  1240. return true;
  1241. }
  1242. static void LoRaMacEnableRequests( LoRaMacRequestHandling_t requestState )
  1243. {
  1244. MacCtx.AllowRequests = requestState;
  1245. }
  1246. static void LoRaMacHandleRequestEvents( void )
  1247. {
  1248. // Handle events
  1249. LoRaMacFlags_t reqEvents = MacCtx.MacFlags;
  1250. if( MacCtx.MacState == LORAMAC_IDLE )
  1251. {
  1252. // Update event bits
  1253. if( MacCtx.MacFlags.Bits.McpsReq == 1 )
  1254. {
  1255. MacCtx.MacFlags.Bits.McpsReq = 0;
  1256. }
  1257. if( MacCtx.MacFlags.Bits.MlmeReq == 1 )
  1258. {
  1259. MacCtx.MacFlags.Bits.MlmeReq = 0;
  1260. }
  1261. // Allow requests again
  1262. LoRaMacEnableRequests( LORAMAC_REQUEST_HANDLING_ON );
  1263. // Handle callbacks
  1264. if( reqEvents.Bits.McpsReq == 1 )
  1265. {
  1266. MacCtx.MacPrimitives->MacMcpsConfirm( &MacCtx.McpsConfirm );
  1267. }
  1268. if( reqEvents.Bits.MlmeReq == 1 )
  1269. {
  1270. LoRaMacConfirmQueueHandleCb( &MacCtx.MlmeConfirm );
  1271. if( LoRaMacConfirmQueueGetCnt( ) > 0 )
  1272. {
  1273. MacCtx.MacFlags.Bits.MlmeReq = 1;
  1274. }
  1275. }
  1276. // Start beaconing again
  1277. LoRaMacClassBResumeBeaconing( );
  1278. // Procedure done. Reset variables.
  1279. MacCtx.MacFlags.Bits.MacDone = 0;
  1280. }
  1281. }
  1282. static void LoRaMacHandleScheduleUplinkEvent( void )
  1283. {
  1284. // Handle events
  1285. if( MacCtx.MacState == LORAMAC_IDLE )
  1286. {
  1287. // Verify if sticky MAC commands are pending or not
  1288. bool isStickyMacCommandPending = false;
  1289. LoRaMacCommandsStickyCmdsPending( &isStickyMacCommandPending );
  1290. if( isStickyMacCommandPending == true )
  1291. {// Setup MLME indication
  1292. SetMlmeScheduleUplinkIndication( );
  1293. }
  1294. }
  1295. }
  1296. static void LoRaMacHandleIndicationEvents( void )
  1297. {
  1298. // Handle MLME indication
  1299. if( MacCtx.MacFlags.Bits.MlmeInd == 1 )
  1300. {
  1301. MacCtx.MacFlags.Bits.MlmeInd = 0;
  1302. MacCtx.MacPrimitives->MacMlmeIndication( &MacCtx.MlmeIndication );
  1303. }
  1304. if( MacCtx.MacFlags.Bits.MlmeSchedUplinkInd == 1 )
  1305. {
  1306. MlmeIndication_t schduleUplinkIndication;
  1307. schduleUplinkIndication.MlmeIndication = MLME_SCHEDULE_UPLINK;
  1308. schduleUplinkIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
  1309. MacCtx.MacPrimitives->MacMlmeIndication( &schduleUplinkIndication );
  1310. MacCtx.MacFlags.Bits.MlmeSchedUplinkInd = 0;
  1311. }
  1312. // Handle MCPS indication
  1313. if( MacCtx.MacFlags.Bits.McpsInd == 1 )
  1314. {
  1315. MacCtx.MacFlags.Bits.McpsInd = 0;
  1316. MacCtx.MacPrimitives->MacMcpsIndication( &MacCtx.McpsIndication );
  1317. }
  1318. }
  1319. static void LoRaMacHandleMcpsRequest( void )
  1320. {
  1321. // Handle MCPS uplinks
  1322. if( MacCtx.MacFlags.Bits.McpsReq == 1 )
  1323. {
  1324. bool stopRetransmission = false;
  1325. bool waitForRetransmission = false;
  1326. if( ( MacCtx.McpsConfirm.McpsRequest == MCPS_UNCONFIRMED ) ||
  1327. ( MacCtx.McpsConfirm.McpsRequest == MCPS_PROPRIETARY ) )
  1328. {
  1329. stopRetransmission = CheckRetransUnconfirmedUplink( );
  1330. }
  1331. else if( MacCtx.McpsConfirm.McpsRequest == MCPS_CONFIRMED )
  1332. {
  1333. if( MacCtx.RetransmitTimeoutRetry == true )
  1334. {
  1335. stopRetransmission = CheckRetransConfirmedUplink( );
  1336. }
  1337. else
  1338. {
  1339. waitForRetransmission = true;
  1340. }
  1341. }
  1342. if( stopRetransmission == true )
  1343. {// Stop retransmission
  1344. TimerStop( &MacCtx.TxDelayedTimer );
  1345. MacCtx.MacState &= ~LORAMAC_TX_DELAYED;
  1346. StopRetransmission( );
  1347. }
  1348. else if( waitForRetransmission == false )
  1349. {// Arrange further retransmission
  1350. MacCtx.MacFlags.Bits.MacDone = 0;
  1351. // Reset the state of the AckTimeout
  1352. MacCtx.RetransmitTimeoutRetry = false;
  1353. // Sends the same frame again
  1354. OnTxDelayedTimerEvent( NULL );
  1355. }
  1356. }
  1357. }
  1358. static void LoRaMacHandleMlmeRequest( void )
  1359. {
  1360. // Handle join request
  1361. if( MacCtx.MacFlags.Bits.MlmeReq == 1 )
  1362. {
  1363. if( LoRaMacConfirmQueueIsCmdActive( MLME_JOIN ) == true )
  1364. {
  1365. if( LoRaMacConfirmQueueGetStatus( MLME_JOIN ) == LORAMAC_EVENT_INFO_STATUS_OK )
  1366. {// Node joined successfully
  1367. MacCtx.ChannelsNbTransCounter = 0;
  1368. }
  1369. MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
  1370. }
  1371. else if( LoRaMacConfirmQueueIsCmdActive( MLME_TXCW ) == true )
  1372. {
  1373. MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
  1374. }
  1375. }
  1376. }
  1377. static uint8_t LoRaMacCheckForBeaconAcquisition( void )
  1378. {
  1379. if( ( LoRaMacConfirmQueueIsCmdActive( MLME_BEACON_ACQUISITION ) == true ) &&
  1380. ( MacCtx.MacFlags.Bits.McpsReq == 0 ) )
  1381. {
  1382. if( MacCtx.MacFlags.Bits.MlmeReq == 1 )
  1383. {
  1384. MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
  1385. return 0x01;
  1386. }
  1387. }
  1388. return 0x00;
  1389. }
  1390. static bool CheckForMinimumAbpDatarate( bool adr, ActivationType_t activation, bool datarateChanged )
  1391. {
  1392. if( ( adr == true ) &&
  1393. ( activation == ACTIVATION_TYPE_ABP ) &&
  1394. ( datarateChanged == false ) )
  1395. {
  1396. return true;
  1397. }
  1398. return false;
  1399. }
  1400. static void LoRaMacCheckForRxAbort( void )
  1401. {
  1402. // A error occurs during receiving
  1403. if( ( MacCtx.MacState & LORAMAC_RX_ABORT ) == LORAMAC_RX_ABORT )
  1404. {
  1405. MacCtx.MacState &= ~LORAMAC_RX_ABORT;
  1406. MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
  1407. }
  1408. }
  1409. static void LoRaMacHandleNvm( LoRaMacNvmData_t* nvmData )
  1410. {
  1411. uint32_t crc = 0;
  1412. uint16_t notifyFlags = LORAMAC_NVM_NOTIFY_FLAG_NONE;
  1413. if( MacCtx.MacState != LORAMAC_IDLE )
  1414. {
  1415. return;
  1416. }
  1417. // Crypto
  1418. crc = Crc32( ( uint8_t* ) &nvmData->Crypto, sizeof( nvmData->Crypto ) -
  1419. sizeof( nvmData->Crypto.Crc32 ) );
  1420. if( crc != nvmData->Crypto.Crc32 )
  1421. {
  1422. nvmData->Crypto.Crc32 = crc;
  1423. notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_CRYPTO;
  1424. }
  1425. // MacGroup1
  1426. crc = Crc32( ( uint8_t* ) &nvmData->MacGroup1, sizeof( nvmData->MacGroup1 ) -
  1427. sizeof( nvmData->MacGroup1.Crc32 ) );
  1428. if( crc != nvmData->MacGroup1.Crc32 )
  1429. {
  1430. nvmData->MacGroup1.Crc32 = crc;
  1431. notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_MAC_GROUP1;
  1432. }
  1433. // MacGroup2
  1434. crc = Crc32( ( uint8_t* ) &nvmData->MacGroup2, sizeof( nvmData->MacGroup2 ) -
  1435. sizeof( nvmData->MacGroup2.Crc32 ) );
  1436. if( crc != nvmData->MacGroup2.Crc32 )
  1437. {
  1438. nvmData->MacGroup2.Crc32 = crc;
  1439. notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_MAC_GROUP2;
  1440. }
  1441. // Secure Element
  1442. crc = Crc32( ( uint8_t* ) &nvmData->SecureElement, sizeof( nvmData->SecureElement ) -
  1443. sizeof( nvmData->SecureElement.Crc32 ) );
  1444. if( crc != nvmData->SecureElement.Crc32 )
  1445. {
  1446. nvmData->SecureElement.Crc32 = crc;
  1447. notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_SECURE_ELEMENT;
  1448. }
  1449. // Region
  1450. crc = Crc32( ( uint8_t* ) &nvmData->RegionGroup1, sizeof( nvmData->RegionGroup1 ) -
  1451. sizeof( nvmData->RegionGroup1.Crc32 ) );
  1452. if( crc != nvmData->RegionGroup1.Crc32 )
  1453. {
  1454. nvmData->RegionGroup1.Crc32 = crc;
  1455. notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_REGION_GROUP1;
  1456. }
  1457. crc = Crc32( ( uint8_t* ) &nvmData->RegionGroup2, sizeof( nvmData->RegionGroup2 ) -
  1458. sizeof( nvmData->RegionGroup2.Crc32 ) );
  1459. if( crc != nvmData->RegionGroup2.Crc32 )
  1460. {
  1461. nvmData->RegionGroup2.Crc32 = crc;
  1462. notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_REGION_GROUP2;
  1463. }
  1464. // ClassB
  1465. crc = Crc32( ( uint8_t* ) &nvmData->ClassB, sizeof( nvmData->ClassB ) -
  1466. sizeof( nvmData->ClassB.Crc32 ) );
  1467. if( crc != nvmData->ClassB.Crc32 )
  1468. {
  1469. nvmData->ClassB.Crc32 = crc;
  1470. notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_CLASS_B;
  1471. }
  1472. CallNvmDataChangeCallback( notifyFlags );
  1473. }
  1474. static bool LoRaMacHandleResponseTimeout( TimerTime_t timeoutInMs, TimerTime_t startTimeInMs )
  1475. {
  1476. if( startTimeInMs != 0 )
  1477. {
  1478. TimerTime_t elapsedTime = TimerGetElapsedTime( startTimeInMs );
  1479. if( elapsedTime > timeoutInMs )
  1480. {
  1481. Nvm.MacGroup1.SrvAckRequested = false;
  1482. return true;
  1483. }
  1484. }
  1485. return false;
  1486. }
  1487. void LoRaMacProcess( void )
  1488. {
  1489. uint8_t noTx = false;
  1490. LoRaMacHandleIrqEvents( );
  1491. LoRaMacClassBProcess( );
  1492. // MAC proceeded a state and is ready to check
  1493. if( MacCtx.MacFlags.Bits.MacDone == 1 )
  1494. {
  1495. LoRaMacEnableRequests( LORAMAC_REQUEST_HANDLING_OFF );
  1496. LoRaMacCheckForRxAbort( );
  1497. // An error occurs during transmitting
  1498. if( IsRequestPending( ) > 0 )
  1499. {
  1500. noTx |= LoRaMacCheckForBeaconAcquisition( );
  1501. }
  1502. if( noTx == 0x00 )
  1503. {
  1504. LoRaMacHandleMlmeRequest( );
  1505. LoRaMacHandleMcpsRequest( );
  1506. }
  1507. LoRaMacHandleRequestEvents( );
  1508. LoRaMacHandleScheduleUplinkEvent( );
  1509. LoRaMacEnableRequests( LORAMAC_REQUEST_HANDLING_ON );
  1510. MacCtx.MacFlags.Bits.NvmHandle = 1;
  1511. }
  1512. LoRaMacHandleIndicationEvents( );
  1513. if( MacCtx.RxSlot == RX_SLOT_WIN_CLASS_C )
  1514. {
  1515. OpenContinuousRxCWindow( );
  1516. }
  1517. if( MacCtx.MacFlags.Bits.NvmHandle == 1 )
  1518. {
  1519. MacCtx.MacFlags.Bits.NvmHandle = 0;
  1520. LoRaMacHandleNvm( &Nvm );
  1521. }
  1522. }
  1523. static void OnTxDelayedTimerEvent( void* context )
  1524. {
  1525. TimerStop( &MacCtx.TxDelayedTimer );
  1526. MacCtx.MacState &= ~LORAMAC_TX_DELAYED;
  1527. if( LoRaMacHandleResponseTimeout( REGION_COMMON_CLASS_B_C_RESP_TIMEOUT,
  1528. MacCtx.ResponseTimeoutStartTime ) == true )
  1529. {
  1530. // Skip retransmission
  1531. return;
  1532. }
  1533. // Schedule frame, allow delayed frame transmissions
  1534. switch( ScheduleTx( true ) )
  1535. {
  1536. case LORAMAC_STATUS_OK:
  1537. case LORAMAC_STATUS_DUTYCYCLE_RESTRICTED:
  1538. {
  1539. break;
  1540. }
  1541. default:
  1542. {
  1543. // Stop retransmission attempt
  1544. MacCtx.McpsConfirm.Datarate = Nvm.MacGroup1.ChannelsDatarate;
  1545. MacCtx.McpsConfirm.NbTrans = MacCtx.ChannelsNbTransCounter;
  1546. MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR;
  1547. LoRaMacConfirmQueueSetStatusCmn( LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR );
  1548. StopRetransmission( );
  1549. break;
  1550. }
  1551. }
  1552. }
  1553. static void OnRxWindow1TimerEvent( void* context )
  1554. {
  1555. MacCtx.RxWindow1Config.Channel = MacCtx.Channel;
  1556. MacCtx.RxWindow1Config.DrOffset = Nvm.MacGroup2.MacParams.Rx1DrOffset;
  1557. MacCtx.RxWindow1Config.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
  1558. MacCtx.RxWindow1Config.RxContinuous = false;
  1559. MacCtx.RxWindow1Config.RxSlot = RX_SLOT_WIN_1;
  1560. MacCtx.RxWindow1Config.NetworkActivation = Nvm.MacGroup2.NetworkActivation;
  1561. RxWindowSetup( &MacCtx.RxWindowTimer1, &MacCtx.RxWindow1Config );
  1562. }
  1563. static void OnRxWindow2TimerEvent( void* context )
  1564. {
  1565. // Check if we are processing Rx1 window.
  1566. // If yes, we don't setup the Rx2 window.
  1567. if( MacCtx.RxSlot == RX_SLOT_WIN_1 )
  1568. {
  1569. return;
  1570. }
  1571. MacCtx.RxWindow2Config.Channel = MacCtx.Channel;
  1572. MacCtx.RxWindow2Config.Frequency = Nvm.MacGroup2.MacParams.Rx2Channel.Frequency;
  1573. MacCtx.RxWindow2Config.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
  1574. MacCtx.RxWindow2Config.RxContinuous = false;
  1575. MacCtx.RxWindow2Config.RxSlot = RX_SLOT_WIN_2;
  1576. MacCtx.RxWindow2Config.NetworkActivation = Nvm.MacGroup2.NetworkActivation;
  1577. RxWindowSetup( &MacCtx.RxWindowTimer2, &MacCtx.RxWindow2Config );
  1578. }
  1579. static void OnRetransmitTimeoutTimerEvent( void* context )
  1580. {
  1581. TimerStop( &MacCtx.RetransmitTimeoutTimer );
  1582. if( MacCtx.NodeAckRequested == true )
  1583. {
  1584. MacCtx.RetransmitTimeoutRetry = true;
  1585. }
  1586. if( ( MacCtx.MacCallbacks != NULL ) && ( MacCtx.MacCallbacks->MacProcessNotify != NULL ) )
  1587. {
  1588. MacCtx.MacCallbacks->MacProcessNotify( );
  1589. }
  1590. }
  1591. static LoRaMacCryptoStatus_t GetFCntDown( AddressIdentifier_t addrID, FType_t fType, LoRaMacMessageData_t* macMsg, Version_t lrWanVersion,
  1592. FCntIdentifier_t* fCntID, uint32_t* currentDown )
  1593. {
  1594. if( ( macMsg == NULL ) || ( fCntID == NULL ) ||
  1595. ( currentDown == NULL ) )
  1596. {
  1597. return LORAMAC_CRYPTO_ERROR_NPE;
  1598. }
  1599. // Determine the frame counter identifier and choose counter from FCntList
  1600. switch( addrID )
  1601. {
  1602. case UNICAST_DEV_ADDR:
  1603. if( lrWanVersion.Fields.Minor == 1 )
  1604. {
  1605. if( ( fType == FRAME_TYPE_A ) || ( fType == FRAME_TYPE_D ) )
  1606. {
  1607. *fCntID = A_FCNT_DOWN;
  1608. }
  1609. else
  1610. {
  1611. *fCntID = N_FCNT_DOWN;
  1612. }
  1613. }
  1614. else
  1615. { // For LoRaWAN 1.0.X
  1616. *fCntID = FCNT_DOWN;
  1617. }
  1618. break;
  1619. case MULTICAST_0_ADDR:
  1620. *fCntID = MC_FCNT_DOWN_0;
  1621. break;
  1622. case MULTICAST_1_ADDR:
  1623. *fCntID = MC_FCNT_DOWN_1;
  1624. break;
  1625. case MULTICAST_2_ADDR:
  1626. *fCntID = MC_FCNT_DOWN_2;
  1627. break;
  1628. case MULTICAST_3_ADDR:
  1629. *fCntID = MC_FCNT_DOWN_3;
  1630. break;
  1631. default:
  1632. return LORAMAC_CRYPTO_FAIL_FCNT_ID;
  1633. }
  1634. return LoRaMacCryptoGetFCntDown( *fCntID, macMsg->FHDR.FCnt, currentDown );
  1635. }
  1636. static LoRaMacStatus_t SwitchClass( DeviceClass_t deviceClass )
  1637. {
  1638. LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
  1639. switch( Nvm.MacGroup2.DeviceClass )
  1640. {
  1641. case CLASS_A:
  1642. {
  1643. if( deviceClass == CLASS_A )
  1644. {
  1645. // Revert back RxC parameters
  1646. Nvm.MacGroup2.MacParams.RxCChannel = Nvm.MacGroup2.MacParams.Rx2Channel;
  1647. }
  1648. if( deviceClass == CLASS_B )
  1649. {
  1650. status = LoRaMacClassBSwitchClass( deviceClass );
  1651. if( status == LORAMAC_STATUS_OK )
  1652. {
  1653. Nvm.MacGroup2.DeviceClass = deviceClass;
  1654. }
  1655. }
  1656. if( deviceClass == CLASS_C )
  1657. {
  1658. Nvm.MacGroup2.DeviceClass = deviceClass;
  1659. MacCtx.RxWindowCConfig = MacCtx.RxWindow2Config;
  1660. MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C;
  1661. for( int8_t i = 0; i < LORAMAC_MAX_MC_CTX; i++ )
  1662. {
  1663. if( Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.IsEnabled == true )
  1664. // TODO: Check multicast channel device class.
  1665. {
  1666. Nvm.MacGroup2.MacParams.RxCChannel.Frequency = Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.RxParams.ClassC.Frequency;
  1667. Nvm.MacGroup2.MacParams.RxCChannel.Datarate = Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.RxParams.ClassC.Datarate;
  1668. MacCtx.RxWindowCConfig.Channel = MacCtx.Channel;
  1669. MacCtx.RxWindowCConfig.Frequency = Nvm.MacGroup2.MacParams.RxCChannel.Frequency;
  1670. MacCtx.RxWindowCConfig.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
  1671. MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C_MULTICAST;
  1672. MacCtx.RxWindowCConfig.RxContinuous = true;
  1673. break;
  1674. }
  1675. }
  1676. // Set the NodeAckRequested indicator to default
  1677. MacCtx.NodeAckRequested = false;
  1678. // Set the radio into sleep mode in case we are still in RX mode
  1679. Radio.Sleep( );
  1680. OpenContinuousRxCWindow( );
  1681. status = LORAMAC_STATUS_OK;
  1682. }
  1683. break;
  1684. }
  1685. case CLASS_B:
  1686. {
  1687. status = LoRaMacClassBSwitchClass( deviceClass );
  1688. if( status == LORAMAC_STATUS_OK )
  1689. {
  1690. Nvm.MacGroup2.DeviceClass = deviceClass;
  1691. }
  1692. break;
  1693. }
  1694. case CLASS_C:
  1695. {
  1696. if( deviceClass == CLASS_A )
  1697. {
  1698. Nvm.MacGroup2.DeviceClass = deviceClass;
  1699. // Set the radio into sleep to setup a defined state
  1700. Radio.Sleep( );
  1701. status = LORAMAC_STATUS_OK;
  1702. }
  1703. break;
  1704. }
  1705. }
  1706. return status;
  1707. }
  1708. static uint8_t GetMaxAppPayloadWithoutFOptsLength( int8_t datarate )
  1709. {
  1710. GetPhyParams_t getPhy;
  1711. PhyParam_t phyParam;
  1712. // Setup PHY request
  1713. getPhy.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
  1714. getPhy.Datarate = datarate;
  1715. getPhy.Attribute = PHY_MAX_PAYLOAD;
  1716. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  1717. return phyParam.Value;
  1718. }
  1719. static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen )
  1720. {
  1721. uint16_t maxN = 0;
  1722. uint16_t payloadSize = 0;
  1723. maxN = GetMaxAppPayloadWithoutFOptsLength( datarate );
  1724. // Calculate the resulting payload size
  1725. payloadSize = ( lenN + fOptsLen );
  1726. // Validation of the application payload size
  1727. if( ( payloadSize <= maxN ) && ( payloadSize <= LORAMAC_PHY_MAXPAYLOAD ) )
  1728. {
  1729. return true;
  1730. }
  1731. return false;
  1732. }
  1733. static void SetMlmeScheduleUplinkIndication( void )
  1734. {
  1735. MacCtx.MacFlags.Bits.MlmeSchedUplinkInd = 1;
  1736. }
  1737. static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, int8_t snr, LoRaMacRxSlot_t rxSlot )
  1738. {
  1739. uint8_t status = 0;
  1740. bool adrBlockFound = false;
  1741. uint8_t macCmdPayload[2] = { 0x00, 0x00 };
  1742. if( ( rxSlot != RX_SLOT_WIN_1 ) && ( rxSlot != RX_SLOT_WIN_2 ) )
  1743. {
  1744. // Do only parse MAC commands for Class A RX windows
  1745. return;
  1746. }
  1747. while( macIndex < commandsSize )
  1748. {
  1749. // Make sure to parse only complete MAC commands
  1750. if( ( LoRaMacCommandsGetCmdSize( payload[macIndex] ) + macIndex ) > commandsSize )
  1751. {
  1752. return;
  1753. }
  1754. // Decode Frame MAC commands
  1755. switch( payload[macIndex++] )
  1756. {
  1757. case SRV_MAC_LINK_CHECK_ANS:
  1758. {
  1759. if( LoRaMacConfirmQueueIsCmdActive( MLME_LINK_CHECK ) == true )
  1760. {
  1761. LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_LINK_CHECK );
  1762. MacCtx.MlmeConfirm.DemodMargin = payload[macIndex++];
  1763. MacCtx.MlmeConfirm.NbGateways = payload[macIndex++];
  1764. }
  1765. break;
  1766. }
  1767. case SRV_MAC_LINK_ADR_REQ:
  1768. {
  1769. LinkAdrReqParams_t linkAdrReq;
  1770. int8_t linkAdrDatarate = DR_0;
  1771. int8_t linkAdrTxPower = TX_POWER_0;
  1772. uint8_t linkAdrNbRep = 0;
  1773. uint8_t linkAdrNbBytesParsed = 0;
  1774. // The end node is allowed to process one block of LinkAdrRequests.
  1775. // It must ignore subsequent blocks
  1776. if( adrBlockFound == false )
  1777. {
  1778. adrBlockFound = true;
  1779. do
  1780. {
  1781. // Fill parameter structure
  1782. linkAdrReq.Payload = &payload[macIndex - 1];
  1783. linkAdrReq.AdrEnabled = Nvm.MacGroup2.AdrCtrlOn;
  1784. linkAdrReq.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
  1785. linkAdrReq.CurrentDatarate = Nvm.MacGroup1.ChannelsDatarate;
  1786. linkAdrReq.CurrentTxPower = Nvm.MacGroup1.ChannelsTxPower;
  1787. linkAdrReq.CurrentNbRep = Nvm.MacGroup2.MacParams.ChannelsNbTrans;
  1788. linkAdrReq.Version = Nvm.MacGroup2.Version;
  1789. // There is a fundamental difference in reporting the status
  1790. // of the LinkAdrRequests when ADR is on or off. When ADR is on, every
  1791. // LinkAdrAns contains the same value. This does not hold when ADR is off,
  1792. // where every LinkAdrAns requires an individual status.
  1793. if( Nvm.MacGroup2.AdrCtrlOn == true )
  1794. {
  1795. // When ADR is on, the function RegionLinkAdrReq will take care
  1796. // about the parsing and interpretation of the LinkAdrRequest block and
  1797. // it provides one status which shall be applied to every LinkAdrAns
  1798. linkAdrReq.PayloadSize = commandsSize - ( macIndex - 1 );
  1799. }
  1800. else
  1801. {
  1802. // When ADR is off, this function will loop over the individual LinkAdrRequests
  1803. // and will call RegionLinkAdrReq for each individually, as every request
  1804. // requires an individual answer.
  1805. // When ADR is off, the function RegionLinkAdrReq ignores the new values for
  1806. // ChannelsDatarate, ChannelsTxPower and ChannelsNbTrans.
  1807. linkAdrReq.PayloadSize = 5;
  1808. }
  1809. // Process the ADR requests
  1810. status = RegionLinkAdrReq( Nvm.MacGroup2.Region, &linkAdrReq, &linkAdrDatarate,
  1811. &linkAdrTxPower, &linkAdrNbRep, &linkAdrNbBytesParsed );
  1812. if( ( status & 0x07 ) == 0x07 )
  1813. {
  1814. // Set the status that the datarate has been increased
  1815. if( linkAdrDatarate > Nvm.MacGroup1.ChannelsDatarate )
  1816. {
  1817. Nvm.MacGroup2.ChannelsDatarateChangedLinkAdrReq = true;
  1818. }
  1819. Nvm.MacGroup1.ChannelsDatarate = linkAdrDatarate;
  1820. Nvm.MacGroup1.ChannelsTxPower = linkAdrTxPower;
  1821. Nvm.MacGroup2.MacParams.ChannelsNbTrans = linkAdrNbRep;
  1822. }
  1823. // Add the answers to the buffer
  1824. for( uint8_t i = 0; i < ( linkAdrNbBytesParsed / 5 ); i++ )
  1825. {
  1826. LoRaMacCommandsAddCmd( MOTE_MAC_LINK_ADR_ANS, &status, 1 );
  1827. }
  1828. // Update MAC index
  1829. macIndex += linkAdrNbBytesParsed - 1;
  1830. // Check to prevent invalid access
  1831. if( macIndex >= commandsSize )
  1832. break;
  1833. } while( payload[macIndex++] == SRV_MAC_LINK_ADR_REQ );
  1834. if( macIndex < commandsSize )
  1835. {
  1836. // Decrease the index such that it points to the next MAC command
  1837. macIndex--;
  1838. }
  1839. }
  1840. else
  1841. {
  1842. // Increase the index by the MAC command size (without command)
  1843. macIndex += 4;
  1844. }
  1845. break;
  1846. }
  1847. case SRV_MAC_DUTY_CYCLE_REQ:
  1848. {
  1849. Nvm.MacGroup2.MaxDCycle = payload[macIndex++] & 0x0F;
  1850. Nvm.MacGroup2.AggregatedDCycle = 1 << Nvm.MacGroup2.MaxDCycle;
  1851. LoRaMacCommandsAddCmd( MOTE_MAC_DUTY_CYCLE_ANS, macCmdPayload, 0 );
  1852. break;
  1853. }
  1854. case SRV_MAC_RX_PARAM_SETUP_REQ:
  1855. {
  1856. RxParamSetupReqParams_t rxParamSetupReq;
  1857. status = 0x07;
  1858. rxParamSetupReq.DrOffset = ( payload[macIndex] >> 4 ) & 0x07;
  1859. rxParamSetupReq.Datarate = payload[macIndex] & 0x0F;
  1860. macIndex++;
  1861. rxParamSetupReq.Frequency = ( uint32_t ) payload[macIndex++];
  1862. rxParamSetupReq.Frequency |= ( uint32_t ) payload[macIndex++] << 8;
  1863. rxParamSetupReq.Frequency |= ( uint32_t ) payload[macIndex++] << 16;
  1864. rxParamSetupReq.Frequency *= 100;
  1865. // Perform request on region
  1866. status = RegionRxParamSetupReq( Nvm.MacGroup2.Region, &rxParamSetupReq );
  1867. if( ( status & 0x07 ) == 0x07 )
  1868. {
  1869. Nvm.MacGroup2.MacParams.Rx2Channel.Datarate = rxParamSetupReq.Datarate;
  1870. Nvm.MacGroup2.MacParams.RxCChannel.Datarate = rxParamSetupReq.Datarate;
  1871. Nvm.MacGroup2.MacParams.Rx2Channel.Frequency = rxParamSetupReq.Frequency;
  1872. Nvm.MacGroup2.MacParams.RxCChannel.Frequency = rxParamSetupReq.Frequency;
  1873. Nvm.MacGroup2.MacParams.Rx1DrOffset = rxParamSetupReq.DrOffset;
  1874. }
  1875. macCmdPayload[0] = status;
  1876. LoRaMacCommandsAddCmd( MOTE_MAC_RX_PARAM_SETUP_ANS, macCmdPayload, 1 );
  1877. // Setup indication to inform the application
  1878. SetMlmeScheduleUplinkIndication( );
  1879. break;
  1880. }
  1881. case SRV_MAC_DEV_STATUS_REQ:
  1882. {
  1883. uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE;
  1884. if( ( MacCtx.MacCallbacks != NULL ) && ( MacCtx.MacCallbacks->GetBatteryLevel != NULL ) )
  1885. {
  1886. batteryLevel = MacCtx.MacCallbacks->GetBatteryLevel( );
  1887. }
  1888. macCmdPayload[0] = batteryLevel;
  1889. macCmdPayload[1] = ( uint8_t )( snr & 0x3F );
  1890. LoRaMacCommandsAddCmd( MOTE_MAC_DEV_STATUS_ANS, macCmdPayload, 2 );
  1891. break;
  1892. }
  1893. case SRV_MAC_NEW_CHANNEL_REQ:
  1894. {
  1895. NewChannelReqParams_t newChannelReq;
  1896. ChannelParams_t chParam;
  1897. status = 0x03;
  1898. newChannelReq.ChannelId = payload[macIndex++];
  1899. newChannelReq.NewChannel = &chParam;
  1900. chParam.Frequency = ( uint32_t ) payload[macIndex++];
  1901. chParam.Frequency |= ( uint32_t ) payload[macIndex++] << 8;
  1902. chParam.Frequency |= ( uint32_t ) payload[macIndex++] << 16;
  1903. chParam.Frequency *= 100;
  1904. chParam.Rx1Frequency = 0;
  1905. chParam.DrRange.Value = payload[macIndex++];
  1906. status = ( uint8_t )RegionNewChannelReq( Nvm.MacGroup2.Region, &newChannelReq );
  1907. if( ( int8_t )status >= 0 )
  1908. {
  1909. macCmdPayload[0] = status;
  1910. LoRaMacCommandsAddCmd( MOTE_MAC_NEW_CHANNEL_ANS, macCmdPayload, 1 );
  1911. }
  1912. break;
  1913. }
  1914. case SRV_MAC_RX_TIMING_SETUP_REQ:
  1915. {
  1916. uint8_t delay = payload[macIndex++] & 0x0F;
  1917. if( delay == 0 )
  1918. {
  1919. delay++;
  1920. }
  1921. Nvm.MacGroup2.MacParams.ReceiveDelay1 = delay * 1000;
  1922. Nvm.MacGroup2.MacParams.ReceiveDelay2 = Nvm.MacGroup2.MacParams.ReceiveDelay1 + 1000;
  1923. LoRaMacCommandsAddCmd( MOTE_MAC_RX_TIMING_SETUP_ANS, macCmdPayload, 0 );
  1924. // Setup indication to inform the application
  1925. SetMlmeScheduleUplinkIndication( );
  1926. break;
  1927. }
  1928. case SRV_MAC_TX_PARAM_SETUP_REQ:
  1929. {
  1930. TxParamSetupReqParams_t txParamSetupReq;
  1931. GetPhyParams_t getPhy;
  1932. PhyParam_t phyParam;
  1933. uint8_t eirpDwellTime = payload[macIndex++];
  1934. txParamSetupReq.UplinkDwellTime = 0;
  1935. txParamSetupReq.DownlinkDwellTime = 0;
  1936. if( ( eirpDwellTime & 0x20 ) == 0x20 )
  1937. {
  1938. txParamSetupReq.DownlinkDwellTime = 1;
  1939. }
  1940. if( ( eirpDwellTime & 0x10 ) == 0x10 )
  1941. {
  1942. txParamSetupReq.UplinkDwellTime = 1;
  1943. }
  1944. txParamSetupReq.MaxEirp = eirpDwellTime & 0x0F;
  1945. // Check the status for correctness
  1946. if( RegionTxParamSetupReq( Nvm.MacGroup2.Region, &txParamSetupReq ) != -1 )
  1947. {
  1948. // Accept command
  1949. Nvm.MacGroup2.MacParams.UplinkDwellTime = txParamSetupReq.UplinkDwellTime;
  1950. Nvm.MacGroup2.MacParams.DownlinkDwellTime = txParamSetupReq.DownlinkDwellTime;
  1951. Nvm.MacGroup2.MacParams.MaxEirp = LoRaMacMaxEirpTable[txParamSetupReq.MaxEirp];
  1952. // Update the datarate in case of the new configuration limits it
  1953. getPhy.Attribute = PHY_MIN_TX_DR;
  1954. getPhy.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
  1955. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  1956. Nvm.MacGroup1.ChannelsDatarate = MAX( Nvm.MacGroup1.ChannelsDatarate, ( int8_t )phyParam.Value );
  1957. // Add command response
  1958. LoRaMacCommandsAddCmd( MOTE_MAC_TX_PARAM_SETUP_ANS, macCmdPayload, 0 );
  1959. }
  1960. break;
  1961. }
  1962. case SRV_MAC_DL_CHANNEL_REQ:
  1963. {
  1964. DlChannelReqParams_t dlChannelReq;
  1965. status = 0x03;
  1966. dlChannelReq.ChannelId = payload[macIndex++];
  1967. dlChannelReq.Rx1Frequency = ( uint32_t ) payload[macIndex++];
  1968. dlChannelReq.Rx1Frequency |= ( uint32_t ) payload[macIndex++] << 8;
  1969. dlChannelReq.Rx1Frequency |= ( uint32_t ) payload[macIndex++] << 16;
  1970. dlChannelReq.Rx1Frequency *= 100;
  1971. status = ( uint8_t )RegionDlChannelReq( Nvm.MacGroup2.Region, &dlChannelReq );
  1972. if( ( int8_t )status >= 0 )
  1973. {
  1974. macCmdPayload[0] = status;
  1975. LoRaMacCommandsAddCmd( MOTE_MAC_DL_CHANNEL_ANS, macCmdPayload, 1 );
  1976. // Setup indication to inform the application
  1977. SetMlmeScheduleUplinkIndication( );
  1978. }
  1979. break;
  1980. }
  1981. case SRV_MAC_DEVICE_TIME_ANS:
  1982. {
  1983. // The mote time can be updated only when the time is received in classA
  1984. // receive windows only.
  1985. if( LoRaMacConfirmQueueIsCmdActive( MLME_DEVICE_TIME ) == true )
  1986. {
  1987. LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_DEVICE_TIME );
  1988. SysTime_t gpsEpochTime = { 0 };
  1989. SysTime_t sysTime = { 0 };
  1990. SysTime_t sysTimeCurrent = { 0 };
  1991. gpsEpochTime.Seconds = ( uint32_t )payload[macIndex++];
  1992. gpsEpochTime.Seconds |= ( uint32_t )payload[macIndex++] << 8;
  1993. gpsEpochTime.Seconds |= ( uint32_t )payload[macIndex++] << 16;
  1994. gpsEpochTime.Seconds |= ( uint32_t )payload[macIndex++] << 24;
  1995. gpsEpochTime.SubSeconds = payload[macIndex++];
  1996. // Convert the fractional second received in ms
  1997. // round( pow( 0.5, 8.0 ) * 1000 ) = 3.90625
  1998. gpsEpochTime.SubSeconds = ( int16_t )( ( ( int32_t )gpsEpochTime.SubSeconds * 1000 ) >> 8 );
  1999. // Copy received GPS Epoch time into system time
  2000. sysTime = gpsEpochTime;
  2001. // Add Unix to Gps epoch offset. The system time is based on Unix time.
  2002. sysTime.Seconds += UNIX_GPS_EPOCH_OFFSET;
  2003. // Compensate time difference between Tx Done time and now
  2004. sysTimeCurrent = SysTimeGet( );
  2005. sysTime = SysTimeAdd( sysTimeCurrent, SysTimeSub( sysTime, MacCtx.LastTxSysTime ) );
  2006. // Apply the new system time.
  2007. SysTimeSet( sysTime );
  2008. LoRaMacClassBDeviceTimeAns( );
  2009. MacCtx.McpsIndication.DeviceTimeAnsReceived = true;
  2010. }
  2011. else
  2012. {
  2013. // Incase of other receive windows the Device Time Answer is not received.
  2014. MacCtx.McpsIndication.DeviceTimeAnsReceived = false;
  2015. }
  2016. break;
  2017. }
  2018. case SRV_MAC_PING_SLOT_INFO_ANS:
  2019. {
  2020. if( LoRaMacConfirmQueueIsCmdActive( MLME_PING_SLOT_INFO ) == true )
  2021. {
  2022. LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_PING_SLOT_INFO );
  2023. // According to the specification, it is not allowed to process this answer in
  2024. // a ping or multicast slot
  2025. if( ( MacCtx.RxSlot != RX_SLOT_WIN_CLASS_B_PING_SLOT ) && ( MacCtx.RxSlot != RX_SLOT_WIN_CLASS_B_MULTICAST_SLOT ) )
  2026. {
  2027. LoRaMacClassBPingSlotInfoAns( );
  2028. }
  2029. }
  2030. break;
  2031. }
  2032. case SRV_MAC_PING_SLOT_CHANNEL_REQ:
  2033. {
  2034. uint8_t status = 0x03;
  2035. uint32_t frequency = 0;
  2036. uint8_t datarate;
  2037. frequency = ( uint32_t )payload[macIndex++];
  2038. frequency |= ( uint32_t )payload[macIndex++] << 8;
  2039. frequency |= ( uint32_t )payload[macIndex++] << 16;
  2040. frequency *= 100;
  2041. datarate = payload[macIndex++] & 0x0F;
  2042. status = LoRaMacClassBPingSlotChannelReq( datarate, frequency );
  2043. macCmdPayload[0] = status;
  2044. LoRaMacCommandsAddCmd( MOTE_MAC_PING_SLOT_CHANNEL_ANS, macCmdPayload, 1 );
  2045. // Setup indication to inform the application
  2046. SetMlmeScheduleUplinkIndication( );
  2047. break;
  2048. }
  2049. case SRV_MAC_BEACON_TIMING_ANS:
  2050. {
  2051. if( LoRaMacConfirmQueueIsCmdActive( MLME_BEACON_TIMING ) == true )
  2052. {
  2053. LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_BEACON_TIMING );
  2054. uint16_t beaconTimingDelay = 0;
  2055. uint8_t beaconTimingChannel = 0;
  2056. beaconTimingDelay = ( uint16_t )payload[macIndex++];
  2057. beaconTimingDelay |= ( uint16_t )payload[macIndex++] << 8;
  2058. beaconTimingChannel = payload[macIndex++];
  2059. LoRaMacClassBBeaconTimingAns( beaconTimingDelay, beaconTimingChannel, RxDoneParams.LastRxDone );
  2060. }
  2061. break;
  2062. }
  2063. case SRV_MAC_BEACON_FREQ_REQ:
  2064. {
  2065. uint32_t frequency = 0;
  2066. frequency = ( uint32_t )payload[macIndex++];
  2067. frequency |= ( uint32_t )payload[macIndex++] << 8;
  2068. frequency |= ( uint32_t )payload[macIndex++] << 16;
  2069. frequency *= 100;
  2070. if( LoRaMacClassBBeaconFreqReq( frequency ) == true )
  2071. {
  2072. macCmdPayload[0] = 1;
  2073. }
  2074. else
  2075. {
  2076. macCmdPayload[0] = 0;
  2077. }
  2078. LoRaMacCommandsAddCmd( MOTE_MAC_BEACON_FREQ_ANS, macCmdPayload, 1 );
  2079. }
  2080. break;
  2081. default:
  2082. // Unknown command. ABORT MAC commands processing
  2083. return;
  2084. }
  2085. }
  2086. }
  2087. LoRaMacStatus_t Send( LoRaMacHeader_t* macHdr, uint8_t fPort, void* fBuffer, uint16_t fBufferSize )
  2088. {
  2089. LoRaMacFrameCtrl_t fCtrl;
  2090. LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
  2091. int8_t datarate = Nvm.MacGroup1.ChannelsDatarate;
  2092. int8_t txPower = Nvm.MacGroup1.ChannelsTxPower;
  2093. uint32_t adrAckCounter = Nvm.MacGroup1.AdrAckCounter;
  2094. CalcNextAdrParams_t adrNext;
  2095. // Check if we are joined
  2096. if( Nvm.MacGroup2.NetworkActivation == ACTIVATION_TYPE_NONE )
  2097. {
  2098. return LORAMAC_STATUS_NO_NETWORK_JOINED;
  2099. }
  2100. if( Nvm.MacGroup2.MaxDCycle == 0 )
  2101. {
  2102. Nvm.MacGroup1.AggregatedTimeOff = 0;
  2103. }
  2104. fCtrl.Value = 0;
  2105. fCtrl.Bits.FOptsLen = 0;
  2106. fCtrl.Bits.Adr = Nvm.MacGroup2.AdrCtrlOn;
  2107. // Check class b
  2108. if( Nvm.MacGroup2.DeviceClass == CLASS_B )
  2109. {
  2110. fCtrl.Bits.FPending = 1;
  2111. }
  2112. else
  2113. {
  2114. fCtrl.Bits.FPending = 0;
  2115. }
  2116. // Check server ack
  2117. if( Nvm.MacGroup1.SrvAckRequested == true )
  2118. {
  2119. fCtrl.Bits.Ack = 1;
  2120. }
  2121. // ADR next request
  2122. adrNext.UpdateChanMask = true;
  2123. adrNext.AdrEnabled = fCtrl.Bits.Adr;
  2124. adrNext.AdrAckCounter = Nvm.MacGroup1.AdrAckCounter;
  2125. adrNext.AdrAckLimit = MacCtx.AdrAckLimit;
  2126. adrNext.AdrAckDelay = MacCtx.AdrAckDelay;
  2127. adrNext.Datarate = Nvm.MacGroup1.ChannelsDatarate;
  2128. adrNext.TxPower = Nvm.MacGroup1.ChannelsTxPower;
  2129. adrNext.NbTrans = Nvm.MacGroup2.MacParams.ChannelsNbTrans;
  2130. adrNext.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
  2131. adrNext.Region = Nvm.MacGroup2.Region;
  2132. fCtrl.Bits.AdrAckReq = LoRaMacAdrCalcNext( &adrNext, &Nvm.MacGroup1.ChannelsDatarate,
  2133. &Nvm.MacGroup1.ChannelsTxPower,
  2134. &Nvm.MacGroup2.MacParams.ChannelsNbTrans, &adrAckCounter );
  2135. // Prepare the frame
  2136. status = PrepareFrame( macHdr, &fCtrl, fPort, fBuffer, fBufferSize );
  2137. // Validate status
  2138. if( ( status == LORAMAC_STATUS_OK ) || ( status == LORAMAC_STATUS_SKIPPED_APP_DATA ) )
  2139. {
  2140. // Schedule frame, do not allow delayed transmissions
  2141. status = ScheduleTx( false );
  2142. }
  2143. // Post processing
  2144. if( status != LORAMAC_STATUS_OK )
  2145. {
  2146. // Bad case - restore
  2147. // Store local variables
  2148. Nvm.MacGroup1.ChannelsDatarate = datarate;
  2149. Nvm.MacGroup1.ChannelsTxPower = txPower;
  2150. }
  2151. else
  2152. {
  2153. // Good case
  2154. Nvm.MacGroup1.SrvAckRequested = false;
  2155. Nvm.MacGroup1.AdrAckCounter = adrAckCounter;
  2156. // Remove all none sticky MAC commands
  2157. if( LoRaMacCommandsRemoveNoneStickyCmds( ) != LORAMAC_COMMANDS_SUCCESS )
  2158. {
  2159. return LORAMAC_STATUS_MAC_COMMAD_ERROR;
  2160. }
  2161. }
  2162. return status;
  2163. }
  2164. LoRaMacStatus_t SendReJoinReq( JoinReqIdentifier_t joinReqType )
  2165. {
  2166. LoRaMacStatus_t status = LORAMAC_STATUS_OK;
  2167. LoRaMacHeader_t macHdr;
  2168. macHdr.Value = 0;
  2169. bool allowDelayedTx = true;
  2170. // Setup join/rejoin message
  2171. switch( joinReqType )
  2172. {
  2173. case JOIN_REQ:
  2174. {
  2175. SwitchClass( CLASS_A );
  2176. MacCtx.TxMsg.Type = LORAMAC_MSG_TYPE_JOIN_REQUEST;
  2177. MacCtx.TxMsg.Message.JoinReq.Buffer = MacCtx.PktBuffer;
  2178. MacCtx.TxMsg.Message.JoinReq.BufSize = LORAMAC_PHY_MAXPAYLOAD;
  2179. macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
  2180. MacCtx.TxMsg.Message.JoinReq.MHDR.Value = macHdr.Value;
  2181. memcpy1( MacCtx.TxMsg.Message.JoinReq.JoinEUI, SecureElementGetJoinEui( ), LORAMAC_JOIN_EUI_FIELD_SIZE );
  2182. memcpy1( MacCtx.TxMsg.Message.JoinReq.DevEUI, SecureElementGetDevEui( ), LORAMAC_DEV_EUI_FIELD_SIZE );
  2183. allowDelayedTx = false;
  2184. break;
  2185. }
  2186. default:
  2187. status = LORAMAC_STATUS_SERVICE_UNKNOWN;
  2188. break;
  2189. }
  2190. // Schedule frame
  2191. status = ScheduleTx( allowDelayedTx );
  2192. return status;
  2193. }
  2194. static LoRaMacStatus_t CheckForClassBCollision( void )
  2195. {
  2196. if( LoRaMacClassBIsBeaconExpected( ) == true )
  2197. {
  2198. return LORAMAC_STATUS_BUSY_BEACON_RESERVED_TIME;
  2199. }
  2200. if( Nvm.MacGroup2.DeviceClass == CLASS_B )
  2201. {
  2202. if( LoRaMacClassBIsPingExpected( ) == true )
  2203. {
  2204. return LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME;
  2205. }
  2206. else if( LoRaMacClassBIsMulticastExpected( ) == true )
  2207. {
  2208. return LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME;
  2209. }
  2210. }
  2211. return LORAMAC_STATUS_OK;
  2212. }
  2213. static void ComputeRxWindowParameters( void )
  2214. {
  2215. // Compute Rx1 windows parameters
  2216. RegionComputeRxWindowParameters( Nvm.MacGroup2.Region,
  2217. RegionApplyDrOffset( Nvm.MacGroup2.Region,
  2218. Nvm.MacGroup2.MacParams.DownlinkDwellTime,
  2219. Nvm.MacGroup1.ChannelsDatarate,
  2220. Nvm.MacGroup2.MacParams.Rx1DrOffset ),
  2221. Nvm.MacGroup2.MacParams.MinRxSymbols,
  2222. Nvm.MacGroup2.MacParams.SystemMaxRxError,
  2223. &MacCtx.RxWindow1Config );
  2224. // Compute Rx2 windows parameters
  2225. RegionComputeRxWindowParameters( Nvm.MacGroup2.Region,
  2226. Nvm.MacGroup2.MacParams.Rx2Channel.Datarate,
  2227. Nvm.MacGroup2.MacParams.MinRxSymbols,
  2228. Nvm.MacGroup2.MacParams.SystemMaxRxError,
  2229. &MacCtx.RxWindow2Config );
  2230. // Default setup, in case the device joined
  2231. MacCtx.RxWindow1Delay = Nvm.MacGroup2.MacParams.ReceiveDelay1 + MacCtx.RxWindow1Config.WindowOffset;
  2232. MacCtx.RxWindow2Delay = Nvm.MacGroup2.MacParams.ReceiveDelay2 + MacCtx.RxWindow2Config.WindowOffset;
  2233. if( Nvm.MacGroup2.NetworkActivation == ACTIVATION_TYPE_NONE )
  2234. {
  2235. MacCtx.RxWindow1Delay = Nvm.MacGroup2.MacParams.JoinAcceptDelay1 + MacCtx.RxWindow1Config.WindowOffset;
  2236. MacCtx.RxWindow2Delay = Nvm.MacGroup2.MacParams.JoinAcceptDelay2 + MacCtx.RxWindow2Config.WindowOffset;
  2237. }
  2238. }
  2239. static LoRaMacStatus_t VerifyTxFrame( void )
  2240. {
  2241. size_t macCmdsSize = 0;
  2242. if( Nvm.MacGroup2.NetworkActivation != ACTIVATION_TYPE_NONE )
  2243. {
  2244. if( LoRaMacCommandsGetSizeSerializedCmds( &macCmdsSize ) != LORAMAC_COMMANDS_SUCCESS )
  2245. {
  2246. return LORAMAC_STATUS_MAC_COMMAD_ERROR;
  2247. }
  2248. if( ValidatePayloadLength( MacCtx.AppDataSize, Nvm.MacGroup1.ChannelsDatarate, macCmdsSize ) == false )
  2249. {
  2250. return LORAMAC_STATUS_LENGTH_ERROR;
  2251. }
  2252. }
  2253. return LORAMAC_STATUS_OK;
  2254. }
  2255. static LoRaMacStatus_t SerializeTxFrame( void )
  2256. {
  2257. LoRaMacSerializerStatus_t serializeStatus;
  2258. switch( MacCtx.TxMsg.Type )
  2259. {
  2260. case LORAMAC_MSG_TYPE_JOIN_REQUEST:
  2261. serializeStatus = LoRaMacSerializerJoinRequest( &MacCtx.TxMsg.Message.JoinReq );
  2262. if( LORAMAC_SERIALIZER_SUCCESS != serializeStatus )
  2263. {
  2264. return LORAMAC_STATUS_CRYPTO_ERROR;
  2265. }
  2266. MacCtx.PktBufferLen = MacCtx.TxMsg.Message.JoinReq.BufSize;
  2267. break;
  2268. case LORAMAC_MSG_TYPE_DATA:
  2269. serializeStatus = LoRaMacSerializerData( &MacCtx.TxMsg.Message.Data );
  2270. if( LORAMAC_SERIALIZER_SUCCESS != serializeStatus )
  2271. {
  2272. return LORAMAC_STATUS_CRYPTO_ERROR;
  2273. }
  2274. MacCtx.PktBufferLen = MacCtx.TxMsg.Message.Data.BufSize;
  2275. break;
  2276. case LORAMAC_MSG_TYPE_JOIN_ACCEPT:
  2277. case LORAMAC_MSG_TYPE_UNDEF:
  2278. default:
  2279. return LORAMAC_STATUS_PARAMETER_INVALID;
  2280. }
  2281. return LORAMAC_STATUS_OK;
  2282. }
  2283. static LoRaMacStatus_t ScheduleTx( bool allowDelayedTx )
  2284. {
  2285. LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
  2286. NextChanParams_t nextChan;
  2287. // Check class b collisions
  2288. status = CheckForClassBCollision( );
  2289. if( status != LORAMAC_STATUS_OK )
  2290. {
  2291. return status;
  2292. }
  2293. // Update back-off
  2294. CalculateBackOff( );
  2295. // Serialize frame
  2296. status = SerializeTxFrame( );
  2297. if( status != LORAMAC_STATUS_OK )
  2298. {
  2299. return status;
  2300. }
  2301. nextChan.AggrTimeOff = Nvm.MacGroup1.AggregatedTimeOff;
  2302. nextChan.Datarate = Nvm.MacGroup1.ChannelsDatarate;
  2303. nextChan.DutyCycleEnabled = Nvm.MacGroup2.DutyCycleOn;
  2304. nextChan.ElapsedTimeSinceStartUp = SysTimeSub( SysTimeGetMcuTime( ), Nvm.MacGroup2.InitializationTime );
  2305. nextChan.LastAggrTx = Nvm.MacGroup1.LastTxDoneTime;
  2306. nextChan.LastTxIsJoinRequest = false;
  2307. nextChan.Joined = true;
  2308. nextChan.PktLen = MacCtx.PktBufferLen;
  2309. // Setup the parameters based on the join status
  2310. if( Nvm.MacGroup2.NetworkActivation == ACTIVATION_TYPE_NONE )
  2311. {
  2312. nextChan.LastTxIsJoinRequest = true;
  2313. nextChan.Joined = false;
  2314. }
  2315. // Select channel
  2316. status = RegionNextChannel( Nvm.MacGroup2.Region, &nextChan, &MacCtx.Channel, &MacCtx.DutyCycleWaitTime, &Nvm.MacGroup1.AggregatedTimeOff );
  2317. if( status != LORAMAC_STATUS_OK )
  2318. {
  2319. if( ( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED ) &&
  2320. ( allowDelayedTx == true ) )
  2321. {
  2322. // Allow delayed transmissions. We have to allow it in case
  2323. // the MAC must retransmit a frame with the frame repetitions
  2324. if( MacCtx.DutyCycleWaitTime != 0 )
  2325. {// Send later - prepare timer
  2326. MacCtx.MacState |= LORAMAC_TX_DELAYED;
  2327. TimerSetValue( &MacCtx.TxDelayedTimer, MacCtx.DutyCycleWaitTime );
  2328. TimerStart( &MacCtx.TxDelayedTimer );
  2329. }
  2330. return LORAMAC_STATUS_OK;
  2331. }
  2332. else
  2333. {// State where the MAC cannot send a frame
  2334. return status;
  2335. }
  2336. }
  2337. // Compute window parameters, offsets, rx symbols, system errors etc.
  2338. ComputeRxWindowParameters( );
  2339. // Verify TX frame
  2340. status = VerifyTxFrame( );
  2341. if( status != LORAMAC_STATUS_OK )
  2342. {
  2343. return status;
  2344. }
  2345. // Try to send now
  2346. return SendFrameOnChannel( MacCtx.Channel );
  2347. }
  2348. static LoRaMacStatus_t SecureFrame( uint8_t txDr, uint8_t txCh )
  2349. {
  2350. LoRaMacCryptoStatus_t macCryptoStatus = LORAMAC_CRYPTO_ERROR;
  2351. uint32_t fCntUp = 0;
  2352. switch( MacCtx.TxMsg.Type )
  2353. {
  2354. case LORAMAC_MSG_TYPE_JOIN_REQUEST:
  2355. macCryptoStatus = LoRaMacCryptoPrepareJoinRequest( &MacCtx.TxMsg.Message.JoinReq );
  2356. if( LORAMAC_CRYPTO_SUCCESS != macCryptoStatus )
  2357. {
  2358. return LORAMAC_STATUS_CRYPTO_ERROR;
  2359. }
  2360. MacCtx.PktBufferLen = MacCtx.TxMsg.Message.JoinReq.BufSize;
  2361. break;
  2362. case LORAMAC_MSG_TYPE_DATA:
  2363. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoGetFCntUp( &fCntUp ) )
  2364. {
  2365. return LORAMAC_STATUS_FCNT_HANDLER_ERROR;
  2366. }
  2367. if( MacCtx.ChannelsNbTransCounter >= 1 )
  2368. {
  2369. fCntUp -= 1;
  2370. }
  2371. macCryptoStatus = LoRaMacCryptoSecureMessage( fCntUp, txDr, txCh, &MacCtx.TxMsg.Message.Data );
  2372. if( LORAMAC_CRYPTO_SUCCESS != macCryptoStatus )
  2373. {
  2374. return LORAMAC_STATUS_CRYPTO_ERROR;
  2375. }
  2376. MacCtx.PktBufferLen = MacCtx.TxMsg.Message.Data.BufSize;
  2377. break;
  2378. case LORAMAC_MSG_TYPE_JOIN_ACCEPT:
  2379. case LORAMAC_MSG_TYPE_UNDEF:
  2380. default:
  2381. return LORAMAC_STATUS_PARAMETER_INVALID;
  2382. }
  2383. return LORAMAC_STATUS_OK;
  2384. }
  2385. static void CalculateBackOff( void )
  2386. {
  2387. // Make sure that the calculation of the backoff time for the aggregated time off will only be done in
  2388. // case the value is zero. It will be set to zero in the function RegionNextChannel.
  2389. if( Nvm.MacGroup1.AggregatedTimeOff == 0 )
  2390. {
  2391. // Update aggregated time-off. This must be an assignment and no incremental
  2392. // update as we do only calculate the time-off based on the last transmission
  2393. Nvm.MacGroup1.AggregatedTimeOff = ( MacCtx.TxTimeOnAir * Nvm.MacGroup2.AggregatedDCycle - MacCtx.TxTimeOnAir );
  2394. }
  2395. }
  2396. static void RemoveMacCommands( LoRaMacRxSlot_t rxSlot, LoRaMacFrameCtrl_t fCtrl, Mcps_t request )
  2397. {
  2398. if( rxSlot == RX_SLOT_WIN_1 || rxSlot == RX_SLOT_WIN_2 )
  2399. {
  2400. // Remove all sticky MAC commands answers since we can assume
  2401. // that they have been received by the server.
  2402. if( request == MCPS_CONFIRMED )
  2403. {
  2404. if( fCtrl.Bits.Ack == 1 )
  2405. { // For confirmed uplinks only if we have received an ACK.
  2406. LoRaMacCommandsRemoveStickyAnsCmds( );
  2407. }
  2408. }
  2409. else
  2410. {
  2411. LoRaMacCommandsRemoveStickyAnsCmds( );
  2412. }
  2413. }
  2414. }
  2415. static void ResetMacParameters( void )
  2416. {
  2417. LoRaMacClassBCallback_t classBCallbacks;
  2418. LoRaMacClassBParams_t classBParams;
  2419. Nvm.MacGroup2.NetworkActivation = ACTIVATION_TYPE_NONE;
  2420. // ADR counter
  2421. Nvm.MacGroup1.AdrAckCounter = 0;
  2422. MacCtx.ChannelsNbTransCounter = 0;
  2423. MacCtx.RetransmitTimeoutRetry = false;
  2424. MacCtx.ResponseTimeoutStartTime = 0;
  2425. Nvm.MacGroup2.MaxDCycle = 0;
  2426. Nvm.MacGroup2.AggregatedDCycle = 1;
  2427. Nvm.MacGroup1.ChannelsTxPower = Nvm.MacGroup2.ChannelsTxPowerDefault;
  2428. Nvm.MacGroup1.ChannelsDatarate = Nvm.MacGroup2.ChannelsDatarateDefault;
  2429. Nvm.MacGroup2.MacParams.Rx1DrOffset = Nvm.MacGroup2.MacParamsDefaults.Rx1DrOffset;
  2430. Nvm.MacGroup2.MacParams.Rx2Channel = Nvm.MacGroup2.MacParamsDefaults.Rx2Channel;
  2431. Nvm.MacGroup2.MacParams.RxCChannel = Nvm.MacGroup2.MacParamsDefaults.RxCChannel;
  2432. Nvm.MacGroup2.MacParams.UplinkDwellTime = Nvm.MacGroup2.MacParamsDefaults.UplinkDwellTime;
  2433. Nvm.MacGroup2.MacParams.DownlinkDwellTime = Nvm.MacGroup2.MacParamsDefaults.DownlinkDwellTime;
  2434. Nvm.MacGroup2.MacParams.MaxEirp = Nvm.MacGroup2.MacParamsDefaults.MaxEirp;
  2435. Nvm.MacGroup2.MacParams.AntennaGain = Nvm.MacGroup2.MacParamsDefaults.AntennaGain;
  2436. MacCtx.NodeAckRequested = false;
  2437. Nvm.MacGroup1.SrvAckRequested = false;
  2438. Nvm.MacGroup2.ChannelsDatarateChangedLinkAdrReq = false;
  2439. Nvm.MacGroup2.DownlinkReceived = false;
  2440. // Reset to application defaults
  2441. InitDefaultsParams_t params;
  2442. params.Type = INIT_TYPE_RESET_TO_DEFAULT_CHANNELS;
  2443. params.NvmGroup1 = &Nvm.RegionGroup1;
  2444. params.NvmGroup2 = &Nvm.RegionGroup2;
  2445. params.Bands = &RegionBands;
  2446. RegionInitDefaults( Nvm.MacGroup2.Region, &params );
  2447. // Initialize channel index.
  2448. MacCtx.Channel = 0;
  2449. // Initialize Rx2 config parameters.
  2450. MacCtx.RxWindow2Config.Channel = MacCtx.Channel;
  2451. MacCtx.RxWindow2Config.Frequency = Nvm.MacGroup2.MacParams.Rx2Channel.Frequency;
  2452. MacCtx.RxWindow2Config.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
  2453. MacCtx.RxWindow2Config.RxContinuous = false;
  2454. MacCtx.RxWindow2Config.RxSlot = RX_SLOT_WIN_2;
  2455. MacCtx.RxWindow2Config.NetworkActivation = Nvm.MacGroup2.NetworkActivation;
  2456. // Initialize RxC config parameters.
  2457. MacCtx.RxWindowCConfig = MacCtx.RxWindow2Config;
  2458. MacCtx.RxWindowCConfig.RxContinuous = true;
  2459. MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C;
  2460. // Initialize class b
  2461. // Apply callback
  2462. classBCallbacks.GetTemperatureLevel = NULL;
  2463. classBCallbacks.MacProcessNotify = NULL;
  2464. if( MacCtx.MacCallbacks != NULL )
  2465. {
  2466. classBCallbacks.GetTemperatureLevel = MacCtx.MacCallbacks->GetTemperatureLevel;
  2467. classBCallbacks.MacProcessNotify = MacCtx.MacCallbacks->MacProcessNotify;
  2468. }
  2469. // Must all be static. Don't use local references.
  2470. classBParams.MlmeIndication = &MacCtx.MlmeIndication;
  2471. classBParams.McpsIndication = &MacCtx.McpsIndication;
  2472. classBParams.MlmeConfirm = &MacCtx.MlmeConfirm;
  2473. classBParams.LoRaMacFlags = &MacCtx.MacFlags;
  2474. classBParams.LoRaMacDevAddr = &Nvm.MacGroup2.DevAddr;
  2475. classBParams.LoRaMacRegion = &Nvm.MacGroup2.Region;
  2476. classBParams.LoRaMacParams = &Nvm.MacGroup2.MacParams;
  2477. classBParams.MulticastChannels = &Nvm.MacGroup2.MulticastChannelList[0];
  2478. LoRaMacClassBInit( &classBParams, &classBCallbacks, &Nvm.ClassB );
  2479. }
  2480. /*!
  2481. * \brief Initializes and opens the reception window
  2482. *
  2483. * \param [IN] rxTimer Window timer to be topped.
  2484. * \param [IN] rxConfig Window parameters to be setup
  2485. */
  2486. static void RxWindowSetup( TimerEvent_t* rxTimer, RxConfigParams_t* rxConfig )
  2487. {
  2488. TimerStop( rxTimer );
  2489. // Ensure the radio is Idle
  2490. Radio.Standby( );
  2491. if( RegionRxConfig( Nvm.MacGroup2.Region, rxConfig, ( int8_t* )&MacCtx.McpsIndication.RxDatarate ) == true )
  2492. {
  2493. Radio.Rx( Nvm.MacGroup2.MacParams.MaxRxWindow );
  2494. MacCtx.RxSlot = rxConfig->RxSlot;
  2495. }
  2496. }
  2497. static void OpenContinuousRxCWindow( void )
  2498. {
  2499. // Compute RxC windows parameters
  2500. RegionComputeRxWindowParameters( Nvm.MacGroup2.Region,
  2501. Nvm.MacGroup2.MacParams.RxCChannel.Datarate,
  2502. Nvm.MacGroup2.MacParams.MinRxSymbols,
  2503. Nvm.MacGroup2.MacParams.SystemMaxRxError,
  2504. &MacCtx.RxWindowCConfig );
  2505. MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C;
  2506. MacCtx.RxWindowCConfig.NetworkActivation = Nvm.MacGroup2.NetworkActivation;
  2507. // Setup continuous listening
  2508. MacCtx.RxWindowCConfig.RxContinuous = true;
  2509. // At this point the Radio should be idle.
  2510. // Thus, there is no need to set the radio in standby mode.
  2511. if( RegionRxConfig( Nvm.MacGroup2.Region, &MacCtx.RxWindowCConfig, ( int8_t* )&MacCtx.McpsIndication.RxDatarate ) == true )
  2512. {
  2513. Radio.Rx( 0 ); // Continuous mode
  2514. MacCtx.RxSlot = MacCtx.RxWindowCConfig.RxSlot;
  2515. }
  2516. }
  2517. LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t* macHdr, LoRaMacFrameCtrl_t* fCtrl, uint8_t fPort, void* fBuffer, uint16_t fBufferSize )
  2518. {
  2519. MacCtx.PktBufferLen = 0;
  2520. MacCtx.NodeAckRequested = false;
  2521. uint32_t fCntUp = 0;
  2522. size_t macCmdsSize = 0;
  2523. uint8_t availableSize = 0;
  2524. if( fBuffer == NULL )
  2525. {
  2526. fBufferSize = 0;
  2527. }
  2528. memcpy1( MacCtx.AppData, ( uint8_t* ) fBuffer, fBufferSize );
  2529. MacCtx.AppDataSize = fBufferSize;
  2530. MacCtx.PktBuffer[0] = macHdr->Value;
  2531. switch( macHdr->Bits.MType )
  2532. {
  2533. case FRAME_TYPE_DATA_CONFIRMED_UP:
  2534. MacCtx.NodeAckRequested = true;
  2535. // Intentional fall through
  2536. case FRAME_TYPE_DATA_UNCONFIRMED_UP:
  2537. MacCtx.TxMsg.Type = LORAMAC_MSG_TYPE_DATA;
  2538. MacCtx.TxMsg.Message.Data.Buffer = MacCtx.PktBuffer;
  2539. MacCtx.TxMsg.Message.Data.BufSize = LORAMAC_PHY_MAXPAYLOAD;
  2540. MacCtx.TxMsg.Message.Data.MHDR.Value = macHdr->Value;
  2541. MacCtx.TxMsg.Message.Data.FPort = fPort;
  2542. MacCtx.TxMsg.Message.Data.FHDR.DevAddr = Nvm.MacGroup2.DevAddr;
  2543. MacCtx.TxMsg.Message.Data.FHDR.FCtrl.Value = fCtrl->Value;
  2544. MacCtx.TxMsg.Message.Data.FRMPayloadSize = MacCtx.AppDataSize;
  2545. MacCtx.TxMsg.Message.Data.FRMPayload = MacCtx.AppData;
  2546. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoGetFCntUp( &fCntUp ) )
  2547. {
  2548. return LORAMAC_STATUS_FCNT_HANDLER_ERROR;
  2549. }
  2550. MacCtx.TxMsg.Message.Data.FHDR.FCnt = ( uint16_t )fCntUp;
  2551. // Reset confirm parameters
  2552. MacCtx.McpsConfirm.NbTrans = 0;
  2553. MacCtx.McpsConfirm.AckReceived = false;
  2554. MacCtx.McpsConfirm.UpLinkCounter = fCntUp;
  2555. // Handle the MAC commands if there are any available
  2556. if( LoRaMacCommandsGetSizeSerializedCmds( &macCmdsSize ) != LORAMAC_COMMANDS_SUCCESS )
  2557. {
  2558. return LORAMAC_STATUS_MAC_COMMAD_ERROR;
  2559. }
  2560. if( macCmdsSize > 0 )
  2561. {
  2562. availableSize = GetMaxAppPayloadWithoutFOptsLength( Nvm.MacGroup1.ChannelsDatarate );
  2563. // There is application payload available and the MAC commands fit into FOpts field.
  2564. if( ( MacCtx.AppDataSize > 0 ) && ( macCmdsSize <= LORA_MAC_COMMAND_MAX_FOPTS_LENGTH ) )
  2565. {
  2566. if( LoRaMacCommandsSerializeCmds( LORA_MAC_COMMAND_MAX_FOPTS_LENGTH, &macCmdsSize, MacCtx.TxMsg.Message.Data.FHDR.FOpts ) != LORAMAC_COMMANDS_SUCCESS )
  2567. {
  2568. return LORAMAC_STATUS_MAC_COMMAD_ERROR;
  2569. }
  2570. fCtrl->Bits.FOptsLen = macCmdsSize;
  2571. // Update FCtrl field with new value of FOptionsLength
  2572. MacCtx.TxMsg.Message.Data.FHDR.FCtrl.Value = fCtrl->Value;
  2573. }
  2574. // There is application payload available but the MAC commands does NOT fit into FOpts field.
  2575. else if( ( MacCtx.AppDataSize > 0 ) && ( macCmdsSize > LORA_MAC_COMMAND_MAX_FOPTS_LENGTH ) )
  2576. {
  2577. if( LoRaMacCommandsSerializeCmds( availableSize, &macCmdsSize, MacCtx.MacCommandsBuffer ) != LORAMAC_COMMANDS_SUCCESS )
  2578. {
  2579. return LORAMAC_STATUS_MAC_COMMAD_ERROR;
  2580. }
  2581. return LORAMAC_STATUS_SKIPPED_APP_DATA;
  2582. }
  2583. // No application payload available therefore add all mac commands to the FRMPayload.
  2584. else
  2585. {
  2586. if( LoRaMacCommandsSerializeCmds( availableSize, &macCmdsSize, MacCtx.MacCommandsBuffer ) != LORAMAC_COMMANDS_SUCCESS )
  2587. {
  2588. return LORAMAC_STATUS_MAC_COMMAD_ERROR;
  2589. }
  2590. // Force FPort to be zero
  2591. MacCtx.TxMsg.Message.Data.FPort = 0;
  2592. MacCtx.TxMsg.Message.Data.FRMPayload = MacCtx.MacCommandsBuffer;
  2593. MacCtx.TxMsg.Message.Data.FRMPayloadSize = macCmdsSize;
  2594. }
  2595. }
  2596. break;
  2597. case FRAME_TYPE_PROPRIETARY:
  2598. if( ( fBuffer != NULL ) && ( MacCtx.AppDataSize > 0 ) )
  2599. {
  2600. memcpy1( MacCtx.PktBuffer + LORAMAC_MHDR_FIELD_SIZE, ( uint8_t* ) fBuffer, MacCtx.AppDataSize );
  2601. MacCtx.PktBufferLen = LORAMAC_MHDR_FIELD_SIZE + MacCtx.AppDataSize;
  2602. }
  2603. break;
  2604. default:
  2605. return LORAMAC_STATUS_SERVICE_UNKNOWN;
  2606. }
  2607. return LORAMAC_STATUS_OK;
  2608. }
  2609. LoRaMacStatus_t SendFrameOnChannel( uint8_t channel )
  2610. {
  2611. LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
  2612. TxConfigParams_t txConfig;
  2613. int8_t txPower = 0;
  2614. txConfig.Channel = channel;
  2615. txConfig.Datarate = Nvm.MacGroup1.ChannelsDatarate;
  2616. txConfig.TxPower = Nvm.MacGroup1.ChannelsTxPower;
  2617. txConfig.MaxEirp = Nvm.MacGroup2.MacParams.MaxEirp;
  2618. txConfig.AntennaGain = Nvm.MacGroup2.MacParams.AntennaGain;
  2619. txConfig.PktLen = MacCtx.PktBufferLen;
  2620. RegionTxConfig( Nvm.MacGroup2.Region, &txConfig, &txPower, &MacCtx.TxTimeOnAir );
  2621. MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  2622. MacCtx.McpsConfirm.Datarate = Nvm.MacGroup1.ChannelsDatarate;
  2623. MacCtx.McpsConfirm.TxPower = txPower;
  2624. MacCtx.McpsConfirm.Channel = channel;
  2625. // Store the time on air
  2626. MacCtx.McpsConfirm.TxTimeOnAir = MacCtx.TxTimeOnAir;
  2627. MacCtx.MlmeConfirm.TxTimeOnAir = MacCtx.TxTimeOnAir;
  2628. if( LoRaMacClassBIsBeaconModeActive( ) == true )
  2629. {
  2630. // Currently, the Time-On-Air can only be computed when the radio is configured with
  2631. // the TX configuration
  2632. TimerTime_t collisionTime = LoRaMacClassBIsUplinkCollision( MacCtx.TxTimeOnAir );
  2633. if( collisionTime > 0 )
  2634. {
  2635. return LORAMAC_STATUS_BUSY_UPLINK_COLLISION;
  2636. }
  2637. }
  2638. if( Nvm.MacGroup2.DeviceClass == CLASS_B )
  2639. {
  2640. // Stop slots for class b
  2641. LoRaMacClassBStopRxSlots( );
  2642. }
  2643. LoRaMacClassBHaltBeaconing( );
  2644. // Secure frame
  2645. status = SecureFrame( Nvm.MacGroup1.ChannelsDatarate, MacCtx.Channel );
  2646. if( status != LORAMAC_STATUS_OK )
  2647. {
  2648. return status;
  2649. }
  2650. MacCtx.MacState |= LORAMAC_TX_RUNNING;
  2651. MacCtx.ChannelsNbTransCounter++;
  2652. MacCtx.McpsConfirm.NbTrans = MacCtx.ChannelsNbTransCounter;
  2653. MacCtx.ResponseTimeoutStartTime = 0;
  2654. // Send now
  2655. Radio.Send( MacCtx.PktBuffer, MacCtx.PktBufferLen );
  2656. return LORAMAC_STATUS_OK;
  2657. }
  2658. LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout, uint32_t frequency, uint8_t power )
  2659. {
  2660. Radio.SetTxContinuousWave( frequency, power, timeout );
  2661. MacCtx.MacState |= LORAMAC_TX_RUNNING;
  2662. return LORAMAC_STATUS_OK;
  2663. }
  2664. LoRaMacNvmData_t* GetNvmData( void )
  2665. {
  2666. return &Nvm;
  2667. }
  2668. LoRaMacStatus_t RestoreNvmData( LoRaMacNvmData_t* nvm )
  2669. {
  2670. uint32_t crc = 0;
  2671. // Status and parameter validation
  2672. if( nvm == NULL )
  2673. {
  2674. return LORAMAC_STATUS_PARAMETER_INVALID;
  2675. }
  2676. if( MacCtx.MacState != LORAMAC_STOPPED )
  2677. {
  2678. return LORAMAC_STATUS_BUSY;
  2679. }
  2680. // Crypto
  2681. crc = Crc32( ( uint8_t* ) &nvm->Crypto, sizeof( nvm->Crypto ) -
  2682. sizeof( nvm->Crypto.Crc32 ) );
  2683. if( crc == nvm->Crypto.Crc32 )
  2684. {
  2685. memcpy1( ( uint8_t* ) &Nvm.Crypto, ( uint8_t* ) &nvm->Crypto,
  2686. sizeof( Nvm.Crypto ) );
  2687. }
  2688. // MacGroup1
  2689. crc = Crc32( ( uint8_t* ) &nvm->MacGroup1, sizeof( nvm->MacGroup1 ) -
  2690. sizeof( nvm->MacGroup1.Crc32 ) );
  2691. if( crc == nvm->MacGroup1.Crc32 )
  2692. {
  2693. memcpy1( ( uint8_t* ) &Nvm.MacGroup1, ( uint8_t* ) &nvm->MacGroup1,
  2694. sizeof( Nvm.MacGroup1 ) );
  2695. }
  2696. // MacGroup2
  2697. crc = Crc32( ( uint8_t* ) &nvm->MacGroup2, sizeof( nvm->MacGroup2 ) -
  2698. sizeof( nvm->MacGroup2.Crc32 ) );
  2699. if( crc == nvm->MacGroup2.Crc32 )
  2700. {
  2701. memcpy1( ( uint8_t* ) &Nvm.MacGroup2, ( uint8_t* ) &nvm->MacGroup2,
  2702. sizeof( Nvm.MacGroup2 ) );
  2703. // Initialize RxC config parameters.
  2704. MacCtx.RxWindowCConfig.Channel = MacCtx.Channel;
  2705. MacCtx.RxWindowCConfig.Frequency = Nvm.MacGroup2.MacParams.RxCChannel.Frequency;
  2706. MacCtx.RxWindowCConfig.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
  2707. MacCtx.RxWindowCConfig.RxContinuous = true;
  2708. MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C;
  2709. }
  2710. // Secure Element
  2711. crc = Crc32( ( uint8_t* ) &nvm->SecureElement, sizeof( nvm->SecureElement ) -
  2712. sizeof( nvm->SecureElement.Crc32 ) );
  2713. if( crc == nvm->SecureElement.Crc32 )
  2714. {
  2715. memcpy1( ( uint8_t* ) &Nvm.SecureElement,( uint8_t* ) &nvm->SecureElement,
  2716. sizeof( Nvm.SecureElement ) );
  2717. }
  2718. // Region
  2719. crc = Crc32( ( uint8_t* ) &nvm->RegionGroup1, sizeof( nvm->RegionGroup1 ) -
  2720. sizeof( nvm->RegionGroup1.Crc32 ) );
  2721. if( crc == nvm->RegionGroup1.Crc32 )
  2722. {
  2723. memcpy1( ( uint8_t* ) &Nvm.RegionGroup1,( uint8_t* ) &nvm->RegionGroup1,
  2724. sizeof( Nvm.RegionGroup1 ) );
  2725. }
  2726. crc = Crc32( ( uint8_t* ) &nvm->ClassB, sizeof( nvm->ClassB ) -
  2727. sizeof( nvm->ClassB.Crc32 ) );
  2728. if( crc == nvm->ClassB.Crc32 )
  2729. {
  2730. memcpy1( ( uint8_t* ) &Nvm.ClassB,( uint8_t* ) &nvm->ClassB,
  2731. sizeof( Nvm.ClassB ) );
  2732. }
  2733. return LORAMAC_STATUS_OK;
  2734. }
  2735. LoRaMacStatus_t DetermineFrameType( LoRaMacMessageData_t* macMsg, FType_t* fType )
  2736. {
  2737. if( ( macMsg == NULL ) || ( fType == NULL ) )
  2738. {
  2739. return LORAMAC_STATUS_PARAMETER_INVALID;
  2740. }
  2741. /* The LoRaWAN specification allows several possible configurations how data up/down frames are built up.
  2742. * In sake of clearness the following naming is applied. Please keep in mind that this is
  2743. * implementation specific since there is no definition in the LoRaWAN specification included.
  2744. *
  2745. * X -> Field is available
  2746. * - -> Field is not available
  2747. *
  2748. * +-------+ +----------+------+-------+--------------+
  2749. * | FType | | FOptsLen | Fopt | FPort | FRMPayload |
  2750. * +-------+ +----------+------+-------+--------------+
  2751. * | A | | > 0 | X | > 0 | X |
  2752. * +-------+ +----------+------+-------+--------------+
  2753. * | B | | >= 0 | X/- | - | - |
  2754. * +-------+ +----------+------+-------+--------------+
  2755. * | C | | = 0 | - | = 0 | MAC commands |
  2756. * +-------+ +----------+------+-------+--------------+
  2757. * | D | | = 0 | - | > 0 | X |
  2758. * +-------+ +----------+------+-------+--------------+
  2759. */
  2760. if( ( macMsg->FHDR.FCtrl.Bits.FOptsLen > 0 ) && ( macMsg->FPort > 0 ) )
  2761. {
  2762. *fType = FRAME_TYPE_A;
  2763. }
  2764. else if( macMsg->FRMPayloadSize == 0 )
  2765. {
  2766. *fType = FRAME_TYPE_B;
  2767. }
  2768. else if( ( macMsg->FHDR.FCtrl.Bits.FOptsLen == 0 ) && ( macMsg->FPort == 0 ) )
  2769. {
  2770. *fType = FRAME_TYPE_C;
  2771. }
  2772. else if( ( macMsg->FHDR.FCtrl.Bits.FOptsLen == 0 ) && ( macMsg->FPort > 0 ) )
  2773. {
  2774. *fType = FRAME_TYPE_D;
  2775. }
  2776. else
  2777. {
  2778. // Should never happen.
  2779. return LORAMAC_STATUS_ERROR;
  2780. }
  2781. return LORAMAC_STATUS_OK;
  2782. }
  2783. static bool CheckRetrans( uint8_t counter, uint8_t limit )
  2784. {
  2785. if( counter >= limit )
  2786. {
  2787. return true;
  2788. }
  2789. return false;
  2790. }
  2791. static bool CheckRetransUnconfirmedUplink( void )
  2792. {
  2793. // Verify, if the max number of retransmissions have been reached
  2794. if( CheckRetrans( MacCtx.ChannelsNbTransCounter,
  2795. Nvm.MacGroup2.MacParams.ChannelsNbTrans ) == true )
  2796. {
  2797. return true;
  2798. }
  2799. if( MacCtx.MacFlags.Bits.McpsInd == 1 )
  2800. {
  2801. // Stop the retransmissions, if a valid downlink is received
  2802. // a class A RX window. This holds also for class B and C.
  2803. if( ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_1 ) ||
  2804. ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_2 ) )
  2805. {
  2806. return true;
  2807. }
  2808. }
  2809. return false;
  2810. }
  2811. static bool CheckRetransConfirmedUplink( void )
  2812. {
  2813. // Verify, if the max number of retransmissions have been reached
  2814. if( CheckRetrans( MacCtx.ChannelsNbTransCounter,
  2815. Nvm.MacGroup2.MacParams.ChannelsNbTrans ) == true )
  2816. {
  2817. return true;
  2818. }
  2819. if( MacCtx.MacFlags.Bits.McpsInd == 1 )
  2820. {
  2821. if( MacCtx.McpsConfirm.AckReceived == true )
  2822. {
  2823. return true;
  2824. }
  2825. }
  2826. return false;
  2827. }
  2828. static uint32_t IncreaseAdrAckCounter( uint32_t counter )
  2829. {
  2830. if( counter < ADR_ACK_COUNTER_MAX )
  2831. {
  2832. counter++;
  2833. }
  2834. return counter;
  2835. }
  2836. static bool StopRetransmission( void )
  2837. {
  2838. if( ( MacCtx.MacFlags.Bits.McpsInd == 0 ) ||
  2839. ( ( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_1 ) &&
  2840. ( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_2 ) ) )
  2841. { // Maximum repetitions without downlink. Increase ADR Ack counter.
  2842. // Only process the case when the MAC did not receive a downlink.
  2843. if( Nvm.MacGroup2.AdrCtrlOn == true )
  2844. {
  2845. Nvm.MacGroup1.AdrAckCounter = IncreaseAdrAckCounter( Nvm.MacGroup1.AdrAckCounter );
  2846. }
  2847. }
  2848. MacCtx.ChannelsNbTransCounter = 0;
  2849. MacCtx.NodeAckRequested = false;
  2850. MacCtx.RetransmitTimeoutRetry = false;
  2851. MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
  2852. return true;
  2853. }
  2854. static void CallNvmDataChangeCallback( uint16_t notifyFlags )
  2855. {
  2856. if( ( MacCtx.MacCallbacks != NULL ) &&
  2857. ( MacCtx.MacCallbacks->NvmDataChange != NULL ) )
  2858. {
  2859. MacCtx.MacCallbacks->NvmDataChange ( notifyFlags );
  2860. }
  2861. }
  2862. static uint8_t IsRequestPending( void )
  2863. {
  2864. if( ( MacCtx.MacFlags.Bits.MlmeReq == 1 ) ||
  2865. ( MacCtx.MacFlags.Bits.McpsReq == 1 ) )
  2866. {
  2867. return 1;
  2868. }
  2869. return 0;
  2870. }
  2871. LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t* primitives, LoRaMacCallback_t* callbacks, LoRaMacRegion_t region )
  2872. {
  2873. GetPhyParams_t getPhy;
  2874. PhyParam_t phyParam;
  2875. if( ( primitives == NULL ) ||
  2876. ( callbacks == NULL ) )
  2877. {
  2878. return LORAMAC_STATUS_PARAMETER_INVALID;
  2879. }
  2880. if( ( primitives->MacMcpsConfirm == NULL ) ||
  2881. ( primitives->MacMcpsIndication == NULL ) ||
  2882. ( primitives->MacMlmeConfirm == NULL ) ||
  2883. ( primitives->MacMlmeIndication == NULL ) )
  2884. {
  2885. return LORAMAC_STATUS_PARAMETER_INVALID;
  2886. }
  2887. // Verify if the region is supported
  2888. if( RegionIsActive( region ) == false )
  2889. {
  2890. return LORAMAC_STATUS_REGION_NOT_SUPPORTED;
  2891. }
  2892. // Confirm queue reset
  2893. LoRaMacConfirmQueueInit( primitives );
  2894. // Initialize the module context with zeros
  2895. memset1( ( uint8_t* ) &Nvm, 0x00, sizeof( LoRaMacNvmData_t ) );
  2896. memset1( ( uint8_t* ) &MacCtx, 0x00, sizeof( LoRaMacCtx_t ) );
  2897. // Set non zero variables to its default value
  2898. Nvm.MacGroup2.Region = region;
  2899. Nvm.MacGroup2.DeviceClass = CLASS_A;
  2900. // Setup version
  2901. Nvm.MacGroup2.Version.Value = LORAMAC_VERSION;
  2902. // Reset to defaults
  2903. getPhy.Attribute = PHY_DUTY_CYCLE;
  2904. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2905. Nvm.MacGroup2.DutyCycleOn = ( bool ) phyParam.Value;
  2906. getPhy.Attribute = PHY_DEF_TX_POWER;
  2907. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2908. Nvm.MacGroup2.ChannelsTxPowerDefault = phyParam.Value;
  2909. getPhy.Attribute = PHY_DEF_TX_DR;
  2910. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2911. Nvm.MacGroup2.ChannelsDatarateDefault = phyParam.Value;
  2912. getPhy.Attribute = PHY_MAX_RX_WINDOW;
  2913. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2914. Nvm.MacGroup2.MacParamsDefaults.MaxRxWindow = phyParam.Value;
  2915. getPhy.Attribute = PHY_RECEIVE_DELAY1;
  2916. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2917. Nvm.MacGroup2.MacParamsDefaults.ReceiveDelay1 = phyParam.Value;
  2918. getPhy.Attribute = PHY_RECEIVE_DELAY2;
  2919. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2920. Nvm.MacGroup2.MacParamsDefaults.ReceiveDelay2 = phyParam.Value;
  2921. getPhy.Attribute = PHY_JOIN_ACCEPT_DELAY1;
  2922. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2923. Nvm.MacGroup2.MacParamsDefaults.JoinAcceptDelay1 = phyParam.Value;
  2924. getPhy.Attribute = PHY_JOIN_ACCEPT_DELAY2;
  2925. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2926. Nvm.MacGroup2.MacParamsDefaults.JoinAcceptDelay2 = phyParam.Value;
  2927. getPhy.Attribute = PHY_DEF_DR1_OFFSET;
  2928. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2929. Nvm.MacGroup2.MacParamsDefaults.Rx1DrOffset = phyParam.Value;
  2930. getPhy.Attribute = PHY_DEF_RX2_FREQUENCY;
  2931. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2932. Nvm.MacGroup2.MacParamsDefaults.Rx2Channel.Frequency = phyParam.Value;
  2933. Nvm.MacGroup2.MacParamsDefaults.RxCChannel.Frequency = phyParam.Value;
  2934. getPhy.Attribute = PHY_DEF_RX2_DR;
  2935. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2936. Nvm.MacGroup2.MacParamsDefaults.Rx2Channel.Datarate = phyParam.Value;
  2937. Nvm.MacGroup2.MacParamsDefaults.RxCChannel.Datarate = phyParam.Value;
  2938. getPhy.Attribute = PHY_DEF_UPLINK_DWELL_TIME;
  2939. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2940. Nvm.MacGroup2.MacParamsDefaults.UplinkDwellTime = phyParam.Value;
  2941. getPhy.Attribute = PHY_DEF_DOWNLINK_DWELL_TIME;
  2942. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2943. Nvm.MacGroup2.MacParamsDefaults.DownlinkDwellTime = phyParam.Value;
  2944. getPhy.Attribute = PHY_DEF_MAX_EIRP;
  2945. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2946. Nvm.MacGroup2.MacParamsDefaults.MaxEirp = phyParam.fValue;
  2947. getPhy.Attribute = PHY_DEF_ANTENNA_GAIN;
  2948. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2949. Nvm.MacGroup2.MacParamsDefaults.AntennaGain = phyParam.fValue;
  2950. getPhy.Attribute = PHY_DEF_ADR_ACK_LIMIT;
  2951. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2952. MacCtx.AdrAckLimit = phyParam.Value;
  2953. getPhy.Attribute = PHY_DEF_ADR_ACK_DELAY;
  2954. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  2955. MacCtx.AdrAckDelay = phyParam.Value;
  2956. // Init parameters which are not set in function ResetMacParameters
  2957. Nvm.MacGroup2.MacParamsDefaults.ChannelsNbTrans = 1;
  2958. Nvm.MacGroup2.MacParamsDefaults.SystemMaxRxError = 10;
  2959. Nvm.MacGroup2.MacParamsDefaults.MinRxSymbols = 6;
  2960. Nvm.MacGroup2.MacParams.SystemMaxRxError = Nvm.MacGroup2.MacParamsDefaults.SystemMaxRxError;
  2961. Nvm.MacGroup2.MacParams.MinRxSymbols = Nvm.MacGroup2.MacParamsDefaults.MinRxSymbols;
  2962. Nvm.MacGroup2.MacParams.MaxRxWindow = Nvm.MacGroup2.MacParamsDefaults.MaxRxWindow;
  2963. Nvm.MacGroup2.MacParams.ReceiveDelay1 = Nvm.MacGroup2.MacParamsDefaults.ReceiveDelay1;
  2964. Nvm.MacGroup2.MacParams.ReceiveDelay2 = Nvm.MacGroup2.MacParamsDefaults.ReceiveDelay2;
  2965. Nvm.MacGroup2.MacParams.JoinAcceptDelay1 = Nvm.MacGroup2.MacParamsDefaults.JoinAcceptDelay1;
  2966. Nvm.MacGroup2.MacParams.JoinAcceptDelay2 = Nvm.MacGroup2.MacParamsDefaults.JoinAcceptDelay2;
  2967. Nvm.MacGroup2.MacParams.ChannelsNbTrans = Nvm.MacGroup2.MacParamsDefaults.ChannelsNbTrans;
  2968. // FPort 224 is enabled by default.
  2969. Nvm.MacGroup2.IsCertPortOn = true;
  2970. InitDefaultsParams_t params;
  2971. params.Type = INIT_TYPE_DEFAULTS;
  2972. params.NvmGroup1 = &Nvm.RegionGroup1;
  2973. params.NvmGroup2 = &Nvm.RegionGroup2;
  2974. params.Bands = &RegionBands;
  2975. RegionInitDefaults( Nvm.MacGroup2.Region, &params );
  2976. ResetMacParameters( );
  2977. Nvm.MacGroup2.PublicNetwork = true;
  2978. MacCtx.MacPrimitives = primitives;
  2979. MacCtx.MacCallbacks = callbacks;
  2980. MacCtx.MacFlags.Value = 0;
  2981. MacCtx.MacState = LORAMAC_STOPPED;
  2982. // Reset duty cycle times
  2983. Nvm.MacGroup1.LastTxDoneTime = 0;
  2984. Nvm.MacGroup1.AggregatedTimeOff = 0;
  2985. // Initialize timers
  2986. TimerInit( &MacCtx.TxDelayedTimer, OnTxDelayedTimerEvent );
  2987. TimerInit( &MacCtx.RxWindowTimer1, OnRxWindow1TimerEvent );
  2988. TimerInit( &MacCtx.RxWindowTimer2, OnRxWindow2TimerEvent );
  2989. TimerInit( &MacCtx.RetransmitTimeoutTimer, OnRetransmitTimeoutTimerEvent );
  2990. // Store the current initialization time
  2991. Nvm.MacGroup2.InitializationTime = SysTimeGetMcuTime( );
  2992. // Initialize Radio driver
  2993. MacCtx.RadioEvents.TxDone = OnRadioTxDone;
  2994. MacCtx.RadioEvents.RxDone = OnRadioRxDone;
  2995. MacCtx.RadioEvents.RxError = OnRadioRxError;
  2996. MacCtx.RadioEvents.TxTimeout = OnRadioTxTimeout;
  2997. MacCtx.RadioEvents.RxTimeout = OnRadioRxTimeout;
  2998. Radio.Init( &MacCtx.RadioEvents );
  2999. // Initialize the Secure Element driver
  3000. if( SecureElementInit( &Nvm.SecureElement ) != SECURE_ELEMENT_SUCCESS )
  3001. {
  3002. return LORAMAC_STATUS_CRYPTO_ERROR;
  3003. }
  3004. // Initialize Crypto module
  3005. if( LoRaMacCryptoInit( &Nvm.Crypto ) != LORAMAC_CRYPTO_SUCCESS )
  3006. {
  3007. return LORAMAC_STATUS_CRYPTO_ERROR;
  3008. }
  3009. // Initialize MAC commands module
  3010. if( LoRaMacCommandsInit( ) != LORAMAC_COMMANDS_SUCCESS )
  3011. {
  3012. return LORAMAC_STATUS_MAC_COMMAD_ERROR;
  3013. }
  3014. // Set multicast downlink counter reference
  3015. if( LoRaMacCryptoSetMulticastReference( Nvm.MacGroup2.MulticastChannelList ) != LORAMAC_CRYPTO_SUCCESS )
  3016. {
  3017. return LORAMAC_STATUS_CRYPTO_ERROR;
  3018. }
  3019. // Random seed initialization
  3020. srand1( Radio.Random( ) );
  3021. Radio.SetPublicNetwork( Nvm.MacGroup2.PublicNetwork );
  3022. Radio.Sleep( );
  3023. LoRaMacEnableRequests( LORAMAC_REQUEST_HANDLING_ON );
  3024. return LORAMAC_STATUS_OK;
  3025. }
  3026. LoRaMacStatus_t LoRaMacStart( void )
  3027. {
  3028. MacCtx.MacState = LORAMAC_IDLE;
  3029. return LORAMAC_STATUS_OK;
  3030. }
  3031. LoRaMacStatus_t LoRaMacStop( void )
  3032. {
  3033. if( LoRaMacIsBusy( ) == false )
  3034. {
  3035. MacCtx.MacState = LORAMAC_STOPPED;
  3036. return LORAMAC_STATUS_OK;
  3037. }
  3038. else if( MacCtx.MacState == LORAMAC_STOPPED )
  3039. {
  3040. return LORAMAC_STATUS_OK;
  3041. }
  3042. return LORAMAC_STATUS_BUSY;
  3043. }
  3044. LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo )
  3045. {
  3046. CalcNextAdrParams_t adrNext;
  3047. uint32_t adrAckCounter = Nvm.MacGroup1.AdrAckCounter;
  3048. int8_t datarate = Nvm.MacGroup2.ChannelsDatarateDefault;
  3049. int8_t txPower = Nvm.MacGroup2.ChannelsTxPowerDefault;
  3050. uint8_t nbTrans = MacCtx.ChannelsNbTransCounter;
  3051. size_t macCmdsSize = 0;
  3052. if( txInfo == NULL )
  3053. {
  3054. return LORAMAC_STATUS_PARAMETER_INVALID;
  3055. }
  3056. // Setup ADR request
  3057. adrNext.UpdateChanMask = false;
  3058. adrNext.AdrEnabled = Nvm.MacGroup2.AdrCtrlOn;
  3059. adrNext.AdrAckCounter = Nvm.MacGroup1.AdrAckCounter;
  3060. adrNext.AdrAckLimit = MacCtx.AdrAckLimit;
  3061. adrNext.AdrAckDelay = MacCtx.AdrAckDelay;
  3062. adrNext.Datarate = Nvm.MacGroup1.ChannelsDatarate;
  3063. adrNext.TxPower = Nvm.MacGroup1.ChannelsTxPower;
  3064. adrNext.NbTrans = MacCtx.ChannelsNbTransCounter;
  3065. adrNext.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
  3066. adrNext.Region = Nvm.MacGroup2.Region;
  3067. // We call the function for information purposes only. We don't want to
  3068. // apply the datarate, the tx power and the ADR ack counter.
  3069. LoRaMacAdrCalcNext( &adrNext, &datarate, &txPower, &nbTrans, &adrAckCounter );
  3070. txInfo->CurrentPossiblePayloadSize = GetMaxAppPayloadWithoutFOptsLength( datarate );
  3071. if( LoRaMacCommandsGetSizeSerializedCmds( &macCmdsSize ) != LORAMAC_COMMANDS_SUCCESS )
  3072. {
  3073. return LORAMAC_STATUS_MAC_COMMAD_ERROR;
  3074. }
  3075. // Verify if the MAC commands fit into the FOpts and into the maximum payload.
  3076. if( ( LORA_MAC_COMMAND_MAX_FOPTS_LENGTH >= macCmdsSize ) && ( txInfo->CurrentPossiblePayloadSize >= macCmdsSize ) )
  3077. {
  3078. txInfo->MaxPossibleApplicationDataSize = txInfo->CurrentPossiblePayloadSize - macCmdsSize;
  3079. // Verify if the application data together with MAC command fit into the maximum payload.
  3080. if( txInfo->CurrentPossiblePayloadSize >= ( macCmdsSize + size ) )
  3081. {
  3082. return LORAMAC_STATUS_OK;
  3083. }
  3084. else
  3085. {
  3086. return LORAMAC_STATUS_LENGTH_ERROR;
  3087. }
  3088. }
  3089. else
  3090. {
  3091. txInfo->MaxPossibleApplicationDataSize = 0;
  3092. return LORAMAC_STATUS_LENGTH_ERROR;
  3093. }
  3094. }
  3095. LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t* mibGet )
  3096. {
  3097. LoRaMacStatus_t status = LORAMAC_STATUS_OK;
  3098. GetPhyParams_t getPhy;
  3099. PhyParam_t phyParam;
  3100. if( mibGet == NULL )
  3101. {
  3102. return LORAMAC_STATUS_PARAMETER_INVALID;
  3103. }
  3104. switch( mibGet->Type )
  3105. {
  3106. case MIB_DEVICE_CLASS:
  3107. {
  3108. mibGet->Param.Class = Nvm.MacGroup2.DeviceClass;
  3109. break;
  3110. }
  3111. case MIB_NETWORK_ACTIVATION:
  3112. {
  3113. mibGet->Param.NetworkActivation = Nvm.MacGroup2.NetworkActivation;
  3114. break;
  3115. }
  3116. case MIB_DEV_EUI:
  3117. {
  3118. mibGet->Param.DevEui = SecureElementGetDevEui( );
  3119. break;
  3120. }
  3121. case MIB_JOIN_EUI:
  3122. {
  3123. mibGet->Param.JoinEui = SecureElementGetJoinEui( );
  3124. break;
  3125. }
  3126. case MIB_SE_PIN:
  3127. {
  3128. mibGet->Param.SePin = SecureElementGetPin( );
  3129. break;
  3130. }
  3131. case MIB_ADR:
  3132. {
  3133. mibGet->Param.AdrEnable = Nvm.MacGroup2.AdrCtrlOn;
  3134. break;
  3135. }
  3136. case MIB_NET_ID:
  3137. {
  3138. mibGet->Param.NetID = Nvm.MacGroup2.NetID;
  3139. break;
  3140. }
  3141. case MIB_DEV_ADDR:
  3142. {
  3143. mibGet->Param.DevAddr = Nvm.MacGroup2.DevAddr;
  3144. break;
  3145. }
  3146. case MIB_PUBLIC_NETWORK:
  3147. {
  3148. mibGet->Param.EnablePublicNetwork = Nvm.MacGroup2.PublicNetwork;
  3149. break;
  3150. }
  3151. case MIB_CHANNELS:
  3152. {
  3153. getPhy.Attribute = PHY_CHANNELS;
  3154. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  3155. mibGet->Param.ChannelList = phyParam.Channels;
  3156. break;
  3157. }
  3158. case MIB_RX2_CHANNEL:
  3159. {
  3160. mibGet->Param.Rx2Channel = Nvm.MacGroup2.MacParams.Rx2Channel;
  3161. break;
  3162. }
  3163. case MIB_RX2_DEFAULT_CHANNEL:
  3164. {
  3165. mibGet->Param.Rx2Channel = Nvm.MacGroup2.MacParamsDefaults.Rx2Channel;
  3166. break;
  3167. }
  3168. case MIB_RXC_CHANNEL:
  3169. {
  3170. mibGet->Param.RxCChannel = Nvm.MacGroup2.MacParams.RxCChannel;
  3171. break;
  3172. }
  3173. case MIB_RXC_DEFAULT_CHANNEL:
  3174. {
  3175. mibGet->Param.RxCChannel = Nvm.MacGroup2.MacParamsDefaults.RxCChannel;
  3176. break;
  3177. }
  3178. case MIB_CHANNELS_DEFAULT_MASK:
  3179. {
  3180. getPhy.Attribute = PHY_CHANNELS_DEFAULT_MASK;
  3181. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  3182. mibGet->Param.ChannelsDefaultMask = phyParam.ChannelsMask;
  3183. break;
  3184. }
  3185. case MIB_CHANNELS_MASK:
  3186. {
  3187. getPhy.Attribute = PHY_CHANNELS_MASK;
  3188. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  3189. mibGet->Param.ChannelsMask = phyParam.ChannelsMask;
  3190. break;
  3191. }
  3192. case MIB_CHANNELS_NB_TRANS:
  3193. {
  3194. mibGet->Param.ChannelsNbTrans = Nvm.MacGroup2.MacParams.ChannelsNbTrans;
  3195. break;
  3196. }
  3197. case MIB_MAX_RX_WINDOW_DURATION:
  3198. {
  3199. mibGet->Param.MaxRxWindow = Nvm.MacGroup2.MacParams.MaxRxWindow;
  3200. break;
  3201. }
  3202. case MIB_RECEIVE_DELAY_1:
  3203. {
  3204. mibGet->Param.ReceiveDelay1 = Nvm.MacGroup2.MacParams.ReceiveDelay1;
  3205. break;
  3206. }
  3207. case MIB_RECEIVE_DELAY_2:
  3208. {
  3209. mibGet->Param.ReceiveDelay2 = Nvm.MacGroup2.MacParams.ReceiveDelay2;
  3210. break;
  3211. }
  3212. case MIB_JOIN_ACCEPT_DELAY_1:
  3213. {
  3214. mibGet->Param.JoinAcceptDelay1 = Nvm.MacGroup2.MacParams.JoinAcceptDelay1;
  3215. break;
  3216. }
  3217. case MIB_JOIN_ACCEPT_DELAY_2:
  3218. {
  3219. mibGet->Param.JoinAcceptDelay2 = Nvm.MacGroup2.MacParams.JoinAcceptDelay2;
  3220. break;
  3221. }
  3222. case MIB_CHANNELS_MIN_TX_DATARATE:
  3223. {
  3224. getPhy.Attribute = PHY_MIN_TX_DR;
  3225. getPhy.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
  3226. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  3227. mibGet->Param.ChannelsMinTxDatarate = phyParam.Value;
  3228. break;
  3229. }
  3230. case MIB_CHANNELS_DEFAULT_DATARATE:
  3231. {
  3232. mibGet->Param.ChannelsDefaultDatarate = Nvm.MacGroup2.ChannelsDatarateDefault;
  3233. break;
  3234. }
  3235. case MIB_CHANNELS_DATARATE:
  3236. {
  3237. mibGet->Param.ChannelsDatarate = Nvm.MacGroup1.ChannelsDatarate;
  3238. break;
  3239. }
  3240. case MIB_CHANNELS_DEFAULT_TX_POWER:
  3241. {
  3242. mibGet->Param.ChannelsDefaultTxPower = Nvm.MacGroup2.ChannelsTxPowerDefault;
  3243. break;
  3244. }
  3245. case MIB_CHANNELS_TX_POWER:
  3246. {
  3247. mibGet->Param.ChannelsTxPower = Nvm.MacGroup1.ChannelsTxPower;
  3248. break;
  3249. }
  3250. case MIB_SYSTEM_MAX_RX_ERROR:
  3251. {
  3252. mibGet->Param.SystemMaxRxError = Nvm.MacGroup2.MacParams.SystemMaxRxError;
  3253. break;
  3254. }
  3255. case MIB_MIN_RX_SYMBOLS:
  3256. {
  3257. mibGet->Param.MinRxSymbols = Nvm.MacGroup2.MacParams.MinRxSymbols;
  3258. break;
  3259. }
  3260. case MIB_ANTENNA_GAIN:
  3261. {
  3262. mibGet->Param.AntennaGain = Nvm.MacGroup2.MacParams.AntennaGain;
  3263. break;
  3264. }
  3265. case MIB_NVM_CTXS:
  3266. {
  3267. mibGet->Param.Contexts = GetNvmData( );
  3268. break;
  3269. }
  3270. case MIB_DEFAULT_ANTENNA_GAIN:
  3271. {
  3272. mibGet->Param.DefaultAntennaGain = Nvm.MacGroup2.MacParamsDefaults.AntennaGain;
  3273. break;
  3274. }
  3275. case MIB_LORAWAN_VERSION:
  3276. {
  3277. mibGet->Param.LrWanVersion.LoRaWan = Nvm.MacGroup2.Version;
  3278. mibGet->Param.LrWanVersion.LoRaWanRegion = RegionGetVersion( );
  3279. break;
  3280. }
  3281. case MIB_IS_CERT_FPORT_ON:
  3282. {
  3283. mibGet->Param.IsCertPortOn = Nvm.MacGroup2.IsCertPortOn;
  3284. break;
  3285. }
  3286. default:
  3287. {
  3288. status = LoRaMacClassBMibGetRequestConfirm( mibGet );
  3289. break;
  3290. }
  3291. }
  3292. return status;
  3293. }
  3294. LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t* mibSet )
  3295. {
  3296. LoRaMacStatus_t status = LORAMAC_STATUS_OK;
  3297. ChanMaskSetParams_t chanMaskSet;
  3298. VerifyParams_t verify;
  3299. if( mibSet == NULL )
  3300. {
  3301. return LORAMAC_STATUS_PARAMETER_INVALID;
  3302. }
  3303. if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
  3304. {
  3305. return LORAMAC_STATUS_BUSY;
  3306. }
  3307. switch( mibSet->Type )
  3308. {
  3309. case MIB_DEVICE_CLASS:
  3310. {
  3311. status = SwitchClass( mibSet->Param.Class );
  3312. break;
  3313. }
  3314. case MIB_NETWORK_ACTIVATION:
  3315. {
  3316. if( mibSet->Param.NetworkActivation != ACTIVATION_TYPE_OTAA )
  3317. {
  3318. Nvm.MacGroup2.NetworkActivation = mibSet->Param.NetworkActivation;
  3319. }
  3320. else
  3321. { // Do not allow to set ACTIVATION_TYPE_OTAA since the MAC will set it automatically after a successful join process.
  3322. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3323. }
  3324. break;
  3325. }
  3326. case MIB_DEV_EUI:
  3327. {
  3328. if( SecureElementSetDevEui( mibSet->Param.DevEui ) != SECURE_ELEMENT_SUCCESS )
  3329. {
  3330. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3331. }
  3332. break;
  3333. }
  3334. case MIB_JOIN_EUI:
  3335. {
  3336. if( SecureElementSetJoinEui( mibSet->Param.JoinEui ) != SECURE_ELEMENT_SUCCESS )
  3337. {
  3338. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3339. }
  3340. break;
  3341. }
  3342. case MIB_SE_PIN:
  3343. {
  3344. if( SecureElementSetPin( mibSet->Param.SePin ) != SECURE_ELEMENT_SUCCESS )
  3345. {
  3346. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3347. }
  3348. break;
  3349. }
  3350. case MIB_ADR:
  3351. {
  3352. Nvm.MacGroup2.AdrCtrlOn = mibSet->Param.AdrEnable;
  3353. break;
  3354. }
  3355. case MIB_NET_ID:
  3356. {
  3357. Nvm.MacGroup2.NetID = mibSet->Param.NetID;
  3358. break;
  3359. }
  3360. case MIB_DEV_ADDR:
  3361. {
  3362. Nvm.MacGroup2.DevAddr = mibSet->Param.DevAddr;
  3363. break;
  3364. }
  3365. case MIB_APP_KEY:
  3366. {
  3367. if( mibSet->Param.AppKey != NULL )
  3368. {
  3369. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( APP_KEY, mibSet->Param.AppKey ) )
  3370. {
  3371. return LORAMAC_STATUS_CRYPTO_ERROR;
  3372. }
  3373. }
  3374. else
  3375. {
  3376. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3377. }
  3378. break;
  3379. }
  3380. case MIB_NWK_KEY:
  3381. {
  3382. if( mibSet->Param.NwkKey != NULL )
  3383. {
  3384. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( NWK_KEY, mibSet->Param.NwkKey ) )
  3385. {
  3386. return LORAMAC_STATUS_CRYPTO_ERROR;
  3387. }
  3388. }
  3389. else
  3390. {
  3391. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3392. }
  3393. break;
  3394. }
  3395. case MIB_J_S_INT_KEY:
  3396. {
  3397. if( mibSet->Param.JSIntKey != NULL )
  3398. {
  3399. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( J_S_INT_KEY, mibSet->Param.JSIntKey ) )
  3400. {
  3401. return LORAMAC_STATUS_CRYPTO_ERROR;
  3402. }
  3403. }
  3404. else
  3405. {
  3406. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3407. }
  3408. break;
  3409. }
  3410. case MIB_J_S_ENC_KEY:
  3411. {
  3412. if( mibSet->Param.JSEncKey != NULL )
  3413. {
  3414. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( J_S_ENC_KEY, mibSet->Param.JSEncKey ) )
  3415. {
  3416. return LORAMAC_STATUS_CRYPTO_ERROR;
  3417. }
  3418. }
  3419. else
  3420. {
  3421. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3422. }
  3423. break;
  3424. }
  3425. case MIB_F_NWK_S_INT_KEY:
  3426. {
  3427. if( mibSet->Param.FNwkSIntKey != NULL )
  3428. {
  3429. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( F_NWK_S_INT_KEY, mibSet->Param.FNwkSIntKey ) )
  3430. {
  3431. return LORAMAC_STATUS_CRYPTO_ERROR;
  3432. }
  3433. }
  3434. else
  3435. {
  3436. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3437. }
  3438. break;
  3439. }
  3440. case MIB_S_NWK_S_INT_KEY:
  3441. {
  3442. if( mibSet->Param.SNwkSIntKey != NULL )
  3443. {
  3444. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( S_NWK_S_INT_KEY, mibSet->Param.SNwkSIntKey ) )
  3445. {
  3446. return LORAMAC_STATUS_CRYPTO_ERROR;
  3447. }
  3448. }
  3449. else
  3450. {
  3451. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3452. }
  3453. break;
  3454. }
  3455. case MIB_NWK_S_ENC_KEY:
  3456. {
  3457. if( mibSet->Param.NwkSEncKey != NULL )
  3458. {
  3459. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( NWK_S_ENC_KEY, mibSet->Param.NwkSEncKey ) )
  3460. {
  3461. return LORAMAC_STATUS_CRYPTO_ERROR;
  3462. }
  3463. }
  3464. else
  3465. {
  3466. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3467. }
  3468. break;
  3469. }
  3470. case MIB_APP_S_KEY:
  3471. {
  3472. if( mibSet->Param.AppSKey != NULL )
  3473. {
  3474. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( APP_S_KEY, mibSet->Param.AppSKey ) )
  3475. {
  3476. return LORAMAC_STATUS_CRYPTO_ERROR;
  3477. }
  3478. }
  3479. else
  3480. {
  3481. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3482. }
  3483. break;
  3484. }
  3485. case MIB_MC_KE_KEY:
  3486. {
  3487. if( mibSet->Param.McKEKey != NULL )
  3488. {
  3489. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_KE_KEY, mibSet->Param.McKEKey ) )
  3490. {
  3491. return LORAMAC_STATUS_CRYPTO_ERROR;
  3492. }
  3493. }
  3494. else
  3495. {
  3496. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3497. }
  3498. break;
  3499. }
  3500. case MIB_MC_KEY_0:
  3501. {
  3502. if( mibSet->Param.McKey0 != NULL )
  3503. {
  3504. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_KEY_0, mibSet->Param.McKey0 ) )
  3505. {
  3506. return LORAMAC_STATUS_CRYPTO_ERROR;
  3507. }
  3508. }
  3509. else
  3510. {
  3511. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3512. }
  3513. break;
  3514. }
  3515. case MIB_MC_APP_S_KEY_0:
  3516. {
  3517. if( mibSet->Param.McAppSKey0 != NULL )
  3518. {
  3519. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_APP_S_KEY_0, mibSet->Param.McAppSKey0 ) )
  3520. {
  3521. return LORAMAC_STATUS_CRYPTO_ERROR;
  3522. }
  3523. }
  3524. else
  3525. {
  3526. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3527. }
  3528. break;
  3529. }
  3530. case MIB_MC_NWK_S_KEY_0:
  3531. {
  3532. if( mibSet->Param.McNwkSKey0 != NULL )
  3533. {
  3534. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_NWK_S_KEY_0, mibSet->Param.McNwkSKey0 ) )
  3535. {
  3536. return LORAMAC_STATUS_CRYPTO_ERROR;
  3537. }
  3538. }
  3539. else
  3540. {
  3541. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3542. }
  3543. break;
  3544. }
  3545. case MIB_MC_KEY_1:
  3546. {
  3547. if( mibSet->Param.McKey1 != NULL )
  3548. {
  3549. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_KEY_1, mibSet->Param.McKey1 ) )
  3550. {
  3551. return LORAMAC_STATUS_CRYPTO_ERROR;
  3552. }
  3553. }
  3554. else
  3555. {
  3556. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3557. }
  3558. break;
  3559. }
  3560. case MIB_MC_APP_S_KEY_1:
  3561. {
  3562. if( mibSet->Param.McAppSKey1 != NULL )
  3563. {
  3564. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_APP_S_KEY_1, mibSet->Param.McAppSKey1 ) )
  3565. {
  3566. return LORAMAC_STATUS_CRYPTO_ERROR;
  3567. }
  3568. }
  3569. else
  3570. {
  3571. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3572. }
  3573. break;
  3574. }
  3575. case MIB_MC_NWK_S_KEY_1:
  3576. {
  3577. if( mibSet->Param.McNwkSKey1 != NULL )
  3578. {
  3579. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_NWK_S_KEY_1, mibSet->Param.McNwkSKey1 ) )
  3580. {
  3581. return LORAMAC_STATUS_CRYPTO_ERROR;
  3582. }
  3583. }
  3584. else
  3585. {
  3586. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3587. }
  3588. break;
  3589. }
  3590. case MIB_MC_KEY_2:
  3591. {
  3592. if( mibSet->Param.McKey2 != NULL )
  3593. {
  3594. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_KEY_2, mibSet->Param.McKey2 ) )
  3595. {
  3596. return LORAMAC_STATUS_CRYPTO_ERROR;
  3597. }
  3598. }
  3599. else
  3600. {
  3601. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3602. }
  3603. break;
  3604. }
  3605. case MIB_MC_APP_S_KEY_2:
  3606. {
  3607. if( mibSet->Param.McAppSKey2 != NULL )
  3608. {
  3609. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_APP_S_KEY_2, mibSet->Param.McAppSKey2 ) )
  3610. {
  3611. return LORAMAC_STATUS_CRYPTO_ERROR;
  3612. }
  3613. }
  3614. else
  3615. {
  3616. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3617. }
  3618. break;
  3619. }
  3620. case MIB_MC_NWK_S_KEY_2:
  3621. {
  3622. if( mibSet->Param.McNwkSKey2 != NULL )
  3623. {
  3624. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_NWK_S_KEY_2, mibSet->Param.McNwkSKey2 ) )
  3625. {
  3626. return LORAMAC_STATUS_CRYPTO_ERROR;
  3627. }
  3628. }
  3629. else
  3630. {
  3631. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3632. }
  3633. break;
  3634. }
  3635. case MIB_MC_KEY_3:
  3636. {
  3637. if( mibSet->Param.McKey3 != NULL )
  3638. {
  3639. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_KEY_3, mibSet->Param.McKey3 ) )
  3640. {
  3641. return LORAMAC_STATUS_CRYPTO_ERROR;
  3642. }
  3643. }
  3644. else
  3645. {
  3646. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3647. }
  3648. break;
  3649. }
  3650. case MIB_MC_APP_S_KEY_3:
  3651. {
  3652. if( mibSet->Param.McAppSKey3 != NULL )
  3653. {
  3654. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_APP_S_KEY_3, mibSet->Param.McAppSKey3 ) )
  3655. {
  3656. return LORAMAC_STATUS_CRYPTO_ERROR;
  3657. }
  3658. }
  3659. else
  3660. {
  3661. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3662. }
  3663. break;
  3664. }
  3665. case MIB_MC_NWK_S_KEY_3:
  3666. {
  3667. if( mibSet->Param.McNwkSKey3 != NULL )
  3668. {
  3669. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_NWK_S_KEY_3, mibSet->Param.McNwkSKey3 ) )
  3670. {
  3671. return LORAMAC_STATUS_CRYPTO_ERROR;
  3672. }
  3673. }
  3674. else
  3675. {
  3676. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3677. }
  3678. break;
  3679. }
  3680. case MIB_PUBLIC_NETWORK:
  3681. {
  3682. Nvm.MacGroup2.PublicNetwork = mibSet->Param.EnablePublicNetwork;
  3683. Radio.SetPublicNetwork( Nvm.MacGroup2.PublicNetwork );
  3684. break;
  3685. }
  3686. case MIB_RX2_CHANNEL:
  3687. {
  3688. verify.DatarateParams.Datarate = mibSet->Param.Rx2Channel.Datarate;
  3689. verify.DatarateParams.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
  3690. if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_RX_DR ) == true )
  3691. {
  3692. Nvm.MacGroup2.MacParams.Rx2Channel = mibSet->Param.Rx2Channel;
  3693. }
  3694. else
  3695. {
  3696. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3697. }
  3698. break;
  3699. }
  3700. case MIB_RX2_DEFAULT_CHANNEL:
  3701. {
  3702. verify.DatarateParams.Datarate = mibSet->Param.Rx2Channel.Datarate;
  3703. verify.DatarateParams.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
  3704. if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_RX_DR ) == true )
  3705. {
  3706. Nvm.MacGroup2.MacParamsDefaults.Rx2Channel = mibSet->Param.Rx2DefaultChannel;
  3707. }
  3708. else
  3709. {
  3710. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3711. }
  3712. break;
  3713. }
  3714. case MIB_RXC_CHANNEL:
  3715. {
  3716. verify.DatarateParams.Datarate = mibSet->Param.RxCChannel.Datarate;
  3717. verify.DatarateParams.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
  3718. if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_RX_DR ) == true )
  3719. {
  3720. Nvm.MacGroup2.MacParams.RxCChannel = mibSet->Param.RxCChannel;
  3721. if( ( Nvm.MacGroup2.DeviceClass == CLASS_C ) && ( Nvm.MacGroup2.NetworkActivation != ACTIVATION_TYPE_NONE ) )
  3722. {
  3723. // We can only compute the RX window parameters directly, if we are already
  3724. // in class c mode and joined. We cannot setup an RX window in case of any other
  3725. // class type.
  3726. // Set the radio into sleep mode in case we are still in RX mode
  3727. Radio.Sleep( );
  3728. OpenContinuousRxCWindow( );
  3729. }
  3730. }
  3731. else
  3732. {
  3733. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3734. }
  3735. break;
  3736. }
  3737. case MIB_RXC_DEFAULT_CHANNEL:
  3738. {
  3739. verify.DatarateParams.Datarate = mibSet->Param.RxCChannel.Datarate;
  3740. verify.DatarateParams.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
  3741. if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_RX_DR ) == true )
  3742. {
  3743. Nvm.MacGroup2.MacParamsDefaults.RxCChannel = mibSet->Param.RxCDefaultChannel;
  3744. }
  3745. else
  3746. {
  3747. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3748. }
  3749. break;
  3750. }
  3751. case MIB_CHANNELS_DEFAULT_MASK:
  3752. {
  3753. chanMaskSet.ChannelsMaskIn = mibSet->Param.ChannelsDefaultMask;
  3754. chanMaskSet.ChannelsMaskType = CHANNELS_DEFAULT_MASK;
  3755. if( RegionChanMaskSet( Nvm.MacGroup2.Region, &chanMaskSet ) == false )
  3756. {
  3757. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3758. }
  3759. break;
  3760. }
  3761. case MIB_CHANNELS_MASK:
  3762. {
  3763. chanMaskSet.ChannelsMaskIn = mibSet->Param.ChannelsMask;
  3764. chanMaskSet.ChannelsMaskType = CHANNELS_MASK;
  3765. if( RegionChanMaskSet( Nvm.MacGroup2.Region, &chanMaskSet ) == false )
  3766. {
  3767. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3768. }
  3769. break;
  3770. }
  3771. case MIB_CHANNELS_NB_TRANS:
  3772. {
  3773. if( ( mibSet->Param.ChannelsNbTrans >= 1 ) &&
  3774. ( mibSet->Param.ChannelsNbTrans <= 15 ) )
  3775. {
  3776. Nvm.MacGroup2.MacParams.ChannelsNbTrans = mibSet->Param.ChannelsNbTrans;
  3777. }
  3778. else
  3779. {
  3780. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3781. }
  3782. break;
  3783. }
  3784. case MIB_MAX_RX_WINDOW_DURATION:
  3785. {
  3786. Nvm.MacGroup2.MacParams.MaxRxWindow = mibSet->Param.MaxRxWindow;
  3787. break;
  3788. }
  3789. case MIB_RECEIVE_DELAY_1:
  3790. {
  3791. Nvm.MacGroup2.MacParams.ReceiveDelay1 = mibSet->Param.ReceiveDelay1;
  3792. break;
  3793. }
  3794. case MIB_RECEIVE_DELAY_2:
  3795. {
  3796. Nvm.MacGroup2.MacParams.ReceiveDelay2 = mibSet->Param.ReceiveDelay2;
  3797. break;
  3798. }
  3799. case MIB_JOIN_ACCEPT_DELAY_1:
  3800. {
  3801. Nvm.MacGroup2.MacParams.JoinAcceptDelay1 = mibSet->Param.JoinAcceptDelay1;
  3802. break;
  3803. }
  3804. case MIB_JOIN_ACCEPT_DELAY_2:
  3805. {
  3806. Nvm.MacGroup2.MacParams.JoinAcceptDelay2 = mibSet->Param.JoinAcceptDelay2;
  3807. break;
  3808. }
  3809. case MIB_CHANNELS_DEFAULT_DATARATE:
  3810. {
  3811. verify.DatarateParams.Datarate = mibSet->Param.ChannelsDefaultDatarate;
  3812. if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_DEF_TX_DR ) == true )
  3813. {
  3814. Nvm.MacGroup2.ChannelsDatarateDefault = verify.DatarateParams.Datarate;
  3815. }
  3816. else
  3817. {
  3818. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3819. }
  3820. break;
  3821. }
  3822. case MIB_CHANNELS_DATARATE:
  3823. {
  3824. verify.DatarateParams.Datarate = mibSet->Param.ChannelsDatarate;
  3825. verify.DatarateParams.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
  3826. if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_TX_DR ) == true )
  3827. {
  3828. Nvm.MacGroup1.ChannelsDatarate = verify.DatarateParams.Datarate;
  3829. }
  3830. else
  3831. {
  3832. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3833. }
  3834. break;
  3835. }
  3836. case MIB_CHANNELS_DEFAULT_TX_POWER:
  3837. {
  3838. verify.TxPower = mibSet->Param.ChannelsDefaultTxPower;
  3839. if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_DEF_TX_POWER ) == true )
  3840. {
  3841. Nvm.MacGroup2.ChannelsTxPowerDefault = verify.TxPower;
  3842. }
  3843. else
  3844. {
  3845. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3846. }
  3847. break;
  3848. }
  3849. case MIB_CHANNELS_TX_POWER:
  3850. {
  3851. verify.TxPower = mibSet->Param.ChannelsTxPower;
  3852. if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_TX_POWER ) == true )
  3853. {
  3854. Nvm.MacGroup1.ChannelsTxPower = verify.TxPower;
  3855. }
  3856. else
  3857. {
  3858. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3859. }
  3860. break;
  3861. }
  3862. case MIB_SYSTEM_MAX_RX_ERROR:
  3863. {
  3864. Nvm.MacGroup2.MacParams.SystemMaxRxError = Nvm.MacGroup2.MacParamsDefaults.SystemMaxRxError = mibSet->Param.SystemMaxRxError;
  3865. break;
  3866. }
  3867. case MIB_MIN_RX_SYMBOLS:
  3868. {
  3869. Nvm.MacGroup2.MacParams.MinRxSymbols = Nvm.MacGroup2.MacParamsDefaults.MinRxSymbols = mibSet->Param.MinRxSymbols;
  3870. break;
  3871. }
  3872. case MIB_ANTENNA_GAIN:
  3873. {
  3874. Nvm.MacGroup2.MacParams.AntennaGain = mibSet->Param.AntennaGain;
  3875. break;
  3876. }
  3877. case MIB_DEFAULT_ANTENNA_GAIN:
  3878. {
  3879. Nvm.MacGroup2.MacParamsDefaults.AntennaGain = mibSet->Param.DefaultAntennaGain;
  3880. break;
  3881. }
  3882. case MIB_NVM_CTXS:
  3883. {
  3884. if( mibSet->Param.Contexts != 0 )
  3885. {
  3886. status = RestoreNvmData( mibSet->Param.Contexts );
  3887. }
  3888. else
  3889. {
  3890. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3891. }
  3892. break;
  3893. }
  3894. case MIB_ABP_LORAWAN_VERSION:
  3895. {
  3896. if( mibSet->Param.AbpLrWanVersion.Fields.Minor <= 1 )
  3897. {
  3898. Nvm.MacGroup2.Version = mibSet->Param.AbpLrWanVersion;
  3899. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetLrWanVersion( mibSet->Param.AbpLrWanVersion ) )
  3900. {
  3901. return LORAMAC_STATUS_CRYPTO_ERROR;
  3902. }
  3903. }
  3904. else
  3905. {
  3906. status = LORAMAC_STATUS_PARAMETER_INVALID;
  3907. }
  3908. break;
  3909. }
  3910. case MIB_IS_CERT_FPORT_ON:
  3911. {
  3912. Nvm.MacGroup2.IsCertPortOn = mibSet->Param.IsCertPortOn;
  3913. break;
  3914. }
  3915. default:
  3916. {
  3917. status = LoRaMacMibClassBSetRequestConfirm( mibSet );
  3918. break;
  3919. }
  3920. }
  3921. if( status == LORAMAC_STATUS_OK )
  3922. {
  3923. // Handle NVM potential changes
  3924. MacCtx.MacFlags.Bits.NvmHandle = 1;
  3925. }
  3926. return status;
  3927. }
  3928. LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params )
  3929. {
  3930. ChannelAddParams_t channelAdd;
  3931. // Validate if the MAC is in a correct state
  3932. if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
  3933. {
  3934. if( ( MacCtx.MacState & LORAMAC_TX_CONFIG ) != LORAMAC_TX_CONFIG )
  3935. {
  3936. return LORAMAC_STATUS_BUSY;
  3937. }
  3938. }
  3939. channelAdd.NewChannel = &params;
  3940. channelAdd.ChannelId = id;
  3941. return RegionChannelAdd( Nvm.MacGroup2.Region, &channelAdd );
  3942. }
  3943. LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id )
  3944. {
  3945. ChannelRemoveParams_t channelRemove;
  3946. if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
  3947. {
  3948. if( ( MacCtx.MacState & LORAMAC_TX_CONFIG ) != LORAMAC_TX_CONFIG )
  3949. {
  3950. return LORAMAC_STATUS_BUSY;
  3951. }
  3952. }
  3953. channelRemove.ChannelId = id;
  3954. if( RegionChannelsRemove( Nvm.MacGroup2.Region, &channelRemove ) == false )
  3955. {
  3956. return LORAMAC_STATUS_PARAMETER_INVALID;
  3957. }
  3958. return LORAMAC_STATUS_OK;
  3959. }
  3960. LoRaMacStatus_t LoRaMacMcChannelSetup( McChannelParams_t *channel )
  3961. {
  3962. if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
  3963. {
  3964. return LORAMAC_STATUS_BUSY;
  3965. }
  3966. if( channel->GroupID >= LORAMAC_MAX_MC_CTX )
  3967. {
  3968. return LORAMAC_STATUS_MC_GROUP_UNDEFINED;
  3969. }
  3970. Nvm.MacGroup2.MulticastChannelList[channel->GroupID].ChannelParams = *channel;
  3971. if( channel->IsRemotelySetup == true )
  3972. {
  3973. const KeyIdentifier_t mcKeys[LORAMAC_MAX_MC_CTX] = { MC_KEY_0, MC_KEY_1, MC_KEY_2, MC_KEY_3 };
  3974. if( LoRaMacCryptoSetKey( mcKeys[channel->GroupID], channel->McKeys.McKeyE ) != LORAMAC_CRYPTO_SUCCESS )
  3975. {
  3976. return LORAMAC_STATUS_CRYPTO_ERROR;
  3977. }
  3978. if( LoRaMacCryptoDeriveMcSessionKeyPair( channel->GroupID, channel->Address ) != LORAMAC_CRYPTO_SUCCESS )
  3979. {
  3980. return LORAMAC_STATUS_CRYPTO_ERROR;
  3981. }
  3982. }
  3983. else
  3984. {
  3985. const KeyIdentifier_t mcAppSKeys[LORAMAC_MAX_MC_CTX] = { MC_APP_S_KEY_0, MC_APP_S_KEY_1, MC_APP_S_KEY_2, MC_APP_S_KEY_3 };
  3986. const KeyIdentifier_t mcNwkSKeys[LORAMAC_MAX_MC_CTX] = { MC_NWK_S_KEY_0, MC_NWK_S_KEY_1, MC_NWK_S_KEY_2, MC_NWK_S_KEY_3 };
  3987. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( mcAppSKeys[channel->GroupID], channel->McKeys.Session.McAppSKey ) )
  3988. {
  3989. return LORAMAC_STATUS_CRYPTO_ERROR;
  3990. }
  3991. if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( mcNwkSKeys[channel->GroupID], channel->McKeys.Session.McNwkSKey ) )
  3992. {
  3993. return LORAMAC_STATUS_CRYPTO_ERROR;
  3994. }
  3995. }
  3996. if( channel->Class == CLASS_B )
  3997. {
  3998. // Calculate class b parameters
  3999. LoRaMacClassBSetMulticastPeriodicity( &Nvm.MacGroup2.MulticastChannelList[channel->GroupID] );
  4000. }
  4001. // Reset multicast channel downlink counter to initial value.
  4002. *Nvm.MacGroup2.MulticastChannelList[channel->GroupID].DownLinkCounter = FCNT_DOWN_INITAL_VALUE;
  4003. return LORAMAC_STATUS_OK;
  4004. }
  4005. LoRaMacStatus_t LoRaMacMcChannelDelete( AddressIdentifier_t groupID )
  4006. {
  4007. if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
  4008. {
  4009. return LORAMAC_STATUS_BUSY;
  4010. }
  4011. if( ( groupID >= LORAMAC_MAX_MC_CTX ) ||
  4012. ( Nvm.MacGroup2.MulticastChannelList[groupID].ChannelParams.IsEnabled == false ) )
  4013. {
  4014. return LORAMAC_STATUS_MC_GROUP_UNDEFINED;
  4015. }
  4016. McChannelParams_t channel;
  4017. // Set all channel fields with 0
  4018. memset1( ( uint8_t* )&channel, 0, sizeof( McChannelParams_t ) );
  4019. Nvm.MacGroup2.MulticastChannelList[groupID].ChannelParams = channel;
  4020. return LORAMAC_STATUS_OK;
  4021. }
  4022. uint8_t LoRaMacMcChannelGetGroupId( uint32_t mcAddress )
  4023. {
  4024. for( uint8_t i = 0; i < LORAMAC_MAX_MC_CTX; i++ )
  4025. {
  4026. if( mcAddress == Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.Address )
  4027. {
  4028. return i;
  4029. }
  4030. }
  4031. return 0xFF;
  4032. }
  4033. LoRaMacStatus_t LoRaMacMcChannelSetupRxParams( AddressIdentifier_t groupID, McRxParams_t *rxParams, uint8_t *status )
  4034. {
  4035. *status = 0x1C + ( groupID & 0x03 );
  4036. if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
  4037. {
  4038. return LORAMAC_STATUS_BUSY;
  4039. }
  4040. DeviceClass_t devClass = Nvm.MacGroup2.MulticastChannelList[groupID].ChannelParams.Class;
  4041. if( ( devClass == CLASS_A ) || ( devClass > CLASS_C ) )
  4042. {
  4043. return LORAMAC_STATUS_PARAMETER_INVALID;
  4044. }
  4045. if( ( groupID >= LORAMAC_MAX_MC_CTX ) ||
  4046. ( Nvm.MacGroup2.MulticastChannelList[groupID].ChannelParams.IsEnabled == false ) )
  4047. {
  4048. return LORAMAC_STATUS_MC_GROUP_UNDEFINED;
  4049. }
  4050. *status &= 0x0F; // groupID OK
  4051. VerifyParams_t verify;
  4052. // Check datarate
  4053. if( devClass == CLASS_B )
  4054. {
  4055. verify.DatarateParams.Datarate = rxParams->ClassB.Datarate;
  4056. }
  4057. else
  4058. {
  4059. verify.DatarateParams.Datarate = rxParams->ClassC.Datarate;
  4060. }
  4061. verify.DatarateParams.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
  4062. if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_RX_DR ) == true )
  4063. {
  4064. *status &= 0xFB; // datarate OK
  4065. }
  4066. // Check frequency
  4067. if( devClass == CLASS_B )
  4068. {
  4069. verify.Frequency = rxParams->ClassB.Frequency;
  4070. }
  4071. else
  4072. {
  4073. verify.Frequency = rxParams->ClassC.Frequency;
  4074. }
  4075. if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_FREQUENCY ) == true )
  4076. {
  4077. *status &= 0xF7; // frequency OK
  4078. }
  4079. if( *status == ( groupID & 0x03 ) )
  4080. {
  4081. // Apply parameters
  4082. Nvm.MacGroup2.MulticastChannelList[groupID].ChannelParams.RxParams = *rxParams;
  4083. }
  4084. return LORAMAC_STATUS_OK;
  4085. }
  4086. LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t* mlmeRequest )
  4087. {
  4088. LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
  4089. MlmeConfirmQueue_t queueElement;
  4090. uint8_t macCmdPayload[2] = { 0x00, 0x00 };
  4091. if( mlmeRequest == NULL )
  4092. {
  4093. return LORAMAC_STATUS_PARAMETER_INVALID;
  4094. }
  4095. // Initialize mlmeRequest->ReqReturn.DutyCycleWaitTime to 0 in order to
  4096. // return a valid value in case the MAC is busy.
  4097. mlmeRequest->ReqReturn.DutyCycleWaitTime = 0;
  4098. if( LoRaMacIsBusy( ) == true )
  4099. {
  4100. return LORAMAC_STATUS_BUSY;
  4101. }
  4102. if( LoRaMacConfirmQueueIsFull( ) == true )
  4103. {
  4104. return LORAMAC_STATUS_BUSY;
  4105. }
  4106. if( LoRaMacConfirmQueueGetCnt( ) == 0 )
  4107. {
  4108. memset1( ( uint8_t* ) &MacCtx.MlmeConfirm, 0, sizeof( MacCtx.MlmeConfirm ) );
  4109. }
  4110. MacCtx.MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  4111. MacCtx.MacFlags.Bits.MlmeReq = 1;
  4112. queueElement.Request = mlmeRequest->Type;
  4113. queueElement.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  4114. queueElement.RestrictCommonReadyToHandle = false;
  4115. queueElement.ReadyToHandle = false;
  4116. switch( mlmeRequest->Type )
  4117. {
  4118. case MLME_JOIN:
  4119. {
  4120. if( ( MacCtx.MacState & LORAMAC_TX_DELAYED ) == LORAMAC_TX_DELAYED )
  4121. {
  4122. return LORAMAC_STATUS_BUSY;
  4123. }
  4124. if( mlmeRequest->Req.Join.NetworkActivation == ACTIVATION_TYPE_OTAA )
  4125. {
  4126. ResetMacParameters( );
  4127. Nvm.MacGroup1.ChannelsDatarate = RegionAlternateDr( Nvm.MacGroup2.Region, mlmeRequest->Req.Join.Datarate, ALTERNATE_DR );
  4128. queueElement.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
  4129. status = SendReJoinReq( JOIN_REQ );
  4130. if( status != LORAMAC_STATUS_OK )
  4131. {
  4132. // Revert back the previous datarate ( mainly used for US915 like regions )
  4133. Nvm.MacGroup1.ChannelsDatarate = RegionAlternateDr( Nvm.MacGroup2.Region, mlmeRequest->Req.Join.Datarate, ALTERNATE_DR_RESTORE );
  4134. }
  4135. }
  4136. else if( mlmeRequest->Req.Join.NetworkActivation == ACTIVATION_TYPE_ABP )
  4137. {
  4138. // Restore default value for ChannelsDatarateChangedLinkAdrReq
  4139. Nvm.MacGroup2.ChannelsDatarateChangedLinkAdrReq = false;
  4140. // Activate the default channels
  4141. InitDefaultsParams_t params;
  4142. params.Type = INIT_TYPE_ACTIVATE_DEFAULT_CHANNELS;
  4143. RegionInitDefaults( Nvm.MacGroup2.Region, &params );
  4144. Nvm.MacGroup2.NetworkActivation = mlmeRequest->Req.Join.NetworkActivation;
  4145. queueElement.Status = LORAMAC_EVENT_INFO_STATUS_OK;
  4146. queueElement.ReadyToHandle = true;
  4147. MacCtx.MacCallbacks->MacProcessNotify( );
  4148. MacCtx.MacFlags.Bits.MacDone = 1;
  4149. status = LORAMAC_STATUS_OK;
  4150. }
  4151. break;
  4152. }
  4153. case MLME_LINK_CHECK:
  4154. {
  4155. // LoRaMac will send this command piggy-pack
  4156. status = LORAMAC_STATUS_OK;
  4157. if( LoRaMacCommandsAddCmd( MOTE_MAC_LINK_CHECK_REQ, macCmdPayload, 0 ) != LORAMAC_COMMANDS_SUCCESS )
  4158. {
  4159. status = LORAMAC_STATUS_MAC_COMMAD_ERROR;
  4160. }
  4161. break;
  4162. }
  4163. case MLME_TXCW:
  4164. {
  4165. status = SetTxContinuousWave( mlmeRequest->Req.TxCw.Timeout, mlmeRequest->Req.TxCw.Frequency, mlmeRequest->Req.TxCw.Power );
  4166. break;
  4167. }
  4168. case MLME_DEVICE_TIME:
  4169. {
  4170. // LoRaMac will send this command piggy-pack
  4171. status = LORAMAC_STATUS_OK;
  4172. if( LoRaMacCommandsAddCmd( MOTE_MAC_DEVICE_TIME_REQ, macCmdPayload, 0 ) != LORAMAC_COMMANDS_SUCCESS )
  4173. {
  4174. status = LORAMAC_STATUS_MAC_COMMAD_ERROR;
  4175. }
  4176. break;
  4177. }
  4178. case MLME_PING_SLOT_INFO:
  4179. {
  4180. if( Nvm.MacGroup2.DeviceClass == CLASS_A )
  4181. {
  4182. uint8_t value = mlmeRequest->Req.PingSlotInfo.PingSlot.Value;
  4183. // LoRaMac will send this command piggy-pack
  4184. LoRaMacClassBSetPingSlotInfo( mlmeRequest->Req.PingSlotInfo.PingSlot.Fields.Periodicity );
  4185. macCmdPayload[0] = value;
  4186. status = LORAMAC_STATUS_OK;
  4187. if( LoRaMacCommandsAddCmd( MOTE_MAC_PING_SLOT_INFO_REQ, macCmdPayload, 1 ) != LORAMAC_COMMANDS_SUCCESS )
  4188. {
  4189. status = LORAMAC_STATUS_MAC_COMMAD_ERROR;
  4190. }
  4191. }
  4192. break;
  4193. }
  4194. case MLME_BEACON_TIMING:
  4195. {
  4196. // LoRaMac will send this command piggy-pack
  4197. status = LORAMAC_STATUS_OK;
  4198. if( LoRaMacCommandsAddCmd( MOTE_MAC_BEACON_TIMING_REQ, macCmdPayload, 0 ) != LORAMAC_COMMANDS_SUCCESS )
  4199. {
  4200. status = LORAMAC_STATUS_MAC_COMMAD_ERROR;
  4201. }
  4202. break;
  4203. }
  4204. case MLME_BEACON_ACQUISITION:
  4205. {
  4206. // Apply the request
  4207. queueElement.RestrictCommonReadyToHandle = true;
  4208. if( LoRaMacClassBIsAcquisitionInProgress( ) == false )
  4209. {
  4210. // Start class B algorithm
  4211. LoRaMacClassBSetBeaconState( BEACON_STATE_ACQUISITION );
  4212. LoRaMacClassBBeaconTimerEvent( NULL );
  4213. status = LORAMAC_STATUS_OK;
  4214. }
  4215. else
  4216. {
  4217. status = LORAMAC_STATUS_BUSY;
  4218. }
  4219. break;
  4220. }
  4221. default:
  4222. break;
  4223. }
  4224. // Fill return structure
  4225. mlmeRequest->ReqReturn.DutyCycleWaitTime = MacCtx.DutyCycleWaitTime;
  4226. if( status != LORAMAC_STATUS_OK )
  4227. {
  4228. if( LoRaMacConfirmQueueGetCnt( ) == 0 )
  4229. {
  4230. MacCtx.NodeAckRequested = false;
  4231. MacCtx.MacFlags.Bits.MlmeReq = 0;
  4232. }
  4233. }
  4234. else
  4235. {
  4236. LoRaMacConfirmQueueAdd( &queueElement );
  4237. }
  4238. return status;
  4239. }
  4240. LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t* mcpsRequest )
  4241. {
  4242. GetPhyParams_t getPhy;
  4243. PhyParam_t phyParam;
  4244. LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
  4245. LoRaMacHeader_t macHdr;
  4246. VerifyParams_t verify;
  4247. uint8_t fPort = 0;
  4248. void* fBuffer;
  4249. uint16_t fBufferSize;
  4250. int8_t datarate = DR_0;
  4251. bool readyToSend = false;
  4252. if( mcpsRequest == NULL )
  4253. {
  4254. return LORAMAC_STATUS_PARAMETER_INVALID;
  4255. }
  4256. // Initialize mcpsRequest->ReqReturn.DutyCycleWaitTime to 0 in order to
  4257. // return a valid value in case the MAC is busy.
  4258. mcpsRequest->ReqReturn.DutyCycleWaitTime = 0;
  4259. if( LoRaMacIsBusy( ) == true )
  4260. {
  4261. return LORAMAC_STATUS_BUSY;
  4262. }
  4263. McpsReq_t request = *mcpsRequest;
  4264. macHdr.Value = 0;
  4265. memset1( ( uint8_t* ) &MacCtx.McpsConfirm, 0, sizeof( MacCtx.McpsConfirm ) );
  4266. MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
  4267. // Apply confirmed downlinks, if the device has not received a valid
  4268. // downlink after a join accept.
  4269. if( ( Nvm.MacGroup2.NetworkActivation == ACTIVATION_TYPE_OTAA ) &&
  4270. ( Nvm.MacGroup2.DeviceClass == CLASS_C ) &&
  4271. ( Nvm.MacGroup2.DownlinkReceived == false ) &&
  4272. ( request.Type == MCPS_UNCONFIRMED ) )
  4273. {
  4274. request.Type = MCPS_CONFIRMED;
  4275. }
  4276. switch( request.Type )
  4277. {
  4278. case MCPS_UNCONFIRMED:
  4279. {
  4280. readyToSend = true;
  4281. macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
  4282. fPort = request.Req.Unconfirmed.fPort;
  4283. fBuffer = request.Req.Unconfirmed.fBuffer;
  4284. fBufferSize = request.Req.Unconfirmed.fBufferSize;
  4285. datarate = request.Req.Unconfirmed.Datarate;
  4286. break;
  4287. }
  4288. case MCPS_CONFIRMED:
  4289. {
  4290. readyToSend = true;
  4291. macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
  4292. fPort = request.Req.Confirmed.fPort;
  4293. fBuffer = request.Req.Confirmed.fBuffer;
  4294. fBufferSize = request.Req.Confirmed.fBufferSize;
  4295. datarate = request.Req.Confirmed.Datarate;
  4296. break;
  4297. }
  4298. case MCPS_PROPRIETARY:
  4299. {
  4300. readyToSend = true;
  4301. macHdr.Bits.MType = FRAME_TYPE_PROPRIETARY;
  4302. fBuffer = request.Req.Proprietary.fBuffer;
  4303. fBufferSize = request.Req.Proprietary.fBufferSize;
  4304. datarate = request.Req.Proprietary.Datarate;
  4305. break;
  4306. }
  4307. default:
  4308. break;
  4309. }
  4310. // Make sure that the input datarate is compliant
  4311. // to the regional specification.
  4312. getPhy.Attribute = PHY_MIN_TX_DR;
  4313. getPhy.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
  4314. phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
  4315. // Apply the minimum possible datarate.
  4316. // Some regions have limitations for the minimum datarate.
  4317. datarate = MAX( datarate, ( int8_t )phyParam.Value );
  4318. // Apply minimum datarate in this special case.
  4319. if( CheckForMinimumAbpDatarate( Nvm.MacGroup2.AdrCtrlOn, Nvm.MacGroup2.NetworkActivation,
  4320. Nvm.MacGroup2.ChannelsDatarateChangedLinkAdrReq ) == true )
  4321. {
  4322. datarate = ( int8_t )phyParam.Value;
  4323. }
  4324. if( readyToSend == true )
  4325. {
  4326. if( ( Nvm.MacGroup2.AdrCtrlOn == false ) ||
  4327. ( CheckForMinimumAbpDatarate( Nvm.MacGroup2.AdrCtrlOn, Nvm.MacGroup2.NetworkActivation,
  4328. Nvm.MacGroup2.ChannelsDatarateChangedLinkAdrReq ) == true ) )
  4329. {
  4330. verify.DatarateParams.Datarate = datarate;
  4331. verify.DatarateParams.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
  4332. if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_TX_DR ) == true )
  4333. {
  4334. Nvm.MacGroup1.ChannelsDatarate = verify.DatarateParams.Datarate;
  4335. }
  4336. else
  4337. {
  4338. return LORAMAC_STATUS_PARAMETER_INVALID;
  4339. }
  4340. }
  4341. // Verification of response timeout for class b and class c
  4342. LoRaMacHandleResponseTimeout( REGION_COMMON_CLASS_B_C_RESP_TIMEOUT,
  4343. MacCtx.ResponseTimeoutStartTime );
  4344. status = Send( &macHdr, fPort, fBuffer, fBufferSize );
  4345. if( status == LORAMAC_STATUS_OK )
  4346. {
  4347. MacCtx.McpsConfirm.McpsRequest = request.Type;
  4348. MacCtx.MacFlags.Bits.McpsReq = 1;
  4349. }
  4350. else
  4351. {
  4352. MacCtx.NodeAckRequested = false;
  4353. }
  4354. }
  4355. // Fill return structure
  4356. mcpsRequest->ReqReturn.DutyCycleWaitTime = MacCtx.DutyCycleWaitTime;
  4357. return status;
  4358. }
  4359. void LoRaMacTestSetDutyCycleOn( bool enable )
  4360. {
  4361. VerifyParams_t verify;
  4362. verify.DutyCycle = enable;
  4363. if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_DUTY_CYCLE ) == true )
  4364. {
  4365. Nvm.MacGroup2.DutyCycleOn = enable;
  4366. }
  4367. }
  4368. LoRaMacStatus_t LoRaMacDeInitialization( void )
  4369. {
  4370. // Check the current state of the LoRaMac
  4371. if ( LoRaMacStop( ) == LORAMAC_STATUS_OK )
  4372. {
  4373. // Stop Timers
  4374. TimerStop( &MacCtx.TxDelayedTimer );
  4375. TimerStop( &MacCtx.RxWindowTimer1 );
  4376. TimerStop( &MacCtx.RxWindowTimer2 );
  4377. // Take care about class B
  4378. LoRaMacClassBHaltBeaconing( );
  4379. // Reset Mac parameters
  4380. ResetMacParameters( );
  4381. // Switch off Radio
  4382. Radio.Sleep( );
  4383. // Return success
  4384. return LORAMAC_STATUS_OK;
  4385. }
  4386. else
  4387. {
  4388. return LORAMAC_STATUS_BUSY;
  4389. }
  4390. }