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, ¶ms );
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, ¶ms );
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 = ¶ms;
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, ¶ms );
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