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