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 
49 #include "LoRaMac.h"
50 
51 /*!
52  * Maximum PHY layer payload size
53  */
54 #define LORAMAC_PHY_MAXPAYLOAD                      255
55 
56 /*!
57  * Maximum length of the fOpts field
58  */
59 #define LORA_MAC_COMMAND_MAX_FOPTS_LENGTH           15
60 
61 /*!
62  * LoRaMac duty cycle for the back-off procedure during the first hour.
63  */
64 #define BACKOFF_DC_1_HOUR                           100
65 
66 /*!
67  * LoRaMac duty cycle for the back-off procedure during the next 10 hours.
68  */
69 #define BACKOFF_DC_10_HOURS                         1000
70 
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 /*!
77  * Maximum value for the ADR ack counter
78  */
79 #define ADR_ACK_COUNTER_MAX                         0xFFFFFFFF
80 
81 /*!
82  * Delay required to simulate an ABP join like an OTAA join
83  */
84 #define ABP_JOIN_PENDING_DELAY_MS                   10
85 
86 /*!
87  * LoRaMac internal states
88  */
89 enum eLoRaMacState
90 {
91     LORAMAC_IDLE             = 0x00000000,
92     LORAMAC_STOPPED          = 0x00000001,
93     LORAMAC_TX_RUNNING       = 0x00000002,
94     LORAMAC_RX               = 0x00000004,
95     LORAMAC_ACK_RETRY        = 0x00000010,
96     LORAMAC_TX_DELAYED       = 0x00000020,
97     LORAMAC_TX_CONFIG        = 0x00000040,
98     LORAMAC_RX_ABORT         = 0x00000080,
99     LORAMAC_ABP_JOIN_PENDING = 0x00000100,
100 };
101 
102 /*
103  * Request permission state
104  */
105 typedef enum eLoRaMacRequestHandling
106 {
107     LORAMAC_REQUEST_HANDLING_OFF = 0,
108     LORAMAC_REQUEST_HANDLING_ON = !LORAMAC_REQUEST_HANDLING_OFF
109 }LoRaMacRequestHandling_t;
110 
111 typedef struct sLoRaMacCtx
112 {
113     /*
114     * Length of packet in PktBuffer
115     */
116     uint16_t PktBufferLen;
117     /*
118     * Buffer containing the data to be sent or received.
119     */
120     uint8_t PktBuffer[LORAMAC_PHY_MAXPAYLOAD];
121     /*!
122     * Current processed transmit message
123     */
124     LoRaMacMessage_t TxMsg;
125     /*!
126     * Buffer containing the data received by the application.
127     */
128     uint8_t AppData[LORAMAC_PHY_MAXPAYLOAD];
129     /*
130     * Size of buffer containing the application data.
131     */
132     uint8_t AppDataSize;
133     /*
134     * Buffer containing the upper layer data.
135     */
136     uint8_t RxPayload[LORAMAC_PHY_MAXPAYLOAD];
137     SysTime_t LastTxSysTime;
138     /*
139     * LoRaMac internal state
140     */
141     uint32_t MacState;
142     /*
143     * LoRaMac upper layer event functions
144     */
145     LoRaMacPrimitives_t* MacPrimitives;
146     /*
147     * LoRaMac upper layer callback functions
148     */
149     LoRaMacCallback_t* MacCallbacks;
150     /*
151     * Radio events function pointer
152     */
153     RadioEvents_t RadioEvents;
154     /*
155     * LoRaMac duty cycle delayed Tx timer
156     */
157     TimerEvent_t TxDelayedTimer;
158     /*
159     * LoRaMac reception windows timers
160     */
161     TimerEvent_t RxWindowTimer1;
162     TimerEvent_t RxWindowTimer2;
163     /*
164     * LoRaMac reception windows delay
165     * \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME
166     *         join frame  : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME
167     */
168     uint32_t RxWindow1Delay;
169     uint32_t RxWindow2Delay;
170     /*
171     * LoRaMac Rx windows configuration
172     */
173     RxConfigParams_t RxWindow1Config;
174     RxConfigParams_t RxWindow2Config;
175     RxConfigParams_t RxWindowCConfig;
176     /*
177     * Acknowledge timeout timer. Used for packet retransmissions.
178     */
179     TimerEvent_t RetransmitTimeoutTimer;
180     /*
181      * Uplink messages repetitions counter
182      */
183     uint8_t ChannelsNbTransCounter;
184     /*
185      * Indicates if the AckTimeout timer has expired or not
186      */
187     bool RetransmitTimeoutRetry;
188     /*
189      * If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates
190      * if the nodes needs to manage the server acknowledgement.
191      */
192     bool NodeAckRequested;
193     /*
194      * Current channel index
195      */
196     uint8_t Channel;
197     /*
198     * Last transmission time on air
199     */
200     TimerTime_t TxTimeOnAir;
201     /*
202     * Structure to hold an MCPS indication data.
203     */
204     McpsIndication_t McpsIndication;
205     /*
206     * Structure to hold MCPS confirm data.
207     */
208     McpsConfirm_t McpsConfirm;
209     /*
210     * Structure to hold MLME confirm data.
211     */
212     MlmeConfirm_t MlmeConfirm;
213     /*
214     * Structure to hold MLME indication data.
215     */
216     MlmeIndication_t MlmeIndication;
217     /*
218     * Holds the current rx window slot
219     */
220     LoRaMacRxSlot_t RxSlot;
221     /*
222     * LoRaMac tx/rx operation state
223     */
224     LoRaMacFlags_t MacFlags;
225     /*
226     * Data structure indicating if a request is allowed or not.
227     */
228     LoRaMacRequestHandling_t AllowRequests;
229     /*
230     * Cycle timer for Type 0 Rejoin requests
231     */
232     TimerEvent_t Rejoin0CycleTimer;
233     /*
234     * Cycle timer for Type 1 Rejoin requests
235     */
236     TimerEvent_t Rejoin1CycleTimer;
237     /*
238     * Cycle timer for Rejoin requests trigged by ForceRejoinReq MAC command
239     */
240     TimerEvent_t ForceRejoinReqCycleTimer;
241     /*
242     * Time of Type 0 Rejoin requests cycles
243     */
244     TimerTime_t Rejoin0CycleTime;
245     /*
246     * Time of Type 1 Rejoin requests cycles
247     */
248     TimerTime_t Rejoin1CycleTime;
249     /*
250     * Time of Force Rejoin requests cycles
251     */
252     TimerTime_t ForceRejonCycleTime;
253     /*
254     * Duty cycle wait time
255     */
256     TimerTime_t DutyCycleWaitTime;
257     /*
258      * Start time of the response timeout
259      */
260     TimerTime_t ResponseTimeoutStartTime;
261     /*
262      * Timer required to simulate an ABP join like an OTAA join
263      */
264     TimerEvent_t AbpJoinPendingTimer;
265     /*
266      * Buffer containing the MAC layer commands
267      */
268     uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH];
269 }LoRaMacCtx_t;
270 
271 /*
272  * Module context.
273  */
274 static LoRaMacCtx_t MacCtx;
275 
276 static LoRaMacNvmData_t Nvm;
277 
278 static Band_t RegionBands[REGION_NVM_MAX_NB_BANDS];
279 
280 /*!
281  * Defines the LoRaMac radio events status
282  */
283 typedef union uLoRaMacRadioEvents
284 {
285     uint32_t Value;
286     struct sEvents
287     {
288         uint32_t RxProcessPending : 1;
289         uint32_t RxTimeout        : 1;
290         uint32_t RxError          : 1;
291         uint32_t TxTimeout        : 1;
292         uint32_t RxDone           : 1;
293         uint32_t TxDone           : 1;
294     }Events;
295 }LoRaMacRadioEvents_t;
296 
297 /*!
298  * LoRaMac radio events status
299  */
300 LoRaMacRadioEvents_t LoRaMacRadioEvents = { .Value = 0 };
301 
302 /*!
303  * \brief Function to be executed on Radio Tx Done event
304  */
305 static void OnRadioTxDone( void );
306 
307 /*!
308  * \brief This function prepares the MAC to abort the execution of function
309  *        OnRadioRxDone in case of a reception error.
310  */
311 static void PrepareRxDoneAbort( void );
312 
313 /*!
314  * \brief Function to be executed on Radio Rx Done event
315  */
316 static void OnRadioRxDone( uint8_t* payload, uint16_t size, int16_t rssi, int8_t snr );
317 
318 /*!
319  * \brief Function executed on Radio Tx Timeout event
320  */
321 static void OnRadioTxTimeout( void );
322 
323 /*!
324  * \brief Function executed on Radio Rx error event
325  */
326 static void OnRadioRxError( void );
327 
328 /*!
329  * \brief Function executed on Radio Rx Timeout event
330  */
331 static void OnRadioRxTimeout( void );
332 
333 /*!
334  * \brief Function executed on duty cycle delayed Tx  timer event
335  */
336 static void OnTxDelayedTimerEvent( void* context );
337 
338 /*!
339  * \brief Function executed on first Rx window timer event
340  */
341 static void OnRxWindow1TimerEvent( void* context );
342 
343 /*!
344  * \brief Function executed on second Rx window timer event
345  */
346 static void OnRxWindow2TimerEvent( void* context );
347 
348 /*!
349  * \brief Function executed on Rejoin Type 0 cycle timer event
350  */
351 static void OnRejoin0CycleTimerEvent( void* context );
352 
353 /*!
354  * \brief Function executed on Rejoin Type 0 cycle timer event
355  */
356 static void OnRejoin1CycleTimerEvent( void* context );
357 
358 /*!
359  * \brief Function executed on Rejoin Type 0 or 2 cycle timer event
360  *        which was requested by a ForceRejoinReq MAC command.
361  */
362 static void OnForceRejoinReqCycleTimerEvent( void* context );
363 
364 /*!
365  * \brief Function executed on AckTimeout timer event
366  */
367 static void OnRetransmitTimeoutTimerEvent( void* context );
368 
369 /*!
370  * Computes next 32 bit downlink counter value and determines the frame counter ID.
371  *
372  * \param[IN]     addrID                - Address identifier
373  * \param[IN]     fType                 - Frame type
374  * \param[IN]     macMsg                - Data message object, holding the current 16 bit transmitted frame counter
375  * \param[IN]     lrWanVersion          - LoRaWAN version
376  * \param[OUT]    fCntID                - Frame counter identifier
377  * \param[OUT]    currentDown           - Current downlink counter value
378  *
379  * \retval                              - Status of the operation
380  */
381 static LoRaMacCryptoStatus_t GetFCntDown( AddressIdentifier_t addrID, FType_t fType, LoRaMacMessageData_t* macMsg, Version_t lrWanVersion,
382                                           FCntIdentifier_t* fCntID, uint32_t* currentDown );
383 
384 /*!
385  * \brief Switches the device class
386  *
387  * \param [IN] deviceClass Device class to switch to
388  */
389 static LoRaMacStatus_t SwitchClass( DeviceClass_t deviceClass );
390 
391 /*!
392  * \brief Gets the maximum application payload length in the absence of the optional FOpt field.
393  *
394  * \param [IN] datarate        Current datarate
395  *
396  * \retval                    Max length
397  */
398 static uint8_t GetMaxAppPayloadWithoutFOptsLength( int8_t datarate );
399 
400 /*!
401  * \brief Validates if the payload fits into the frame, taking the datarate
402  *        into account.
403  *
404  * \details Refer to chapter 4.3.2 of the LoRaWAN specification, v1.0
405  *
406  * \param lenN Length of the application payload. The length depends on the
407  *             datarate and is region specific
408  *
409  * \param datarate Current datarate
410  *
411  * \param fOptsLen Length of the fOpts field
412  *
413  * \retval [false: payload does not fit into the frame, true: payload fits into
414  *          the frame]
415  */
416 static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen );
417 
418 /*!
419  * \brief Decodes MAC commands in the fOpts field and in the payload
420  *
421  * \param [IN] payload      A pointer to the payload
422  * \param [IN] macIndex     The index of the payload where the MAC commands start
423  * \param [IN] commandsSize The size of the MAC commands
424  * \param [IN] snr          The SNR value  of the frame
425  * \param [IN] rxSlot       The RX slot where the frame was received
426  */
427 static void ProcessMacCommands( uint8_t* payload, uint8_t macIndex, uint8_t commandsSize, int8_t snr, LoRaMacRxSlot_t rxSlot );
428 
429 /*!
430  * \brief LoRaMAC layer generic send frame
431  *
432  * \param [IN] macHdr      MAC header field
433  * \param [IN] fPort       MAC payload port
434  * \param [IN] fBuffer     MAC data buffer to be sent
435  * \param [IN] fBufferSize MAC data buffer size
436  * \retval status          Status of the operation.
437  */
438 LoRaMacStatus_t Send( LoRaMacHeader_t* macHdr, uint8_t fPort, void* fBuffer, uint16_t fBufferSize );
439 
440 /*!
441  * \brief LoRaMAC layer send join/rejoin request
442  *
443  * \param [IN] joinReqType Type of join-request or rejoin
444  *
445  * \retval status          Status of the operation.
446  */
447 LoRaMacStatus_t SendReJoinReq( JoinReqIdentifier_t joinReqType );
448 
449 /*!
450  * \brief LoRaMAC layer frame buffer initialization
451  *
452  * \param [IN] macHdr      MAC header field
453  * \param [IN] fCtrl       MAC frame control field
454  * \param [IN] fOpts       MAC commands buffer
455  * \param [IN] fPort       MAC payload port
456  * \param [IN] fBuffer     MAC data buffer to be sent
457  * \param [IN] fBufferSize MAC data buffer size
458  * \retval status          Status of the operation.
459  */
460 LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t* macHdr, LoRaMacFrameCtrl_t* fCtrl, uint8_t fPort, void* fBuffer, uint16_t fBufferSize );
461 
462 /*
463  * \brief Schedules the frame according to the duty cycle
464  *
465  * \param [IN] allowDelayedTx When set to true, the a frame will be delayed,
466  *                            the duty cycle restriction is active
467  * \retval Status of the operation
468  */
469 static LoRaMacStatus_t ScheduleTx( bool allowDelayedTx );
470 
471 /*
472  * \brief Secures the current processed frame ( TxMsg )
473  * \param[IN]     txDr      Data rate used for the transmission
474  * \param[IN]     txCh      Index of the channel used for the transmission
475  * \retval status           Status of the operation
476  */
477 static LoRaMacStatus_t SecureFrame( uint8_t txDr, uint8_t txCh );
478 
479 /*
480  * \brief Calculates the aggregated back off time.
481  */
482 static void CalculateBackOff( void );
483 
484 /*
485  * \brief Function to remove pending MAC commands
486  *
487  * \param [IN] rxSlot     The RX slot on which the frame was received
488  * \param [IN] fCtrl      The frame control field of the received frame
489  * \param [IN] request    The request type
490  */
491 static void RemoveMacCommands( LoRaMacRxSlot_t rxSlot, LoRaMacFrameCtrl_t fCtrl, Mcps_t request );
492 
493 /*!
494  * \brief LoRaMAC layer prepared frame buffer transmission with channel specification
495  *
496  * \remark PrepareFrame must be called at least once before calling this
497  *         function.
498  *
499  * \param [IN] channel     Channel to transmit on
500  * \retval status          Status of the operation.
501  */
502 LoRaMacStatus_t SendFrameOnChannel( uint8_t channel );
503 
504 /*!
505  * \brief Sets the radio in continuous transmission mode
506  *
507  * \remark Uses the radio parameters set on the previous transmission.
508  *
509  * \param [IN] timeout     Time in seconds while the radio is kept in continuous wave mode
510  * \param [IN] frequency   RF frequency to be set.
511  * \param [IN] power       RF output power to be set.
512  * \retval status          Status of the operation.
513  */
514 LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout, uint32_t frequency, uint8_t power );
515 
516 /*!
517  * \brief Converts a second based Rejoin Cycle base in the from timer module required format.
518  *
519  * \param [IN]  rejoinCycleTime     The time in second
520  * \param [out] timeInMiliSec       The time in second
521  * \retval status          Status of the operation.
522  */
523 static bool ConvertRejoinCycleTime( uint32_t rejoinCycleTime, uint32_t* timeInMiliSec );
524 
525 /*!
526  * \brief Resets MAC specific parameters to default
527  *
528  * \param [in] isRejoin             Reset activation or not.
529  */
530 static void ResetMacParameters( bool isRejoin );
531 
532 /*!
533  * \brief Checks if it's required to send a Rejoin (Type 0) request.
534  *
535  * \retval [false: Rejoin not required, true: Rejoin required]
536  */
537 static bool IsReJoin0Required( void );
538 
539 /*!
540  * \brief Initializes and opens the reception window
541  *
542  * \param [IN] rxTimer  Window timer to be topped.
543  * \param [IN] rxConfig Window parameters to be setup
544  */
545 static void RxWindowSetup( TimerEvent_t* rxTimer, RxConfigParams_t* rxConfig );
546 
547 /*!
548  * \brief Opens up a continuous RX C window. This is used for
549  *        class c devices.
550  */
551 static void OpenContinuousRxCWindow( void );
552 
553 /*!
554  * \brief   Returns a pointer to the internal contexts structure.
555  *
556  * \retval  void Points to a structure containing all contexts
557  */
558 static LoRaMacNvmData_t* GetNvmData( void );
559 
560 /*!
561  * \brief   Restoring of internal module contexts
562  *
563  * \details This function allows to restore module contexts by a given pointer.
564  *
565  *
566  * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
567  *          returns are:
568  *          \ref LORAMAC_STATUS_OK,
569  *          \ref LORAMAC_STATUS_PARAMETER_INVALID,
570  */
571 static LoRaMacStatus_t RestoreNvmData( LoRaMacNvmData_t* contexts );
572 
573 /*!
574  * \brief   Determines the frame type
575  *
576  * \param [IN] macMsg Data message object
577  *
578  * \param [OUT] fType Frame type
579  *
580  * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
581  *          returns are:
582  *          \ref LORAMAC_STATUS_OK,
583  *          \ref LORAMAC_STATUS_PARAMETER_INVALID,
584  */
585 LoRaMacStatus_t DetermineFrameType( LoRaMacMessageData_t* macMsg, FType_t* fType );
586 
587 /*!
588  * \brief Verifies, if the retransmission counter has reached the limit
589  *
590  * \param [IN] counter Current retransmission counter
591  * \param [IN] limit Retransmission counter limit
592  *
593  * \retval Returns true if the number of retransmissions have reached the limit.
594  */
595 static bool CheckRetrans( uint8_t counter, uint8_t limit );
596 
597 /*!
598  * \brief Checks if the retransmission should be stopped in case of a unconfirmed uplink
599  *
600  * \retval Returns true if it should be stopped.
601  */
602 static bool CheckRetransUnconfirmedUplink( void );
603 
604 /*!
605  * \brief Checks if the retransmission should be stopped in case of a confirmed uplink
606  *
607  * \retval Returns true it should be stopped.
608  */
609 static bool CheckRetransConfirmedUplink( void );
610 
611 /*!
612  * \brief Increases the ADR ack counter. Takes the maximum
613  *        value into account.
614  *
615  * \param [IN] counter Current counter value.
616  *
617  * \retval Returns the next counter value.
618  */
619 static uint32_t IncreaseAdrAckCounter( uint32_t counter );
620 
621 /*!
622  * \brief Stops the uplink retransmission
623  *
624  * \retval Returns true if successful.
625  */
626 static bool StopRetransmission( void );
627 
628 /*!
629  * \brief Calls the MacProcessNotify callback to indicate that a LoRaMacProcess call is pending
630  */
631 static void OnMacProcessNotify( void );
632 
633 /*!
634  * \brief Calls the callback to indicate that a context changed
635  */
636 static void CallNvmDataChangeCallback( uint16_t notifyFlags );
637 
638 /*!
639  * \brief Verifies if a request is pending currently
640  *
641  * \retval 1: Request pending, 0: request not pending
642  */
643 static uint8_t IsRequestPending( void );
644 
645 /*!
646  * \brief Enabled the possibility to perform requests
647  *
648  * \param [IN] requestState Request permission state
649  */
650 static void LoRaMacEnableRequests( LoRaMacRequestHandling_t requestState );
651 
652 /*!
653  * \brief This function verifies if a RX abort occurred
654  */
655 static void LoRaMacCheckForRxAbort( void );
656 
657 /*!
658  * \brief This function verifies if a beacon acquisition MLME
659  *        request was pending
660  *
661  * \retval 1: Request pending, 0: no request pending
662  */
663 static uint8_t LoRaMacCheckForBeaconAcquisition( void );
664 
665 /*!
666  * \brief Returns true, if the device must apply the minium datarate
667  *
668  * \param [IN] adr ADR status bit
669  *
670  * \param [IN] activation Activation type of the device
671  *
672  * \param [IN] datarateChanged Set to true, if the datarate was changed
673  *                             with the LinkAdrReq.
674  */
675 static bool CheckForMinimumAbpDatarate( bool adr, ActivationType_t activation, bool datarateChanged );
676 
677 /*!
678  * \brief This function handles join request
679  */
680 static void LoRaMacHandleMlmeRequest( void );
681 
682 /*!
683  * \brief This function handles mcps request
684  */
685 static void LoRaMacHandleMcpsRequest( void );
686 
687 /*!
688  * \brief This function handles callback events for requests
689  */
690 static void LoRaMacHandleRequestEvents( void );
691 
692 /*!
693  * \brief This function handles callback events for indications
694  */
695 static void LoRaMacHandleIndicationEvents( void );
696 
697 /*!
698  * \brief This function handles events for re-join procedure
699  */
700 static void LoRaMacHandleRejoinEvents( void );
701 
702 /*!
703  * \brief This function handles callback events for NVM updates
704  *
705  * \param [IN] nvmData Data structure containing NVM data.
706  */
707 static void LoRaMacHandleNvm( LoRaMacNvmData_t* nvmData );
708 
709 /*!
710  * \brief This function verifies if the response timeout has been elapsed. If
711  *        this is the case, the status of Nvm.MacGroup1.SrvAckRequested will be
712  *        reset.
713  *
714  * \param [IN] timeoutInMs Timeout [ms] to be compared.
715  *
716  * \param [IN] startTimeInMs Start time [ms] used as a base. If set to 0,
717  *                           no comparison will be done.
718  *
719  * \retval true: Response timeout has been elapsed, false: Response timeout
720  *         has not been elapsed or startTimeInMs is 0.
721  */
722 static bool LoRaMacHandleResponseTimeout( TimerTime_t timeoutInMs, TimerTime_t startTimeInMs );
723 
724 /*!
725  * Structure used to store the radio Tx event data
726  */
727 struct
728 {
729     TimerTime_t CurTime;
730 }TxDoneParams;
731 
732 /*!
733  * Structure used to store the radio Rx event data
734  */
735 struct
736 {
737     TimerTime_t LastRxDone;
738     uint8_t *Payload;
739     uint16_t Size;
740     int16_t Rssi;
741     int8_t Snr;
742 }RxDoneParams;
743 
OnRadioTxDone(void)744 static void OnRadioTxDone( void )
745 {
746     TxDoneParams.CurTime = TimerGetCurrentTime( );
747     MacCtx.LastTxSysTime = SysTimeGet( );
748 
749     LoRaMacRadioEvents.Events.TxDone = 1;
750 
751     OnMacProcessNotify( );
752 }
753 
OnRadioRxDone(uint8_t * payload,uint16_t size,int16_t rssi,int8_t snr)754 static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
755 {
756     RxDoneParams.LastRxDone = TimerGetCurrentTime( );
757     RxDoneParams.Payload = payload;
758     RxDoneParams.Size = size;
759     RxDoneParams.Rssi = rssi;
760     RxDoneParams.Snr = snr;
761 
762     LoRaMacRadioEvents.Events.RxDone = 1;
763     LoRaMacRadioEvents.Events.RxProcessPending = 1;
764 
765     OnMacProcessNotify( );
766 }
767 
OnRadioTxTimeout(void)768 static void OnRadioTxTimeout( void )
769 {
770     LoRaMacRadioEvents.Events.TxTimeout = 1;
771 
772     OnMacProcessNotify( );
773 }
774 
OnRadioRxError(void)775 static void OnRadioRxError( void )
776 {
777     LoRaMacRadioEvents.Events.RxError = 1;
778 
779     OnMacProcessNotify( );
780 }
781 
OnRadioRxTimeout(void)782 static void OnRadioRxTimeout( void )
783 {
784     LoRaMacRadioEvents.Events.RxTimeout = 1;
785 
786     OnMacProcessNotify( );
787 }
788 
UpdateRxSlotIdleState(void)789 static void UpdateRxSlotIdleState( void )
790 {
791     if( Nvm.MacGroup2.DeviceClass != CLASS_C )
792     {
793         MacCtx.RxSlot = RX_SLOT_NONE;
794     }
795     else
796     {
797         MacCtx.RxSlot = RX_SLOT_WIN_CLASS_C;
798     }
799 }
800 
ProcessRadioTxDone(void)801 static void ProcessRadioTxDone( void )
802 {
803     GetPhyParams_t getPhy;
804     PhyParam_t phyParam;
805     SetBandTxDoneParams_t txDone;
806 
807     if( Nvm.MacGroup2.DeviceClass != CLASS_C )
808     {
809         Radio.Sleep( );
810     }
811 
812     // Setup timers
813     CRITICAL_SECTION_BEGIN( );
814     uint32_t offset = TimerGetCurrentTime( ) - TxDoneParams.CurTime;
815     TimerSetValue( &MacCtx.RxWindowTimer1, MacCtx.RxWindow1Delay - offset );
816     TimerStart( &MacCtx.RxWindowTimer1 );
817     TimerSetValue( &MacCtx.RxWindowTimer2, MacCtx.RxWindow2Delay - offset );
818     TimerStart( &MacCtx.RxWindowTimer2 );
819     CRITICAL_SECTION_END( );
820 
821     if( MacCtx.NodeAckRequested == true )
822     {
823         getPhy.Attribute = PHY_RETRANSMIT_TIMEOUT;
824         phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
825         TimerSetValue( &MacCtx.RetransmitTimeoutTimer, MacCtx.RxWindow2Delay + phyParam.Value );
826         TimerStart( &MacCtx.RetransmitTimeoutTimer );
827     }
828     else
829     {
830         // Transmission successful, setup status directly
831         MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
832     }
833 
834     // Update Aggregated last tx done time
835     Nvm.MacGroup1.LastTxDoneTime = TxDoneParams.CurTime;
836 
837     // Update last tx done time for the current channel
838     txDone.Channel = MacCtx.Channel;
839     txDone.LastTxDoneTime = TxDoneParams.CurTime;
840     txDone.ElapsedTimeSinceStartUp = SysTimeSub( SysTimeGetMcuTime( ), Nvm.MacGroup2.InitializationTime );
841     txDone.LastTxAirTime = MacCtx.TxTimeOnAir;
842     txDone.Joined  = true;
843     if( Nvm.MacGroup2.NetworkActivation == ACTIVATION_TYPE_NONE )
844     {
845         txDone.Joined  = false;
846     }
847 
848     RegionSetBandTxDone( Nvm.MacGroup2.Region, &txDone );
849 }
850 
PrepareRxDoneAbort(void)851 static void PrepareRxDoneAbort( void )
852 {
853     MacCtx.MacState |= LORAMAC_RX_ABORT;
854 
855     if( MacCtx.NodeAckRequested == true )
856     {
857         OnRetransmitTimeoutTimerEvent( NULL );
858     }
859 
860     MacCtx.MacFlags.Bits.McpsInd = 1;
861     MacCtx.MacFlags.Bits.MacDone = 1;
862 
863     UpdateRxSlotIdleState( );
864 }
865 
ProcessRadioRxDone(void)866 static void ProcessRadioRxDone( void )
867 {
868     LoRaMacHeader_t macHdr;
869     ApplyCFListParams_t applyCFList;
870     GetPhyParams_t getPhy;
871     PhyParam_t phyParam;
872     LoRaMacCryptoStatus_t macCryptoStatus = LORAMAC_CRYPTO_ERROR;
873 
874     LoRaMacMessageData_t macMsgData;
875     LoRaMacMessageJoinAccept_t macMsgJoinAccept;
876     uint8_t *payload = RxDoneParams.Payload;
877     uint16_t size = RxDoneParams.Size;
878     int16_t rssi = RxDoneParams.Rssi;
879     int8_t snr = RxDoneParams.Snr;
880 
881     uint8_t pktHeaderLen = 0;
882 
883     uint32_t downLinkCounter = 0;
884     uint32_t address = Nvm.MacGroup2.DevAddr;
885     uint8_t multicast = 0;
886     AddressIdentifier_t addrID = UNICAST_DEV_ADDR;
887     FCntIdentifier_t fCntID;
888     uint8_t macCmdPayload[2] = { 0 };
889     Mlme_t joinType = MLME_JOIN;
890 
891     LoRaMacRadioEvents.Events.RxProcessPending = 0;
892 
893     MacCtx.McpsConfirm.AckReceived = false;
894     MacCtx.McpsIndication.Rssi = rssi;
895     MacCtx.McpsIndication.Snr = snr;
896     MacCtx.McpsIndication.RxSlot = MacCtx.RxSlot;
897     MacCtx.McpsIndication.Port = 0;
898     MacCtx.McpsIndication.Multicast = 0;
899     MacCtx.McpsIndication.IsUplinkTxPending = 0;
900     MacCtx.McpsIndication.Buffer = NULL;
901     MacCtx.McpsIndication.BufferSize = 0;
902     MacCtx.McpsIndication.RxData = false;
903     MacCtx.McpsIndication.AckReceived = false;
904     MacCtx.McpsIndication.DownLinkCounter = 0;
905     MacCtx.McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
906     MacCtx.McpsIndication.DevAddress = 0;
907     MacCtx.McpsIndication.DeviceTimeAnsReceived = false;
908     MacCtx.McpsIndication.ResponseTimeout = 0;
909 
910     Radio.Sleep( );
911 
912     if( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_1 )
913     {
914         TimerStop( &MacCtx.RxWindowTimer2 );
915     }
916 
917     // This function must be called even if we are not in class b mode yet.
918     if( LoRaMacClassBRxBeacon( payload, size ) == true )
919     {
920         MacCtx.MlmeIndication.BeaconInfo.Rssi = rssi;
921         MacCtx.MlmeIndication.BeaconInfo.Snr = snr;
922         return;
923     }
924     // Check if we expect a ping or a multicast slot.
925     if( Nvm.MacGroup2.DeviceClass == CLASS_B )
926     {
927         if( LoRaMacClassBIsPingExpected( ) == true )
928         {
929             LoRaMacClassBSetPingSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
930             LoRaMacClassBPingSlotTimerEvent( NULL );
931             MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_B_PING_SLOT;
932         }
933         else if( LoRaMacClassBIsMulticastExpected( ) == true )
934         {
935             LoRaMacClassBSetMulticastSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
936             LoRaMacClassBMulticastSlotTimerEvent( NULL );
937             MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_B_MULTICAST_SLOT;
938         }
939     }
940 
941     // Abort on empty radio frames
942     if( size == 0 )
943     {
944         MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
945         PrepareRxDoneAbort( );
946         return;
947     }
948 
949     macHdr.Value = payload[pktHeaderLen++];
950 
951     // Accept frames of LoRaWAN Major Version 1 only
952     if( macHdr.Bits.Major != 0 )
953     {
954         MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
955         PrepareRxDoneAbort( );
956         return;
957     }
958 
959     switch( macHdr.Bits.MType )
960     {
961         case FRAME_TYPE_JOIN_ACCEPT:
962         {
963             // Check if the received frame size is valid
964             if( size < LORAMAC_JOIN_ACCEPT_FRAME_MIN_SIZE )
965             {
966                 MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
967                 PrepareRxDoneAbort( );
968                 return;
969             }
970             macMsgJoinAccept.Buffer = payload;
971             macMsgJoinAccept.BufSize = size;
972 
973             // Abort in case if the device is already joined and no rejoin request is ongoing.
974             if( ( Nvm.MacGroup2.NetworkActivation != ACTIVATION_TYPE_NONE ) && ( Nvm.MacGroup2.IsRejoinAcceptPending == false ) )
975             {
976                 MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
977                 PrepareRxDoneAbort( );
978                 return;
979             }
980             macCryptoStatus = LoRaMacCryptoHandleJoinAccept( JOIN_REQ, SecureElementGetJoinEui( ), &macMsgJoinAccept );
981 
982             if( LORAMAC_CRYPTO_SUCCESS != macCryptoStatus )
983             {
984                 macCryptoStatus = LoRaMacCryptoHandleJoinAccept( REJOIN_REQ_0, SecureElementGetJoinEui( ), &macMsgJoinAccept );
985                 joinType = MLME_REJOIN_0;
986             }
987 
988             if( LORAMAC_CRYPTO_SUCCESS != macCryptoStatus )
989             {
990                 macCryptoStatus = LoRaMacCryptoHandleJoinAccept( REJOIN_REQ_1, SecureElementGetJoinEui( ), &macMsgJoinAccept );
991                 joinType = MLME_REJOIN_1;
992             }
993 
994             if( LORAMAC_CRYPTO_SUCCESS != macCryptoStatus )
995             {
996                 macCryptoStatus = LoRaMacCryptoHandleJoinAccept( REJOIN_REQ_2, SecureElementGetJoinEui( ), &macMsgJoinAccept );
997                 joinType = MLME_REJOIN_2;
998             }
999 
1000             if( LORAMAC_CRYPTO_SUCCESS == macCryptoStatus )
1001             {
1002                 VerifyParams_t verifyRxDr;
1003 
1004                 if( macMsgJoinAccept.DLSettings.Bits.RX2DataRate != 0x0F )
1005                 {
1006                     verifyRxDr.DatarateParams.Datarate = macMsgJoinAccept.DLSettings.Bits.RX2DataRate;
1007                     verifyRxDr.DatarateParams.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
1008                     if( RegionVerify( Nvm.MacGroup2.Region, &verifyRxDr, PHY_RX_DR ) == false )
1009                     {
1010                         // MLME handling
1011                         if( LoRaMacConfirmQueueIsCmdActive( MLME_JOIN ) == true )
1012                         {
1013                             LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL, MLME_JOIN );
1014                         }
1015                         break;
1016                     }
1017                 }
1018 
1019                 // Network ID
1020                 Nvm.MacGroup2.NetID = ( uint32_t ) macMsgJoinAccept.NetID[0];
1021                 Nvm.MacGroup2.NetID |= ( ( uint32_t ) macMsgJoinAccept.NetID[1] << 8 );
1022                 Nvm.MacGroup2.NetID |= ( ( uint32_t ) macMsgJoinAccept.NetID[2] << 16 );
1023 
1024                 // Device Address
1025                 Nvm.MacGroup2.DevAddr = macMsgJoinAccept.DevAddr;
1026 
1027                 // DLSettings
1028                 Nvm.MacGroup2.MacParams.Rx1DrOffset = macMsgJoinAccept.DLSettings.Bits.RX1DRoffset;
1029 
1030                 // Verify if we shall assign the new datarate
1031                 if( macMsgJoinAccept.DLSettings.Bits.RX2DataRate != 0x0F )
1032                 {
1033                     Nvm.MacGroup2.MacParams.Rx2Channel.Datarate = macMsgJoinAccept.DLSettings.Bits.RX2DataRate;
1034                     Nvm.MacGroup2.MacParams.RxCChannel.Datarate = macMsgJoinAccept.DLSettings.Bits.RX2DataRate;
1035                 }
1036 
1037                 // RxDelay
1038                 Nvm.MacGroup2.MacParams.ReceiveDelay1 = macMsgJoinAccept.RxDelay;
1039                 if( Nvm.MacGroup2.MacParams.ReceiveDelay1 == 0 )
1040                 {
1041                     Nvm.MacGroup2.MacParams.ReceiveDelay1 = 1;
1042                 }
1043                 Nvm.MacGroup2.MacParams.ReceiveDelay1 *= 1000;
1044                 Nvm.MacGroup2.MacParams.ReceiveDelay2 = Nvm.MacGroup2.MacParams.ReceiveDelay1 + 1000;
1045 
1046                 // Reset NbTrans to default value
1047                 Nvm.MacGroup2.MacParams.ChannelsNbTrans = 1;
1048 
1049                 // Is Networkserver's LoRaWAN Version before 1.1.0 ?
1050                 if( macMsgJoinAccept.DLSettings.Bits.OptNeg == 0 )
1051                 {
1052                     Nvm.MacGroup2.Version.Value = LORAMAC_FALLBACK_VERSION;
1053                 }
1054                 else
1055                 {
1056                     Nvm.MacGroup2.Version.Value = LORAMAC_VERSION;
1057                 }
1058 
1059                 // Apply CF list
1060                 applyCFList.Payload = macMsgJoinAccept.CFList;
1061                 // Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC
1062                 applyCFList.Size = size - 17;
1063                 // Apply the last tx channel
1064                 applyCFList.JoinChannel = MacCtx.Channel;
1065 
1066                 RegionApplyCFList( Nvm.MacGroup2.Region, &applyCFList );
1067 
1068                 Nvm.MacGroup2.NetworkActivation = ACTIVATION_TYPE_OTAA;
1069 
1070                 // Add a RekeyInd MAC command to confirm the security key update.
1071                 if( Nvm.MacGroup2.Version.Fields.Minor >= 1 )
1072                 {
1073                     Nvm.MacGroup1.RekeyIndUplinksCounter = 0;
1074                     macCmdPayload[0] = Nvm.MacGroup2.Version.Fields.Minor;
1075                     LoRaMacCommandsAddCmd( MOTE_MAC_REKEY_IND, macCmdPayload, 1 );
1076                 }
1077 
1078                 // MLME handling
1079                 if( LoRaMacConfirmQueueIsCmdActive( joinType ) == true )
1080                 {
1081                     LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, joinType );
1082                 }
1083 
1084                 // Rejoin handling
1085                 if( Nvm.MacGroup2.IsRejoinAcceptPending == true )
1086                 {
1087                     Nvm.MacGroup2.IsRejoinAcceptPending = false;
1088 
1089                     // Stop in any case the ForceRejoinReqCycleTimer
1090                     TimerStop( &MacCtx.ForceRejoinReqCycleTimer );
1091                 }
1092 
1093                 // Reset MAC parameters for specific re-join types
1094                 if( ( joinType == MLME_REJOIN_0 ) || ( joinType == MLME_REJOIN_1 ) )
1095                 {
1096                     ResetMacParameters( true );
1097                 }
1098             }
1099             else
1100             {
1101                 // MLME handling
1102                 if( LoRaMacConfirmQueueIsCmdActive( MLME_JOIN ) == true )
1103                 {
1104                     LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL, MLME_JOIN );
1105                 }
1106             }
1107             break;
1108         }
1109         case FRAME_TYPE_DATA_CONFIRMED_DOWN:
1110             MacCtx.McpsIndication.McpsIndication = MCPS_CONFIRMED;
1111             // Intentional fall through
1112         case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
1113             // Check if the received payload size is valid
1114             getPhy.UplinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
1115             getPhy.Datarate = MacCtx.McpsIndication.RxDatarate;
1116             getPhy.Attribute = PHY_MAX_PAYLOAD;
1117             phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
1118             if( ( MAX( 0, ( int16_t )( ( int16_t ) size - ( int16_t ) LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE ) ) > ( int16_t )phyParam.Value ) ||
1119                 ( size < LORAMAC_FRAME_PAYLOAD_MIN_SIZE ) )
1120             {
1121                 MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
1122                 PrepareRxDoneAbort( );
1123                 return;
1124             }
1125             macMsgData.Buffer = payload;
1126             macMsgData.BufSize = size;
1127             macMsgData.FRMPayload = MacCtx.RxPayload;
1128             macMsgData.FRMPayloadSize = LORAMAC_PHY_MAXPAYLOAD;
1129 
1130             if( LORAMAC_PARSER_SUCCESS != LoRaMacParserData( &macMsgData ) )
1131             {
1132                 MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
1133                 PrepareRxDoneAbort( );
1134                 return;
1135             }
1136 
1137             // Handle Class B
1138             // Check if we expect a ping or a multicast slot.
1139             if( Nvm.MacGroup2.DeviceClass == CLASS_B )
1140             {
1141                 if( LoRaMacClassBIsPingExpected( ) == true )
1142                 {
1143                     LoRaMacClassBSetPingSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
1144                     LoRaMacClassBPingSlotTimerEvent( NULL );
1145                     MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_B_PING_SLOT;
1146                     LoRaMacClassBSetFPendingBit( macMsgData.FHDR.DevAddr, ( uint8_t ) macMsgData.FHDR.FCtrl.Bits.FPending );
1147                 }
1148                 else if( LoRaMacClassBIsMulticastExpected( ) == true )
1149                 {
1150                     LoRaMacClassBSetMulticastSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
1151                     LoRaMacClassBMulticastSlotTimerEvent( NULL );
1152                     MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_B_MULTICAST_SLOT;
1153                     LoRaMacClassBSetFPendingBit( macMsgData.FHDR.DevAddr, ( uint8_t ) macMsgData.FHDR.FCtrl.Bits.FPending );
1154                 }
1155             }
1156 
1157             // Store device address
1158             MacCtx.McpsIndication.DevAddress = macMsgData.FHDR.DevAddr;
1159 
1160             FType_t fType;
1161             if( LORAMAC_STATUS_OK != DetermineFrameType( &macMsgData, &fType ) )
1162             {
1163                 MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
1164                 PrepareRxDoneAbort( );
1165                 return;
1166             }
1167 
1168             //Check if it is a multicast message
1169             multicast = 0;
1170             downLinkCounter = 0;
1171             for( uint8_t i = 0; i < LORAMAC_MAX_MC_CTX; i++ )
1172             {
1173                 if( ( Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.Address == macMsgData.FHDR.DevAddr ) &&
1174                     ( Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.IsEnabled == true ) )
1175                 {
1176                     multicast = 1;
1177                     addrID = Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.GroupID;
1178                     downLinkCounter = *( Nvm.MacGroup2.MulticastChannelList[i].DownLinkCounter );
1179                     address = Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.Address;
1180                     if( Nvm.MacGroup2.DeviceClass == CLASS_C )
1181                     {
1182                         MacCtx.McpsIndication.RxSlot = RX_SLOT_WIN_CLASS_C_MULTICAST;
1183                     }
1184                     break;
1185                 }
1186             }
1187 
1188             // Filter messages according to multicast downlink exceptions
1189             if( ( multicast == 1 ) && ( ( fType != FRAME_TYPE_D ) ||
1190                                         ( macMsgData.FHDR.FCtrl.Bits.Ack != 0 ) ||
1191                                         ( macMsgData.FHDR.FCtrl.Bits.AdrAckReq != 0 ) ) )
1192             {
1193                 MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
1194                 PrepareRxDoneAbort( );
1195                 return;
1196             }
1197 
1198             // Get downlink frame counter value
1199             macCryptoStatus = GetFCntDown( addrID, fType, &macMsgData, Nvm.MacGroup2.Version, &fCntID, &downLinkCounter );
1200             if( macCryptoStatus != LORAMAC_CRYPTO_SUCCESS )
1201             {
1202                 if( macCryptoStatus == LORAMAC_CRYPTO_FAIL_FCNT_DUPLICATED )
1203                 {
1204                     // Catch the case of repeated downlink frame counter
1205                     MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
1206                 }
1207                 else
1208                 {
1209                     // Other errors
1210                     MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
1211                 }
1212                 MacCtx.McpsIndication.DownLinkCounter = downLinkCounter;
1213                 PrepareRxDoneAbort( );
1214                 return;
1215             }
1216 
1217             macCryptoStatus = LoRaMacCryptoUnsecureMessage( addrID, address, fCntID, downLinkCounter, &macMsgData );
1218             if( macCryptoStatus != LORAMAC_CRYPTO_SUCCESS )
1219             {
1220                 if( macCryptoStatus == LORAMAC_CRYPTO_FAIL_ADDRESS )
1221                 {
1222                     // We are not the destination of this frame.
1223                     MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
1224                 }
1225                 else
1226                 {
1227                     // MIC calculation fail
1228                     MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
1229                 }
1230                 PrepareRxDoneAbort( );
1231                 return;
1232             }
1233 
1234             MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
1235             MacCtx.McpsIndication.Multicast = multicast;
1236             MacCtx.McpsIndication.Buffer = NULL;
1237             MacCtx.McpsIndication.BufferSize = 0;
1238             MacCtx.McpsIndication.DownLinkCounter = downLinkCounter;
1239             MacCtx.McpsIndication.AckReceived = macMsgData.FHDR.FCtrl.Bits.Ack;
1240 
1241             MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
1242             MacCtx.McpsConfirm.AckReceived = macMsgData.FHDR.FCtrl.Bits.Ack;
1243 
1244             // Reset ADR ACK Counter only, when RX1 or RX2 slot
1245             if( ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_1 ) ||
1246                 ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_2 ) )
1247             {
1248                 Nvm.MacGroup1.AdrAckCounter = 0;
1249                 Nvm.MacGroup2.DownlinkReceived = true;
1250             }
1251 
1252             // MCPS Indication and ack requested handling
1253             if( multicast == 1 )
1254             {
1255                 MacCtx.McpsIndication.McpsIndication = MCPS_MULTICAST;
1256             }
1257             else
1258             {
1259                 if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN )
1260                 {
1261                     Nvm.MacGroup1.SrvAckRequested = true;
1262                     if( Nvm.MacGroup2.Version.Fields.Minor == 0 )
1263                     {
1264                         Nvm.MacGroup1.LastRxMic = macMsgData.MIC;
1265                     }
1266                     MacCtx.McpsIndication.McpsIndication = MCPS_CONFIRMED;
1267 
1268                     // Handle response timeout for class c and class b downlinks
1269                     if( ( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_1 ) &&
1270                         ( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_2 ) )
1271                     {
1272                         // Calculate timeout
1273                         MacCtx.McpsIndication.ResponseTimeout = REGION_COMMON_CLASS_B_C_RESP_TIMEOUT;
1274                         MacCtx.ResponseTimeoutStartTime = RxDoneParams.LastRxDone;
1275                     }
1276                 }
1277                 else
1278                 {
1279                     Nvm.MacGroup1.SrvAckRequested = false;
1280                     MacCtx.McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
1281                 }
1282             }
1283 
1284             // Set the pending status
1285             if( ( ( ( Nvm.MacGroup1.SrvAckRequested == true ) || ( macMsgData.FHDR.FCtrl.Bits.FPending > 0 ) ) && ( Nvm.MacGroup2.DeviceClass == CLASS_A ) ) ||
1286                 ( MacCtx.McpsIndication.ResponseTimeout > 0 ) )
1287             {
1288                 MacCtx.McpsIndication.IsUplinkTxPending = 1;
1289             }
1290 
1291             RemoveMacCommands( MacCtx.McpsIndication.RxSlot, macMsgData.FHDR.FCtrl, MacCtx.McpsConfirm.McpsRequest );
1292 
1293             switch( fType )
1294             {
1295                 case FRAME_TYPE_A:
1296                 {  /* +----------+------+-------+--------------+
1297                     * | FOptsLen | Fopt | FPort |  FRMPayload  |
1298                     * +----------+------+-------+--------------+
1299                     * |    > 0   |   X  |  > 0  |       X      |
1300                     * +----------+------+-------+--------------+
1301                     */
1302 
1303                     // Decode MAC commands in FOpts field
1304                     ProcessMacCommands( macMsgData.FHDR.FOpts, 0, macMsgData.FHDR.FCtrl.Bits.FOptsLen, snr, MacCtx.McpsIndication.RxSlot );
1305                     MacCtx.McpsIndication.Port = macMsgData.FPort;
1306                     MacCtx.McpsIndication.Buffer = macMsgData.FRMPayload;
1307                     MacCtx.McpsIndication.BufferSize = macMsgData.FRMPayloadSize;
1308                     MacCtx.McpsIndication.RxData = true;
1309                     break;
1310                 }
1311                 case FRAME_TYPE_B:
1312                 {  /* +----------+------+-------+--------------+
1313                     * | FOptsLen | Fopt | FPort |  FRMPayload  |
1314                     * +----------+------+-------+--------------+
1315                     * |    > 0   |   X  |   -   |       -      |
1316                     * +----------+------+-------+--------------+
1317                     */
1318 
1319                     // Decode MAC commands in FOpts field
1320                     ProcessMacCommands( macMsgData.FHDR.FOpts, 0, macMsgData.FHDR.FCtrl.Bits.FOptsLen, snr, MacCtx.McpsIndication.RxSlot );
1321                     MacCtx.McpsIndication.Port = macMsgData.FPort;
1322                     break;
1323                 }
1324                 case FRAME_TYPE_C:
1325                 {  /* +----------+------+-------+--------------+
1326                     * | FOptsLen | Fopt | FPort |  FRMPayload  |
1327                     * +----------+------+-------+--------------+
1328                     * |    = 0   |   -  |  = 0  | MAC commands |
1329                     * +----------+------+-------+--------------+
1330                     */
1331 
1332                     // Decode MAC commands in FRMPayload
1333                     ProcessMacCommands( macMsgData.FRMPayload, 0, macMsgData.FRMPayloadSize, snr, MacCtx.McpsIndication.RxSlot );
1334                     MacCtx.McpsIndication.Port = macMsgData.FPort;
1335                     break;
1336                 }
1337                 case FRAME_TYPE_D:
1338                 {  /* +----------+------+-------+--------------+
1339                     * | FOptsLen | Fopt | FPort |  FRMPayload  |
1340                     * +----------+------+-------+--------------+
1341                     * |    = 0   |   -  |  > 0  |       X      |
1342                     * +----------+------+-------+--------------+
1343                     */
1344 
1345                     // No MAC commands just application payload
1346                     MacCtx.McpsIndication.Port = macMsgData.FPort;
1347                     MacCtx.McpsIndication.Buffer = macMsgData.FRMPayload;
1348                     MacCtx.McpsIndication.BufferSize = macMsgData.FRMPayloadSize;
1349                     MacCtx.McpsIndication.RxData = true;
1350                     break;
1351                 }
1352                 default:
1353                     MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
1354                     PrepareRxDoneAbort( );
1355                     break;
1356             }
1357 
1358             // Rejoin handling
1359             if( Nvm.MacGroup2.IsRejoinAcceptPending == true )
1360             {
1361                 Nvm.MacGroup2.IsRejoinAcceptPending = false;
1362 
1363                 // Stop in any case the ForceRejoinReqCycleTimer
1364                 TimerStop( &MacCtx.ForceRejoinReqCycleTimer );
1365 
1366                 // If the rejoin was trigged by MLME, set confirmation status
1367                 if( MacCtx.MacFlags.Bits.MlmeReq == 1 )
1368                 {
1369                     MacCtx.MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
1370                 }
1371             }
1372 
1373             if( ( macMsgData.FPort == LORAMAC_CERT_FPORT ) && (Nvm.MacGroup2.IsCertPortOn == false ) )
1374             { // Do not notify the upper layer of data reception on FPort LORAMAC_CERT_FPORT if the port
1375               // handling is disabled.
1376                 MacCtx.McpsIndication.Port = macMsgData.FPort;
1377                 MacCtx.McpsIndication.Buffer = NULL;
1378                 MacCtx.McpsIndication.BufferSize = 0;
1379                 MacCtx.McpsIndication.RxData = false;
1380             }
1381 
1382             // Provide always an indication, skip the callback to the user application,
1383             // in case of a confirmed downlink retransmission.
1384             MacCtx.MacFlags.Bits.McpsInd = 1;
1385 
1386             break;
1387         case FRAME_TYPE_PROPRIETARY:
1388             memcpy1( MacCtx.RxPayload, &payload[pktHeaderLen], size - pktHeaderLen );
1389 
1390             MacCtx.McpsIndication.McpsIndication = MCPS_PROPRIETARY;
1391             MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
1392             MacCtx.McpsIndication.Buffer = MacCtx.RxPayload;
1393             MacCtx.McpsIndication.BufferSize = size - pktHeaderLen;
1394 
1395             MacCtx.MacFlags.Bits.McpsInd = 1;
1396             break;
1397         default:
1398             MacCtx.McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
1399             PrepareRxDoneAbort( );
1400             break;
1401     }
1402 
1403     // Verify if we need to disable the RetransmitTimeoutTimer
1404     // Only aplies if downlink is received on Rx1 or Rx2 windows.
1405     if( ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_1 ) ||
1406         ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_2 ) )
1407     {
1408         if( MacCtx.NodeAckRequested == true )
1409         {
1410             if( MacCtx.McpsConfirm.AckReceived == true )
1411             {
1412                 OnRetransmitTimeoutTimerEvent( NULL );
1413             }
1414         }
1415     }
1416 
1417     if( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_CLASS_C )
1418     {
1419         MacCtx.MacFlags.Bits.MacDone = 1;
1420     }
1421 
1422     UpdateRxSlotIdleState( );
1423 }
1424 
ProcessRadioTxTimeout(void)1425 static void ProcessRadioTxTimeout( void )
1426 {
1427     if( Nvm.MacGroup2.DeviceClass != CLASS_C )
1428     {
1429         Radio.Sleep( );
1430     }
1431     UpdateRxSlotIdleState( );
1432 
1433     MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
1434     LoRaMacConfirmQueueSetStatusCmn( LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT );
1435     if( MacCtx.NodeAckRequested == true )
1436     {
1437         MacCtx.RetransmitTimeoutRetry = true;
1438     }
1439     MacCtx.MacFlags.Bits.MacDone = 1;
1440 }
1441 
HandleRadioRxErrorTimeout(LoRaMacEventInfoStatus_t rx1EventInfoStatus,LoRaMacEventInfoStatus_t rx2EventInfoStatus)1442 static void HandleRadioRxErrorTimeout( LoRaMacEventInfoStatus_t rx1EventInfoStatus, LoRaMacEventInfoStatus_t rx2EventInfoStatus )
1443 {
1444     bool classBRx = false;
1445 
1446     if( Nvm.MacGroup2.DeviceClass != CLASS_C )
1447     {
1448         Radio.Sleep( );
1449     }
1450 
1451     if( LoRaMacClassBIsBeaconExpected( ) == true )
1452     {
1453         LoRaMacClassBSetBeaconState( BEACON_STATE_TIMEOUT );
1454         LoRaMacClassBBeaconTimerEvent( NULL );
1455         classBRx = true;
1456     }
1457     if( Nvm.MacGroup2.DeviceClass == CLASS_B )
1458     {
1459         if( LoRaMacClassBIsPingExpected( ) == true )
1460         {
1461             LoRaMacClassBSetPingSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
1462             LoRaMacClassBPingSlotTimerEvent( NULL );
1463             classBRx = true;
1464         }
1465         if( LoRaMacClassBIsMulticastExpected( ) == true )
1466         {
1467             LoRaMacClassBSetMulticastSlotState( PINGSLOT_STATE_CALC_PING_OFFSET );
1468             LoRaMacClassBMulticastSlotTimerEvent( NULL );
1469             classBRx = true;
1470         }
1471     }
1472 
1473     if( classBRx == false )
1474     {
1475         if( MacCtx.RxSlot == RX_SLOT_WIN_1 )
1476         {
1477             if( MacCtx.NodeAckRequested == true )
1478             {
1479                 MacCtx.McpsConfirm.Status = rx1EventInfoStatus;
1480             }
1481             LoRaMacConfirmQueueSetStatusCmn( rx1EventInfoStatus );
1482 
1483             if( TimerGetElapsedTime( Nvm.MacGroup1.LastTxDoneTime ) >= MacCtx.RxWindow2Delay )
1484             {
1485                 TimerStop( &MacCtx.RxWindowTimer2 );
1486                 MacCtx.MacFlags.Bits.MacDone = 1;
1487             }
1488         }
1489         else
1490         {
1491             if( MacCtx.NodeAckRequested == true )
1492             {
1493                 MacCtx.McpsConfirm.Status = rx2EventInfoStatus;
1494             }
1495             LoRaMacConfirmQueueSetStatusCmn( rx2EventInfoStatus );
1496             MacCtx.MacFlags.Bits.MacDone = 1;
1497         }
1498     }
1499 
1500     UpdateRxSlotIdleState( );
1501 }
1502 
ProcessRadioRxError(void)1503 static void ProcessRadioRxError( void )
1504 {
1505     HandleRadioRxErrorTimeout( LORAMAC_EVENT_INFO_STATUS_RX1_ERROR, LORAMAC_EVENT_INFO_STATUS_RX2_ERROR );
1506 }
1507 
ProcessRadioRxTimeout(void)1508 static void ProcessRadioRxTimeout( void )
1509 {
1510     HandleRadioRxErrorTimeout( LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT, LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT );
1511 }
1512 
LoRaMacHandleIrqEvents(void)1513 static void LoRaMacHandleIrqEvents( void )
1514 {
1515     LoRaMacRadioEvents_t events;
1516 
1517     CRITICAL_SECTION_BEGIN( );
1518     events = LoRaMacRadioEvents;
1519     LoRaMacRadioEvents.Value = 0;
1520     CRITICAL_SECTION_END( );
1521 
1522     if( events.Value != 0 )
1523     {
1524         if( events.Events.TxDone == 1 )
1525         {
1526             ProcessRadioTxDone( );
1527         }
1528         if( events.Events.RxDone == 1 )
1529         {
1530             ProcessRadioRxDone( );
1531         }
1532         if( events.Events.TxTimeout == 1 )
1533         {
1534             ProcessRadioTxTimeout( );
1535         }
1536         if( events.Events.RxError == 1 )
1537         {
1538             ProcessRadioRxError( );
1539         }
1540         if( events.Events.RxTimeout == 1 )
1541         {
1542             ProcessRadioRxTimeout( );
1543         }
1544     }
1545 }
1546 
LoRaMacIsBusy(void)1547 bool LoRaMacIsBusy( void )
1548 {
1549     if( MacCtx.MacState == LORAMAC_STOPPED )
1550     {
1551         return false;
1552     }
1553 
1554     if( LoRaMacRadioEvents.Events.RxProcessPending == 1 )
1555     {
1556         return true;
1557     }
1558 
1559     if( ( MacCtx.MacState == LORAMAC_IDLE ) &&
1560         ( MacCtx.AllowRequests == LORAMAC_REQUEST_HANDLING_ON ) )
1561     {
1562         return false;
1563     }
1564     return true;
1565 }
1566 
1567 
LoRaMacEnableRequests(LoRaMacRequestHandling_t requestState)1568 static void LoRaMacEnableRequests( LoRaMacRequestHandling_t requestState )
1569 {
1570     MacCtx.AllowRequests = requestState;
1571 }
1572 
LoRaMacHandleRequestEvents(void)1573 static void LoRaMacHandleRequestEvents( void )
1574 {
1575     // Handle events
1576     LoRaMacFlags_t reqEvents = MacCtx.MacFlags;
1577 
1578     if( MacCtx.MacState == LORAMAC_IDLE )
1579     {
1580         // Update event bits
1581         if( MacCtx.MacFlags.Bits.McpsReq == 1 )
1582         {
1583             MacCtx.MacFlags.Bits.McpsReq = 0;
1584         }
1585 
1586         if( MacCtx.MacFlags.Bits.MlmeReq == 1 )
1587         {
1588             MacCtx.MacFlags.Bits.MlmeReq = 0;
1589         }
1590 
1591         // Allow requests again
1592         LoRaMacEnableRequests( LORAMAC_REQUEST_HANDLING_ON );
1593 
1594         // Handle callbacks
1595         if( reqEvents.Bits.McpsReq == 1 )
1596         {
1597             MacCtx.MacPrimitives->MacMcpsConfirm( &MacCtx.McpsConfirm );
1598         }
1599 
1600         if( reqEvents.Bits.MlmeReq == 1 )
1601         {
1602             LoRaMacConfirmQueueHandleCb( &MacCtx.MlmeConfirm );
1603             if( LoRaMacConfirmQueueGetCnt( ) > 0 )
1604             {
1605                 MacCtx.MacFlags.Bits.MlmeReq = 1;
1606             }
1607         }
1608 
1609         // Start beaconing again
1610         LoRaMacClassBResumeBeaconing( );
1611 
1612         // Procedure done. Reset variables.
1613         MacCtx.MacFlags.Bits.MacDone = 0;
1614     }
1615 }
1616 
LoRaMacHandleIndicationEvents(void)1617 static void LoRaMacHandleIndicationEvents( void )
1618 {
1619     // Handle MLME indication
1620     if( MacCtx.MacFlags.Bits.MlmeInd == 1 )
1621     {
1622         MacCtx.MacFlags.Bits.MlmeInd = 0;
1623         MacCtx.MacPrimitives->MacMlmeIndication( &MacCtx.MlmeIndication );
1624     }
1625 
1626     // Handle MCPS indication
1627     if( MacCtx.MacFlags.Bits.McpsInd == 1 )
1628     {
1629         MacCtx.MacFlags.Bits.McpsInd = 0;
1630         MacCtx.MacPrimitives->MacMcpsIndication( &MacCtx.McpsIndication );
1631     }
1632 }
1633 
LoRaMacHandleRejoinEvents(void)1634 static void LoRaMacHandleRejoinEvents( void )
1635 {
1636     if( MacCtx.MacState == LORAMAC_IDLE )
1637     {
1638         MlmeReq_t mlmeReq;
1639         if( IsReJoin0Required( ) == true )
1640         {
1641             mlmeReq.Type = MLME_REJOIN_0;
1642             LoRaMacMlmeRequest( &mlmeReq );
1643         }
1644         else if( Nvm.MacGroup2.IsRejoin0RequestQueued == true )
1645         {
1646             mlmeReq.Type = MLME_REJOIN_0;
1647             if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK )
1648             {
1649                 Nvm.MacGroup2.IsRejoin0RequestQueued = false;
1650             }
1651         }
1652         else if( Nvm.MacGroup2.IsRejoin1RequestQueued == true )
1653         {
1654             mlmeReq.Type = MLME_REJOIN_1;
1655             if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK )
1656             {
1657                 Nvm.MacGroup2.IsRejoin1RequestQueued = false;
1658             }
1659         }
1660         else if( Nvm.MacGroup2.IsRejoin2RequestQueued == true )
1661         {
1662             mlmeReq.Type = MLME_REJOIN_2;
1663             if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK )
1664             {
1665                 Nvm.MacGroup2.IsRejoin2RequestQueued = false;
1666             }
1667         }
1668     }
1669 }
1670 
LoRaMacHandleMcpsRequest(void)1671 static void LoRaMacHandleMcpsRequest( void )
1672 {
1673     // Handle MCPS uplinks
1674     if( MacCtx.MacFlags.Bits.McpsReq == 1 )
1675     {
1676         bool stopRetransmission = false;
1677         bool waitForRetransmission = false;
1678 
1679         if( ( MacCtx.McpsConfirm.McpsRequest == MCPS_UNCONFIRMED ) ||
1680             ( MacCtx.McpsConfirm.McpsRequest == MCPS_PROPRIETARY ) )
1681         {
1682             stopRetransmission = CheckRetransUnconfirmedUplink( );
1683         }
1684         else if( MacCtx.McpsConfirm.McpsRequest == MCPS_CONFIRMED )
1685         {
1686             if( MacCtx.RetransmitTimeoutRetry == true )
1687             {
1688                 stopRetransmission = CheckRetransConfirmedUplink( );
1689             }
1690             else
1691             {
1692                 waitForRetransmission = true;
1693             }
1694         }
1695 
1696         if( stopRetransmission == true )
1697         {// Stop retransmission
1698             TimerStop( &MacCtx.TxDelayedTimer );
1699             MacCtx.MacState &= ~LORAMAC_TX_DELAYED;
1700             StopRetransmission( );
1701         }
1702         else if( waitForRetransmission == false )
1703         {// Arrange further retransmission
1704             MacCtx.MacFlags.Bits.MacDone = 0;
1705             // Reset the state of the AckTimeout
1706             MacCtx.RetransmitTimeoutRetry = false;
1707             // Sends the same frame again
1708             OnTxDelayedTimerEvent( NULL );
1709         }
1710     }
1711 }
1712 
LoRaMacHandleMlmeRequest(void)1713 static void LoRaMacHandleMlmeRequest( void )
1714 {
1715     // Handle join request
1716     if( MacCtx.MacFlags.Bits.MlmeReq == 1 )
1717     {
1718         if( ( LoRaMacConfirmQueueIsCmdActive( MLME_JOIN ) == true ) ||
1719             ( LoRaMacConfirmQueueIsCmdActive( MLME_REJOIN_0 ) == true ) ||
1720             ( LoRaMacConfirmQueueIsCmdActive( MLME_REJOIN_1 ) == true ) ||
1721             ( LoRaMacConfirmQueueIsCmdActive( MLME_REJOIN_2 ) == true ) )
1722         {
1723             MacCtx.ChannelsNbTransCounter = 0;
1724             MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
1725         }
1726         else if( LoRaMacConfirmQueueIsCmdActive( MLME_TXCW ) == true )
1727         {
1728             MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
1729         }
1730     }
1731 }
1732 
LoRaMacCheckForBeaconAcquisition(void)1733 static uint8_t LoRaMacCheckForBeaconAcquisition( void )
1734 {
1735     if( ( LoRaMacConfirmQueueIsCmdActive( MLME_BEACON_ACQUISITION ) == true ) &&
1736         ( MacCtx.MacFlags.Bits.McpsReq == 0 ) )
1737     {
1738         if( MacCtx.MacFlags.Bits.MlmeReq == 1 )
1739         {
1740             MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
1741             return 0x01;
1742         }
1743     }
1744     return 0x00;
1745 }
1746 
CheckForMinimumAbpDatarate(bool adr,ActivationType_t activation,bool datarateChanged)1747 static bool CheckForMinimumAbpDatarate( bool adr, ActivationType_t activation, bool datarateChanged )
1748 {
1749     if( ( adr == true ) &&
1750         ( activation == ACTIVATION_TYPE_ABP ) &&
1751         ( datarateChanged == false ) )
1752     {
1753         return true;
1754     }
1755     return false;
1756 }
1757 
LoRaMacCheckForRxAbort(void)1758 static void LoRaMacCheckForRxAbort( void )
1759 {
1760     // A error occurs during receiving
1761     if( ( MacCtx.MacState & LORAMAC_RX_ABORT ) == LORAMAC_RX_ABORT )
1762     {
1763         MacCtx.MacState &= ~LORAMAC_RX_ABORT;
1764         MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
1765     }
1766 }
1767 
LoRaMacHandleNvm(LoRaMacNvmData_t * nvmData)1768 static void LoRaMacHandleNvm( LoRaMacNvmData_t* nvmData )
1769 {
1770     uint32_t crc = 0;
1771     uint16_t notifyFlags = LORAMAC_NVM_NOTIFY_FLAG_NONE;
1772 
1773     if( MacCtx.MacState != LORAMAC_IDLE )
1774     {
1775         return;
1776     }
1777 
1778     // Crypto
1779     crc = Crc32( ( uint8_t* ) &nvmData->Crypto, sizeof( nvmData->Crypto ) -
1780                                                 sizeof( nvmData->Crypto.Crc32 ) );
1781     if( crc != nvmData->Crypto.Crc32 )
1782     {
1783         nvmData->Crypto.Crc32 = crc;
1784         notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_CRYPTO;
1785     }
1786 
1787     // MacGroup1
1788     crc = Crc32( ( uint8_t* ) &nvmData->MacGroup1, sizeof( nvmData->MacGroup1 ) -
1789                                                    sizeof( nvmData->MacGroup1.Crc32 ) );
1790     if( crc != nvmData->MacGroup1.Crc32 )
1791     {
1792         nvmData->MacGroup1.Crc32 = crc;
1793         notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_MAC_GROUP1;
1794     }
1795 
1796     // MacGroup2
1797     crc = Crc32( ( uint8_t* ) &nvmData->MacGroup2, sizeof( nvmData->MacGroup2 ) -
1798                                                    sizeof( nvmData->MacGroup2.Crc32 ) );
1799     if( crc != nvmData->MacGroup2.Crc32 )
1800     {
1801         nvmData->MacGroup2.Crc32 = crc;
1802         notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_MAC_GROUP2;
1803     }
1804 
1805     // Secure Element
1806     crc = Crc32( ( uint8_t* ) &nvmData->SecureElement, sizeof( nvmData->SecureElement ) -
1807                                                        sizeof( nvmData->SecureElement.Crc32 ) );
1808     if( crc != nvmData->SecureElement.Crc32 )
1809     {
1810         nvmData->SecureElement.Crc32 = crc;
1811         notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_SECURE_ELEMENT;
1812     }
1813 
1814     // Region
1815     crc = Crc32( ( uint8_t* ) &nvmData->RegionGroup1, sizeof( nvmData->RegionGroup1 ) -
1816                                                 sizeof( nvmData->RegionGroup1.Crc32 ) );
1817     if( crc != nvmData->RegionGroup1.Crc32 )
1818     {
1819         nvmData->RegionGroup1.Crc32 = crc;
1820         notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_REGION_GROUP1;
1821     }
1822 
1823     crc = Crc32( ( uint8_t* ) &nvmData->RegionGroup2, sizeof( nvmData->RegionGroup2 ) -
1824                                                 sizeof( nvmData->RegionGroup2.Crc32 ) );
1825     if( crc != nvmData->RegionGroup2.Crc32 )
1826     {
1827         nvmData->RegionGroup2.Crc32 = crc;
1828         notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_REGION_GROUP2;
1829     }
1830 
1831     // ClassB
1832     crc = Crc32( ( uint8_t* ) &nvmData->ClassB, sizeof( nvmData->ClassB ) -
1833                                                 sizeof( nvmData->ClassB.Crc32 ) );
1834     if( crc != nvmData->ClassB.Crc32 )
1835     {
1836         nvmData->ClassB.Crc32 = crc;
1837         notifyFlags |= LORAMAC_NVM_NOTIFY_FLAG_CLASS_B;
1838     }
1839 
1840     CallNvmDataChangeCallback( notifyFlags );
1841 }
1842 
LoRaMacHandleResponseTimeout(TimerTime_t timeoutInMs,TimerTime_t startTimeInMs)1843 static bool LoRaMacHandleResponseTimeout( TimerTime_t timeoutInMs, TimerTime_t startTimeInMs )
1844 {
1845     if( startTimeInMs != 0 )
1846     {
1847         TimerTime_t elapsedTime = TimerGetElapsedTime( startTimeInMs );
1848         if( elapsedTime > timeoutInMs )
1849         {
1850             Nvm.MacGroup1.SrvAckRequested = false;
1851             return true;
1852         }
1853     }
1854     return false;
1855 }
1856 
LoRaMacProcess(void)1857 void LoRaMacProcess( void )
1858 {
1859     uint8_t noTx = false;
1860 
1861     LoRaMacHandleIrqEvents( );
1862     LoRaMacClassBProcess( );
1863 
1864     // MAC proceeded a state and is ready to check
1865     if( MacCtx.MacFlags.Bits.MacDone == 1 )
1866     {
1867         LoRaMacEnableRequests( LORAMAC_REQUEST_HANDLING_OFF );
1868         LoRaMacCheckForRxAbort( );
1869 
1870         // An error occurs during transmitting
1871         if( IsRequestPending( ) > 0 )
1872         {
1873             noTx |= LoRaMacCheckForBeaconAcquisition( );
1874         }
1875 
1876         if( noTx == 0x00 )
1877         {
1878             LoRaMacHandleMlmeRequest( );
1879             LoRaMacHandleMcpsRequest( );
1880         }
1881         LoRaMacHandleRequestEvents( );
1882         LoRaMacEnableRequests( LORAMAC_REQUEST_HANDLING_ON );
1883         MacCtx.MacFlags.Bits.NvmHandle = 1;
1884     }
1885     LoRaMacHandleIndicationEvents( );
1886     LoRaMacHandleRejoinEvents( );
1887 
1888     if( MacCtx.RxSlot == RX_SLOT_WIN_CLASS_C )
1889     {
1890         OpenContinuousRxCWindow( );
1891     }
1892     if( MacCtx.MacFlags.Bits.NvmHandle == 1 )
1893     {
1894         MacCtx.MacFlags.Bits.NvmHandle = 0;
1895         LoRaMacHandleNvm( &Nvm );
1896     }
1897 }
1898 
OnTxDelayedTimerEvent(void * context)1899 static void OnTxDelayedTimerEvent( void* context )
1900 {
1901     TimerStop( &MacCtx.TxDelayedTimer );
1902     MacCtx.MacState &= ~LORAMAC_TX_DELAYED;
1903 
1904     if( LoRaMacHandleResponseTimeout( REGION_COMMON_CLASS_B_C_RESP_TIMEOUT,
1905                                       MacCtx.ResponseTimeoutStartTime ) == true )
1906     {
1907         // Skip retransmission
1908         return;
1909     }
1910 
1911     // Schedule frame, allow delayed frame transmissions
1912     switch( ScheduleTx( true ) )
1913     {
1914         case LORAMAC_STATUS_OK:
1915         case LORAMAC_STATUS_DUTYCYCLE_RESTRICTED:
1916         {
1917             break;
1918         }
1919         default:
1920         {
1921             // Stop retransmission attempt
1922             MacCtx.McpsConfirm.Datarate = Nvm.MacGroup1.ChannelsDatarate;
1923             MacCtx.McpsConfirm.NbTrans = MacCtx.ChannelsNbTransCounter;
1924             MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR;
1925             LoRaMacConfirmQueueSetStatusCmn( LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR );
1926             StopRetransmission( );
1927             break;
1928         }
1929     }
1930 }
1931 
OnRxWindow1TimerEvent(void * context)1932 static void OnRxWindow1TimerEvent( void* context )
1933 {
1934     MacCtx.RxWindow1Config.Channel = MacCtx.Channel;
1935     MacCtx.RxWindow1Config.DrOffset = Nvm.MacGroup2.MacParams.Rx1DrOffset;
1936     MacCtx.RxWindow1Config.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
1937     MacCtx.RxWindow1Config.RxContinuous = false;
1938     MacCtx.RxWindow1Config.RxSlot = RX_SLOT_WIN_1;
1939     MacCtx.RxWindow1Config.NetworkActivation = Nvm.MacGroup2.NetworkActivation;
1940 
1941     RxWindowSetup( &MacCtx.RxWindowTimer1, &MacCtx.RxWindow1Config );
1942 }
1943 
OnRxWindow2TimerEvent(void * context)1944 static void OnRxWindow2TimerEvent( void* context )
1945 {
1946     // Check if we are processing Rx1 window.
1947     // If yes, we don't setup the Rx2 window.
1948     if( MacCtx.RxSlot == RX_SLOT_WIN_1 )
1949     {
1950         return;
1951     }
1952     MacCtx.RxWindow2Config.Channel = MacCtx.Channel;
1953     MacCtx.RxWindow2Config.Frequency = Nvm.MacGroup2.MacParams.Rx2Channel.Frequency;
1954     MacCtx.RxWindow2Config.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
1955     MacCtx.RxWindow2Config.RxContinuous = false;
1956     MacCtx.RxWindow2Config.RxSlot = RX_SLOT_WIN_2;
1957     MacCtx.RxWindow2Config.NetworkActivation = Nvm.MacGroup2.NetworkActivation;
1958 
1959     RxWindowSetup( &MacCtx.RxWindowTimer2, &MacCtx.RxWindow2Config );
1960 }
1961 
OnRetransmitTimeoutTimerEvent(void * context)1962 static void OnRetransmitTimeoutTimerEvent( void* context )
1963 {
1964     TimerStop( &MacCtx.RetransmitTimeoutTimer );
1965 
1966     if( MacCtx.NodeAckRequested == true )
1967     {
1968         MacCtx.RetransmitTimeoutRetry = true;
1969     }
1970     OnMacProcessNotify( );
1971 }
1972 
GetFCntDown(AddressIdentifier_t addrID,FType_t fType,LoRaMacMessageData_t * macMsg,Version_t lrWanVersion,FCntIdentifier_t * fCntID,uint32_t * currentDown)1973 static LoRaMacCryptoStatus_t GetFCntDown( AddressIdentifier_t addrID, FType_t fType, LoRaMacMessageData_t* macMsg, Version_t lrWanVersion,
1974                                           FCntIdentifier_t* fCntID, uint32_t* currentDown )
1975 {
1976     if( ( macMsg == NULL ) || ( fCntID == NULL ) ||
1977         ( currentDown == NULL ) )
1978     {
1979         return LORAMAC_CRYPTO_ERROR_NPE;
1980     }
1981 
1982     // Determine the frame counter identifier and choose counter from FCntList
1983     switch( addrID )
1984     {
1985         case UNICAST_DEV_ADDR:
1986             if( lrWanVersion.Fields.Minor == 1 )
1987             {
1988                 if( ( fType == FRAME_TYPE_A ) || ( fType == FRAME_TYPE_D ) )
1989                 {
1990                     *fCntID = A_FCNT_DOWN;
1991                 }
1992                 else
1993                 {
1994                     *fCntID = N_FCNT_DOWN;
1995                 }
1996             }
1997             else
1998             { // For LoRaWAN 1.0.X
1999                 *fCntID = FCNT_DOWN;
2000             }
2001             break;
2002         case MULTICAST_0_ADDR:
2003             *fCntID = MC_FCNT_DOWN_0;
2004             break;
2005         case MULTICAST_1_ADDR:
2006             *fCntID = MC_FCNT_DOWN_1;
2007             break;
2008         case MULTICAST_2_ADDR:
2009             *fCntID = MC_FCNT_DOWN_2;
2010             break;
2011         case MULTICAST_3_ADDR:
2012             *fCntID = MC_FCNT_DOWN_3;
2013             break;
2014         default:
2015             return LORAMAC_CRYPTO_FAIL_FCNT_ID;
2016     }
2017 
2018     return LoRaMacCryptoGetFCntDown( *fCntID, macMsg->FHDR.FCnt, currentDown );
2019 }
2020 
SwitchClass(DeviceClass_t deviceClass)2021 static LoRaMacStatus_t SwitchClass( DeviceClass_t deviceClass )
2022 {
2023     LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
2024 
2025     switch( Nvm.MacGroup2.DeviceClass )
2026     {
2027         case CLASS_A:
2028         {
2029             if( deviceClass == CLASS_A )
2030             {
2031                 // Revert back RxC parameters
2032                 Nvm.MacGroup2.MacParams.RxCChannel = Nvm.MacGroup2.MacParams.Rx2Channel;
2033 
2034                 status = LORAMAC_STATUS_OK;
2035             }
2036             if( deviceClass == CLASS_B )
2037             {
2038                 status = LoRaMacClassBSwitchClass( deviceClass );
2039                 if( status == LORAMAC_STATUS_OK )
2040                 {
2041                     Nvm.MacGroup2.DeviceClass = deviceClass;
2042                 }
2043             }
2044 
2045             if( deviceClass == CLASS_C )
2046             {
2047                 Nvm.MacGroup2.DeviceClass = deviceClass;
2048 
2049                 MacCtx.RxWindowCConfig = MacCtx.RxWindow2Config;
2050                 MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C;
2051 
2052                 for( int8_t i = 0; i < LORAMAC_MAX_MC_CTX; i++ )
2053                 {
2054                     if( ( Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.IsEnabled == true ) &&
2055                         ( Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.RxParams.Class == CLASS_C ) )
2056                     {
2057                         Nvm.MacGroup2.MacParams.RxCChannel.Frequency = Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.RxParams.Params.ClassC.Frequency;
2058                         Nvm.MacGroup2.MacParams.RxCChannel.Datarate = Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.RxParams.Params.ClassC.Datarate;
2059 
2060                         MacCtx.RxWindowCConfig.Channel = MacCtx.Channel;
2061                         MacCtx.RxWindowCConfig.Frequency = Nvm.MacGroup2.MacParams.RxCChannel.Frequency;
2062                         MacCtx.RxWindowCConfig.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
2063                         MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C_MULTICAST;
2064                         MacCtx.RxWindowCConfig.RxContinuous = true;
2065                         break;
2066                     }
2067                 }
2068 
2069                 // Set the NodeAckRequested indicator to default
2070                 MacCtx.NodeAckRequested = false;
2071                 // Set the radio into sleep mode in case we are still in RX mode
2072                 Radio.Sleep( );
2073 
2074                 OpenContinuousRxCWindow( );
2075 
2076                 // Add a DeviceModeInd MAC Command to indicate the network a device mode change.
2077                 if( Nvm.MacGroup2.Version.Fields.Minor >= 1 )
2078                 {
2079                     LoRaMacCommandsAddCmd( MOTE_MAC_DEVICE_MODE_IND, ( uint8_t* )&Nvm.MacGroup2.DeviceClass, 1 );
2080                 }
2081 
2082                 status = LORAMAC_STATUS_OK;
2083             }
2084             break;
2085         }
2086         case CLASS_B:
2087         {
2088             status = LoRaMacClassBSwitchClass( deviceClass );
2089             if( status == LORAMAC_STATUS_OK )
2090             {
2091                 Nvm.MacGroup2.DeviceClass = deviceClass;
2092             }
2093             break;
2094         }
2095         case CLASS_C:
2096         {
2097             if( deviceClass == CLASS_A )
2098             {
2099                 // Reset RxSlot to NONE
2100                 MacCtx.RxSlot = RX_SLOT_NONE;
2101 
2102                 Nvm.MacGroup2.DeviceClass = deviceClass;
2103 
2104                 // Set the radio into sleep to setup a defined state
2105                 Radio.Sleep( );
2106 
2107                 status = LORAMAC_STATUS_OK;
2108 
2109                 // Add a DeviceModeInd MAC Command to indicate the network a device mode change.
2110                 if( Nvm.MacGroup2.Version.Fields.Minor >= 1 )
2111                 {
2112                     LoRaMacCommandsAddCmd( MOTE_MAC_DEVICE_MODE_IND, ( uint8_t* )&Nvm.MacGroup2.DeviceClass, 1 );
2113                 }
2114             }
2115             break;
2116         }
2117     }
2118 
2119     return status;
2120 }
2121 
GetMaxAppPayloadWithoutFOptsLength(int8_t datarate)2122 static uint8_t GetMaxAppPayloadWithoutFOptsLength( int8_t datarate )
2123 {
2124     GetPhyParams_t getPhy;
2125     PhyParam_t phyParam;
2126 
2127     // Setup PHY request
2128     getPhy.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
2129     getPhy.Datarate = datarate;
2130     getPhy.Attribute = PHY_MAX_PAYLOAD;
2131     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
2132 
2133     return phyParam.Value;
2134 }
2135 
ValidatePayloadLength(uint8_t lenN,int8_t datarate,uint8_t fOptsLen)2136 static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen )
2137 {
2138     uint16_t maxN = 0;
2139     uint16_t payloadSize = 0;
2140 
2141     maxN = GetMaxAppPayloadWithoutFOptsLength( datarate );
2142 
2143     // Calculate the resulting payload size
2144     payloadSize = ( lenN + fOptsLen );
2145 
2146     // Validation of the application payload size
2147     if( ( payloadSize <= maxN ) && ( payloadSize <= LORAMAC_PHY_MAXPAYLOAD ) )
2148     {
2149         return true;
2150     }
2151     return false;
2152 }
2153 
ProcessMacCommands(uint8_t * payload,uint8_t macIndex,uint8_t commandsSize,int8_t snr,LoRaMacRxSlot_t rxSlot)2154 static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, int8_t snr, LoRaMacRxSlot_t rxSlot )
2155 {
2156     uint8_t status = 0;
2157     bool adrBlockFound = false;
2158     uint8_t macCmdPayload[2] = { 0x00, 0x00 };
2159     MacCommand_t* macCmd;
2160 
2161     if( ( rxSlot != RX_SLOT_WIN_1 ) && ( rxSlot != RX_SLOT_WIN_2 ) )
2162     {
2163         // Do only parse MAC commands for Class A RX windows
2164         return;
2165     }
2166 
2167     while( macIndex < commandsSize )
2168     {
2169         // Make sure to parse only complete MAC commands
2170         if( ( LoRaMacCommandsGetCmdSize( payload[macIndex] ) + macIndex ) > commandsSize )
2171         {
2172             return;
2173         }
2174 
2175         // Decode Frame MAC commands
2176         switch( payload[macIndex++] )
2177         {
2178             case SRV_MAC_RESET_CONF:
2179             {
2180                 uint8_t serverMinorVersion = payload[macIndex++];
2181 
2182                 // Compare own LoRaWAN Version with server's
2183                 if( Nvm.MacGroup2.Version.Fields.Minor >= serverMinorVersion )
2184                 {
2185                     // If they equal remove the sticky ResetInd MAC-Command.
2186                     if( LoRaMacCommandsGetCmd( MOTE_MAC_RESET_IND, &macCmd) == LORAMAC_COMMANDS_SUCCESS )
2187                     {
2188                         LoRaMacCommandsRemoveCmd( macCmd );
2189                     }
2190                 }
2191                 break;
2192             }
2193             case SRV_MAC_LINK_CHECK_ANS:
2194             {
2195                 if( LoRaMacConfirmQueueIsCmdActive( MLME_LINK_CHECK ) == true )
2196                 {
2197                     LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_LINK_CHECK );
2198                     MacCtx.MlmeConfirm.DemodMargin = payload[macIndex++];
2199                     MacCtx.MlmeConfirm.NbGateways = payload[macIndex++];
2200                 }
2201                 break;
2202             }
2203             case SRV_MAC_LINK_ADR_REQ:
2204             {
2205                 LinkAdrReqParams_t linkAdrReq;
2206                 int8_t linkAdrDatarate = DR_0;
2207                 int8_t linkAdrTxPower = TX_POWER_0;
2208                 uint8_t linkAdrNbRep = 0;
2209                 uint8_t linkAdrNbBytesParsed = 0;
2210 
2211                 // The end node is allowed to process one block of LinkAdrRequests.
2212                 // It must ignore subsequent blocks
2213                 if( adrBlockFound == false )
2214                 {
2215                     adrBlockFound = true;
2216 
2217                     do
2218                     {
2219                         // Fill parameter structure
2220                         linkAdrReq.Payload = &payload[macIndex - 1];
2221                         linkAdrReq.AdrEnabled = Nvm.MacGroup2.AdrCtrlOn;
2222                         linkAdrReq.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
2223                         linkAdrReq.CurrentDatarate = Nvm.MacGroup1.ChannelsDatarate;
2224                         linkAdrReq.CurrentTxPower = Nvm.MacGroup1.ChannelsTxPower;
2225                         linkAdrReq.CurrentNbRep = Nvm.MacGroup2.MacParams.ChannelsNbTrans;
2226                         linkAdrReq.Version = Nvm.MacGroup2.Version;
2227 
2228                         // There is a fundamental difference in reporting the status
2229                         // of the LinkAdrRequests when ADR is on or off. When ADR is on, every
2230                         // LinkAdrAns contains the same value. This does not hold when ADR is off,
2231                         // where every LinkAdrAns requires an individual status.
2232                         if( Nvm.MacGroup2.AdrCtrlOn == true )
2233                         {
2234                             // When ADR is on, the function RegionLinkAdrReq will take care
2235                             // about the parsing and interpretation of the LinkAdrRequest block and
2236                             // it provides one status which shall be applied to every LinkAdrAns
2237                             linkAdrReq.PayloadSize = commandsSize - ( macIndex - 1 );
2238                         }
2239                         else
2240                         {
2241                             // When ADR is off, this function will loop over the individual LinkAdrRequests
2242                             // and will call RegionLinkAdrReq for each individually, as every request
2243                             // requires an individual answer.
2244                             // When ADR is off, the function RegionLinkAdrReq ignores the new values for
2245                             // ChannelsDatarate, ChannelsTxPower and ChannelsNbTrans.
2246                             linkAdrReq.PayloadSize = 5;
2247                         }
2248 
2249                         // Process the ADR requests
2250                         status = RegionLinkAdrReq( Nvm.MacGroup2.Region, &linkAdrReq, &linkAdrDatarate,
2251                                                 &linkAdrTxPower, &linkAdrNbRep, &linkAdrNbBytesParsed );
2252 
2253                         if( ( status & 0x07 ) == 0x07 )
2254                         {
2255                             // Set the status that the datarate has been increased
2256                             if( linkAdrDatarate > Nvm.MacGroup1.ChannelsDatarate )
2257                             {
2258                                 Nvm.MacGroup2.ChannelsDatarateChangedLinkAdrReq = true;
2259                             }
2260                             Nvm.MacGroup1.ChannelsDatarate = linkAdrDatarate;
2261                             Nvm.MacGroup1.ChannelsTxPower = linkAdrTxPower;
2262                             Nvm.MacGroup2.MacParams.ChannelsNbTrans = linkAdrNbRep;
2263                         }
2264 
2265                         // Add the answers to the buffer
2266                         for( uint8_t i = 0; i < ( linkAdrNbBytesParsed / 5 ); i++ )
2267                         {
2268                             LoRaMacCommandsAddCmd( MOTE_MAC_LINK_ADR_ANS, &status, 1 );
2269                         }
2270                         // Update MAC index
2271                         macIndex += linkAdrNbBytesParsed - 1;
2272 
2273                         // Check to prevent invalid access
2274                         if( macIndex >= commandsSize )
2275                             break;
2276 
2277                     } while( payload[macIndex++] == SRV_MAC_LINK_ADR_REQ );
2278 
2279                     if( macIndex < commandsSize )
2280                     {
2281                         // Decrease the index such that it points to the next MAC command
2282                         macIndex--;
2283                     }
2284                 }
2285                 else
2286                 {
2287                     // Increase the index by the MAC command size (without command)
2288                     macIndex += 4;
2289                 }
2290                 break;
2291             }
2292             case SRV_MAC_DUTY_CYCLE_REQ:
2293             {
2294                 Nvm.MacGroup2.MaxDCycle = payload[macIndex++] & 0x0F;
2295                 Nvm.MacGroup2.AggregatedDCycle = 1 << Nvm.MacGroup2.MaxDCycle;
2296                 LoRaMacCommandsAddCmd( MOTE_MAC_DUTY_CYCLE_ANS, macCmdPayload, 0 );
2297                 break;
2298             }
2299             case SRV_MAC_RX_PARAM_SETUP_REQ:
2300             {
2301                 RxParamSetupReqParams_t rxParamSetupReq;
2302                 status = 0x07;
2303 
2304                 rxParamSetupReq.DrOffset = ( payload[macIndex] >> 4 ) & 0x07;
2305                 rxParamSetupReq.Datarate = payload[macIndex] & 0x0F;
2306                 macIndex++;
2307 
2308                 if( rxParamSetupReq.Datarate == 0x0F )
2309                 {
2310                     // Keep the current datarate
2311                     rxParamSetupReq.Datarate = Nvm.MacGroup2.MacParams.Rx2Channel.Datarate;
2312                 }
2313 
2314                 rxParamSetupReq.Frequency = ( uint32_t ) payload[macIndex++];
2315                 rxParamSetupReq.Frequency |= ( uint32_t ) payload[macIndex++] << 8;
2316                 rxParamSetupReq.Frequency |= ( uint32_t ) payload[macIndex++] << 16;
2317                 rxParamSetupReq.Frequency *= 100;
2318 
2319                 // Perform request on region
2320                 status = RegionRxParamSetupReq( Nvm.MacGroup2.Region, &rxParamSetupReq );
2321 
2322                 if( ( status & 0x07 ) == 0x07 )
2323                 {
2324                     Nvm.MacGroup2.MacParams.Rx2Channel.Datarate = rxParamSetupReq.Datarate;
2325                     Nvm.MacGroup2.MacParams.RxCChannel.Datarate = rxParamSetupReq.Datarate;
2326                     Nvm.MacGroup2.MacParams.Rx2Channel.Frequency = rxParamSetupReq.Frequency;
2327                     Nvm.MacGroup2.MacParams.RxCChannel.Frequency = rxParamSetupReq.Frequency;
2328                     Nvm.MacGroup2.MacParams.Rx1DrOffset = rxParamSetupReq.DrOffset;
2329                 }
2330                 macCmdPayload[0] = status;
2331                 LoRaMacCommandsAddCmd( MOTE_MAC_RX_PARAM_SETUP_ANS, macCmdPayload, 1 );
2332                 break;
2333             }
2334             case SRV_MAC_DEV_STATUS_REQ:
2335             {
2336                 uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE;
2337                 if( ( MacCtx.MacCallbacks != NULL ) && ( MacCtx.MacCallbacks->GetBatteryLevel != NULL ) )
2338                 {
2339                     batteryLevel = MacCtx.MacCallbacks->GetBatteryLevel( );
2340                 }
2341                 macCmdPayload[0] = batteryLevel;
2342                 macCmdPayload[1] = ( uint8_t )( snr & 0x3F );
2343                 LoRaMacCommandsAddCmd( MOTE_MAC_DEV_STATUS_ANS, macCmdPayload, 2 );
2344                 break;
2345             }
2346             case SRV_MAC_NEW_CHANNEL_REQ:
2347             {
2348                 NewChannelReqParams_t newChannelReq;
2349                 ChannelParams_t chParam;
2350                 status = 0x03;
2351 
2352                 newChannelReq.ChannelId = payload[macIndex++];
2353                 newChannelReq.NewChannel = &chParam;
2354 
2355                 chParam.Frequency = ( uint32_t ) payload[macIndex++];
2356                 chParam.Frequency |= ( uint32_t ) payload[macIndex++] << 8;
2357                 chParam.Frequency |= ( uint32_t ) payload[macIndex++] << 16;
2358                 chParam.Frequency *= 100;
2359                 chParam.Rx1Frequency = 0;
2360                 chParam.DrRange.Value = payload[macIndex++];
2361 
2362                 status = ( uint8_t )RegionNewChannelReq( Nvm.MacGroup2.Region, &newChannelReq );
2363 
2364                 if( ( int8_t )status >= 0 )
2365                 {
2366                     macCmdPayload[0] = status;
2367                     LoRaMacCommandsAddCmd( MOTE_MAC_NEW_CHANNEL_ANS, macCmdPayload, 1 );
2368                 }
2369                 break;
2370             }
2371             case SRV_MAC_RX_TIMING_SETUP_REQ:
2372             {
2373                 uint8_t delay = payload[macIndex++] & 0x0F;
2374 
2375                 if( delay == 0 )
2376                 {
2377                     delay++;
2378                 }
2379                 Nvm.MacGroup2.MacParams.ReceiveDelay1 = delay * 1000;
2380                 Nvm.MacGroup2.MacParams.ReceiveDelay2 = Nvm.MacGroup2.MacParams.ReceiveDelay1 + 1000;
2381                 LoRaMacCommandsAddCmd( MOTE_MAC_RX_TIMING_SETUP_ANS, macCmdPayload, 0 );
2382                 break;
2383             }
2384             case SRV_MAC_TX_PARAM_SETUP_REQ:
2385             {
2386                 TxParamSetupReqParams_t txParamSetupReq;
2387                 GetPhyParams_t getPhy;
2388                 PhyParam_t phyParam;
2389                 uint8_t eirpDwellTime = payload[macIndex++];
2390 
2391                 txParamSetupReq.UplinkDwellTime = 0;
2392                 txParamSetupReq.DownlinkDwellTime = 0;
2393 
2394                 if( ( eirpDwellTime & 0x20 ) == 0x20 )
2395                 {
2396                     txParamSetupReq.DownlinkDwellTime = 1;
2397                 }
2398                 if( ( eirpDwellTime & 0x10 ) == 0x10 )
2399                 {
2400                     txParamSetupReq.UplinkDwellTime = 1;
2401                 }
2402                 txParamSetupReq.MaxEirp = eirpDwellTime & 0x0F;
2403 
2404                 // Check the status for correctness
2405                 if( RegionTxParamSetupReq( Nvm.MacGroup2.Region, &txParamSetupReq ) != -1 )
2406                 {
2407                     // Accept command
2408                     Nvm.MacGroup2.MacParams.UplinkDwellTime = txParamSetupReq.UplinkDwellTime;
2409                     Nvm.MacGroup2.MacParams.DownlinkDwellTime = txParamSetupReq.DownlinkDwellTime;
2410                     Nvm.MacGroup2.MacParams.MaxEirp = LoRaMacMaxEirpTable[txParamSetupReq.MaxEirp];
2411                     // Update the datarate in case of the new configuration limits it
2412                     getPhy.Attribute = PHY_MIN_TX_DR;
2413                     getPhy.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
2414                     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
2415                     Nvm.MacGroup1.ChannelsDatarate = MAX( Nvm.MacGroup1.ChannelsDatarate, ( int8_t )phyParam.Value );
2416 
2417                     // Add command response
2418                     LoRaMacCommandsAddCmd( MOTE_MAC_TX_PARAM_SETUP_ANS, macCmdPayload, 0 );
2419                 }
2420                 break;
2421             }
2422             case SRV_MAC_REKEY_CONF:
2423             {
2424                 uint8_t serverMinorVersion = payload[macIndex++];
2425 
2426                 // Compare own LoRaWAN Version with server's
2427                 if( Nvm.MacGroup2.Version.Fields.Minor >= serverMinorVersion )
2428                 {
2429                     // If they equal remove the sticky RekeyInd MAC-Command.
2430                     if( LoRaMacCommandsGetCmd( MOTE_MAC_REKEY_IND, &macCmd) == LORAMAC_COMMANDS_SUCCESS )
2431                     {
2432                         LoRaMacCommandsRemoveCmd( macCmd );
2433                     }
2434                 }
2435                 break;
2436             }
2437             case SRV_MAC_DL_CHANNEL_REQ:
2438             {
2439                 DlChannelReqParams_t dlChannelReq;
2440                 status = 0x03;
2441 
2442                 dlChannelReq.ChannelId = payload[macIndex++];
2443                 dlChannelReq.Rx1Frequency = ( uint32_t ) payload[macIndex++];
2444                 dlChannelReq.Rx1Frequency |= ( uint32_t ) payload[macIndex++] << 8;
2445                 dlChannelReq.Rx1Frequency |= ( uint32_t ) payload[macIndex++] << 16;
2446                 dlChannelReq.Rx1Frequency *= 100;
2447 
2448                 status = ( uint8_t )RegionDlChannelReq( Nvm.MacGroup2.Region, &dlChannelReq );
2449 
2450                 if( ( int8_t )status >= 0 )
2451                 {
2452                     macCmdPayload[0] = status;
2453                     LoRaMacCommandsAddCmd( MOTE_MAC_DL_CHANNEL_ANS, macCmdPayload, 1 );
2454                 }
2455                 break;
2456             }
2457             case SRV_MAC_ADR_PARAM_SETUP_REQ:
2458             {
2459                 /* ADRParamSetupReq Payload:  ADRparam
2460                  * +----------------+---------------+
2461                  * | 7:4 Limit_exp  | 3:0 Delay_exp |
2462                  * +----------------+---------------+
2463                  */
2464 
2465                 uint8_t delayExp = 0x0F & payload[macIndex];
2466                 uint8_t limitExp = 0x0F & ( payload[macIndex] >> 4 );
2467                 macIndex++;
2468 
2469                 // ADR_ACK_ DELAY = 2^Delay_exp
2470                 Nvm.MacGroup2.MacParams.AdrAckDelay = 0x01 << delayExp;
2471 
2472                 // ADR_ACK_LIMIT = 2^Limit_exp
2473                 Nvm.MacGroup2.MacParams.AdrAckLimit = 0x01 << limitExp;
2474 
2475                 LoRaMacCommandsAddCmd( MOTE_MAC_ADR_PARAM_SETUP_ANS, macCmdPayload, 0 );
2476                 break;
2477             }
2478             case SRV_MAC_FORCE_REJOIN_REQ:
2479             {
2480                 /* ForceRejoinReq Payload:
2481                  * +--------------+------------------+-------+----------------+--------+
2482                  * | 13:11 Period | 10:8 Max_Retries | 7 RFU | 6:4 RejoinType | 3:0 DR |
2483                  * +--------------+------------------+-------+----------------+--------+
2484                  */
2485 
2486                 // Parse payload
2487                 uint8_t period = ( 0x38 & payload[macIndex] ) >> 3;
2488                 Nvm.MacGroup2.ForceRejoinMaxRetries = 0x07 & payload[macIndex];
2489                 macIndex++;
2490                 Nvm.MacGroup2.ForceRejoinType = ( 0x70 & payload[macIndex] ) >> 4;
2491                 Nvm.MacGroup1.ChannelsDatarate = 0x0F & payload[macIndex];
2492                 macIndex ++;
2493 
2494                 // Calc delay between retransmissions: 32 seconds x 2^Period + Rand32
2495                 uint32_t rejoinCycleInSec = 32 * ( 0x01 << period ) + randr( 0, 32 );
2496 
2497                 MacCtx.ForceRejonCycleTime = 0;
2498                 Nvm.MacGroup1.ForceRejoinRetriesCounter = 0;
2499                 ConvertRejoinCycleTime( rejoinCycleInSec, &MacCtx.ForceRejonCycleTime );
2500                 OnForceRejoinReqCycleTimerEvent( NULL );
2501                 break;
2502             }
2503             case SRV_MAC_REJOIN_PARAM_REQ:
2504             {
2505                 /* RejoinParamSetupReq Payload:
2506                  * +----------------+---------------+
2507                  * | 7:4 MaxTimeN   | 3:0 MaxCountN |
2508                  * +----------------+---------------+
2509                  */
2510                 uint8_t maxCountN = 0x0F & payload[macIndex];
2511                 uint8_t maxTimeN = 0x0F & ( payload[macIndex] >> 4 );
2512                 uint32_t cycleInSec = 0x01 << ( maxTimeN + 10 );
2513                 uint32_t timeInMs = 0;
2514                 uint16_t uplinkLimit = 0x01 << ( maxCountN + 4 );
2515                 macIndex++;
2516                 macCmdPayload[0] = 0;
2517 
2518                 if( ConvertRejoinCycleTime( cycleInSec, &timeInMs ) == true )
2519                 {
2520                     // Calc delay between retransmissions: 2^(maxTimeN+10)
2521                     Nvm.MacGroup2.Rejoin0CycleInSec = cycleInSec;
2522                     // Calc number if uplinks without rejoin request: 2^(maxCountN+4)
2523                     Nvm.MacGroup2.Rejoin0UplinksLimit = uplinkLimit;
2524                     MacCtx.Rejoin0CycleTime = timeInMs;
2525 
2526                     macCmdPayload[0] = 0x01;
2527                     TimerStop( &MacCtx.Rejoin0CycleTimer );
2528                     TimerSetValue( &MacCtx.Rejoin0CycleTimer, MacCtx.Rejoin0CycleTime );
2529                     TimerStart( &MacCtx.Rejoin0CycleTimer );
2530                 }
2531                 LoRaMacCommandsAddCmd( MOTE_MAC_REJOIN_PARAM_ANS, macCmdPayload, 1 );
2532                 break;
2533              }
2534             case SRV_MAC_DEVICE_MODE_CONF:
2535             {
2536                 // 1 byte payload which we do not handle.
2537                 macIndex++;
2538                 if( LoRaMacCommandsGetCmd( MOTE_MAC_DEVICE_MODE_IND, &macCmd) == LORAMAC_COMMANDS_SUCCESS )
2539                 {
2540                     LoRaMacCommandsRemoveCmd( macCmd );
2541                 }
2542                 break;
2543             }
2544             case SRV_MAC_DEVICE_TIME_ANS:
2545             {
2546                 // The mote time can be updated only when the time is received in classA
2547                 // receive windows only.
2548                 if( LoRaMacConfirmQueueIsCmdActive( MLME_DEVICE_TIME ) == true )
2549                 {
2550                     LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_DEVICE_TIME );
2551 
2552                     SysTime_t gpsEpochTime = { 0 };
2553                     SysTime_t sysTime = { 0 };
2554                     SysTime_t sysTimeCurrent = { 0 };
2555 
2556                     gpsEpochTime.Seconds = ( uint32_t )payload[macIndex++];
2557                     gpsEpochTime.Seconds |= ( uint32_t )payload[macIndex++] << 8;
2558                     gpsEpochTime.Seconds |= ( uint32_t )payload[macIndex++] << 16;
2559                     gpsEpochTime.Seconds |= ( uint32_t )payload[macIndex++] << 24;
2560                     gpsEpochTime.SubSeconds = payload[macIndex++];
2561 
2562                     // Convert the fractional second received in ms
2563                     // round( pow( 0.5, 8.0 ) * 1000 ) = 3.90625
2564                     gpsEpochTime.SubSeconds = ( int16_t )( ( ( int32_t )gpsEpochTime.SubSeconds * 1000 ) >> 8 );
2565 
2566                     // Copy received GPS Epoch time into system time
2567                     sysTime = gpsEpochTime;
2568                     // Add Unix to Gps epoch offset. The system time is based on Unix time.
2569                     sysTime.Seconds += UNIX_GPS_EPOCH_OFFSET;
2570 
2571                     // Compensate time difference between Tx Done time and now
2572                     sysTimeCurrent = SysTimeGet( );
2573                     sysTime = SysTimeAdd( sysTimeCurrent, SysTimeSub( sysTime, MacCtx.LastTxSysTime ) );
2574 
2575                     // Apply the new system time.
2576                     SysTimeSet( sysTime );
2577                     LoRaMacClassBDeviceTimeAns( );
2578                     MacCtx.McpsIndication.DeviceTimeAnsReceived = true;
2579                 }
2580                 else
2581                 {
2582                     // Incase of other receive windows the Device Time Answer is not received.
2583                     MacCtx.McpsIndication.DeviceTimeAnsReceived = false;
2584                 }
2585                 break;
2586             }
2587             case SRV_MAC_PING_SLOT_INFO_ANS:
2588             {
2589                 if( LoRaMacConfirmQueueIsCmdActive( MLME_PING_SLOT_INFO ) == true )
2590                 {
2591                     LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_PING_SLOT_INFO );
2592                     // According to the specification, it is not allowed to process this answer in
2593                     // a ping or multicast slot
2594                     if( ( MacCtx.RxSlot != RX_SLOT_WIN_CLASS_B_PING_SLOT ) && ( MacCtx.RxSlot != RX_SLOT_WIN_CLASS_B_MULTICAST_SLOT ) )
2595                     {
2596                         LoRaMacClassBPingSlotInfoAns( );
2597                     }
2598                 }
2599                 break;
2600             }
2601             case SRV_MAC_PING_SLOT_CHANNEL_REQ:
2602             {
2603                 uint8_t status = 0x03;
2604                 uint32_t frequency = 0;
2605                 uint8_t datarate;
2606 
2607                 frequency = ( uint32_t )payload[macIndex++];
2608                 frequency |= ( uint32_t )payload[macIndex++] << 8;
2609                 frequency |= ( uint32_t )payload[macIndex++] << 16;
2610                 frequency *= 100;
2611                 datarate = payload[macIndex++] & 0x0F;
2612 
2613                 status = LoRaMacClassBPingSlotChannelReq( datarate, frequency );
2614                 macCmdPayload[0] = status;
2615                 LoRaMacCommandsAddCmd( MOTE_MAC_PING_SLOT_CHANNEL_ANS, macCmdPayload, 1 );
2616                 break;
2617             }
2618             case SRV_MAC_BEACON_TIMING_ANS:
2619             {
2620                 if( LoRaMacConfirmQueueIsCmdActive( MLME_BEACON_TIMING ) == true )
2621                 {
2622                     LoRaMacConfirmQueueSetStatus( LORAMAC_EVENT_INFO_STATUS_OK, MLME_BEACON_TIMING );
2623                     uint16_t beaconTimingDelay = 0;
2624                     uint8_t beaconTimingChannel = 0;
2625 
2626                     beaconTimingDelay = ( uint16_t )payload[macIndex++];
2627                     beaconTimingDelay |= ( uint16_t )payload[macIndex++] << 8;
2628                     beaconTimingChannel = payload[macIndex++];
2629 
2630                     LoRaMacClassBBeaconTimingAns( beaconTimingDelay, beaconTimingChannel, RxDoneParams.LastRxDone );
2631                 }
2632                 break;
2633             }
2634             case SRV_MAC_BEACON_FREQ_REQ:
2635                 {
2636                     uint32_t frequency = 0;
2637 
2638                     frequency = ( uint32_t )payload[macIndex++];
2639                     frequency |= ( uint32_t )payload[macIndex++] << 8;
2640                     frequency |= ( uint32_t )payload[macIndex++] << 16;
2641                     frequency *= 100;
2642 
2643                     if( LoRaMacClassBBeaconFreqReq( frequency ) == true )
2644                     {
2645                         macCmdPayload[0] = 1;
2646                     }
2647                     else
2648                     {
2649                         macCmdPayload[0] = 0;
2650                     }
2651                     LoRaMacCommandsAddCmd( MOTE_MAC_BEACON_FREQ_ANS, macCmdPayload, 1 );
2652                 }
2653                 break;
2654             default:
2655                 // Unknown command. ABORT MAC commands processing
2656                 return;
2657         }
2658     }
2659 }
2660 
Send(LoRaMacHeader_t * macHdr,uint8_t fPort,void * fBuffer,uint16_t fBufferSize)2661 LoRaMacStatus_t Send( LoRaMacHeader_t* macHdr, uint8_t fPort, void* fBuffer, uint16_t fBufferSize )
2662 {
2663     LoRaMacFrameCtrl_t fCtrl;
2664     LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
2665     int8_t datarate = Nvm.MacGroup1.ChannelsDatarate;
2666     int8_t txPower = Nvm.MacGroup1.ChannelsTxPower;
2667     uint32_t adrAckCounter = Nvm.MacGroup1.AdrAckCounter;
2668     CalcNextAdrParams_t adrNext;
2669 
2670     // Check if we are joined
2671     if( Nvm.MacGroup2.NetworkActivation == ACTIVATION_TYPE_NONE )
2672     {
2673         return LORAMAC_STATUS_NO_NETWORK_JOINED;
2674     }
2675     if( Nvm.MacGroup2.MaxDCycle == 0 )
2676     {
2677         Nvm.MacGroup1.AggregatedTimeOff = 0;
2678     }
2679 
2680     fCtrl.Value = 0;
2681     fCtrl.Bits.FOptsLen      = 0;
2682     fCtrl.Bits.Adr           = Nvm.MacGroup2.AdrCtrlOn;
2683 
2684     // Check class b
2685     if( Nvm.MacGroup2.DeviceClass == CLASS_B )
2686     {
2687         fCtrl.Bits.FPending      = 1;
2688     }
2689     else
2690     {
2691         fCtrl.Bits.FPending      = 0;
2692     }
2693 
2694     // Check server ack
2695     if( Nvm.MacGroup1.SrvAckRequested == true )
2696     {
2697         fCtrl.Bits.Ack = 1;
2698     }
2699 
2700     // ADR next request
2701     adrNext.UpdateChanMask = true;
2702     adrNext.AdrEnabled = fCtrl.Bits.Adr;
2703     adrNext.AdrAckCounter = Nvm.MacGroup1.AdrAckCounter;
2704     adrNext.AdrAckLimit = Nvm.MacGroup2.MacParams.AdrAckLimit;
2705     adrNext.AdrAckDelay = Nvm.MacGroup2.MacParams.AdrAckDelay;
2706     adrNext.Datarate = Nvm.MacGroup1.ChannelsDatarate;
2707     adrNext.TxPower = Nvm.MacGroup1.ChannelsTxPower;
2708     adrNext.NbTrans = Nvm.MacGroup2.MacParams.ChannelsNbTrans;
2709     adrNext.UplinkDwellTime =  Nvm.MacGroup2.MacParams.UplinkDwellTime;
2710     adrNext.Region = Nvm.MacGroup2.Region;
2711 
2712     fCtrl.Bits.AdrAckReq = LoRaMacAdrCalcNext( &adrNext, &Nvm.MacGroup1.ChannelsDatarate,
2713                                                &Nvm.MacGroup1.ChannelsTxPower,
2714                                                &Nvm.MacGroup2.MacParams.ChannelsNbTrans, &adrAckCounter );
2715 
2716     // Prepare the frame
2717     status = PrepareFrame( macHdr, &fCtrl, fPort, fBuffer, fBufferSize );
2718 
2719     // Validate status
2720     if( ( status == LORAMAC_STATUS_OK ) || ( status == LORAMAC_STATUS_SKIPPED_APP_DATA ) )
2721     {
2722         // Schedule frame, do not allow delayed transmissions
2723         status = ScheduleTx( false );
2724     }
2725 
2726     // Post processing
2727     if( status != LORAMAC_STATUS_OK )
2728     {
2729         // Bad case - restore
2730         // Store local variables
2731         Nvm.MacGroup1.ChannelsDatarate = datarate;
2732         Nvm.MacGroup1.ChannelsTxPower = txPower;
2733     }
2734     else
2735     {
2736         // Good case
2737         Nvm.MacGroup1.SrvAckRequested = false;
2738         Nvm.MacGroup1.AdrAckCounter = adrAckCounter;
2739         // Remove all none sticky MAC commands
2740         if( LoRaMacCommandsRemoveNoneStickyCmds( ) != LORAMAC_COMMANDS_SUCCESS )
2741         {
2742             return LORAMAC_STATUS_MAC_COMMAD_ERROR;
2743         }
2744     }
2745     return status;
2746 }
2747 
SendReJoinReq(JoinReqIdentifier_t joinReqType)2748 LoRaMacStatus_t SendReJoinReq( JoinReqIdentifier_t joinReqType )
2749 {
2750     LoRaMacStatus_t status = LORAMAC_STATUS_OK;
2751     LoRaMacHeader_t macHdr;
2752     macHdr.Value = 0;
2753     bool allowDelayedTx = true;
2754 
2755     // Setup join/rejoin message
2756     switch( joinReqType )
2757     {
2758         case REJOIN_REQ_1:
2759         {
2760             Nvm.MacGroup2.IsRejoinAcceptPending = true;
2761 
2762             MacCtx.TxMsg.Type = LORAMAC_MSG_TYPE_RE_JOIN_1;
2763             MacCtx.TxMsg.Message.ReJoin1.Buffer = MacCtx.PktBuffer;
2764             MacCtx.TxMsg.Message.ReJoin1.BufSize = LORAMAC_PHY_MAXPAYLOAD;
2765 
2766             macHdr.Bits.MType = FRAME_TYPE_REJOIN;
2767             MacCtx.TxMsg.Message.ReJoin1.MHDR.Value = macHdr.Value;
2768 
2769             MacCtx.TxMsg.Message.ReJoin1.ReJoinType = 1;
2770 
2771             memcpy1( MacCtx.TxMsg.Message.ReJoin1.JoinEUI, SecureElementGetJoinEui( ), LORAMAC_JOIN_EUI_FIELD_SIZE );
2772             memcpy1( MacCtx.TxMsg.Message.ReJoin1.DevEUI, SecureElementGetDevEui( ), LORAMAC_DEV_EUI_FIELD_SIZE );
2773 
2774             if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoGetRJcount( RJ_COUNT_1, &MacCtx.TxMsg.Message.ReJoin1.RJcount1 ) )
2775             {
2776                 return LORAMAC_STATUS_CRYPTO_ERROR;
2777             }
2778 
2779             break;
2780         }
2781         case REJOIN_REQ_0:
2782         case REJOIN_REQ_2:
2783         {
2784             if( joinReqType == REJOIN_REQ_0 )
2785             {
2786                 MacCtx.TxMsg.Message.ReJoin0or2.ReJoinType = 0;
2787             }
2788             else
2789             {
2790                 MacCtx.TxMsg.Message.ReJoin0or2.ReJoinType = 2;
2791             }
2792 
2793             Nvm.MacGroup2.IsRejoinAcceptPending = true;
2794 
2795             MacCtx.TxMsg.Type = LORAMAC_MSG_TYPE_RE_JOIN_0_2;
2796             MacCtx.TxMsg.Message.ReJoin0or2.Buffer = MacCtx.PktBuffer;
2797             MacCtx.TxMsg.Message.ReJoin0or2.BufSize = LORAMAC_PHY_MAXPAYLOAD;
2798 
2799             macHdr.Bits.MType = FRAME_TYPE_REJOIN;
2800             MacCtx.TxMsg.Message.ReJoin0or2.MHDR.Value = macHdr.Value;
2801 
2802             MacCtx.TxMsg.Message.ReJoin0or2.NetID[0] = Nvm.MacGroup2.NetID & 0xFF;
2803             MacCtx.TxMsg.Message.ReJoin0or2.NetID[1] = ( Nvm.MacGroup2.NetID >> 8 ) & 0xFF;
2804             MacCtx.TxMsg.Message.ReJoin0or2.NetID[2] = ( Nvm.MacGroup2.NetID >> 16 ) & 0xFF;
2805 
2806             memcpy1( MacCtx.TxMsg.Message.ReJoin0or2.DevEUI, SecureElementGetDevEui( ), LORAMAC_DEV_EUI_FIELD_SIZE );
2807 
2808             if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoGetRJcount( RJ_COUNT_0, &MacCtx.TxMsg.Message.ReJoin0or2.RJcount0 ) )
2809             {
2810                 return LORAMAC_STATUS_CRYPTO_ERROR;
2811             }
2812 
2813             break;
2814         }
2815         case JOIN_REQ:
2816         {
2817             SwitchClass( CLASS_A );
2818 
2819             MacCtx.TxMsg.Type = LORAMAC_MSG_TYPE_JOIN_REQUEST;
2820             MacCtx.TxMsg.Message.JoinReq.Buffer = MacCtx.PktBuffer;
2821             MacCtx.TxMsg.Message.JoinReq.BufSize = LORAMAC_PHY_MAXPAYLOAD;
2822 
2823             macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
2824             MacCtx.TxMsg.Message.JoinReq.MHDR.Value = macHdr.Value;
2825 
2826             memcpy1( MacCtx.TxMsg.Message.JoinReq.JoinEUI, SecureElementGetJoinEui( ), LORAMAC_JOIN_EUI_FIELD_SIZE );
2827             memcpy1( MacCtx.TxMsg.Message.JoinReq.DevEUI, SecureElementGetDevEui( ), LORAMAC_DEV_EUI_FIELD_SIZE );
2828 
2829             allowDelayedTx = false;
2830 
2831             break;
2832         }
2833         default:
2834             status = LORAMAC_STATUS_SERVICE_UNKNOWN;
2835             break;
2836     }
2837 
2838     // Schedule frame
2839     status = ScheduleTx( allowDelayedTx );
2840     return status;
2841 }
2842 
CheckForClassBCollision(void)2843 static LoRaMacStatus_t CheckForClassBCollision( void )
2844 {
2845     if( LoRaMacClassBIsBeaconExpected( ) == true )
2846     {
2847         return LORAMAC_STATUS_BUSY_BEACON_RESERVED_TIME;
2848     }
2849 
2850     if( Nvm.MacGroup2.DeviceClass == CLASS_B )
2851     {
2852         if( LoRaMacClassBIsPingExpected( ) == true )
2853         {
2854             return LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME;
2855         }
2856         else if( LoRaMacClassBIsMulticastExpected( ) == true )
2857         {
2858             return LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME;
2859         }
2860     }
2861     return LORAMAC_STATUS_OK;
2862 }
2863 
ComputeRxWindowParameters(void)2864 static void ComputeRxWindowParameters( void )
2865 {
2866     // Compute Rx1 windows parameters
2867     RegionComputeRxWindowParameters( Nvm.MacGroup2.Region,
2868                                      RegionApplyDrOffset( Nvm.MacGroup2.Region,
2869                                                           Nvm.MacGroup2.MacParams.DownlinkDwellTime,
2870                                                           Nvm.MacGroup1.ChannelsDatarate,
2871                                                           Nvm.MacGroup2.MacParams.Rx1DrOffset ),
2872                                      Nvm.MacGroup2.MacParams.MinRxSymbols,
2873                                      Nvm.MacGroup2.MacParams.SystemMaxRxError,
2874                                      &MacCtx.RxWindow1Config );
2875     // Compute Rx2 windows parameters
2876     RegionComputeRxWindowParameters( Nvm.MacGroup2.Region,
2877                                      Nvm.MacGroup2.MacParams.Rx2Channel.Datarate,
2878                                      Nvm.MacGroup2.MacParams.MinRxSymbols,
2879                                      Nvm.MacGroup2.MacParams.SystemMaxRxError,
2880                                      &MacCtx.RxWindow2Config );
2881 
2882     // Default setup, in case the device joined
2883     MacCtx.RxWindow1Delay = Nvm.MacGroup2.MacParams.ReceiveDelay1 + MacCtx.RxWindow1Config.WindowOffset;
2884     MacCtx.RxWindow2Delay = Nvm.MacGroup2.MacParams.ReceiveDelay2 + MacCtx.RxWindow2Config.WindowOffset;
2885 
2886     if( MacCtx.TxMsg.Type != LORAMAC_MSG_TYPE_DATA )
2887     {
2888         MacCtx.RxWindow1Delay = Nvm.MacGroup2.MacParams.JoinAcceptDelay1 + MacCtx.RxWindow1Config.WindowOffset;
2889         MacCtx.RxWindow2Delay = Nvm.MacGroup2.MacParams.JoinAcceptDelay2 + MacCtx.RxWindow2Config.WindowOffset;
2890     }
2891 }
2892 
VerifyTxFrame(void)2893 static LoRaMacStatus_t VerifyTxFrame( void )
2894 {
2895     size_t macCmdsSize = 0;
2896 
2897     if( Nvm.MacGroup2.NetworkActivation != ACTIVATION_TYPE_NONE )
2898     {
2899         if( LoRaMacCommandsGetSizeSerializedCmds( &macCmdsSize ) != LORAMAC_COMMANDS_SUCCESS )
2900         {
2901             return LORAMAC_STATUS_MAC_COMMAD_ERROR;
2902         }
2903 
2904         if( ValidatePayloadLength( MacCtx.AppDataSize, Nvm.MacGroup1.ChannelsDatarate, macCmdsSize ) == false )
2905         {
2906             return LORAMAC_STATUS_LENGTH_ERROR;
2907         }
2908     }
2909     return LORAMAC_STATUS_OK;
2910 }
2911 
SerializeTxFrame(void)2912 static LoRaMacStatus_t SerializeTxFrame( void )
2913 {
2914     LoRaMacSerializerStatus_t serializeStatus;
2915 
2916     switch( MacCtx.TxMsg.Type )
2917     {
2918         case LORAMAC_MSG_TYPE_JOIN_REQUEST:
2919             serializeStatus = LoRaMacSerializerJoinRequest( &MacCtx.TxMsg.Message.JoinReq );
2920             if( LORAMAC_SERIALIZER_SUCCESS != serializeStatus )
2921             {
2922                 return LORAMAC_STATUS_CRYPTO_ERROR;
2923             }
2924             MacCtx.PktBufferLen = MacCtx.TxMsg.Message.JoinReq.BufSize;
2925             break;
2926         case LORAMAC_MSG_TYPE_RE_JOIN_1:
2927             serializeStatus = LoRaMacSerializerReJoinType1( &MacCtx.TxMsg.Message.ReJoin1 );
2928             if( LORAMAC_SERIALIZER_SUCCESS != serializeStatus )
2929             {
2930                 return LORAMAC_STATUS_CRYPTO_ERROR;
2931             }
2932             MacCtx.PktBufferLen = MacCtx.TxMsg.Message.ReJoin1.BufSize;
2933             break;
2934         case LORAMAC_MSG_TYPE_RE_JOIN_0_2:
2935             serializeStatus = LoRaMacSerializerReJoinType0or2( &MacCtx.TxMsg.Message.ReJoin0or2 );
2936             if( LORAMAC_SERIALIZER_SUCCESS != serializeStatus )
2937             {
2938                 return LORAMAC_STATUS_CRYPTO_ERROR;
2939             }
2940             MacCtx.PktBufferLen = MacCtx.TxMsg.Message.ReJoin0or2.BufSize;
2941             break;
2942         case LORAMAC_MSG_TYPE_DATA:
2943             serializeStatus = LoRaMacSerializerData( &MacCtx.TxMsg.Message.Data );
2944             if( LORAMAC_SERIALIZER_SUCCESS != serializeStatus )
2945             {
2946                 return LORAMAC_STATUS_CRYPTO_ERROR;
2947             }
2948             MacCtx.PktBufferLen = MacCtx.TxMsg.Message.Data.BufSize;
2949             break;
2950         case LORAMAC_MSG_TYPE_JOIN_ACCEPT:
2951         case LORAMAC_MSG_TYPE_UNDEF:
2952         default:
2953             return LORAMAC_STATUS_PARAMETER_INVALID;
2954     }
2955     return LORAMAC_STATUS_OK;
2956 }
2957 
ScheduleTx(bool allowDelayedTx)2958 static LoRaMacStatus_t ScheduleTx( bool allowDelayedTx )
2959 {
2960     LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
2961     NextChanParams_t nextChan;
2962 
2963     // Check class b collisions
2964     status = CheckForClassBCollision( );
2965     if( status != LORAMAC_STATUS_OK )
2966     {
2967         return status;
2968     }
2969 
2970     // Update back-off
2971     CalculateBackOff( );
2972 
2973     // Serialize frame
2974     status = SerializeTxFrame( );
2975     if( status != LORAMAC_STATUS_OK )
2976     {
2977         return status;
2978     }
2979 
2980     nextChan.AggrTimeOff = Nvm.MacGroup1.AggregatedTimeOff;
2981     nextChan.Datarate = Nvm.MacGroup1.ChannelsDatarate;
2982     nextChan.DutyCycleEnabled = Nvm.MacGroup2.DutyCycleOn;
2983     nextChan.ElapsedTimeSinceStartUp = SysTimeSub( SysTimeGetMcuTime( ), Nvm.MacGroup2.InitializationTime );
2984     nextChan.LastAggrTx = Nvm.MacGroup1.LastTxDoneTime;
2985     nextChan.LastTxIsJoinRequest = false;
2986     nextChan.Joined = true;
2987     nextChan.PktLen = MacCtx.PktBufferLen;
2988 
2989     // Setup the parameters based on the join status
2990     if( Nvm.MacGroup2.NetworkActivation == ACTIVATION_TYPE_NONE )
2991     {
2992         nextChan.LastTxIsJoinRequest = true;
2993         nextChan.Joined = false;
2994     }
2995 
2996     // Select channel
2997     status = RegionNextChannel( Nvm.MacGroup2.Region, &nextChan, &MacCtx.Channel, &MacCtx.DutyCycleWaitTime, &Nvm.MacGroup1.AggregatedTimeOff );
2998 
2999     if( status != LORAMAC_STATUS_OK )
3000     {
3001         if( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED )
3002         {
3003             if( MacCtx.DutyCycleWaitTime != 0 )
3004             {
3005                 if( allowDelayedTx == true )
3006                 {
3007                     // Allow delayed transmissions. We have to allow it in case
3008                     // the MAC must retransmit a frame with the frame repetitions
3009                     MacCtx.MacState |= LORAMAC_TX_DELAYED;
3010                     TimerSetValue( &MacCtx.TxDelayedTimer, MacCtx.DutyCycleWaitTime );
3011                     TimerStart( &MacCtx.TxDelayedTimer );
3012                     return LORAMAC_STATUS_OK;
3013                 }
3014                 // Need to delay, but allowDelayedTx does not allow it
3015                 return status;
3016             }
3017         }
3018         else
3019         {// State where the MAC cannot send a frame
3020             return status;
3021         }
3022     }
3023 
3024     // Compute window parameters, offsets, rx symbols, system errors etc.
3025     ComputeRxWindowParameters( );
3026 
3027     // Verify TX frame
3028     status = VerifyTxFrame( );
3029     if( status != LORAMAC_STATUS_OK )
3030     {
3031         return status;
3032     }
3033 
3034     // Try to send now
3035     return SendFrameOnChannel( MacCtx.Channel );
3036 }
3037 
SecureFrame(uint8_t txDr,uint8_t txCh)3038 static LoRaMacStatus_t SecureFrame( uint8_t txDr, uint8_t txCh )
3039 {
3040     LoRaMacCryptoStatus_t macCryptoStatus = LORAMAC_CRYPTO_ERROR;
3041     uint32_t fCntUp = 0;
3042 
3043     switch( MacCtx.TxMsg.Type )
3044     {
3045         case LORAMAC_MSG_TYPE_JOIN_REQUEST:
3046             macCryptoStatus = LoRaMacCryptoPrepareJoinRequest( &MacCtx.TxMsg.Message.JoinReq );
3047             if( LORAMAC_CRYPTO_SUCCESS != macCryptoStatus )
3048             {
3049                 return LORAMAC_STATUS_CRYPTO_ERROR;
3050             }
3051             MacCtx.PktBufferLen = MacCtx.TxMsg.Message.JoinReq.BufSize;
3052             break;
3053         case LORAMAC_MSG_TYPE_RE_JOIN_1:
3054             macCryptoStatus = LoRaMacCryptoPrepareReJoinType1( &MacCtx.TxMsg.Message.ReJoin1 );
3055             if( LORAMAC_CRYPTO_SUCCESS != macCryptoStatus )
3056             {
3057                 return LORAMAC_STATUS_CRYPTO_ERROR;
3058             }
3059             MacCtx.PktBufferLen = MacCtx.TxMsg.Message.ReJoin1.BufSize;
3060             break;
3061         case LORAMAC_MSG_TYPE_RE_JOIN_0_2:
3062             macCryptoStatus = LoRaMacCryptoPrepareReJoinType0or2( &MacCtx.TxMsg.Message.ReJoin0or2 );
3063             if( LORAMAC_CRYPTO_SUCCESS != macCryptoStatus )
3064             {
3065                 return LORAMAC_STATUS_CRYPTO_ERROR;
3066             }
3067             MacCtx.PktBufferLen = MacCtx.TxMsg.Message.ReJoin0or2.BufSize;
3068             break;
3069         case LORAMAC_MSG_TYPE_DATA:
3070 
3071             if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoGetFCntUp( &fCntUp ) )
3072             {
3073                 return LORAMAC_STATUS_FCNT_HANDLER_ERROR;
3074             }
3075 
3076             if( MacCtx.ChannelsNbTransCounter >= 1 )
3077             {
3078                 fCntUp -= 1;
3079             }
3080 
3081             macCryptoStatus = LoRaMacCryptoSecureMessage( fCntUp, txDr, txCh, &MacCtx.TxMsg.Message.Data );
3082             if( LORAMAC_CRYPTO_SUCCESS != macCryptoStatus )
3083             {
3084                 return LORAMAC_STATUS_CRYPTO_ERROR;
3085             }
3086             MacCtx.PktBufferLen = MacCtx.TxMsg.Message.Data.BufSize;
3087             break;
3088         case LORAMAC_MSG_TYPE_JOIN_ACCEPT:
3089         case LORAMAC_MSG_TYPE_UNDEF:
3090         default:
3091             return LORAMAC_STATUS_PARAMETER_INVALID;
3092     }
3093     return LORAMAC_STATUS_OK;
3094 }
3095 
CalculateBackOff(void)3096 static void CalculateBackOff( void )
3097 {
3098     // Make sure that the calculation of the backoff time for the aggregated time off will only be done in
3099     // case the value is zero. It will be set to zero in the function RegionNextChannel.
3100     if( Nvm.MacGroup1.AggregatedTimeOff == 0 )
3101     {
3102         // Update aggregated time-off. This must be an assignment and no incremental
3103         // update as we do only calculate the time-off based on the last transmission
3104         Nvm.MacGroup1.AggregatedTimeOff = ( MacCtx.TxTimeOnAir * Nvm.MacGroup2.AggregatedDCycle - MacCtx.TxTimeOnAir );
3105     }
3106 }
3107 
RemoveMacCommands(LoRaMacRxSlot_t rxSlot,LoRaMacFrameCtrl_t fCtrl,Mcps_t request)3108 static void RemoveMacCommands( LoRaMacRxSlot_t rxSlot, LoRaMacFrameCtrl_t fCtrl, Mcps_t request )
3109 {
3110     if( rxSlot == RX_SLOT_WIN_1 || rxSlot == RX_SLOT_WIN_2  )
3111     {
3112         // Remove all sticky MAC commands answers since we can assume
3113         // that they have been received by the server.
3114         if( request == MCPS_CONFIRMED )
3115         {
3116             if( fCtrl.Bits.Ack == 1 )
3117             {  // For confirmed uplinks only if we have received an ACK.
3118                 LoRaMacCommandsRemoveStickyAnsCmds( );
3119             }
3120         }
3121         else
3122         {
3123             LoRaMacCommandsRemoveStickyAnsCmds( );
3124         }
3125     }
3126 }
3127 
3128 
ResetMacParameters(bool isRejoin)3129 static void ResetMacParameters( bool isRejoin )
3130 {
3131     LoRaMacClassBCallback_t classBCallbacks;
3132     LoRaMacClassBParams_t classBParams;
3133 
3134     if( isRejoin == false )
3135     {
3136         Nvm.MacGroup2.NetworkActivation = ACTIVATION_TYPE_NONE;
3137     }
3138 
3139     // ADR counter
3140     Nvm.MacGroup1.AdrAckCounter = 0;
3141 
3142     MacCtx.ChannelsNbTransCounter = 0;
3143     MacCtx.RetransmitTimeoutRetry = false;
3144     MacCtx.ResponseTimeoutStartTime = 0;
3145 
3146     Nvm.MacGroup2.MaxDCycle = 0;
3147     Nvm.MacGroup2.AggregatedDCycle = 1;
3148 
3149     Nvm.MacGroup1.ChannelsTxPower = Nvm.MacGroup2.ChannelsTxPowerDefault;
3150     Nvm.MacGroup1.ChannelsDatarate = Nvm.MacGroup2.ChannelsDatarateDefault;
3151     Nvm.MacGroup2.MacParams.Rx1DrOffset = Nvm.MacGroup2.MacParamsDefaults.Rx1DrOffset;
3152     Nvm.MacGroup2.MacParams.Rx2Channel = Nvm.MacGroup2.MacParamsDefaults.Rx2Channel;
3153     Nvm.MacGroup2.MacParams.RxCChannel = Nvm.MacGroup2.MacParamsDefaults.RxCChannel;
3154     Nvm.MacGroup2.MacParams.UplinkDwellTime = Nvm.MacGroup2.MacParamsDefaults.UplinkDwellTime;
3155     Nvm.MacGroup2.MacParams.DownlinkDwellTime = Nvm.MacGroup2.MacParamsDefaults.DownlinkDwellTime;
3156     Nvm.MacGroup2.MacParams.MaxEirp = Nvm.MacGroup2.MacParamsDefaults.MaxEirp;
3157     Nvm.MacGroup2.MacParams.AntennaGain = Nvm.MacGroup2.MacParamsDefaults.AntennaGain;
3158     Nvm.MacGroup2.MacParams.AdrAckLimit = Nvm.MacGroup2.MacParamsDefaults.AdrAckLimit;
3159     Nvm.MacGroup2.MacParams.AdrAckDelay = Nvm.MacGroup2.MacParamsDefaults.AdrAckDelay;
3160 
3161     MacCtx.NodeAckRequested = false;
3162     Nvm.MacGroup1.SrvAckRequested = false;
3163     Nvm.MacGroup2.ChannelsDatarateChangedLinkAdrReq = false;
3164     Nvm.MacGroup2.DownlinkReceived = false;
3165 
3166     Nvm.MacGroup2.Rejoin0UplinksLimit = 0;
3167     Nvm.MacGroup2.ForceRejoinMaxRetries = 0;
3168     Nvm.MacGroup2.ForceRejoinType = 0;
3169     Nvm.MacGroup2.Rejoin0CycleInSec = 0;
3170     Nvm.MacGroup2.Rejoin1CycleInSec = 0;
3171     Nvm.MacGroup2.IsRejoin0RequestQueued = 0;
3172     Nvm.MacGroup2.IsRejoin1RequestQueued = 0;
3173     Nvm.MacGroup2.IsRejoin2RequestQueued = 0;
3174 
3175     // Reset to application defaults
3176     InitDefaultsParams_t params;
3177     params.Type = INIT_TYPE_RESET_TO_DEFAULT_CHANNELS;
3178     params.NvmGroup1 = &Nvm.RegionGroup1;
3179     params.NvmGroup2 = &Nvm.RegionGroup2;
3180     params.Bands = &RegionBands;
3181     RegionInitDefaults( Nvm.MacGroup2.Region, &params );
3182 
3183     // Initialize channel index.
3184     MacCtx.Channel = 0;
3185 
3186     // Initialize Rx2 config parameters.
3187     MacCtx.RxWindow2Config.Channel = MacCtx.Channel;
3188     MacCtx.RxWindow2Config.Frequency = Nvm.MacGroup2.MacParams.Rx2Channel.Frequency;
3189     MacCtx.RxWindow2Config.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
3190     MacCtx.RxWindow2Config.RxContinuous = false;
3191     MacCtx.RxWindow2Config.RxSlot = RX_SLOT_WIN_2;
3192     MacCtx.RxWindow2Config.NetworkActivation = Nvm.MacGroup2.NetworkActivation;
3193 
3194     // Initialize RxC config parameters.
3195     MacCtx.RxWindowCConfig = MacCtx.RxWindow2Config;
3196     MacCtx.RxWindowCConfig.RxContinuous = true;
3197     MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C;
3198 
3199     // Initialize class b
3200     // Apply callback
3201     classBCallbacks.GetTemperatureLevel = NULL;
3202     classBCallbacks.MacProcessNotify = NULL;
3203 
3204     if( MacCtx.MacCallbacks != NULL )
3205     {
3206         classBCallbacks.GetTemperatureLevel = MacCtx.MacCallbacks->GetTemperatureLevel;
3207         classBCallbacks.MacProcessNotify = MacCtx.MacCallbacks->MacProcessNotify;
3208     }
3209 
3210     // Must all be static. Don't use local references.
3211     classBParams.MlmeIndication = &MacCtx.MlmeIndication;
3212     classBParams.McpsIndication = &MacCtx.McpsIndication;
3213     classBParams.MlmeConfirm = &MacCtx.MlmeConfirm;
3214     classBParams.LoRaMacFlags = &MacCtx.MacFlags;
3215     classBParams.LoRaMacDevAddr = &Nvm.MacGroup2.DevAddr;
3216     classBParams.LoRaMacRegion = &Nvm.MacGroup2.Region;
3217     classBParams.LoRaMacParams = &Nvm.MacGroup2.MacParams;
3218     classBParams.MulticastChannels = &Nvm.MacGroup2.MulticastChannelList[0];
3219     classBParams.NetworkActivation = &Nvm.MacGroup2.NetworkActivation;
3220 
3221     LoRaMacClassBInit( &classBParams, &classBCallbacks, &Nvm.ClassB );
3222 }
3223 
IsReJoin0Required()3224 static bool IsReJoin0Required( )
3225 {
3226 
3227     if( ( Nvm.MacGroup2.Rejoin0UplinksLimit == Nvm.MacGroup1.Rejoin0UplinksCounter ) &&
3228         ( Nvm.MacGroup2.Version.Fields.Minor >= 1 ) &&
3229         ( Nvm.MacGroup2.Rejoin0UplinksLimit != 0 ) )
3230     {
3231         Nvm.MacGroup1.Rejoin0UplinksCounter = 0;
3232         return true;
3233     }
3234     return false;
3235 }
3236 
3237 /*!
3238  * \brief Initializes and opens the reception window
3239  *
3240  * \param [IN] rxTimer  Window timer to be topped.
3241  * \param [IN] rxConfig Window parameters to be setup
3242  */
RxWindowSetup(TimerEvent_t * rxTimer,RxConfigParams_t * rxConfig)3243 static void RxWindowSetup( TimerEvent_t* rxTimer, RxConfigParams_t* rxConfig )
3244 {
3245     TimerStop( rxTimer );
3246 
3247     // Ensure the radio is Idle
3248     Radio.Standby( );
3249 
3250     if( RegionRxConfig( Nvm.MacGroup2.Region, rxConfig, ( int8_t* )&MacCtx.McpsIndication.RxDatarate ) == true )
3251     {
3252         Radio.Rx( Nvm.MacGroup2.MacParams.MaxRxWindow );
3253         MacCtx.RxSlot = rxConfig->RxSlot;
3254     }
3255 }
3256 
OpenContinuousRxCWindow(void)3257 static void OpenContinuousRxCWindow( void )
3258 {
3259     // Compute RxC windows parameters
3260     RegionComputeRxWindowParameters( Nvm.MacGroup2.Region,
3261                                      Nvm.MacGroup2.MacParams.RxCChannel.Datarate,
3262                                      Nvm.MacGroup2.MacParams.MinRxSymbols,
3263                                      Nvm.MacGroup2.MacParams.SystemMaxRxError,
3264                                      &MacCtx.RxWindowCConfig );
3265 
3266     MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C;
3267     MacCtx.RxWindowCConfig.NetworkActivation = Nvm.MacGroup2.NetworkActivation;
3268     // Setup continuous listening
3269     MacCtx.RxWindowCConfig.RxContinuous = true;
3270 
3271     // At this point the Radio should be idle.
3272     // Thus, there is no need to set the radio in standby mode.
3273     if( RegionRxConfig( Nvm.MacGroup2.Region, &MacCtx.RxWindowCConfig, ( int8_t* )&MacCtx.McpsIndication.RxDatarate ) == true )
3274     {
3275         Radio.Rx( 0 ); // Continuous mode
3276         MacCtx.RxSlot = MacCtx.RxWindowCConfig.RxSlot;
3277     }
3278 }
3279 
PrepareFrame(LoRaMacHeader_t * macHdr,LoRaMacFrameCtrl_t * fCtrl,uint8_t fPort,void * fBuffer,uint16_t fBufferSize)3280 LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t* macHdr, LoRaMacFrameCtrl_t* fCtrl, uint8_t fPort, void* fBuffer, uint16_t fBufferSize )
3281 {
3282     MacCtx.PktBufferLen = 0;
3283     MacCtx.NodeAckRequested = false;
3284     uint32_t fCntUp = 0;
3285     size_t macCmdsSize = 0;
3286     uint8_t availableSize = 0;
3287 
3288     if( fBuffer == NULL )
3289     {
3290         fBufferSize = 0;
3291     }
3292 
3293     memcpy1( MacCtx.AppData, ( uint8_t* ) fBuffer, fBufferSize );
3294     MacCtx.AppDataSize = fBufferSize;
3295     MacCtx.PktBuffer[0] = macHdr->Value;
3296 
3297     switch( macHdr->Bits.MType )
3298     {
3299         case FRAME_TYPE_DATA_CONFIRMED_UP:
3300             MacCtx.NodeAckRequested = true;
3301             // Intentional fall through
3302         case FRAME_TYPE_DATA_UNCONFIRMED_UP:
3303             MacCtx.TxMsg.Type = LORAMAC_MSG_TYPE_DATA;
3304             MacCtx.TxMsg.Message.Data.Buffer = MacCtx.PktBuffer;
3305             MacCtx.TxMsg.Message.Data.BufSize = LORAMAC_PHY_MAXPAYLOAD;
3306             MacCtx.TxMsg.Message.Data.MHDR.Value = macHdr->Value;
3307             MacCtx.TxMsg.Message.Data.FPort = fPort;
3308             MacCtx.TxMsg.Message.Data.FHDR.DevAddr = Nvm.MacGroup2.DevAddr;
3309             MacCtx.TxMsg.Message.Data.FHDR.FCtrl.Value = fCtrl->Value;
3310             MacCtx.TxMsg.Message.Data.FRMPayloadSize = MacCtx.AppDataSize;
3311             MacCtx.TxMsg.Message.Data.FRMPayload = MacCtx.AppData;
3312 
3313             if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoGetFCntUp( &fCntUp ) )
3314             {
3315                 return LORAMAC_STATUS_FCNT_HANDLER_ERROR;
3316             }
3317             MacCtx.TxMsg.Message.Data.FHDR.FCnt = ( uint16_t )fCntUp;
3318 
3319             // Reset confirm parameters
3320             MacCtx.McpsConfirm.NbTrans = 0;
3321             MacCtx.McpsConfirm.AckReceived = false;
3322             MacCtx.McpsConfirm.UpLinkCounter = fCntUp;
3323 
3324             // Handle the MAC commands if there are any available
3325             if( LoRaMacCommandsGetSizeSerializedCmds( &macCmdsSize ) != LORAMAC_COMMANDS_SUCCESS )
3326             {
3327                 return LORAMAC_STATUS_MAC_COMMAD_ERROR;
3328             }
3329 
3330             if( macCmdsSize > 0 )
3331             {
3332                 availableSize = GetMaxAppPayloadWithoutFOptsLength( Nvm.MacGroup1.ChannelsDatarate );
3333 
3334                 // There is application payload available and the MAC commands fit into FOpts field.
3335                 if( ( MacCtx.AppDataSize > 0 ) && ( macCmdsSize <= LORA_MAC_COMMAND_MAX_FOPTS_LENGTH ) )
3336                 {
3337                     if( LoRaMacCommandsSerializeCmds( LORA_MAC_COMMAND_MAX_FOPTS_LENGTH, &macCmdsSize, MacCtx.TxMsg.Message.Data.FHDR.FOpts ) != LORAMAC_COMMANDS_SUCCESS )
3338                     {
3339                         return LORAMAC_STATUS_MAC_COMMAD_ERROR;
3340                     }
3341                     fCtrl->Bits.FOptsLen = macCmdsSize;
3342                     // Update FCtrl field with new value of FOptionsLength
3343                     MacCtx.TxMsg.Message.Data.FHDR.FCtrl.Value = fCtrl->Value;
3344                 }
3345                 // There is application payload available but the MAC commands does NOT fit into FOpts field.
3346                 else if( ( MacCtx.AppDataSize > 0 ) && ( macCmdsSize > LORA_MAC_COMMAND_MAX_FOPTS_LENGTH ) )
3347                 {
3348 
3349                     if( LoRaMacCommandsSerializeCmds( availableSize, &macCmdsSize, MacCtx.MacCommandsBuffer ) != LORAMAC_COMMANDS_SUCCESS )
3350                     {
3351                         return LORAMAC_STATUS_MAC_COMMAD_ERROR;
3352                     }
3353                     return LORAMAC_STATUS_SKIPPED_APP_DATA;
3354                 }
3355                 // No application payload available therefore add all mac commands to the FRMPayload.
3356                 else
3357                 {
3358                     if( LoRaMacCommandsSerializeCmds( availableSize, &macCmdsSize, MacCtx.MacCommandsBuffer ) != LORAMAC_COMMANDS_SUCCESS )
3359                     {
3360                         return LORAMAC_STATUS_MAC_COMMAD_ERROR;
3361                     }
3362                     // Force FPort to be zero
3363                     MacCtx.TxMsg.Message.Data.FPort = 0;
3364 
3365                     MacCtx.TxMsg.Message.Data.FRMPayload = MacCtx.MacCommandsBuffer;
3366                     MacCtx.TxMsg.Message.Data.FRMPayloadSize = macCmdsSize;
3367                 }
3368             }
3369 
3370             break;
3371         case FRAME_TYPE_PROPRIETARY:
3372             if( ( fBuffer != NULL ) && ( MacCtx.AppDataSize > 0 ) )
3373             {
3374                 memcpy1( MacCtx.PktBuffer + LORAMAC_MHDR_FIELD_SIZE, ( uint8_t* ) fBuffer, MacCtx.AppDataSize );
3375                 MacCtx.PktBufferLen = LORAMAC_MHDR_FIELD_SIZE + MacCtx.AppDataSize;
3376             }
3377             break;
3378         default:
3379             return LORAMAC_STATUS_SERVICE_UNKNOWN;
3380     }
3381 
3382     return LORAMAC_STATUS_OK;
3383 }
3384 
SendFrameOnChannel(uint8_t channel)3385 LoRaMacStatus_t SendFrameOnChannel( uint8_t channel )
3386 {
3387     LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
3388     TxConfigParams_t txConfig;
3389     int8_t txPower = 0;
3390 
3391     txConfig.Channel = channel;
3392     txConfig.Datarate = Nvm.MacGroup1.ChannelsDatarate;
3393     txConfig.TxPower = Nvm.MacGroup1.ChannelsTxPower;
3394     txConfig.MaxEirp = Nvm.MacGroup2.MacParams.MaxEirp;
3395     txConfig.AntennaGain = Nvm.MacGroup2.MacParams.AntennaGain;
3396     txConfig.PktLen = MacCtx.PktBufferLen;
3397 
3398     RegionTxConfig( Nvm.MacGroup2.Region, &txConfig, &txPower, &MacCtx.TxTimeOnAir );
3399 
3400     MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
3401     MacCtx.McpsConfirm.Datarate = Nvm.MacGroup1.ChannelsDatarate;
3402     MacCtx.McpsConfirm.TxPower = txPower;
3403     MacCtx.McpsConfirm.Channel = channel;
3404 
3405     // Store the time on air
3406     MacCtx.McpsConfirm.TxTimeOnAir = MacCtx.TxTimeOnAir;
3407     MacCtx.MlmeConfirm.TxTimeOnAir = MacCtx.TxTimeOnAir;
3408 
3409     if( LoRaMacClassBIsBeaconModeActive( ) == true )
3410     {
3411         // Currently, the Time-On-Air can only be computed when the radio is configured with
3412         // the TX configuration
3413         TimerTime_t collisionTime = LoRaMacClassBIsUplinkCollision( MacCtx.TxTimeOnAir );
3414 
3415         if( collisionTime > 0 )
3416         {
3417             return LORAMAC_STATUS_BUSY_UPLINK_COLLISION;
3418         }
3419     }
3420 
3421     if( Nvm.MacGroup2.DeviceClass == CLASS_B )
3422     {
3423         // Stop slots for class b
3424         LoRaMacClassBStopRxSlots( );
3425     }
3426 
3427     LoRaMacClassBHaltBeaconing( );
3428 
3429     // Secure frame
3430     status = SecureFrame( Nvm.MacGroup1.ChannelsDatarate, MacCtx.Channel );
3431     if( status != LORAMAC_STATUS_OK )
3432     {
3433         return status;
3434     }
3435 
3436     MacCtx.MacState |= LORAMAC_TX_RUNNING;
3437 
3438     MacCtx.ChannelsNbTransCounter++;
3439     MacCtx.McpsConfirm.NbTrans = MacCtx.ChannelsNbTransCounter;
3440     MacCtx.ResponseTimeoutStartTime = 0;
3441 
3442     // Send now
3443     Radio.Send( MacCtx.PktBuffer, MacCtx.PktBufferLen );
3444 
3445     return LORAMAC_STATUS_OK;
3446 }
3447 
SetTxContinuousWave(uint16_t timeout,uint32_t frequency,uint8_t power)3448 LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout, uint32_t frequency, uint8_t power )
3449 {
3450     Radio.SetTxContinuousWave( frequency, power, timeout );
3451 
3452     MacCtx.MacState |= LORAMAC_TX_RUNNING;
3453 
3454     return LORAMAC_STATUS_OK;
3455 }
3456 
GetNvmData(void)3457 LoRaMacNvmData_t* GetNvmData( void )
3458 {
3459     return &Nvm;
3460 }
3461 
RestoreNvmData(LoRaMacNvmData_t * nvm)3462 LoRaMacStatus_t RestoreNvmData( LoRaMacNvmData_t* nvm )
3463 {
3464     uint32_t crc = 0;
3465 
3466     // Status and parameter validation
3467     if( nvm == NULL )
3468     {
3469         return LORAMAC_STATUS_PARAMETER_INVALID;
3470     }
3471     if( MacCtx.MacState != LORAMAC_STOPPED )
3472     {
3473         return LORAMAC_STATUS_BUSY;
3474     }
3475 
3476     // Crypto
3477     crc = Crc32( ( uint8_t* ) &nvm->Crypto, sizeof( nvm->Crypto ) -
3478                                             sizeof( nvm->Crypto.Crc32 ) );
3479     if( crc == nvm->Crypto.Crc32 )
3480     {
3481         memcpy1( ( uint8_t* ) &Nvm.Crypto, ( uint8_t* ) &nvm->Crypto,
3482                  sizeof( Nvm.Crypto ) );
3483     }
3484 
3485     // MacGroup1
3486     crc = Crc32( ( uint8_t* ) &nvm->MacGroup1, sizeof( nvm->MacGroup1 ) -
3487                                                sizeof( nvm->MacGroup1.Crc32 ) );
3488     if( crc == nvm->MacGroup1.Crc32 )
3489     {
3490         memcpy1( ( uint8_t* ) &Nvm.MacGroup1, ( uint8_t* ) &nvm->MacGroup1,
3491                  sizeof( Nvm.MacGroup1 ) );
3492     }
3493 
3494     // MacGroup2
3495     crc = Crc32( ( uint8_t* ) &nvm->MacGroup2, sizeof( nvm->MacGroup2 ) -
3496                                                sizeof( nvm->MacGroup2.Crc32 ) );
3497     if( crc == nvm->MacGroup2.Crc32 )
3498     {
3499         memcpy1( ( uint8_t* ) &Nvm.MacGroup2, ( uint8_t* ) &nvm->MacGroup2,
3500                  sizeof( Nvm.MacGroup2 ) );
3501 
3502         // Initialize RxC config parameters.
3503         MacCtx.RxWindowCConfig.Channel = MacCtx.Channel;
3504         MacCtx.RxWindowCConfig.Frequency = Nvm.MacGroup2.MacParams.RxCChannel.Frequency;
3505         MacCtx.RxWindowCConfig.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
3506         MacCtx.RxWindowCConfig.RxContinuous = true;
3507         MacCtx.RxWindowCConfig.RxSlot = RX_SLOT_WIN_CLASS_C;
3508 
3509         // The public/private network flag may change upon reloading MacGroup2
3510         // from NVM and we thus need to synchronize the radio. The same function
3511         // is invoked in LoRaMacInitialization.
3512         Radio.SetPublicNetwork( Nvm.MacGroup2.PublicNetwork );
3513     }
3514 
3515     // Secure Element
3516     crc = Crc32( ( uint8_t* ) &nvm->SecureElement, sizeof( nvm->SecureElement ) -
3517                                                    sizeof( nvm->SecureElement.Crc32 ) );
3518     if( crc == nvm->SecureElement.Crc32 )
3519     {
3520         memcpy1( ( uint8_t* ) &Nvm.SecureElement,( uint8_t* ) &nvm->SecureElement,
3521                  sizeof( Nvm.SecureElement ) );
3522     }
3523 
3524     // RegionGroup1
3525     crc = Crc32( ( uint8_t* ) &nvm->RegionGroup1, sizeof( nvm->RegionGroup1 ) -
3526                                             sizeof( nvm->RegionGroup1.Crc32 ) );
3527     if( crc == nvm->RegionGroup1.Crc32 )
3528     {
3529         memcpy1( ( uint8_t* ) &Nvm.RegionGroup1,( uint8_t* ) &nvm->RegionGroup1,
3530                  sizeof( Nvm.RegionGroup1 ) );
3531     }
3532 
3533     // RegionGroup2
3534     crc = Crc32( ( uint8_t* ) &nvm->RegionGroup2, sizeof( nvm->RegionGroup2 ) -
3535                                             sizeof( nvm->RegionGroup2.Crc32 ) );
3536     if( crc == nvm->RegionGroup2.Crc32 )
3537     {
3538         memcpy1( ( uint8_t* ) &Nvm.RegionGroup2,( uint8_t* ) &nvm->RegionGroup2,
3539                  sizeof( Nvm.RegionGroup2 ) );
3540     }
3541 
3542     crc = Crc32( ( uint8_t* ) &nvm->ClassB, sizeof( nvm->ClassB ) -
3543                                             sizeof( nvm->ClassB.Crc32 ) );
3544     if( crc == nvm->ClassB.Crc32 )
3545     {
3546         memcpy1( ( uint8_t* ) &Nvm.ClassB,( uint8_t* ) &nvm->ClassB,
3547                  sizeof( Nvm.ClassB ) );
3548     }
3549 
3550     return LORAMAC_STATUS_OK;
3551 }
3552 
DetermineFrameType(LoRaMacMessageData_t * macMsg,FType_t * fType)3553 LoRaMacStatus_t DetermineFrameType( LoRaMacMessageData_t* macMsg, FType_t* fType )
3554 {
3555     if( ( macMsg == NULL ) || ( fType == NULL ) )
3556     {
3557         return LORAMAC_STATUS_PARAMETER_INVALID;
3558     }
3559 
3560     /* The LoRaWAN specification allows several possible configurations how data up/down frames are built up.
3561      * In sake of clearness the following naming is applied. Please keep in mind that this is
3562      * implementation specific since there is no definition in the LoRaWAN specification included.
3563      *
3564      * X -> Field is available
3565      * - -> Field is not available
3566      *
3567      * +-------+  +----------+------+-------+--------------+
3568      * | FType |  | FOptsLen | Fopt | FPort |  FRMPayload  |
3569      * +-------+  +----------+------+-------+--------------+
3570      * |   A   |  |    > 0   |   X  |  > 0  |       X      |
3571      * +-------+  +----------+------+-------+--------------+
3572      * |   B   |  |   >= 0   |  X/- |   -   |       -      |
3573      * +-------+  +----------+------+-------+--------------+
3574      * |   C   |  |    = 0   |   -  |  = 0  | MAC commands |
3575      * +-------+  +----------+------+-------+--------------+
3576      * |   D   |  |    = 0   |   -  |  > 0  |       X      |
3577      * +-------+  +----------+------+-------+--------------+
3578      */
3579 
3580     if( ( macMsg->FHDR.FCtrl.Bits.FOptsLen > 0 ) && ( macMsg->FPort > 0 ) )
3581     {
3582         *fType = FRAME_TYPE_A;
3583     }
3584     else if( macMsg->FRMPayloadSize == 0 )
3585     {
3586         *fType = FRAME_TYPE_B;
3587     }
3588     else if( ( macMsg->FHDR.FCtrl.Bits.FOptsLen == 0 ) && ( macMsg->FPort == 0 ) )
3589     {
3590         *fType = FRAME_TYPE_C;
3591     }
3592     else if( ( macMsg->FHDR.FCtrl.Bits.FOptsLen == 0 ) && ( macMsg->FPort > 0 ) )
3593     {
3594         *fType = FRAME_TYPE_D;
3595     }
3596     else
3597     {
3598         // Should never happen.
3599         return LORAMAC_STATUS_ERROR;
3600     }
3601 
3602     return LORAMAC_STATUS_OK;
3603 }
3604 
CheckRetrans(uint8_t counter,uint8_t limit)3605 static bool CheckRetrans( uint8_t counter, uint8_t limit )
3606 {
3607     if( counter >= limit )
3608     {
3609         return true;
3610     }
3611     return false;
3612 }
3613 
CheckRetransUnconfirmedUplink(void)3614 static bool CheckRetransUnconfirmedUplink( void )
3615 {
3616     // Verify, if the max number of retransmissions have been reached
3617     if( CheckRetrans( MacCtx.ChannelsNbTransCounter,
3618                       Nvm.MacGroup2.MacParams.ChannelsNbTrans ) == true )
3619     {
3620         return true;
3621     }
3622 
3623     if( MacCtx.MacFlags.Bits.McpsInd == 1 )
3624     {
3625         // Stop the retransmissions, if a valid downlink is received
3626         // a class A RX window. This holds also for class B and C.
3627         if( ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_1 ) ||
3628             ( MacCtx.McpsIndication.RxSlot == RX_SLOT_WIN_2 ) )
3629         {
3630             return true;
3631         }
3632     }
3633     return false;
3634 }
3635 
CheckRetransConfirmedUplink(void)3636 static bool CheckRetransConfirmedUplink( void )
3637 {
3638     // Verify, if the max number of retransmissions have been reached
3639     if( CheckRetrans( MacCtx.ChannelsNbTransCounter,
3640                       Nvm.MacGroup2.MacParams.ChannelsNbTrans ) == true )
3641     {
3642         return true;
3643     }
3644 
3645     if( MacCtx.MacFlags.Bits.McpsInd == 1 )
3646     {
3647         if( MacCtx.McpsConfirm.AckReceived == true )
3648         {
3649             return true;
3650         }
3651     }
3652     return false;
3653 }
3654 
IncreaseAdrAckCounter(uint32_t counter)3655 static uint32_t IncreaseAdrAckCounter( uint32_t counter )
3656 {
3657     if( counter < ADR_ACK_COUNTER_MAX )
3658     {
3659         counter++;
3660     }
3661     return counter;
3662 }
3663 
StopRetransmission(void)3664 static bool StopRetransmission( void )
3665 {
3666     // Increase Rejoin Uplinks counter
3667     if( Nvm.MacGroup2.Rejoin0UplinksLimit != 0 )
3668     {
3669         Nvm.MacGroup1.Rejoin0UplinksCounter++;
3670     }
3671 
3672     if( Nvm.MacGroup2.Version.Fields.Minor >= 1 )
3673     {
3674         MacCommand_t* macCmd;
3675         if( LoRaMacCommandsGetCmd( MOTE_MAC_REKEY_IND, &macCmd ) == LORAMAC_COMMANDS_SUCCESS )
3676         {
3677             // Increase the Rekey Uplinks counter
3678             Nvm.MacGroup1.RekeyIndUplinksCounter++;
3679 
3680             /*
3681              * If the device has not received a RekeyConf within
3682              * the first ADR_ACK_LIMIT uplinks it SHALL revert to the Join state.
3683              */
3684             if( Nvm.MacGroup1.RekeyIndUplinksCounter == Nvm.MacGroup2.MacParams.AdrAckLimit )
3685             {
3686                 Nvm.MacGroup2.NetworkActivation = ACTIVATION_TYPE_NONE;
3687                 MacCtx.MacFlags.Bits.MlmeInd = 1;
3688                 MacCtx.MlmeIndication.MlmeIndication = MLME_REVERT_JOIN;
3689             }
3690         }
3691     }
3692 
3693     if( ( MacCtx.MacFlags.Bits.McpsInd == 0 ) ||
3694         ( ( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_1 ) &&
3695           ( MacCtx.McpsIndication.RxSlot != RX_SLOT_WIN_2 ) ) )
3696     {   // Maximum repetitions without downlink. Increase ADR Ack counter.
3697         // Only process the case when the MAC did not receive a downlink.
3698         if( Nvm.MacGroup2.AdrCtrlOn == true )
3699         {
3700             Nvm.MacGroup1.AdrAckCounter = IncreaseAdrAckCounter( Nvm.MacGroup1.AdrAckCounter );
3701         }
3702     }
3703 
3704     MacCtx.ChannelsNbTransCounter = 0;
3705     MacCtx.NodeAckRequested = false;
3706     MacCtx.RetransmitTimeoutRetry = false;
3707     MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
3708 
3709     return true;
3710 }
3711 
OnMacProcessNotify(void)3712 static void OnMacProcessNotify( void )
3713 {
3714     if( ( MacCtx.MacCallbacks != NULL ) && ( MacCtx.MacCallbacks->MacProcessNotify != NULL ) )
3715     {
3716         MacCtx.MacCallbacks->MacProcessNotify( );
3717     }
3718 }
3719 
CallNvmDataChangeCallback(uint16_t notifyFlags)3720 static void CallNvmDataChangeCallback( uint16_t notifyFlags )
3721 {
3722     if( ( MacCtx.MacCallbacks != NULL ) && ( MacCtx.MacCallbacks->NvmDataChange != NULL ) )
3723     {
3724         MacCtx.MacCallbacks->NvmDataChange ( notifyFlags );
3725     }
3726 }
3727 
IsRequestPending(void)3728 static uint8_t IsRequestPending( void )
3729 {
3730     if( ( MacCtx.MacFlags.Bits.MlmeReq == 1 ) ||
3731         ( MacCtx.MacFlags.Bits.McpsReq == 1 ) )
3732     {
3733         return 1;
3734     }
3735     return 0;
3736 }
3737 
3738 
LoRaMacInitialization(LoRaMacPrimitives_t * primitives,LoRaMacCallback_t * callbacks,LoRaMacRegion_t region)3739 LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t* primitives, LoRaMacCallback_t* callbacks, LoRaMacRegion_t region )
3740 {
3741     GetPhyParams_t getPhy;
3742     PhyParam_t phyParam;
3743 
3744     if( ( primitives == NULL ) ||
3745         ( callbacks == NULL ) )
3746     {
3747         return LORAMAC_STATUS_PARAMETER_INVALID;
3748     }
3749 
3750     if( ( primitives->MacMcpsConfirm == NULL ) ||
3751         ( primitives->MacMcpsIndication == NULL ) ||
3752         ( primitives->MacMlmeConfirm == NULL ) ||
3753         ( primitives->MacMlmeIndication == NULL ) )
3754     {
3755         return LORAMAC_STATUS_PARAMETER_INVALID;
3756     }
3757     // Verify if the region is supported
3758     if( RegionIsActive( region ) == false )
3759     {
3760         return LORAMAC_STATUS_REGION_NOT_SUPPORTED;
3761     }
3762 
3763     // Confirm queue reset
3764     LoRaMacConfirmQueueInit( primitives );
3765 
3766     // Initialize the module context with zeros
3767     memset1( ( uint8_t* ) &Nvm, 0x00, sizeof( LoRaMacNvmData_t ) );
3768     memset1( ( uint8_t* ) &MacCtx, 0x00, sizeof( LoRaMacCtx_t ) );
3769 
3770     // Set non zero variables to its default value
3771     Nvm.MacGroup2.Region = region;
3772     Nvm.MacGroup2.DeviceClass = CLASS_A;
3773 
3774     // Setup version
3775     Nvm.MacGroup2.Version.Value = LORAMAC_VERSION;
3776 
3777     InitDefaultsParams_t params;
3778     params.Type = INIT_TYPE_DEFAULTS;
3779     params.NvmGroup1 = &Nvm.RegionGroup1;
3780     params.NvmGroup2 = &Nvm.RegionGroup2;
3781     params.Bands = &RegionBands;
3782     RegionInitDefaults( Nvm.MacGroup2.Region, &params );
3783 
3784     // Reset to defaults
3785     getPhy.Attribute = PHY_DUTY_CYCLE;
3786     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3787     Nvm.MacGroup2.DutyCycleOn = ( bool ) phyParam.Value;
3788 
3789     getPhy.Attribute = PHY_DEF_TX_POWER;
3790     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3791     Nvm.MacGroup2.ChannelsTxPowerDefault = phyParam.Value;
3792 
3793     getPhy.Attribute = PHY_DEF_TX_DR;
3794     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3795     Nvm.MacGroup2.ChannelsDatarateDefault = phyParam.Value;
3796 
3797     getPhy.Attribute = PHY_MAX_RX_WINDOW;
3798     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3799     Nvm.MacGroup2.MacParamsDefaults.MaxRxWindow = phyParam.Value;
3800 
3801     getPhy.Attribute = PHY_RECEIVE_DELAY1;
3802     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3803     Nvm.MacGroup2.MacParamsDefaults.ReceiveDelay1 = phyParam.Value;
3804 
3805     getPhy.Attribute = PHY_RECEIVE_DELAY2;
3806     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3807     Nvm.MacGroup2.MacParamsDefaults.ReceiveDelay2 = phyParam.Value;
3808 
3809     getPhy.Attribute = PHY_JOIN_ACCEPT_DELAY1;
3810     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3811     Nvm.MacGroup2.MacParamsDefaults.JoinAcceptDelay1 = phyParam.Value;
3812 
3813     getPhy.Attribute = PHY_JOIN_ACCEPT_DELAY2;
3814     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3815     Nvm.MacGroup2.MacParamsDefaults.JoinAcceptDelay2 = phyParam.Value;
3816 
3817     getPhy.Attribute = PHY_DEF_DR1_OFFSET;
3818     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3819     Nvm.MacGroup2.MacParamsDefaults.Rx1DrOffset = phyParam.Value;
3820 
3821     getPhy.Attribute = PHY_DEF_RX2_FREQUENCY;
3822     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3823     Nvm.MacGroup2.MacParamsDefaults.Rx2Channel.Frequency = phyParam.Value;
3824     Nvm.MacGroup2.MacParamsDefaults.RxCChannel.Frequency = phyParam.Value;
3825 
3826     getPhy.Attribute = PHY_DEF_RX2_DR;
3827     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3828     Nvm.MacGroup2.MacParamsDefaults.Rx2Channel.Datarate = phyParam.Value;
3829     Nvm.MacGroup2.MacParamsDefaults.RxCChannel.Datarate = phyParam.Value;
3830 
3831     getPhy.Attribute = PHY_DEF_UPLINK_DWELL_TIME;
3832     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3833     Nvm.MacGroup2.MacParamsDefaults.UplinkDwellTime = phyParam.Value;
3834 
3835     getPhy.Attribute = PHY_DEF_DOWNLINK_DWELL_TIME;
3836     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3837     Nvm.MacGroup2.MacParamsDefaults.DownlinkDwellTime = phyParam.Value;
3838 
3839     getPhy.Attribute = PHY_DEF_MAX_EIRP;
3840     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3841     Nvm.MacGroup2.MacParamsDefaults.MaxEirp = phyParam.fValue;
3842 
3843     getPhy.Attribute = PHY_DEF_ANTENNA_GAIN;
3844     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3845     Nvm.MacGroup2.MacParamsDefaults.AntennaGain = phyParam.fValue;
3846 
3847     getPhy.Attribute = PHY_DEF_ADR_ACK_LIMIT;
3848     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3849     Nvm.MacGroup2.MacParamsDefaults.AdrAckLimit = phyParam.Value;
3850 
3851     getPhy.Attribute = PHY_DEF_ADR_ACK_DELAY;
3852     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
3853     Nvm.MacGroup2.MacParamsDefaults.AdrAckDelay = phyParam.Value;
3854 
3855     // Init parameters which are not set in function ResetMacParameters
3856     Nvm.MacGroup2.MacParamsDefaults.ChannelsNbTrans = 1;
3857     Nvm.MacGroup2.MacParamsDefaults.SystemMaxRxError = 10;
3858     Nvm.MacGroup2.MacParamsDefaults.MinRxSymbols = 6;
3859 
3860     Nvm.MacGroup2.MacParams.SystemMaxRxError = Nvm.MacGroup2.MacParamsDefaults.SystemMaxRxError;
3861     Nvm.MacGroup2.MacParams.MinRxSymbols = Nvm.MacGroup2.MacParamsDefaults.MinRxSymbols;
3862     Nvm.MacGroup2.MacParams.MaxRxWindow = Nvm.MacGroup2.MacParamsDefaults.MaxRxWindow;
3863     Nvm.MacGroup2.MacParams.ReceiveDelay1 = Nvm.MacGroup2.MacParamsDefaults.ReceiveDelay1;
3864     Nvm.MacGroup2.MacParams.ReceiveDelay2 = Nvm.MacGroup2.MacParamsDefaults.ReceiveDelay2;
3865     Nvm.MacGroup2.MacParams.JoinAcceptDelay1 = Nvm.MacGroup2.MacParamsDefaults.JoinAcceptDelay1;
3866     Nvm.MacGroup2.MacParams.JoinAcceptDelay2 = Nvm.MacGroup2.MacParamsDefaults.JoinAcceptDelay2;
3867     Nvm.MacGroup2.MacParams.ChannelsNbTrans = Nvm.MacGroup2.MacParamsDefaults.ChannelsNbTrans;
3868 
3869     // FPort 224 is enabled by default.
3870     Nvm.MacGroup2.IsCertPortOn = true;
3871 
3872     ResetMacParameters( false );
3873 
3874     Nvm.MacGroup2.PublicNetwork = true;
3875 
3876     MacCtx.MacPrimitives = primitives;
3877     MacCtx.MacCallbacks = callbacks;
3878     MacCtx.MacFlags.Value = 0;
3879     MacCtx.MacState = LORAMAC_STOPPED;
3880 
3881     // Reset duty cycle times
3882     Nvm.MacGroup1.LastTxDoneTime = 0;
3883     Nvm.MacGroup1.AggregatedTimeOff = 0;
3884 
3885     // Initialize timers
3886     TimerInit( &MacCtx.TxDelayedTimer, OnTxDelayedTimerEvent );
3887     TimerInit( &MacCtx.RxWindowTimer1, OnRxWindow1TimerEvent );
3888     TimerInit( &MacCtx.RxWindowTimer2, OnRxWindow2TimerEvent );
3889     TimerInit( &MacCtx.RetransmitTimeoutTimer, OnRetransmitTimeoutTimerEvent );
3890     TimerInit( &MacCtx.Rejoin0CycleTimer, OnRejoin0CycleTimerEvent );
3891     TimerInit( &MacCtx.Rejoin1CycleTimer, OnRejoin1CycleTimerEvent );
3892     TimerInit( &MacCtx.ForceRejoinReqCycleTimer, OnForceRejoinReqCycleTimerEvent );
3893 
3894     // Store the current initialization time
3895     Nvm.MacGroup2.InitializationTime = SysTimeGetMcuTime( );
3896 
3897     // Initialize MAC radio events
3898     LoRaMacRadioEvents.Value = 0;
3899 
3900     // Initialize Radio driver
3901     MacCtx.RadioEvents.TxDone = OnRadioTxDone;
3902     MacCtx.RadioEvents.RxDone = OnRadioRxDone;
3903     MacCtx.RadioEvents.RxError = OnRadioRxError;
3904     MacCtx.RadioEvents.TxTimeout = OnRadioTxTimeout;
3905     MacCtx.RadioEvents.RxTimeout = OnRadioRxTimeout;
3906     Radio.Init( &MacCtx.RadioEvents );
3907 
3908     // Initialize the Secure Element driver
3909     if( SecureElementInit( &Nvm.SecureElement ) != SECURE_ELEMENT_SUCCESS )
3910     {
3911         return LORAMAC_STATUS_CRYPTO_ERROR;
3912     }
3913 
3914     // Initialize Crypto module
3915     if( LoRaMacCryptoInit( &Nvm.Crypto ) != LORAMAC_CRYPTO_SUCCESS )
3916     {
3917         return LORAMAC_STATUS_CRYPTO_ERROR;
3918     }
3919 
3920     // Initialize MAC commands module
3921     if( LoRaMacCommandsInit( ) != LORAMAC_COMMANDS_SUCCESS )
3922     {
3923         return LORAMAC_STATUS_MAC_COMMAD_ERROR;
3924     }
3925 
3926     // Set multicast downlink counter reference
3927     if( LoRaMacCryptoSetMulticastReference( Nvm.MacGroup2.MulticastChannelList ) != LORAMAC_CRYPTO_SUCCESS )
3928     {
3929         return LORAMAC_STATUS_CRYPTO_ERROR;
3930     }
3931 
3932     // Random seed initialization
3933     srand1( Radio.Random( ) );
3934 
3935     Radio.SetPublicNetwork( Nvm.MacGroup2.PublicNetwork );
3936     Radio.Sleep( );
3937 
3938     LoRaMacEnableRequests( LORAMAC_REQUEST_HANDLING_ON );
3939 
3940     return LORAMAC_STATUS_OK;
3941 }
3942 
LoRaMacStart(void)3943 LoRaMacStatus_t LoRaMacStart( void )
3944 {
3945     MacCtx.MacState = LORAMAC_IDLE;
3946     UpdateRxSlotIdleState();
3947     return LORAMAC_STATUS_OK;
3948 }
3949 
LoRaMacStop(void)3950 LoRaMacStatus_t LoRaMacStop( void )
3951 {
3952     if( LoRaMacIsBusy( ) == false )
3953     {
3954         if( Nvm.MacGroup2.DeviceClass == CLASS_C )
3955         {
3956             Radio.Sleep( );
3957         }
3958         MacCtx.MacState = LORAMAC_STOPPED;
3959         return LORAMAC_STATUS_OK;
3960     }
3961     else if(  MacCtx.MacState == LORAMAC_STOPPED )
3962     {
3963         return LORAMAC_STATUS_OK;
3964     }
3965     return LORAMAC_STATUS_BUSY;
3966 }
3967 
LoRaMacQueryTxPossible(uint8_t size,LoRaMacTxInfo_t * txInfo)3968 LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo )
3969 {
3970     CalcNextAdrParams_t adrNext;
3971     uint32_t adrAckCounter = Nvm.MacGroup1.AdrAckCounter;
3972     int8_t datarate = Nvm.MacGroup2.ChannelsDatarateDefault;
3973     int8_t txPower = Nvm.MacGroup2.ChannelsTxPowerDefault;
3974     uint8_t nbTrans = MacCtx.ChannelsNbTransCounter;
3975     size_t macCmdsSize = 0;
3976 
3977     if( txInfo == NULL )
3978     {
3979         return LORAMAC_STATUS_PARAMETER_INVALID;
3980     }
3981 
3982     // Setup ADR request
3983     adrNext.UpdateChanMask = false;
3984     adrNext.AdrEnabled = Nvm.MacGroup2.AdrCtrlOn;
3985     adrNext.AdrAckCounter = Nvm.MacGroup1.AdrAckCounter;
3986     adrNext.AdrAckLimit = Nvm.MacGroup2.MacParams.AdrAckLimit;
3987     adrNext.AdrAckDelay = Nvm.MacGroup2.MacParams.AdrAckDelay;
3988     adrNext.Datarate = Nvm.MacGroup1.ChannelsDatarate;
3989     adrNext.TxPower = Nvm.MacGroup1.ChannelsTxPower;
3990     adrNext.NbTrans = MacCtx.ChannelsNbTransCounter;
3991     adrNext.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
3992     adrNext.Region = Nvm.MacGroup2.Region;
3993 
3994     // We call the function for information purposes only. We don't want to
3995     // apply the datarate, the tx power and the ADR ack counter.
3996     LoRaMacAdrCalcNext( &adrNext, &datarate, &txPower, &nbTrans, &adrAckCounter );
3997 
3998     txInfo->CurrentPossiblePayloadSize = GetMaxAppPayloadWithoutFOptsLength( datarate );
3999 
4000     if( LoRaMacCommandsGetSizeSerializedCmds( &macCmdsSize ) != LORAMAC_COMMANDS_SUCCESS )
4001     {
4002         return LORAMAC_STATUS_MAC_COMMAD_ERROR;
4003     }
4004 
4005     // Verify if the MAC commands fit into the FOpts and into the maximum payload.
4006     if( ( LORA_MAC_COMMAND_MAX_FOPTS_LENGTH >= macCmdsSize ) && ( txInfo->CurrentPossiblePayloadSize >= macCmdsSize ) )
4007     {
4008         txInfo->MaxPossibleApplicationDataSize = txInfo->CurrentPossiblePayloadSize - macCmdsSize;
4009 
4010         // Verify if the application data together with MAC command fit into the maximum payload.
4011         if( txInfo->CurrentPossiblePayloadSize >= ( macCmdsSize + size ) )
4012         {
4013             return LORAMAC_STATUS_OK;
4014         }
4015         else
4016         {
4017            return LORAMAC_STATUS_LENGTH_ERROR;
4018         }
4019     }
4020     else
4021     {
4022         txInfo->MaxPossibleApplicationDataSize = 0;
4023         return LORAMAC_STATUS_LENGTH_ERROR;
4024     }
4025 }
4026 
LoRaMacMibGetRequestConfirm(MibRequestConfirm_t * mibGet)4027 LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t* mibGet )
4028 {
4029     LoRaMacStatus_t status = LORAMAC_STATUS_OK;
4030     GetPhyParams_t getPhy;
4031     PhyParam_t phyParam;
4032 
4033     if( mibGet == NULL )
4034     {
4035         return LORAMAC_STATUS_PARAMETER_INVALID;
4036     }
4037 
4038     switch( mibGet->Type )
4039     {
4040         case MIB_DEVICE_CLASS:
4041         {
4042             mibGet->Param.Class = Nvm.MacGroup2.DeviceClass;
4043             break;
4044         }
4045         case MIB_NETWORK_ACTIVATION:
4046         {
4047             mibGet->Param.NetworkActivation = Nvm.MacGroup2.NetworkActivation;
4048             break;
4049         }
4050         case MIB_DEV_EUI:
4051         {
4052             mibGet->Param.DevEui = SecureElementGetDevEui( );
4053             break;
4054         }
4055         case MIB_JOIN_EUI:
4056         {
4057             mibGet->Param.JoinEui = SecureElementGetJoinEui( );
4058             break;
4059         }
4060         case MIB_SE_PIN:
4061         {
4062             mibGet->Param.SePin = SecureElementGetPin( );
4063             break;
4064         }
4065         case MIB_ADR:
4066         {
4067             mibGet->Param.AdrEnable = Nvm.MacGroup2.AdrCtrlOn;
4068             break;
4069         }
4070         case MIB_NET_ID:
4071         {
4072             mibGet->Param.NetID = Nvm.MacGroup2.NetID;
4073             break;
4074         }
4075         case MIB_DEV_ADDR:
4076         {
4077             mibGet->Param.DevAddr = Nvm.MacGroup2.DevAddr;
4078             break;
4079         }
4080         case MIB_PUBLIC_NETWORK:
4081         {
4082             mibGet->Param.EnablePublicNetwork = Nvm.MacGroup2.PublicNetwork;
4083             break;
4084         }
4085         case MIB_CHANNELS:
4086         {
4087             getPhy.Attribute = PHY_CHANNELS;
4088             phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
4089 
4090             mibGet->Param.ChannelList = phyParam.Channels;
4091             break;
4092         }
4093         case MIB_RX2_CHANNEL:
4094         {
4095             mibGet->Param.Rx2Channel = Nvm.MacGroup2.MacParams.Rx2Channel;
4096             break;
4097         }
4098         case MIB_RX2_DEFAULT_CHANNEL:
4099         {
4100             mibGet->Param.Rx2Channel = Nvm.MacGroup2.MacParamsDefaults.Rx2Channel;
4101             break;
4102         }
4103         case MIB_RXC_CHANNEL:
4104         {
4105             mibGet->Param.RxCChannel = Nvm.MacGroup2.MacParams.RxCChannel;
4106             break;
4107         }
4108         case MIB_RXC_DEFAULT_CHANNEL:
4109         {
4110             mibGet->Param.RxCChannel = Nvm.MacGroup2.MacParamsDefaults.RxCChannel;
4111             break;
4112         }
4113         case MIB_CHANNELS_DEFAULT_MASK:
4114         {
4115             getPhy.Attribute = PHY_CHANNELS_DEFAULT_MASK;
4116             phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
4117 
4118             mibGet->Param.ChannelsDefaultMask = phyParam.ChannelsMask;
4119             break;
4120         }
4121         case MIB_CHANNELS_MASK:
4122         {
4123             getPhy.Attribute = PHY_CHANNELS_MASK;
4124             phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
4125 
4126             mibGet->Param.ChannelsMask = phyParam.ChannelsMask;
4127             break;
4128         }
4129         case MIB_CHANNELS_NB_TRANS:
4130         {
4131             mibGet->Param.ChannelsNbTrans = Nvm.MacGroup2.MacParams.ChannelsNbTrans;
4132             break;
4133         }
4134         case MIB_MAX_RX_WINDOW_DURATION:
4135         {
4136             mibGet->Param.MaxRxWindow = Nvm.MacGroup2.MacParams.MaxRxWindow;
4137             break;
4138         }
4139         case MIB_RECEIVE_DELAY_1:
4140         {
4141             mibGet->Param.ReceiveDelay1 = Nvm.MacGroup2.MacParams.ReceiveDelay1;
4142             break;
4143         }
4144         case MIB_RECEIVE_DELAY_2:
4145         {
4146             mibGet->Param.ReceiveDelay2 = Nvm.MacGroup2.MacParams.ReceiveDelay2;
4147             break;
4148         }
4149         case MIB_JOIN_ACCEPT_DELAY_1:
4150         {
4151             mibGet->Param.JoinAcceptDelay1 = Nvm.MacGroup2.MacParams.JoinAcceptDelay1;
4152             break;
4153         }
4154         case MIB_JOIN_ACCEPT_DELAY_2:
4155         {
4156             mibGet->Param.JoinAcceptDelay2 = Nvm.MacGroup2.MacParams.JoinAcceptDelay2;
4157             break;
4158         }
4159         case MIB_CHANNELS_MIN_TX_DATARATE:
4160         {
4161             getPhy.Attribute = PHY_MIN_TX_DR;
4162             getPhy.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
4163             phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
4164 
4165             mibGet->Param.ChannelsMinTxDatarate = phyParam.Value;
4166             break;
4167         }
4168         case MIB_CHANNELS_DEFAULT_DATARATE:
4169         {
4170             mibGet->Param.ChannelsDefaultDatarate = Nvm.MacGroup2.ChannelsDatarateDefault;
4171             break;
4172         }
4173         case MIB_CHANNELS_DATARATE:
4174         {
4175             mibGet->Param.ChannelsDatarate = Nvm.MacGroup1.ChannelsDatarate;
4176             break;
4177         }
4178         case MIB_CHANNELS_DEFAULT_TX_POWER:
4179         {
4180             mibGet->Param.ChannelsDefaultTxPower = Nvm.MacGroup2.ChannelsTxPowerDefault;
4181             break;
4182         }
4183         case MIB_CHANNELS_TX_POWER:
4184         {
4185             mibGet->Param.ChannelsTxPower = Nvm.MacGroup1.ChannelsTxPower;
4186             break;
4187         }
4188         case MIB_SYSTEM_MAX_RX_ERROR:
4189         {
4190             mibGet->Param.SystemMaxRxError = Nvm.MacGroup2.MacParams.SystemMaxRxError;
4191             break;
4192         }
4193         case MIB_MIN_RX_SYMBOLS:
4194         {
4195             mibGet->Param.MinRxSymbols = Nvm.MacGroup2.MacParams.MinRxSymbols;
4196             break;
4197         }
4198         case MIB_ANTENNA_GAIN:
4199         {
4200             mibGet->Param.AntennaGain = Nvm.MacGroup2.MacParams.AntennaGain;
4201             break;
4202         }
4203         case MIB_NVM_CTXS:
4204         {
4205             mibGet->Param.Contexts = GetNvmData( );
4206             break;
4207         }
4208         case MIB_DEFAULT_ANTENNA_GAIN:
4209         {
4210             mibGet->Param.DefaultAntennaGain = Nvm.MacGroup2.MacParamsDefaults.AntennaGain;
4211             break;
4212         }
4213         case MIB_LORAWAN_VERSION:
4214         {
4215             mibGet->Param.LrWanVersion.LoRaWan = Nvm.MacGroup2.Version;
4216             mibGet->Param.LrWanVersion.LoRaWanRegion = RegionGetVersion( );
4217             break;
4218         }
4219         case MIB_IS_CERT_FPORT_ON:
4220         {
4221             mibGet->Param.IsCertPortOn = Nvm.MacGroup2.IsCertPortOn;
4222             break;
4223         }
4224         case MIB_REJOIN_0_CYCLE:
4225         {
4226             mibGet->Param.Rejoin0CycleInSec = Nvm.MacGroup2.Rejoin0CycleInSec;
4227             break;
4228         }
4229         case MIB_REJOIN_1_CYCLE:
4230         {
4231             mibGet->Param.Rejoin1CycleInSec = Nvm.MacGroup2.Rejoin1CycleInSec;
4232             break;
4233         }
4234         case MIB_ADR_ACK_LIMIT:
4235         {
4236             mibGet->Param.AdrAckLimit = Nvm.MacGroup2.MacParams.AdrAckLimit;
4237             break;
4238         }
4239         case MIB_ADR_ACK_DELAY:
4240         {
4241             mibGet->Param.AdrAckDelay = Nvm.MacGroup2.MacParams.AdrAckDelay;
4242             break;
4243         }
4244         case MIB_ADR_ACK_DEFAULT_LIMIT:
4245         {
4246             mibGet->Param.AdrAckLimit = Nvm.MacGroup2.MacParamsDefaults.AdrAckLimit;
4247             break;
4248         }
4249         case MIB_ADR_ACK_DEFAULT_DELAY:
4250         {
4251             mibGet->Param.AdrAckDelay = Nvm.MacGroup2.MacParamsDefaults.AdrAckDelay;
4252             break;
4253         }
4254         case MIB_RSSI_FREE_THRESHOLD:
4255         {
4256 #if defined(REGION_KR920) || defined(REGION_AS923)
4257             if( Nvm.MacGroup2.Region != LORAMAC_REGION_AS923 && Nvm.MacGroup2.Region != LORAMAC_REGION_KR920 )
4258             {
4259                 status = LORAMAC_STATUS_ERROR;
4260             }
4261             else
4262             {
4263                 mibGet->Param.RssiFreeThreshold = Nvm.RegionGroup2.RssiFreeThreshold;
4264             }
4265 #else
4266             status = LORAMAC_STATUS_ERROR;
4267 #endif
4268             break;
4269         }
4270         case MIB_CARRIER_SENSE_TIME:
4271         {
4272 #if defined(REGION_KR920) || defined(REGION_AS923)
4273             if( Nvm.MacGroup2.Region != LORAMAC_REGION_AS923 && Nvm.MacGroup2.Region != LORAMAC_REGION_KR920 )
4274             {
4275                 status = LORAMAC_STATUS_ERROR;
4276             }
4277             else
4278             {
4279                 mibGet->Param.CarrierSenseTime = Nvm.RegionGroup2.CarrierSenseTime;
4280             }
4281 #else
4282             status = LORAMAC_STATUS_ERROR;
4283 #endif
4284             break;
4285         }
4286         default:
4287         {
4288             status = LoRaMacClassBMibGetRequestConfirm( mibGet );
4289             break;
4290         }
4291     }
4292     return status;
4293 }
4294 
LoRaMacMibSetRequestConfirm(MibRequestConfirm_t * mibSet)4295 LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t* mibSet )
4296 {
4297     LoRaMacStatus_t status = LORAMAC_STATUS_OK;
4298     ChanMaskSetParams_t chanMaskSet;
4299     VerifyParams_t verify;
4300 
4301     if( mibSet == NULL )
4302     {
4303         return LORAMAC_STATUS_PARAMETER_INVALID;
4304     }
4305     if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
4306     {
4307         return LORAMAC_STATUS_BUSY;
4308     }
4309 
4310     switch( mibSet->Type )
4311     {
4312         case MIB_DEVICE_CLASS:
4313         {
4314             status = SwitchClass( mibSet->Param.Class );
4315             break;
4316         }
4317         case MIB_NETWORK_ACTIVATION:
4318         {
4319             if( mibSet->Param.NetworkActivation != ACTIVATION_TYPE_OTAA  )
4320             {
4321                 Nvm.MacGroup2.NetworkActivation = mibSet->Param.NetworkActivation;
4322             }
4323             else
4324             {   // Do not allow to set ACTIVATION_TYPE_OTAA since the MAC will set it automatically after a successful join process.
4325                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4326             }
4327             break;
4328         }
4329         case MIB_DEV_EUI:
4330         {
4331             if( SecureElementSetDevEui( mibSet->Param.DevEui ) != SECURE_ELEMENT_SUCCESS )
4332             {
4333                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4334             }
4335             break;
4336         }
4337         case MIB_JOIN_EUI:
4338         {
4339             if( SecureElementSetJoinEui( mibSet->Param.JoinEui ) != SECURE_ELEMENT_SUCCESS )
4340             {
4341                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4342             }
4343             break;
4344         }
4345         case MIB_SE_PIN:
4346         {
4347             if( SecureElementSetPin( mibSet->Param.SePin ) != SECURE_ELEMENT_SUCCESS )
4348             {
4349                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4350             }
4351             break;
4352         }
4353         case MIB_ADR:
4354         {
4355             Nvm.MacGroup2.AdrCtrlOn = mibSet->Param.AdrEnable;
4356             break;
4357         }
4358         case MIB_NET_ID:
4359         {
4360             Nvm.MacGroup2.NetID = mibSet->Param.NetID;
4361             break;
4362         }
4363         case MIB_DEV_ADDR:
4364         {
4365             Nvm.MacGroup2.DevAddr = mibSet->Param.DevAddr;
4366             break;
4367         }
4368         case MIB_APP_KEY:
4369         {
4370             if( mibSet->Param.AppKey != NULL )
4371             {
4372                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( APP_KEY, mibSet->Param.AppKey ) )
4373                 {
4374                     return LORAMAC_STATUS_CRYPTO_ERROR;
4375                 }
4376             }
4377             else
4378             {
4379                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4380             }
4381             break;
4382         }
4383         case MIB_NWK_KEY:
4384         {
4385             if( mibSet->Param.NwkKey != NULL )
4386             {
4387                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( NWK_KEY, mibSet->Param.NwkKey ) )
4388                 {
4389                     return LORAMAC_STATUS_CRYPTO_ERROR;
4390                 }
4391             }
4392             else
4393             {
4394                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4395             }
4396             break;
4397         }
4398         case MIB_J_S_INT_KEY:
4399         {
4400             if( mibSet->Param.JSIntKey != NULL )
4401             {
4402                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( J_S_INT_KEY, mibSet->Param.JSIntKey ) )
4403                 {
4404                     return LORAMAC_STATUS_CRYPTO_ERROR;
4405                 }
4406             }
4407             else
4408             {
4409                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4410             }
4411             break;
4412         }
4413         case MIB_J_S_ENC_KEY:
4414         {
4415             if( mibSet->Param.JSEncKey != NULL )
4416             {
4417                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( J_S_ENC_KEY, mibSet->Param.JSEncKey ) )
4418                 {
4419                     return LORAMAC_STATUS_CRYPTO_ERROR;
4420                 }
4421             }
4422             else
4423             {
4424                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4425             }
4426             break;
4427         }
4428         case MIB_F_NWK_S_INT_KEY:
4429         {
4430             if( mibSet->Param.FNwkSIntKey != NULL )
4431             {
4432                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( F_NWK_S_INT_KEY, mibSet->Param.FNwkSIntKey ) )
4433                 {
4434                     return LORAMAC_STATUS_CRYPTO_ERROR;
4435                 }
4436             }
4437             else
4438             {
4439                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4440             }
4441             break;
4442         }
4443         case MIB_S_NWK_S_INT_KEY:
4444         {
4445             if( mibSet->Param.SNwkSIntKey != NULL )
4446             {
4447                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( S_NWK_S_INT_KEY, mibSet->Param.SNwkSIntKey ) )
4448                 {
4449                     return LORAMAC_STATUS_CRYPTO_ERROR;
4450                 }
4451             }
4452             else
4453             {
4454                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4455             }
4456             break;
4457         }
4458         case MIB_NWK_S_ENC_KEY:
4459         {
4460             if( mibSet->Param.NwkSEncKey != NULL )
4461             {
4462                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( NWK_S_ENC_KEY, mibSet->Param.NwkSEncKey ) )
4463                 {
4464                     return LORAMAC_STATUS_CRYPTO_ERROR;
4465                 }
4466             }
4467             else
4468             {
4469                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4470             }
4471             break;
4472         }
4473         case MIB_APP_S_KEY:
4474         {
4475             if( mibSet->Param.AppSKey != NULL )
4476             {
4477                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( APP_S_KEY, mibSet->Param.AppSKey ) )
4478                 {
4479                     return LORAMAC_STATUS_CRYPTO_ERROR;
4480                 }
4481             }
4482             else
4483             {
4484                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4485             }
4486             break;
4487         }
4488         case MIB_MC_KE_KEY:
4489         {
4490             if( mibSet->Param.McKEKey != NULL )
4491             {
4492                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_KE_KEY, mibSet->Param.McKEKey ) )
4493                 {
4494                     return LORAMAC_STATUS_CRYPTO_ERROR;
4495                 }
4496             }
4497             else
4498             {
4499                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4500             }
4501             break;
4502         }
4503         case MIB_MC_KEY_0:
4504         {
4505             if( mibSet->Param.McKey0 != NULL )
4506             {
4507                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_KEY_0, mibSet->Param.McKey0 ) )
4508                 {
4509                     return LORAMAC_STATUS_CRYPTO_ERROR;
4510                 }
4511             }
4512             else
4513             {
4514                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4515             }
4516             break;
4517         }
4518         case MIB_MC_APP_S_KEY_0:
4519         {
4520             if( mibSet->Param.McAppSKey0 != NULL )
4521             {
4522                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_APP_S_KEY_0, mibSet->Param.McAppSKey0 ) )
4523                 {
4524                     return LORAMAC_STATUS_CRYPTO_ERROR;
4525                 }
4526             }
4527             else
4528             {
4529                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4530             }
4531             break;
4532         }
4533         case MIB_MC_NWK_S_KEY_0:
4534         {
4535             if( mibSet->Param.McNwkSKey0 != NULL )
4536             {
4537                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_NWK_S_KEY_0, mibSet->Param.McNwkSKey0 ) )
4538                 {
4539                     return LORAMAC_STATUS_CRYPTO_ERROR;
4540                 }
4541             }
4542             else
4543             {
4544                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4545             }
4546             break;
4547         }
4548         case MIB_MC_KEY_1:
4549         {
4550             if( mibSet->Param.McKey1 != NULL )
4551             {
4552                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_KEY_1, mibSet->Param.McKey1 ) )
4553                 {
4554                     return LORAMAC_STATUS_CRYPTO_ERROR;
4555                 }
4556             }
4557             else
4558             {
4559                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4560             }
4561             break;
4562         }
4563         case MIB_MC_APP_S_KEY_1:
4564         {
4565             if( mibSet->Param.McAppSKey1 != NULL )
4566             {
4567                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_APP_S_KEY_1, mibSet->Param.McAppSKey1 ) )
4568                 {
4569                     return LORAMAC_STATUS_CRYPTO_ERROR;
4570                 }
4571             }
4572             else
4573             {
4574                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4575             }
4576             break;
4577         }
4578         case MIB_MC_NWK_S_KEY_1:
4579         {
4580             if( mibSet->Param.McNwkSKey1 != NULL )
4581             {
4582                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_NWK_S_KEY_1, mibSet->Param.McNwkSKey1 ) )
4583                 {
4584                     return LORAMAC_STATUS_CRYPTO_ERROR;
4585                 }
4586             }
4587             else
4588             {
4589                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4590             }
4591             break;
4592         }
4593         case MIB_MC_KEY_2:
4594         {
4595             if( mibSet->Param.McKey2 != NULL )
4596             {
4597                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_KEY_2, mibSet->Param.McKey2 ) )
4598                 {
4599                     return LORAMAC_STATUS_CRYPTO_ERROR;
4600                 }
4601             }
4602             else
4603             {
4604                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4605             }
4606             break;
4607         }
4608         case MIB_MC_APP_S_KEY_2:
4609         {
4610             if( mibSet->Param.McAppSKey2 != NULL )
4611             {
4612                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_APP_S_KEY_2, mibSet->Param.McAppSKey2 ) )
4613                 {
4614                     return LORAMAC_STATUS_CRYPTO_ERROR;
4615                 }
4616             }
4617             else
4618             {
4619                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4620             }
4621             break;
4622         }
4623         case MIB_MC_NWK_S_KEY_2:
4624         {
4625             if( mibSet->Param.McNwkSKey2 != NULL )
4626             {
4627                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_NWK_S_KEY_2, mibSet->Param.McNwkSKey2 ) )
4628                 {
4629                     return LORAMAC_STATUS_CRYPTO_ERROR;
4630                 }
4631             }
4632             else
4633             {
4634                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4635             }
4636             break;
4637         }
4638         case MIB_MC_KEY_3:
4639         {
4640             if( mibSet->Param.McKey3 != NULL )
4641             {
4642                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_KEY_3, mibSet->Param.McKey3 ) )
4643                 {
4644                     return LORAMAC_STATUS_CRYPTO_ERROR;
4645                 }
4646             }
4647             else
4648             {
4649                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4650             }
4651             break;
4652         }
4653         case MIB_MC_APP_S_KEY_3:
4654         {
4655             if( mibSet->Param.McAppSKey3 != NULL )
4656             {
4657                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_APP_S_KEY_3, mibSet->Param.McAppSKey3 ) )
4658                 {
4659                     return LORAMAC_STATUS_CRYPTO_ERROR;
4660                 }
4661             }
4662             else
4663             {
4664                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4665             }
4666             break;
4667         }
4668         case MIB_MC_NWK_S_KEY_3:
4669         {
4670             if( mibSet->Param.McNwkSKey3 != NULL )
4671             {
4672                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( MC_NWK_S_KEY_3, mibSet->Param.McNwkSKey3 ) )
4673                 {
4674                     return LORAMAC_STATUS_CRYPTO_ERROR;
4675                 }
4676             }
4677             else
4678             {
4679                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4680             }
4681             break;
4682         }
4683         case MIB_PUBLIC_NETWORK:
4684         {
4685             Nvm.MacGroup2.PublicNetwork = mibSet->Param.EnablePublicNetwork;
4686             Radio.SetPublicNetwork( Nvm.MacGroup2.PublicNetwork );
4687             break;
4688         }
4689         case MIB_RX2_CHANNEL:
4690         {
4691             verify.DatarateParams.Datarate = mibSet->Param.Rx2Channel.Datarate;
4692             verify.DatarateParams.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
4693 
4694             if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_RX_DR ) == true )
4695             {
4696                 Nvm.MacGroup2.MacParams.Rx2Channel = mibSet->Param.Rx2Channel;
4697             }
4698             else
4699             {
4700                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4701             }
4702             break;
4703         }
4704         case MIB_RX2_DEFAULT_CHANNEL:
4705         {
4706             verify.DatarateParams.Datarate = mibSet->Param.Rx2Channel.Datarate;
4707             verify.DatarateParams.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
4708 
4709             if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_RX_DR ) == true )
4710             {
4711                 Nvm.MacGroup2.MacParamsDefaults.Rx2Channel = mibSet->Param.Rx2DefaultChannel;
4712             }
4713             else
4714             {
4715                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4716             }
4717             break;
4718         }
4719         case MIB_RXC_CHANNEL:
4720         {
4721             verify.DatarateParams.Datarate = mibSet->Param.RxCChannel.Datarate;
4722             verify.DatarateParams.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
4723 
4724             if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_RX_DR ) == true )
4725             {
4726                 Nvm.MacGroup2.MacParams.RxCChannel = mibSet->Param.RxCChannel;
4727 
4728                 if( ( Nvm.MacGroup2.DeviceClass == CLASS_C ) && ( Nvm.MacGroup2.NetworkActivation != ACTIVATION_TYPE_NONE ) )
4729                 {
4730                     // We can only compute the RX window parameters directly, if we are already
4731                     // in class c mode and joined. We cannot setup an RX window in case of any other
4732                     // class type.
4733                     // Set the radio into sleep mode in case we are still in RX mode
4734                     Radio.Sleep( );
4735 
4736                     OpenContinuousRxCWindow( );
4737                 }
4738             }
4739             else
4740             {
4741                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4742             }
4743             break;
4744         }
4745         case MIB_RXC_DEFAULT_CHANNEL:
4746         {
4747             verify.DatarateParams.Datarate = mibSet->Param.RxCChannel.Datarate;
4748             verify.DatarateParams.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
4749 
4750             if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_RX_DR ) == true )
4751             {
4752                 Nvm.MacGroup2.MacParamsDefaults.RxCChannel = mibSet->Param.RxCDefaultChannel;
4753             }
4754             else
4755             {
4756                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4757             }
4758             break;
4759         }
4760         case MIB_CHANNELS_DEFAULT_MASK:
4761         {
4762             chanMaskSet.ChannelsMaskIn = mibSet->Param.ChannelsDefaultMask;
4763             chanMaskSet.ChannelsMaskType = CHANNELS_DEFAULT_MASK;
4764 
4765             if( RegionChanMaskSet( Nvm.MacGroup2.Region, &chanMaskSet ) == false )
4766             {
4767                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4768             }
4769             break;
4770         }
4771         case MIB_CHANNELS_MASK:
4772         {
4773             chanMaskSet.ChannelsMaskIn = mibSet->Param.ChannelsMask;
4774             chanMaskSet.ChannelsMaskType = CHANNELS_MASK;
4775 
4776             if( RegionChanMaskSet( Nvm.MacGroup2.Region, &chanMaskSet ) == false )
4777             {
4778                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4779             }
4780             break;
4781         }
4782         case MIB_CHANNELS_NB_TRANS:
4783         {
4784             if( ( mibSet->Param.ChannelsNbTrans >= 1 ) &&
4785                 ( mibSet->Param.ChannelsNbTrans <= 15 ) )
4786             {
4787                 Nvm.MacGroup2.MacParams.ChannelsNbTrans = mibSet->Param.ChannelsNbTrans;
4788             }
4789             else
4790             {
4791                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4792             }
4793             break;
4794         }
4795         case MIB_MAX_RX_WINDOW_DURATION:
4796         {
4797             Nvm.MacGroup2.MacParams.MaxRxWindow = mibSet->Param.MaxRxWindow;
4798             break;
4799         }
4800         case MIB_RECEIVE_DELAY_1:
4801         {
4802             Nvm.MacGroup2.MacParams.ReceiveDelay1 = mibSet->Param.ReceiveDelay1;
4803             break;
4804         }
4805         case MIB_RECEIVE_DELAY_2:
4806         {
4807             Nvm.MacGroup2.MacParams.ReceiveDelay2 = mibSet->Param.ReceiveDelay2;
4808             break;
4809         }
4810         case MIB_JOIN_ACCEPT_DELAY_1:
4811         {
4812             Nvm.MacGroup2.MacParams.JoinAcceptDelay1 = mibSet->Param.JoinAcceptDelay1;
4813             break;
4814         }
4815         case MIB_JOIN_ACCEPT_DELAY_2:
4816         {
4817             Nvm.MacGroup2.MacParams.JoinAcceptDelay2 = mibSet->Param.JoinAcceptDelay2;
4818             break;
4819         }
4820         case MIB_CHANNELS_DEFAULT_DATARATE:
4821         {
4822             verify.DatarateParams.Datarate = mibSet->Param.ChannelsDefaultDatarate;
4823 
4824             if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_DEF_TX_DR ) == true )
4825             {
4826                 Nvm.MacGroup2.ChannelsDatarateDefault = verify.DatarateParams.Datarate;
4827             }
4828             else
4829             {
4830                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4831             }
4832             break;
4833         }
4834         case MIB_CHANNELS_DATARATE:
4835         {
4836             verify.DatarateParams.Datarate = mibSet->Param.ChannelsDatarate;
4837             verify.DatarateParams.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
4838 
4839             if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_TX_DR ) == true )
4840             {
4841                 Nvm.MacGroup1.ChannelsDatarate = verify.DatarateParams.Datarate;
4842             }
4843             else
4844             {
4845                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4846             }
4847             break;
4848         }
4849         case MIB_CHANNELS_DEFAULT_TX_POWER:
4850         {
4851             verify.TxPower = mibSet->Param.ChannelsDefaultTxPower;
4852 
4853             if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_DEF_TX_POWER ) == true )
4854             {
4855                 Nvm.MacGroup2.ChannelsTxPowerDefault = verify.TxPower;
4856             }
4857             else
4858             {
4859                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4860             }
4861             break;
4862         }
4863         case MIB_CHANNELS_TX_POWER:
4864         {
4865             verify.TxPower = mibSet->Param.ChannelsTxPower;
4866 
4867             if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_TX_POWER ) == true )
4868             {
4869                 Nvm.MacGroup1.ChannelsTxPower = verify.TxPower;
4870             }
4871             else
4872             {
4873                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4874             }
4875             break;
4876         }
4877         case MIB_SYSTEM_MAX_RX_ERROR:
4878         {
4879             if( mibSet->Param.SystemMaxRxError <= 500 )
4880             { // Only apply the new value if in range 0..500 ms else keep current value.
4881                 Nvm.MacGroup2.MacParams.SystemMaxRxError = Nvm.MacGroup2.MacParamsDefaults.SystemMaxRxError = mibSet->Param.SystemMaxRxError;
4882             }
4883             else
4884             {
4885                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4886             }
4887             break;
4888         }
4889         case MIB_MIN_RX_SYMBOLS:
4890         {
4891             Nvm.MacGroup2.MacParams.MinRxSymbols = Nvm.MacGroup2.MacParamsDefaults.MinRxSymbols = mibSet->Param.MinRxSymbols;
4892             break;
4893         }
4894         case MIB_ANTENNA_GAIN:
4895         {
4896             Nvm.MacGroup2.MacParams.AntennaGain = mibSet->Param.AntennaGain;
4897             break;
4898         }
4899         case MIB_DEFAULT_ANTENNA_GAIN:
4900         {
4901             Nvm.MacGroup2.MacParamsDefaults.AntennaGain = mibSet->Param.DefaultAntennaGain;
4902             break;
4903         }
4904         case MIB_NVM_CTXS:
4905         {
4906             if( mibSet->Param.Contexts != 0 )
4907             {
4908                 status = RestoreNvmData( mibSet->Param.Contexts );
4909             }
4910             else
4911             {
4912                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4913             }
4914             break;
4915         }
4916         case MIB_ABP_LORAWAN_VERSION:
4917         {
4918             if( mibSet->Param.AbpLrWanVersion.Fields.Minor <= 1 )
4919             {
4920                 Nvm.MacGroup2.Version = mibSet->Param.AbpLrWanVersion;
4921 
4922                 if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetLrWanVersion( mibSet->Param.AbpLrWanVersion ) )
4923                 {
4924                     return LORAMAC_STATUS_CRYPTO_ERROR;
4925                 }
4926             }
4927             else
4928             {
4929                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4930             }
4931             break;
4932         }
4933         case MIB_IS_CERT_FPORT_ON:
4934         {
4935             Nvm.MacGroup2.IsCertPortOn = mibSet->Param.IsCertPortOn;
4936             break;
4937         }
4938         case MIB_REJOIN_0_CYCLE:
4939         {
4940             uint32_t cycleTime = 0;
4941             if( ( ConvertRejoinCycleTime( mibSet->Param.Rejoin0CycleInSec, &cycleTime ) == true ) &&
4942                 ( Nvm.MacGroup2.NetworkActivation == ACTIVATION_TYPE_OTAA ) )
4943             {
4944                 Nvm.MacGroup2.Rejoin0CycleInSec = mibSet->Param.Rejoin0CycleInSec;
4945                 MacCtx.Rejoin0CycleTime = cycleTime;
4946                 TimerStop( &MacCtx.Rejoin0CycleTimer );
4947                 TimerSetValue( &MacCtx.Rejoin0CycleTimer, MacCtx.Rejoin0CycleTime );
4948                 TimerStart( &MacCtx.Rejoin0CycleTimer );
4949             }
4950             else
4951             {
4952                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4953             }
4954             break;
4955         }
4956         case MIB_REJOIN_1_CYCLE:
4957         {
4958             uint32_t cycleTime = 0;
4959             if( ( ConvertRejoinCycleTime( mibSet->Param.Rejoin1CycleInSec, &cycleTime ) == true ) &&
4960                 ( Nvm.MacGroup2.NetworkActivation == ACTIVATION_TYPE_OTAA ) )
4961             {
4962                 Nvm.MacGroup2.Rejoin1CycleInSec = mibSet->Param.Rejoin1CycleInSec;
4963                 MacCtx.Rejoin0CycleTime = cycleTime;
4964                 TimerStop( &MacCtx.Rejoin1CycleTimer );
4965                 TimerSetValue( &MacCtx.Rejoin1CycleTimer, MacCtx.Rejoin1CycleTime );
4966                 TimerStart( &MacCtx.Rejoin1CycleTimer );
4967             }
4968             else
4969             {
4970                 status = LORAMAC_STATUS_PARAMETER_INVALID;
4971             }
4972             break;
4973         }
4974         case MIB_ADR_ACK_LIMIT:
4975         {
4976             Nvm.MacGroup2.MacParams.AdrAckLimit = mibSet->Param.AdrAckLimit;
4977             break;
4978         }
4979         case MIB_ADR_ACK_DELAY:
4980         {
4981             Nvm.MacGroup2.MacParams.AdrAckDelay = mibSet->Param.AdrAckDelay;
4982             break;
4983         }
4984         case MIB_ADR_ACK_DEFAULT_LIMIT:
4985         {
4986             Nvm.MacGroup2.MacParamsDefaults.AdrAckLimit = mibSet->Param.AdrAckLimit;
4987             break;
4988         }
4989         case MIB_ADR_ACK_DEFAULT_DELAY:
4990         {
4991             Nvm.MacGroup2.MacParamsDefaults.AdrAckDelay = mibSet->Param.AdrAckDelay;
4992             break;
4993         }
4994         case MIB_RSSI_FREE_THRESHOLD:
4995         {
4996 #if defined(REGION_KR920) || defined(REGION_AS923)
4997             if( Nvm.MacGroup2.Region != LORAMAC_REGION_AS923 && Nvm.MacGroup2.Region != LORAMAC_REGION_KR920 )
4998             {
4999                 status = LORAMAC_STATUS_ERROR;
5000             }
5001             else
5002             {
5003                 Nvm.RegionGroup2.RssiFreeThreshold = mibSet->Param.RssiFreeThreshold;
5004             }
5005 #else
5006             status = LORAMAC_STATUS_ERROR;
5007 #endif
5008             break;
5009         }
5010         case MIB_CARRIER_SENSE_TIME:
5011         {
5012 #if defined(REGION_KR920) || defined(REGION_AS923)
5013             if( Nvm.MacGroup2.Region != LORAMAC_REGION_AS923 && Nvm.MacGroup2.Region != LORAMAC_REGION_KR920 )
5014             {
5015                 status = LORAMAC_STATUS_ERROR;
5016             }
5017             else
5018             {
5019                 Nvm.RegionGroup2.CarrierSenseTime = mibSet->Param.CarrierSenseTime;
5020             }
5021 #else
5022             status = LORAMAC_STATUS_ERROR;
5023 #endif
5024             break;
5025         }
5026         default:
5027         {
5028             status = LoRaMacMibClassBSetRequestConfirm( mibSet );
5029             break;
5030         }
5031     }
5032 
5033     if( status == LORAMAC_STATUS_OK )
5034     {
5035         // Handle NVM potential changes
5036         MacCtx.MacFlags.Bits.NvmHandle = 1;
5037     }
5038     return status;
5039 }
5040 
LoRaMacChannelAdd(uint8_t id,ChannelParams_t params)5041 LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params )
5042 {
5043     ChannelAddParams_t channelAdd;
5044 
5045     // Validate if the MAC is in a correct state
5046     if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
5047     {
5048         if( ( MacCtx.MacState & LORAMAC_TX_CONFIG ) != LORAMAC_TX_CONFIG )
5049         {
5050             return LORAMAC_STATUS_BUSY;
5051         }
5052     }
5053 
5054     channelAdd.NewChannel = &params;
5055     channelAdd.ChannelId = id;
5056     return RegionChannelAdd( Nvm.MacGroup2.Region, &channelAdd );
5057 }
5058 
LoRaMacChannelRemove(uint8_t id)5059 LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id )
5060 {
5061     ChannelRemoveParams_t channelRemove;
5062 
5063     if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
5064     {
5065         if( ( MacCtx.MacState & LORAMAC_TX_CONFIG ) != LORAMAC_TX_CONFIG )
5066         {
5067             return LORAMAC_STATUS_BUSY;
5068         }
5069     }
5070 
5071     channelRemove.ChannelId = id;
5072 
5073     if( RegionChannelsRemove( Nvm.MacGroup2.Region, &channelRemove ) == false )
5074     {
5075         return LORAMAC_STATUS_PARAMETER_INVALID;
5076     }
5077     return LORAMAC_STATUS_OK;
5078 }
5079 
LoRaMacMcChannelSetup(McChannelParams_t * channel)5080 LoRaMacStatus_t LoRaMacMcChannelSetup( McChannelParams_t *channel )
5081 {
5082     if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
5083     {
5084         return LORAMAC_STATUS_BUSY;
5085     }
5086 
5087     if( channel->GroupID >= LORAMAC_MAX_MC_CTX )
5088     {
5089         return LORAMAC_STATUS_MC_GROUP_UNDEFINED;
5090     }
5091 
5092     Nvm.MacGroup2.MulticastChannelList[channel->GroupID].ChannelParams = *channel;
5093     MacCtx.MacFlags.Bits.NvmHandle = 1;
5094 
5095     if( channel->IsRemotelySetup == true )
5096     {
5097         const KeyIdentifier_t mcKeys[LORAMAC_MAX_MC_CTX] = { MC_KEY_0, MC_KEY_1, MC_KEY_2, MC_KEY_3 };
5098         if( LoRaMacCryptoSetKey( mcKeys[channel->GroupID], channel->McKeys.McKeyE ) != LORAMAC_CRYPTO_SUCCESS )
5099         {
5100             return LORAMAC_STATUS_CRYPTO_ERROR;
5101         }
5102 
5103         if( LoRaMacCryptoDeriveMcSessionKeyPair( channel->GroupID, channel->Address ) != LORAMAC_CRYPTO_SUCCESS )
5104         {
5105             return LORAMAC_STATUS_CRYPTO_ERROR;
5106         }
5107     }
5108     else
5109     {
5110         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 };
5111         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 };
5112         if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( mcAppSKeys[channel->GroupID], channel->McKeys.Session.McAppSKey ) )
5113         {
5114             return LORAMAC_STATUS_CRYPTO_ERROR;
5115         }
5116         if( LORAMAC_CRYPTO_SUCCESS != LoRaMacCryptoSetKey( mcNwkSKeys[channel->GroupID], channel->McKeys.Session.McNwkSKey ) )
5117         {
5118             return LORAMAC_STATUS_CRYPTO_ERROR;
5119         }
5120     }
5121 
5122     // Reset multicast channel downlink counter to initial value.
5123     *Nvm.MacGroup2.MulticastChannelList[channel->GroupID].DownLinkCounter = FCNT_DOWN_INITIAL_VALUE;
5124     return LORAMAC_STATUS_OK;
5125 }
5126 
LoRaMacMcChannelDelete(AddressIdentifier_t groupID)5127 LoRaMacStatus_t LoRaMacMcChannelDelete( AddressIdentifier_t groupID )
5128 {
5129     if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
5130     {
5131         return LORAMAC_STATUS_BUSY;
5132     }
5133 
5134     if( ( groupID >= LORAMAC_MAX_MC_CTX ) ||
5135         ( Nvm.MacGroup2.MulticastChannelList[groupID].ChannelParams.IsEnabled == false ) )
5136     {
5137         return LORAMAC_STATUS_MC_GROUP_UNDEFINED;
5138     }
5139 
5140     McChannelParams_t channel;
5141 
5142     // Set all channel fields with 0
5143     memset1( ( uint8_t* )&channel, 0, sizeof( McChannelParams_t ) );
5144 
5145     Nvm.MacGroup2.MulticastChannelList[groupID].ChannelParams = channel;
5146     MacCtx.MacFlags.Bits.NvmHandle = 1;
5147     return LORAMAC_STATUS_OK;
5148 }
5149 
LoRaMacMcChannelGetGroupId(uint32_t mcAddress)5150 uint8_t LoRaMacMcChannelGetGroupId( uint32_t mcAddress )
5151 {
5152     for( uint8_t i = 0; i < LORAMAC_MAX_MC_CTX; i++ )
5153     {
5154         if( mcAddress == Nvm.MacGroup2.MulticastChannelList[i].ChannelParams.Address )
5155         {
5156             return i;
5157         }
5158     }
5159     return 0xFF;
5160 }
5161 
LoRaMacMcChannelSetupRxParams(AddressIdentifier_t groupID,McRxParams_t * rxParams,uint8_t * status)5162 LoRaMacStatus_t LoRaMacMcChannelSetupRxParams( AddressIdentifier_t groupID, McRxParams_t *rxParams, uint8_t *status )
5163 {
5164    *status = 0x1C + ( groupID & 0x03 );
5165 
5166     if( ( MacCtx.MacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
5167     {
5168         return LORAMAC_STATUS_BUSY;
5169     }
5170 
5171     if( ( rxParams->Class == CLASS_A ) || ( rxParams->Class > CLASS_C ) )
5172     {
5173         return LORAMAC_STATUS_PARAMETER_INVALID;
5174     }
5175 
5176     if( ( groupID >= LORAMAC_MAX_MC_CTX ) ||
5177         ( Nvm.MacGroup2.MulticastChannelList[groupID].ChannelParams.IsEnabled == false ) )
5178     {
5179         return LORAMAC_STATUS_MC_GROUP_UNDEFINED;
5180     }
5181     *status &= 0x0F; // groupID OK
5182 
5183     VerifyParams_t verify;
5184     // Check datarate
5185     if( rxParams->Class == CLASS_B )
5186     {
5187         verify.DatarateParams.Datarate = rxParams->Params.ClassB.Datarate;
5188     }
5189     else
5190     {
5191         verify.DatarateParams.Datarate = rxParams->Params.ClassC.Datarate;
5192     }
5193     verify.DatarateParams.DownlinkDwellTime = Nvm.MacGroup2.MacParams.DownlinkDwellTime;
5194 
5195     if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_RX_DR ) == true )
5196     {
5197         *status &= 0xFB; // datarate OK
5198     }
5199 
5200     // Check frequency
5201     if( rxParams->Class == CLASS_B )
5202     {
5203         verify.Frequency = rxParams->Params.ClassB.Frequency;
5204     }
5205     else
5206     {
5207         verify.Frequency = rxParams->Params.ClassC.Frequency;
5208     }
5209     if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_FREQUENCY ) == true )
5210     {
5211         *status &= 0xF7; // frequency OK
5212     }
5213 
5214     if( *status == ( groupID & 0x03 ) )
5215     {
5216         // Apply parameters
5217         Nvm.MacGroup2.MulticastChannelList[groupID].ChannelParams.RxParams = *rxParams;
5218         MacCtx.MacFlags.Bits.NvmHandle = 1;
5219     }
5220     else
5221     {
5222         return LORAMAC_STATUS_PARAMETER_INVALID;
5223     }
5224 
5225     if( rxParams->Class == CLASS_B )
5226     {
5227         // Calculate class b parameters
5228         LoRaMacClassBSetMulticastPeriodicity( &Nvm.MacGroup2.MulticastChannelList[groupID] );
5229     }
5230     return LORAMAC_STATUS_OK;
5231 }
5232 
5233 /*!
5234  * \brief Function executed on AbpJoinPendingTimer timer event
5235  */
OnAbpJoinPendingTimerEvent(void * context)5236 static void OnAbpJoinPendingTimerEvent( void *context )
5237 {
5238     MacCtx.MacState &= ~LORAMAC_ABP_JOIN_PENDING;
5239     MacCtx.MacFlags.Bits.MacDone = 1;
5240     OnMacProcessNotify( );
5241 }
5242 
5243 /*!
5244  * \brief Start ABP join simulation
5245  */
AbpJoinPendingStart(void)5246 static void AbpJoinPendingStart( void )
5247 {
5248     static bool initialized = false;
5249 
5250     if( initialized == false )
5251     {
5252         initialized = true;
5253         TimerInit( &MacCtx.AbpJoinPendingTimer, OnAbpJoinPendingTimerEvent );
5254     }
5255 
5256     MacCtx.MacState |= LORAMAC_ABP_JOIN_PENDING;
5257 
5258     TimerStop( &MacCtx.AbpJoinPendingTimer );
5259     TimerSetValue( &MacCtx.AbpJoinPendingTimer, ABP_JOIN_PENDING_DELAY_MS );
5260     TimerStart( &MacCtx.AbpJoinPendingTimer );
5261 }
5262 
LoRaMacMlmeRequest(MlmeReq_t * mlmeRequest)5263 LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t* mlmeRequest )
5264 {
5265     LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
5266     MlmeConfirmQueue_t queueElement;
5267     bool isAbpJoinPending = false;
5268     uint8_t macCmdPayload[2] = { 0x00, 0x00 };
5269 
5270     if( mlmeRequest == NULL )
5271     {
5272         return LORAMAC_STATUS_PARAMETER_INVALID;
5273     }
5274     // Initialize mlmeRequest->ReqReturn.DutyCycleWaitTime to 0 in order to
5275     // return a valid value in case the MAC is busy.
5276     mlmeRequest->ReqReturn.DutyCycleWaitTime = 0;
5277 
5278     if( LoRaMacIsBusy( ) == true )
5279     {
5280         return LORAMAC_STATUS_BUSY;
5281     }
5282     if( LoRaMacConfirmQueueIsFull( ) == true )
5283     {
5284         return LORAMAC_STATUS_BUSY;
5285     }
5286 
5287     if( LoRaMacConfirmQueueGetCnt( ) == 0 )
5288     {
5289         memset1( ( uint8_t* ) &MacCtx.MlmeConfirm, 0, sizeof( MacCtx.MlmeConfirm ) );
5290     }
5291     MacCtx.MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
5292 
5293     MacCtx.MacFlags.Bits.MlmeReq = 1;
5294     queueElement.Request = mlmeRequest->Type;
5295     queueElement.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
5296     queueElement.RestrictCommonReadyToHandle = false;
5297     queueElement.ReadyToHandle = false;
5298 
5299     switch( mlmeRequest->Type )
5300     {
5301         case MLME_JOIN:
5302         {
5303             if( ( MacCtx.MacState & LORAMAC_TX_DELAYED ) == LORAMAC_TX_DELAYED )
5304             {
5305                 return LORAMAC_STATUS_BUSY;
5306             }
5307 
5308             if( mlmeRequest->Req.Join.NetworkActivation == ACTIVATION_TYPE_OTAA )
5309             {
5310                 ResetMacParameters( false );
5311 
5312                 Nvm.MacGroup1.ChannelsDatarate = RegionAlternateDr( Nvm.MacGroup2.Region, mlmeRequest->Req.Join.Datarate, ALTERNATE_DR );
5313 
5314                 queueElement.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
5315 
5316                 status = SendReJoinReq( JOIN_REQ );
5317 
5318                 if( status != LORAMAC_STATUS_OK )
5319                 {
5320                     // Revert back the previous datarate ( mainly used for US915 like regions )
5321                     Nvm.MacGroup1.ChannelsDatarate = RegionAlternateDr( Nvm.MacGroup2.Region, mlmeRequest->Req.Join.Datarate, ALTERNATE_DR_RESTORE );
5322                 }
5323             }
5324             else if( mlmeRequest->Req.Join.NetworkActivation == ACTIVATION_TYPE_ABP )
5325             {
5326                 // Restore default value for ChannelsDatarateChangedLinkAdrReq
5327                 Nvm.MacGroup2.ChannelsDatarateChangedLinkAdrReq = false;
5328 
5329                 // Activate the default channels
5330                 InitDefaultsParams_t params;
5331                 params.Type = INIT_TYPE_ACTIVATE_DEFAULT_CHANNELS;
5332                 RegionInitDefaults( Nvm.MacGroup2.Region, &params );
5333 
5334                 Nvm.MacGroup2.NetworkActivation = mlmeRequest->Req.Join.NetworkActivation;
5335                 queueElement.Status = LORAMAC_EVENT_INFO_STATUS_OK;
5336                 queueElement.ReadyToHandle = true;
5337                 isAbpJoinPending = true;
5338                 status = LORAMAC_STATUS_OK;
5339             }
5340             break;
5341         }
5342         case MLME_REJOIN_0:
5343         {
5344             MacCtx.MacFlags.Bits.MlmeReq = 1;
5345             MacCtx.MlmeConfirm.MlmeRequest = mlmeRequest->Type;
5346 
5347             status = SendReJoinReq( REJOIN_REQ_0 );
5348 
5349             break;
5350         }
5351         case MLME_REJOIN_1:
5352         {
5353             MacCtx.MacFlags.Bits.MlmeReq = 1;
5354             MacCtx.MlmeConfirm.MlmeRequest = mlmeRequest->Type;
5355 
5356             status = SendReJoinReq( REJOIN_REQ_1 );
5357 
5358             break;
5359         }
5360         case MLME_REJOIN_2:
5361         {
5362             MacCtx.MacFlags.Bits.MlmeReq = 1;
5363             MacCtx.MlmeConfirm.MlmeRequest = mlmeRequest->Type;
5364 
5365             status = SendReJoinReq( REJOIN_REQ_2 );
5366 
5367             break;
5368         }
5369         case MLME_LINK_CHECK:
5370         {
5371             // LoRaMac will send this command piggy-pack
5372             status = LORAMAC_STATUS_OK;
5373             if( LoRaMacCommandsAddCmd( MOTE_MAC_LINK_CHECK_REQ, macCmdPayload, 0 ) != LORAMAC_COMMANDS_SUCCESS )
5374             {
5375                 status = LORAMAC_STATUS_MAC_COMMAD_ERROR;
5376             }
5377             break;
5378         }
5379         case MLME_TXCW:
5380         {
5381             status = SetTxContinuousWave( mlmeRequest->Req.TxCw.Timeout, mlmeRequest->Req.TxCw.Frequency, mlmeRequest->Req.TxCw.Power );
5382             break;
5383         }
5384         case MLME_DEVICE_TIME:
5385         {
5386             // LoRaMac will send this command piggy-pack
5387             status = LORAMAC_STATUS_OK;
5388             if( LoRaMacCommandsAddCmd( MOTE_MAC_DEVICE_TIME_REQ, macCmdPayload, 0 ) != LORAMAC_COMMANDS_SUCCESS )
5389             {
5390                 status = LORAMAC_STATUS_MAC_COMMAD_ERROR;
5391             }
5392             break;
5393         }
5394         case MLME_PING_SLOT_INFO:
5395         {
5396             if( Nvm.MacGroup2.DeviceClass == CLASS_A )
5397             {
5398                 uint8_t value = mlmeRequest->Req.PingSlotInfo.PingSlot.Value;
5399 
5400                 // LoRaMac will send this command piggy-pack
5401                 LoRaMacClassBSetPingSlotInfo( mlmeRequest->Req.PingSlotInfo.PingSlot.Fields.Periodicity );
5402                 macCmdPayload[0] = value;
5403                 status = LORAMAC_STATUS_OK;
5404                 if( LoRaMacCommandsAddCmd( MOTE_MAC_PING_SLOT_INFO_REQ, macCmdPayload, 1 ) != LORAMAC_COMMANDS_SUCCESS )
5405                 {
5406                     status = LORAMAC_STATUS_MAC_COMMAD_ERROR;
5407                 }
5408             }
5409             break;
5410         }
5411         case MLME_BEACON_TIMING:
5412         {
5413             // LoRaMac will send this command piggy-pack
5414             status = LORAMAC_STATUS_OK;
5415             if( LoRaMacCommandsAddCmd( MOTE_MAC_BEACON_TIMING_REQ, macCmdPayload, 0 ) != LORAMAC_COMMANDS_SUCCESS )
5416             {
5417                 status = LORAMAC_STATUS_MAC_COMMAD_ERROR;
5418             }
5419             break;
5420         }
5421         case MLME_BEACON_ACQUISITION:
5422         {
5423             // Apply the request
5424             queueElement.RestrictCommonReadyToHandle = true;
5425 
5426             if( LoRaMacClassBIsAcquisitionInProgress( ) == false )
5427             {
5428                 // Start class B algorithm
5429                 LoRaMacClassBSetBeaconState( BEACON_STATE_ACQUISITION );
5430                 LoRaMacClassBBeaconTimerEvent( NULL );
5431 
5432                 status = LORAMAC_STATUS_OK;
5433             }
5434             else
5435             {
5436                 status = LORAMAC_STATUS_BUSY;
5437             }
5438             break;
5439         }
5440         default:
5441             break;
5442     }
5443 
5444     // Fill return structure
5445     mlmeRequest->ReqReturn.DutyCycleWaitTime = MacCtx.DutyCycleWaitTime;
5446 
5447     if( status != LORAMAC_STATUS_OK )
5448     {
5449         if( LoRaMacConfirmQueueGetCnt( ) == 0 )
5450         {
5451             MacCtx.NodeAckRequested = false;
5452             MacCtx.MacFlags.Bits.MlmeReq = 0;
5453         }
5454     }
5455     else
5456     {
5457         LoRaMacConfirmQueueAdd( &queueElement );
5458         if( isAbpJoinPending == true )
5459         {
5460             AbpJoinPendingStart( );
5461         }
5462     }
5463     return status;
5464 }
5465 
LoRaMacMcpsRequest(McpsReq_t * mcpsRequest)5466 LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t* mcpsRequest )
5467 {
5468     GetPhyParams_t getPhy;
5469     PhyParam_t phyParam;
5470     LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
5471     LoRaMacHeader_t macHdr;
5472     VerifyParams_t verify;
5473     uint8_t fPort = 0;
5474     void* fBuffer;
5475     uint16_t fBufferSize;
5476     int8_t datarate = DR_0;
5477     bool readyToSend = false;
5478 
5479     if( mcpsRequest == NULL )
5480     {
5481         return LORAMAC_STATUS_PARAMETER_INVALID;
5482     }
5483     // Initialize mcpsRequest->ReqReturn.DutyCycleWaitTime to 0 in order to
5484     // return a valid value in case the MAC is busy.
5485     mcpsRequest->ReqReturn.DutyCycleWaitTime = 0;
5486 
5487     if( LoRaMacIsBusy( ) == true )
5488     {
5489         return LORAMAC_STATUS_BUSY;
5490     }
5491 
5492     McpsReq_t request = *mcpsRequest;
5493 
5494     macHdr.Value = 0;
5495     memset1( ( uint8_t* ) &MacCtx.McpsConfirm, 0, sizeof( MacCtx.McpsConfirm ) );
5496     MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
5497 
5498     // Apply confirmed downlinks, if the device has not received a valid
5499     // downlink after a join accept.
5500     if( ( Nvm.MacGroup2.NetworkActivation == ACTIVATION_TYPE_OTAA ) &&
5501         ( Nvm.MacGroup2.DeviceClass == CLASS_C ) &&
5502         ( Nvm.MacGroup2.DownlinkReceived == false ) &&
5503         ( request.Type == MCPS_UNCONFIRMED ) )
5504     {
5505         request.Type = MCPS_CONFIRMED;
5506     }
5507 
5508     switch( request.Type )
5509     {
5510         case MCPS_UNCONFIRMED:
5511         {
5512             readyToSend = true;
5513 
5514             macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
5515             fPort = request.Req.Unconfirmed.fPort;
5516             fBuffer = request.Req.Unconfirmed.fBuffer;
5517             fBufferSize = request.Req.Unconfirmed.fBufferSize;
5518             datarate = request.Req.Unconfirmed.Datarate;
5519             break;
5520         }
5521         case MCPS_CONFIRMED:
5522         {
5523             readyToSend = true;
5524 
5525             macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
5526             fPort = request.Req.Confirmed.fPort;
5527             fBuffer = request.Req.Confirmed.fBuffer;
5528             fBufferSize = request.Req.Confirmed.fBufferSize;
5529             datarate = request.Req.Confirmed.Datarate;
5530             break;
5531         }
5532         case MCPS_PROPRIETARY:
5533         {
5534             readyToSend = true;
5535 
5536             macHdr.Bits.MType = FRAME_TYPE_PROPRIETARY;
5537             fBuffer = request.Req.Proprietary.fBuffer;
5538             fBufferSize = request.Req.Proprietary.fBufferSize;
5539             datarate = request.Req.Proprietary.Datarate;
5540             break;
5541         }
5542         default:
5543             break;
5544     }
5545 
5546     // Make sure that the input datarate is compliant
5547     // to the regional specification.
5548     getPhy.Attribute = PHY_MIN_TX_DR;
5549     getPhy.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
5550     phyParam = RegionGetPhyParam( Nvm.MacGroup2.Region, &getPhy );
5551     // Apply the minimum possible datarate.
5552     // Some regions have limitations for the minimum datarate.
5553     datarate = MAX( datarate, ( int8_t )phyParam.Value );
5554 
5555     // Apply minimum datarate in this special case.
5556     if( CheckForMinimumAbpDatarate( Nvm.MacGroup2.AdrCtrlOn, Nvm.MacGroup2.NetworkActivation,
5557                                     Nvm.MacGroup2.ChannelsDatarateChangedLinkAdrReq ) == true )
5558     {
5559         datarate = ( int8_t )phyParam.Value;
5560     }
5561 
5562     if( readyToSend == true )
5563     {
5564         if( ( Nvm.MacGroup2.AdrCtrlOn == false ) ||
5565             ( CheckForMinimumAbpDatarate( Nvm.MacGroup2.AdrCtrlOn, Nvm.MacGroup2.NetworkActivation,
5566                                           Nvm.MacGroup2.ChannelsDatarateChangedLinkAdrReq ) == true ) )
5567         {
5568             verify.DatarateParams.Datarate = datarate;
5569             verify.DatarateParams.UplinkDwellTime = Nvm.MacGroup2.MacParams.UplinkDwellTime;
5570 
5571             if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_TX_DR ) == true )
5572             {
5573                 Nvm.MacGroup1.ChannelsDatarate = verify.DatarateParams.Datarate;
5574             }
5575             else
5576             {
5577                 return LORAMAC_STATUS_PARAMETER_INVALID;
5578             }
5579         }
5580 
5581         // Verification of response timeout for class b and class c
5582         LoRaMacHandleResponseTimeout( REGION_COMMON_CLASS_B_C_RESP_TIMEOUT,
5583                                       MacCtx.ResponseTimeoutStartTime );
5584 
5585         status = Send( &macHdr, fPort, fBuffer, fBufferSize );
5586         if( status == LORAMAC_STATUS_OK )
5587         {
5588             MacCtx.McpsConfirm.McpsRequest = request.Type;
5589             MacCtx.MacFlags.Bits.McpsReq = 1;
5590         }
5591         else
5592         {
5593             MacCtx.NodeAckRequested = false;
5594         }
5595     }
5596 
5597     // Fill return structure
5598     mcpsRequest->ReqReturn.DutyCycleWaitTime = MacCtx.DutyCycleWaitTime;
5599 
5600     return status;
5601 }
5602 
ConvertRejoinCycleTime(uint32_t rejoinCycleTime,uint32_t * timeInMiliSec)5603 static bool ConvertRejoinCycleTime( uint32_t rejoinCycleTime, uint32_t* timeInMiliSec )
5604 {
5605     // Our timer implementation do not allow longer times than 4294967295 ms
5606     if( rejoinCycleTime <= 4294967 )
5607     {
5608         *timeInMiliSec = rejoinCycleTime * 1000;
5609         return true;
5610     }
5611     else
5612     {
5613         return false;
5614     }
5615 }
5616 
OnRejoin0CycleTimerEvent(void * context)5617 static void OnRejoin0CycleTimerEvent( void* context )
5618 {
5619     TimerStop( &MacCtx.Rejoin0CycleTimer );
5620     ConvertRejoinCycleTime( Nvm.MacGroup2.Rejoin0CycleInSec, &MacCtx.Rejoin0CycleTime );
5621 
5622     OnMacProcessNotify( );
5623 
5624     Nvm.MacGroup2.IsRejoin0RequestQueued = true;
5625 
5626     TimerSetValue( &MacCtx.Rejoin0CycleTimer, MacCtx.Rejoin0CycleTime );
5627     TimerStart( &MacCtx.Rejoin0CycleTimer );
5628 }
5629 
OnRejoin1CycleTimerEvent(void * context)5630 static void OnRejoin1CycleTimerEvent( void* context )
5631 {
5632     TimerStop( &MacCtx.Rejoin1CycleTimer );
5633     ConvertRejoinCycleTime( Nvm.MacGroup2.Rejoin1CycleInSec, &MacCtx.Rejoin1CycleTime );
5634 
5635     OnMacProcessNotify( );
5636 
5637     Nvm.MacGroup2.IsRejoin1RequestQueued = true;
5638 
5639     TimerSetValue( &MacCtx.Rejoin1CycleTimer, MacCtx.Rejoin1CycleTime );
5640     TimerStart( &MacCtx.Rejoin1CycleTimer );
5641 }
5642 
OnForceRejoinReqCycleTimerEvent(void * context)5643 static void OnForceRejoinReqCycleTimerEvent( void* context )
5644 {
5645     Nvm.MacGroup1.ForceRejoinRetriesCounter++;
5646     if( ( Nvm.MacGroup2.ForceRejoinType == 0 ) || ( Nvm.MacGroup2.ForceRejoinType == 1 ) )
5647     {
5648         Nvm.MacGroup2.IsRejoin0RequestQueued = true;
5649     }
5650     else
5651     {
5652         Nvm.MacGroup2.IsRejoin2RequestQueued = true;
5653     }
5654 
5655     if( Nvm.MacGroup1.ForceRejoinRetriesCounter >= Nvm.MacGroup2.ForceRejoinMaxRetries )
5656     {
5657         TimerStop( &MacCtx.ForceRejoinReqCycleTimer );
5658         Nvm.MacGroup1.ForceRejoinRetriesCounter = 0;
5659     }
5660     else
5661     {
5662         TimerSetValue( &MacCtx.ForceRejoinReqCycleTimer, MacCtx.ForceRejonCycleTime );
5663         TimerStart( &MacCtx.ForceRejoinReqCycleTimer );
5664     }
5665 
5666     OnMacProcessNotify( );
5667 }
5668 
LoRaMacTestSetDutyCycleOn(bool enable)5669 void LoRaMacTestSetDutyCycleOn( bool enable )
5670 {
5671     VerifyParams_t verify;
5672 
5673     verify.DutyCycle = enable;
5674 
5675     if( RegionVerify( Nvm.MacGroup2.Region, &verify, PHY_DUTY_CYCLE ) == true )
5676     {
5677         Nvm.MacGroup2.DutyCycleOn = enable;
5678         // Handle NVM potential changes
5679         MacCtx.MacFlags.Bits.NvmHandle = 1;
5680     }
5681 }
5682 
LoRaMacDeInitialization(void)5683 LoRaMacStatus_t LoRaMacDeInitialization( void )
5684 {
5685     // Check the current state of the LoRaMac
5686     if ( LoRaMacStop( ) == LORAMAC_STATUS_OK )
5687     {
5688         // Stop Timers
5689         TimerStop( &MacCtx.TxDelayedTimer );
5690         TimerStop( &MacCtx.RxWindowTimer1 );
5691         TimerStop( &MacCtx.RxWindowTimer2 );
5692 
5693         // Take care about class B
5694         LoRaMacClassBHaltBeaconing( );
5695 
5696         // Reset Mac parameters
5697         ResetMacParameters( false );
5698 
5699         // Switch off Radio
5700         Radio.Sleep( );
5701 
5702         // Return success
5703         return LORAMAC_STATUS_OK;
5704     }
5705     else
5706     {
5707         return LORAMAC_STATUS_BUSY;
5708     }
5709 }
5710 
LoRaMacReset(void)5711 void LoRaMacReset( void )
5712 {
5713     // Reset state machine
5714     MacCtx.MacState &= ~LORAMAC_TX_RUNNING;
5715     MacCtx.MacFlags.Bits.MacDone = 1;
5716 
5717     // Stop Timers
5718     TimerStop( &MacCtx.TxDelayedTimer );
5719     TimerStop( &MacCtx.RxWindowTimer1 );
5720     TimerStop( &MacCtx.RxWindowTimer2 );
5721 
5722     // Stop retransmissions
5723     MacCtx.ChannelsNbTransCounter = Nvm.MacGroup2.MacParams.ChannelsNbTrans;
5724 
5725     // Inform application layer
5726     OnMacProcessNotify( );
5727 }
5728