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