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