1 /*!
2  * \file      LmHandler.c
3  *
4  * \brief     Implements the LoRaMac layer handling.
5  *            Provides the possibility to register applicative packages.
6  *
7  * \remark    Inspired by the examples provided on the en.i-cube_lrwan fork.
8  *            MCD Application Team ( STMicroelectronics International )
9  *
10  * \copyright Revised BSD License, see section \ref LICENSE.
11  *
12  * \code
13  *                ______                              _
14  *               / _____)             _              | |
15  *              ( (____  _____ ____ _| |_ _____  ____| |__
16  *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
17  *               _____) ) ____| | | || |_| ____( (___| | | |
18  *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
19  *              (C)2013-2018 Semtech
20  *
21  * \endcode
22  *
23  * \author    Miguel Luis ( Semtech )
24  */
25 #include <stdlib.h>
26 #include <stdint.h>
27 #include <stdbool.h>
28 #include "utilities.h"
29 #include "timer.h"
30 #include "Commissioning.h"
31 #include "NvmDataMgmt.h"
32 #include "radio.h"
33 #include "LmHandler.h"
34 #include "LmhPackage.h"
35 #include "LmhpCompliance.h"
36 #include "LmhpClockSync.h"
37 #include "LmhpRemoteMcastSetup.h"
38 #include "LmhpFragmentation.h"
39 
40 #ifndef ACTIVE_REGION
41 
42 #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default."
43 
44 #define ACTIVE_REGION LORAMAC_REGION_EU868
45 
46 #endif
47 
48 #include "LoRaMacTest.h"
49 
50 static CommissioningParams_t CommissioningParams =
51 {
52     .IsOtaaActivation = OVER_THE_AIR_ACTIVATION,
53     .DevEui = { 0 },  // Automatically filed from secure-element
54     .JoinEui = { 0 }, // Automatically filed from secure-element
55     .SePin = { 0 },   // Automatically filed from secure-element
56     .NetworkId = LORAWAN_NETWORK_ID,
57     .DevAddr = LORAWAN_DEVICE_ADDRESS,
58 };
59 
60 static LmhPackage_t *LmHandlerPackages[PKG_MAX_NUMBER];
61 
62 /*!
63  * Upper layer LoRaMac parameters
64  */
65 static LmHandlerParams_t *LmHandlerParams;
66 
67 /*!
68  * Upper layer callbacks
69  */
70 static LmHandlerCallbacks_t *LmHandlerCallbacks;
71 
72 /*!
73  * Used to notify LmHandler of LoRaMac events
74  */
75 static LoRaMacPrimitives_t LoRaMacPrimitives;
76 
77 /*!
78  * LoRaMac callbacks
79  */
80 static LoRaMacCallback_t LoRaMacCallbacks;
81 
82 static LmHandlerJoinParams_t JoinParams =
83 {
84     .CommissioningParams = &CommissioningParams,
85     .Datarate = DR_0,
86     .Status = LORAMAC_HANDLER_ERROR
87 };
88 
89 static LmHandlerTxParams_t TxParams =
90 {
91     .CommissioningParams = &CommissioningParams,
92     .MsgType = LORAMAC_HANDLER_UNCONFIRMED_MSG,
93     .AckReceived = 0,
94     .Datarate = DR_0,
95     .UplinkCounter = 0,
96     .AppData =
97     {
98         .Port = 0,
99         .BufferSize = 0,
100         .Buffer = NULL,
101     },
102     .TxPower = TX_POWER_0,
103     .Channel = 0,
104 };
105 
106 static LmHandlerRxParams_t RxParams =
107 {
108     .CommissioningParams = &CommissioningParams,
109     .Rssi = 0,
110     .Snr = 0,
111     .DownlinkCounter = 0,
112     .RxSlot = -1,
113 };
114 
115 static LoRaMacHandlerBeaconParams_t BeaconParams =
116 {
117     .State = LORAMAC_HANDLER_BEACON_ACQUIRING,
118     .Info =
119     {
120         .Time = { .Seconds = 0, .SubSeconds = 0 },
121         .Frequency = 0,
122         .Datarate = 0,
123         .Rssi = 0,
124         .Snr = 0,
125         .GwSpecific =
126         {
127             .InfoDesc = 0,
128             .Info = { 0 },
129         },
130     },
131 };
132 
133 /*!
134  * Indicates if a switch to Class B operation is pending or not.
135  *
136  * TODO: Create a new structure to store the current handler states/status
137  *       and add the below variable to it.
138  */
139 static bool IsClassBSwitchPending = false;
140 
141 /*!
142  * Stores the time to wait before next transmission
143  *
144  * TODO: Create a new structure to store the current handler states/status
145  *       and add the below variable to it.
146  */
147 static TimerTime_t DutyCycleWaitTime = 0;
148 
149 /*!
150  * Indicates if an uplink is pending upon MAC layer request
151  *
152  * TODO: Create a new structure to store the current handler states/status
153  *       and add the below variable to it.
154  */
155 static bool IsUplinkTxPending = false;
156 
157 /*!
158  * \brief   MCPS-Confirm event function
159  *
160  * \param   [IN] mcpsConfirm - Pointer to the confirm structure,
161  *                             containing confirm attributes.
162  */
163 static void McpsConfirm( McpsConfirm_t *mcpsConfirm );
164 
165 /*!
166  * \brief   MCPS-Indication event function
167  *
168  * \param   [IN] mcpsIndication - Pointer to the indication structure,
169  *               containing indication attributes.
170  */
171 static void McpsIndication( McpsIndication_t *mcpsIndication );
172 
173 /*!
174  * \brief   MLME-Confirm event function
175  *
176  * \param   [IN] MlmeConfirm - Pointer to the confirm structure,
177  *               containing confirm attributes.
178  */
179 static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm );
180 
181 /*!
182  * \brief   MLME-Indication event function
183  *
184  * \param   [IN] mlmeIndication - Pointer to the indication structure,
185  *               containing indication attributes.
186  */
187 static void MlmeIndication( MlmeIndication_t *mlmeIndication );
188 
189 /*!
190  * Starts the beacon search
191  *
192  * \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET
193  */
194 static LmHandlerErrorStatus_t LmHandlerBeaconReq( void );
195 
196 /*
197  *=============================================================================
198  * PACKAGES HANDLING
199  *=============================================================================
200  */
201 typedef enum PackageNotifyTypes_e
202 {
203     PACKAGE_MCPS_CONFIRM,
204     PACKAGE_MCPS_INDICATION,
205     PACKAGE_MLME_CONFIRM,
206     PACKAGE_MLME_INDICATION,
207 }PackageNotifyTypes_t;
208 
209 /*!
210  * Notifies the package to process the LoRaMac callbacks.
211  *
212  * \param [IN] notifyType MAC notification type [PACKAGE_MCPS_CONFIRM,
213  *                                               PACKAGE_MCPS_INDICATION,
214  *                                               PACKAGE_MLME_CONFIRM,
215  *                                               PACKAGE_MLME_INDICATION]
216  * \param[IN] params      Notification parameters. The params type can be
217  *                        [McpsConfirm_t, McpsIndication_t, MlmeConfirm_t, MlmeIndication_t]
218  */
219 static void LmHandlerPackagesNotify( PackageNotifyTypes_t notifyType, void *params );
220 
221 static bool LmHandlerPackageIsTxPending( void );
222 
223 static void LmHandlerPackagesProcess( void );
224 
LmHandlerInit(LmHandlerCallbacks_t * handlerCallbacks,LmHandlerParams_t * handlerParams)225 LmHandlerErrorStatus_t LmHandlerInit( LmHandlerCallbacks_t *handlerCallbacks,
226                                       LmHandlerParams_t *handlerParams )
227 {
228     //
229     uint16_t nbNvmData = 0;
230     MibRequestConfirm_t mibReq;
231     LmHandlerParams = handlerParams;
232     LmHandlerCallbacks = handlerCallbacks;
233 
234     LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
235     LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
236     LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
237     LoRaMacPrimitives.MacMlmeIndication = MlmeIndication;
238     LoRaMacCallbacks.GetBatteryLevel = LmHandlerCallbacks->GetBatteryLevel;
239     LoRaMacCallbacks.GetTemperatureLevel = LmHandlerCallbacks->GetTemperature;
240     LoRaMacCallbacks.NvmDataChange  = NvmDataMgmtEvent;
241     LoRaMacCallbacks.MacProcessNotify = LmHandlerCallbacks->OnMacProcess;
242 
243     IsClassBSwitchPending = false;
244     IsUplinkTxPending = false;
245 
246     if( LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LmHandlerParams->Region ) != LORAMAC_STATUS_OK )
247     {
248         return LORAMAC_HANDLER_ERROR;
249     }
250 
251     // Restore data if required
252     nbNvmData = NvmDataMgmtRestore( );
253 
254     // Try to restore from NVM and query the mac if possible.
255     if( nbNvmData > 0 )
256     {
257         LmHandlerCallbacks->OnNvmDataChange( LORAMAC_HANDLER_NVM_RESTORE, nbNvmData );
258     }
259     else
260     {
261         // Configure the default datarate
262         mibReq.Type = MIB_CHANNELS_DEFAULT_DATARATE;
263         mibReq.Param.ChannelsDefaultDatarate = LmHandlerParams->TxDatarate;
264         LoRaMacMibSetRequestConfirm( &mibReq );
265 
266         mibReq.Type = MIB_CHANNELS_DATARATE;
267         mibReq.Param.ChannelsDatarate = LmHandlerParams->TxDatarate;
268         LoRaMacMibSetRequestConfirm( &mibReq );
269 
270 #if( OVER_THE_AIR_ACTIVATION == 0 )
271         // Tell the MAC layer which network server version are we connecting too.
272         mibReq.Type = MIB_ABP_LORAWAN_VERSION;
273         mibReq.Param.AbpLrWanVersion.Value = ABP_ACTIVATION_LRWAN_VERSION;
274         LoRaMacMibSetRequestConfirm( &mibReq );
275 
276         mibReq.Type = MIB_NET_ID;
277         mibReq.Param.NetID = LORAWAN_NETWORK_ID;
278         LoRaMacMibSetRequestConfirm( &mibReq );
279 
280 #if( STATIC_DEVICE_ADDRESS != 1 )
281         // Random seed initialization
282         srand1( LmHandlerCallbacks->GetRandomSeed( ) );
283         // Choose a random device address
284         CommissioningParams.DevAddr = randr( 0, 0x01FFFFFF );
285 #endif
286 
287         mibReq.Type = MIB_DEV_ADDR;
288         mibReq.Param.DevAddr = CommissioningParams.DevAddr;
289         LoRaMacMibSetRequestConfirm( &mibReq );
290 #endif // #if( OVER_THE_AIR_ACTIVATION == 0 )
291     }
292 
293     // Read secure-element DEV_EUI, JOI_EUI and SE_PIN values.
294     mibReq.Type = MIB_DEV_EUI;
295     LoRaMacMibGetRequestConfirm( &mibReq );
296     memcpy1( CommissioningParams.DevEui, mibReq.Param.DevEui, 8 );
297 
298     mibReq.Type = MIB_JOIN_EUI;
299     LoRaMacMibGetRequestConfirm( &mibReq );
300     memcpy1( CommissioningParams.JoinEui, mibReq.Param.JoinEui, 8 );
301 
302     mibReq.Type = MIB_SE_PIN;
303     LoRaMacMibGetRequestConfirm( &mibReq );
304     memcpy1( CommissioningParams.SePin, mibReq.Param.SePin, 4 );
305 
306     mibReq.Type = MIB_PUBLIC_NETWORK;
307     mibReq.Param.EnablePublicNetwork = LmHandlerParams->PublicNetworkEnable;
308     LoRaMacMibSetRequestConfirm( &mibReq );
309 
310     mibReq.Type = MIB_ADR;
311     mibReq.Param.AdrEnable = LmHandlerParams->AdrEnable;
312     LoRaMacMibSetRequestConfirm( &mibReq );
313 
314     LoRaMacTestSetDutyCycleOn( LmHandlerParams->DutyCycleEnabled );
315 
316     LoRaMacStart( );
317 
318     mibReq.Type = MIB_NETWORK_ACTIVATION;
319     if( LoRaMacMibGetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
320     {
321         if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE )
322         {
323             LmHandlerCallbacks->OnNetworkParametersChange( &CommissioningParams );
324         }
325     }
326     return LORAMAC_HANDLER_SUCCESS;
327 }
328 
LmHandlerIsBusy(void)329 bool LmHandlerIsBusy( void )
330 {
331     if( LoRaMacIsBusy( ) == true )
332     {
333         return true;
334     }
335     if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET )
336     {
337         // The network isn't yet joined, try again later.
338         LmHandlerJoin( );
339         return true;
340     }
341 
342     if( LmHandlerPackageIsTxPending( ) == true )
343     {
344         return true;
345     }
346 
347     return false;
348 }
349 
LmHandlerProcess(void)350 void LmHandlerProcess( void )
351 {
352     uint16_t size = 0;
353 
354     // Process Radio IRQ
355     if( Radio.IrqProcess != NULL )
356     {
357         Radio.IrqProcess( );
358     }
359 
360     // Processes the LoRaMac events
361     LoRaMacProcess( );
362 
363     // Store to NVM if required
364     size = NvmDataMgmtStore( );
365 
366     if( size > 0 )
367     {
368         LmHandlerCallbacks->OnNvmDataChange( LORAMAC_HANDLER_NVM_STORE, size );
369     }
370 
371     // Call all packages process functions
372     LmHandlerPackagesProcess( );
373 
374     // Check if a package transmission is pending.
375     // If it is the case exit function earlier
376     if( LmHandlerPackageIsTxPending( ) == true )
377     {
378         return;
379     }
380 
381     // If a MAC layer scheduled uplink is still pending try to send it.
382     if( IsUplinkTxPending == true )
383     {
384         // Send an empty message
385         LmHandlerAppData_t appData =
386         {
387             .Buffer = NULL,
388             .BufferSize = 0,
389             .Port = 0,
390         };
391 
392         if( LmHandlerSend( &appData, LmHandlerParams->IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS )
393         {
394             IsUplinkTxPending = false;
395         }
396     }
397 }
398 
LmHandlerGetDutyCycleWaitTime(void)399 TimerTime_t LmHandlerGetDutyCycleWaitTime( void )
400 {
401     return DutyCycleWaitTime;
402 }
403 
404 /*!
405  * Join a LoRa Network in classA
406  *
407  * \Note if the device is ABP, this is a pass through function
408  *
409  * \param [IN] isOtaa Indicates which activation mode must be used
410  */
LmHandlerJoinRequest(bool isOtaa)411 static void LmHandlerJoinRequest( bool isOtaa )
412 {
413     MlmeReq_t mlmeReq;
414 
415     mlmeReq.Type = MLME_JOIN;
416     mlmeReq.Req.Join.Datarate = LmHandlerParams->TxDatarate;
417 
418     if( isOtaa == true )
419     {
420         mlmeReq.Req.Join.NetworkActivation = ACTIVATION_TYPE_OTAA;
421         // Update commissioning parameters activation type variable.
422         CommissioningParams.IsOtaaActivation = true;
423     }
424     else
425     {
426         mlmeReq.Req.Join.NetworkActivation = ACTIVATION_TYPE_ABP;
427         // Update commissioning parameters activation type variable.
428         CommissioningParams.IsOtaaActivation = false;
429     }
430     // Starts the join procedure
431     LmHandlerCallbacks->OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime );
432     DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
433 }
434 
LmHandlerJoin(void)435 void LmHandlerJoin( void )
436 {
437     LmHandlerJoinRequest( CommissioningParams.IsOtaaActivation );
438 }
439 
LmHandlerJoinStatus(void)440 LmHandlerFlagStatus_t LmHandlerJoinStatus( void )
441 {
442     MibRequestConfirm_t mibReq;
443     LoRaMacStatus_t status;
444 
445     mibReq.Type = MIB_NETWORK_ACTIVATION;
446     status = LoRaMacMibGetRequestConfirm( &mibReq );
447 
448     if( status == LORAMAC_STATUS_OK )
449     {
450         if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE )
451         {
452             return LORAMAC_HANDLER_RESET;
453         }
454         else
455         {
456             return LORAMAC_HANDLER_SET;
457         }
458     }
459     else
460     {
461         return LORAMAC_HANDLER_RESET;
462     }
463 }
464 
LmHandlerSend(LmHandlerAppData_t * appData,LmHandlerMsgTypes_t isTxConfirmed)465 LmHandlerErrorStatus_t LmHandlerSend( LmHandlerAppData_t *appData, LmHandlerMsgTypes_t isTxConfirmed )
466 {
467     LoRaMacStatus_t status;
468     McpsReq_t mcpsReq;
469     LoRaMacTxInfo_t txInfo;
470 
471     if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET )
472     {
473         // The network isn't joined, try again.
474         LmHandlerJoinRequest( CommissioningParams.IsOtaaActivation );
475         return LORAMAC_HANDLER_ERROR;
476     }
477 
478     TxParams.MsgType = isTxConfirmed;
479     mcpsReq.Type = ( isTxConfirmed == LORAMAC_HANDLER_UNCONFIRMED_MSG ) ? MCPS_UNCONFIRMED : MCPS_CONFIRMED;
480     mcpsReq.Req.Unconfirmed.Datarate = LmHandlerParams->TxDatarate;
481     if( LoRaMacQueryTxPossible( appData->BufferSize, &txInfo ) != LORAMAC_STATUS_OK )
482     {
483         // Send empty frame in order to flush MAC commands
484         mcpsReq.Type = MCPS_UNCONFIRMED;
485         mcpsReq.Req.Unconfirmed.fBuffer = NULL;
486         mcpsReq.Req.Unconfirmed.fBufferSize = 0;
487     }
488     else
489     {
490         mcpsReq.Req.Unconfirmed.fPort = appData->Port;
491         mcpsReq.Req.Unconfirmed.fBufferSize = appData->BufferSize;
492         mcpsReq.Req.Unconfirmed.fBuffer = appData->Buffer;
493     }
494 
495     TxParams.AppData = *appData;
496     TxParams.Datarate = LmHandlerParams->TxDatarate;
497 
498     status = LoRaMacMcpsRequest( &mcpsReq );
499     LmHandlerCallbacks->OnMacMcpsRequest( status, &mcpsReq, mcpsReq.ReqReturn.DutyCycleWaitTime );
500     DutyCycleWaitTime = mcpsReq.ReqReturn.DutyCycleWaitTime;
501 
502     if( status == LORAMAC_STATUS_OK )
503     {
504         IsUplinkTxPending = false;
505         return LORAMAC_HANDLER_SUCCESS;
506     }
507     else
508     {
509         return LORAMAC_HANDLER_ERROR;
510     }
511 }
512 
LmHandlerDeviceTimeReq(void)513 LmHandlerErrorStatus_t LmHandlerDeviceTimeReq( void )
514 {
515     LoRaMacStatus_t status;
516     MlmeReq_t mlmeReq;
517 
518     mlmeReq.Type = MLME_DEVICE_TIME;
519 
520     status = LoRaMacMlmeRequest( &mlmeReq );
521     LmHandlerCallbacks->OnMacMlmeRequest( status, &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime );
522     DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
523 
524     if( status == LORAMAC_STATUS_OK )
525     {
526         return LORAMAC_HANDLER_SUCCESS;
527     }
528     else
529     {
530         return LORAMAC_HANDLER_ERROR;
531     }
532 }
533 
LmHandlerBeaconReq(void)534 static LmHandlerErrorStatus_t LmHandlerBeaconReq( void )
535 {
536     LoRaMacStatus_t status;
537     MlmeReq_t mlmeReq;
538 
539     mlmeReq.Type = MLME_BEACON_ACQUISITION;
540 
541     status = LoRaMacMlmeRequest( &mlmeReq );
542     LmHandlerCallbacks->OnMacMlmeRequest( status, &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime );
543     DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
544 
545     if( status == LORAMAC_STATUS_OK )
546     {
547         return LORAMAC_HANDLER_SUCCESS;
548     }
549     else
550     {
551         return LORAMAC_HANDLER_ERROR;
552     }
553 }
554 
LmHandlerPingSlotReq(uint8_t periodicity)555 LmHandlerErrorStatus_t LmHandlerPingSlotReq( uint8_t periodicity )
556 {
557     LoRaMacStatus_t status;
558     MlmeReq_t mlmeReq;
559 
560     mlmeReq.Type = MLME_PING_SLOT_INFO;
561     mlmeReq.Req.PingSlotInfo.PingSlot.Fields.Periodicity = periodicity;
562     mlmeReq.Req.PingSlotInfo.PingSlot.Fields.RFU = 0;
563 
564     status = LoRaMacMlmeRequest( &mlmeReq );
565     LmHandlerCallbacks->OnMacMlmeRequest( status, &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime );
566     DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
567 
568     if( status == LORAMAC_STATUS_OK )
569     {
570         // Send an empty message
571         LmHandlerAppData_t appData =
572         {
573             .Buffer = NULL,
574             .BufferSize = 0,
575             .Port = 0,
576         };
577         return LmHandlerSend( &appData, LmHandlerParams->IsTxConfirmed );
578     }
579     else
580     {
581         return LORAMAC_HANDLER_ERROR;
582     }
583 }
584 
LmHandlerRequestClass(DeviceClass_t newClass)585 LmHandlerErrorStatus_t LmHandlerRequestClass( DeviceClass_t newClass )
586 {
587     MibRequestConfirm_t mibReq;
588     DeviceClass_t currentClass;
589     LmHandlerErrorStatus_t errorStatus = LORAMAC_HANDLER_SUCCESS;
590 
591     mibReq.Type = MIB_DEVICE_CLASS;
592     LoRaMacMibGetRequestConfirm( &mibReq );
593     currentClass = mibReq.Param.Class;
594 
595     // Attempt to switch only if class update
596     if( currentClass != newClass )
597     {
598         switch( newClass )
599         {
600         case CLASS_A:
601             {
602                 if( currentClass != CLASS_A )
603                 {
604                     mibReq.Param.Class = CLASS_A;
605                     if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
606                     {
607                         // Switch is instantaneous
608                         LmHandlerCallbacks->OnClassChange( CLASS_A );
609                     }
610                     else
611                     {
612                         errorStatus = LORAMAC_HANDLER_ERROR;
613                     }
614                 }
615             }
616             break;
617         case CLASS_B:
618             {
619                 if( currentClass != CLASS_A )
620                 {
621                     errorStatus = LORAMAC_HANDLER_ERROR;
622                 }
623                 // Beacon must first be acquired
624                 errorStatus = LmHandlerDeviceTimeReq( );
625                 IsClassBSwitchPending = true;
626             }
627             break;
628         case CLASS_C:
629             {
630                 if( currentClass != CLASS_A )
631                 {
632                     errorStatus = LORAMAC_HANDLER_ERROR;
633                 }
634                 // Switch is instantaneous
635                 mibReq.Param.Class = CLASS_C;
636                 if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
637                 {
638                     LmHandlerCallbacks->OnClassChange( CLASS_C );
639                 }
640                 else
641                 {
642                     errorStatus = LORAMAC_HANDLER_ERROR;
643                 }
644             }
645             break;
646         default:
647             break;
648         }
649     }
650     return errorStatus;
651 }
652 
LmHandlerGetCurrentClass(void)653 DeviceClass_t LmHandlerGetCurrentClass( void )
654 {
655     MibRequestConfirm_t mibReq;
656 
657     mibReq.Type = MIB_DEVICE_CLASS;
658     LoRaMacMibGetRequestConfirm( &mibReq );
659 
660     return mibReq.Param.Class;
661 }
662 
LmHandlerGetCurrentDatarate(void)663 int8_t LmHandlerGetCurrentDatarate( void )
664 {
665     MibRequestConfirm_t mibGet;
666 
667     mibGet.Type = MIB_CHANNELS_DATARATE;
668     LoRaMacMibGetRequestConfirm( &mibGet );
669 
670     return mibGet.Param.ChannelsDatarate;
671 }
672 
LmHandlerGetActiveRegion(void)673 LoRaMacRegion_t LmHandlerGetActiveRegion( void )
674 {
675     return LmHandlerParams->Region;
676 }
677 
LmHandlerSetSystemMaxRxError(uint32_t maxErrorInMs)678 LmHandlerErrorStatus_t LmHandlerSetSystemMaxRxError( uint32_t maxErrorInMs )
679 {
680     MibRequestConfirm_t mibReq;
681 
682     mibReq.Type = MIB_SYSTEM_MAX_RX_ERROR;
683     mibReq.Param.SystemMaxRxError = maxErrorInMs;
684     if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
685     {
686         return LORAMAC_HANDLER_ERROR;
687     }
688     return LORAMAC_HANDLER_SUCCESS;
689 }
690 
691 /*
692  *=============================================================================
693  * LORAMAC NOTIFICATIONS HANDLING
694  *=============================================================================
695  */
696 
McpsConfirm(McpsConfirm_t * mcpsConfirm)697 static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
698 {
699     TxParams.IsMcpsConfirm = 1;
700     TxParams.Status = mcpsConfirm->Status;
701     TxParams.Datarate = mcpsConfirm->Datarate;
702     TxParams.UplinkCounter = mcpsConfirm->UpLinkCounter;
703     TxParams.TxPower = mcpsConfirm->TxPower;
704     TxParams.Channel = mcpsConfirm->Channel;
705     TxParams.AckReceived = mcpsConfirm->AckReceived;
706 
707     LmHandlerCallbacks->OnTxData( &TxParams );
708 
709     LmHandlerPackagesNotify( PACKAGE_MCPS_CONFIRM, mcpsConfirm );
710 }
711 
McpsIndication(McpsIndication_t * mcpsIndication)712 static void McpsIndication( McpsIndication_t *mcpsIndication )
713 {
714     LmHandlerAppData_t appData;
715 
716     RxParams.IsMcpsIndication = 1;
717     RxParams.Status = mcpsIndication->Status;
718 
719     if( RxParams.Status != LORAMAC_EVENT_INFO_STATUS_OK )
720     {
721         return;
722     }
723 
724     RxParams.Datarate = mcpsIndication->RxDatarate;
725     RxParams.Rssi = mcpsIndication->Rssi;
726     RxParams.Snr = mcpsIndication->Snr;
727     RxParams.DownlinkCounter = mcpsIndication->DownLinkCounter;
728     RxParams.RxSlot = mcpsIndication->RxSlot;
729 
730     appData.Port = mcpsIndication->Port;
731     appData.BufferSize = mcpsIndication->BufferSize;
732     appData.Buffer = mcpsIndication->Buffer;
733 
734     LmHandlerCallbacks->OnRxData( &appData, &RxParams );
735 
736     if( mcpsIndication->DeviceTimeAnsReceived == true )
737     {
738 #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 )
739         // Provide fix values. DeviceTimeAns is accurate
740         LmHandlerCallbacks->OnSysTimeUpdate( true, 0 );
741 #else
742         LmHandlerCallbacks->OnSysTimeUpdate( );
743 #endif
744     }
745     // Call packages RxProcess function
746     LmHandlerPackagesNotify( PACKAGE_MCPS_INDICATION, mcpsIndication );
747 
748     if( mcpsIndication->IsUplinkTxPending != 0 )
749     {
750         // The server signals that it has pending data to be sent.
751         // We schedule an uplink as soon as possible to flush the server.
752         IsUplinkTxPending = true;
753     }
754 }
755 
MlmeConfirm(MlmeConfirm_t * mlmeConfirm)756 static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm )
757 {
758     TxParams.IsMcpsConfirm = 0;
759     TxParams.Status = mlmeConfirm->Status;
760     LmHandlerCallbacks->OnTxData( &TxParams );
761 
762     LmHandlerPackagesNotify( PACKAGE_MLME_CONFIRM, mlmeConfirm );
763 
764     switch( mlmeConfirm->MlmeRequest )
765     {
766     case MLME_JOIN:
767         {
768             MibRequestConfirm_t mibReq;
769             mibReq.Type = MIB_DEV_ADDR;
770             LoRaMacMibGetRequestConfirm( &mibReq );
771             JoinParams.CommissioningParams->DevAddr = mibReq.Param.DevAddr;
772             JoinParams.Datarate = LmHandlerGetCurrentDatarate( );
773 
774             if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
775             {
776                 // Status is OK, node has joined the network
777                 JoinParams.Status = LORAMAC_HANDLER_SUCCESS;
778             }
779             else
780             {
781                 // Join was not successful. Try to join again
782                 JoinParams.Status = LORAMAC_HANDLER_ERROR;
783             }
784             // Notify upper layer
785             LmHandlerCallbacks->OnJoinRequest( &JoinParams );
786         }
787         break;
788     case MLME_LINK_CHECK:
789         {
790             // Check DemodMargin
791             // Check NbGateways
792         }
793         break;
794     case MLME_DEVICE_TIME:
795         {
796             if( IsClassBSwitchPending == true )
797             {
798                 LmHandlerBeaconReq( );
799             }
800         }
801         break;
802     case MLME_BEACON_ACQUISITION:
803         {
804             if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
805             {
806                 // Beacon has been acquired
807                 // Request server for ping slot
808                 LmHandlerPingSlotReq( LmHandlerParams->PingSlotPeriodicity );
809             }
810             else
811             {
812                 // Beacon not acquired
813                 // Request Device Time again.
814                 LmHandlerDeviceTimeReq( );
815             }
816         }
817         break;
818     case MLME_PING_SLOT_INFO:
819         {
820             if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
821             {
822                 MibRequestConfirm_t mibReq;
823 
824                 // Class B is now activated
825                 mibReq.Type = MIB_DEVICE_CLASS;
826                 mibReq.Param.Class = CLASS_B;
827                 LoRaMacMibSetRequestConfirm( &mibReq );
828                 // Notify upper layer
829                 LmHandlerCallbacks->OnClassChange( CLASS_B );
830                 IsClassBSwitchPending = false;
831             }
832             else
833             {
834                 LmHandlerPingSlotReq( LmHandlerParams->PingSlotPeriodicity );
835             }
836         }
837         break;
838     default:
839         break;
840     }
841 }
842 
MlmeIndication(MlmeIndication_t * mlmeIndication)843 static void MlmeIndication( MlmeIndication_t *mlmeIndication )
844 {
845     RxParams.IsMcpsIndication = 0;
846     RxParams.Status = mlmeIndication->Status;
847     if( RxParams.Status != LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED )
848     {
849         LmHandlerCallbacks->OnRxData( NULL, &RxParams );
850     }
851 
852     // Call packages RxProcess function
853     LmHandlerPackagesNotify( PACKAGE_MLME_INDICATION, mlmeIndication );
854 
855     switch( mlmeIndication->MlmeIndication )
856     {
857     case MLME_BEACON_LOST:
858         {
859             MibRequestConfirm_t mibReq;
860             // Switch to class A again
861             mibReq.Type = MIB_DEVICE_CLASS;
862             mibReq.Param.Class = CLASS_A;
863             LoRaMacMibSetRequestConfirm( &mibReq );
864 
865             BeaconParams.State = LORAMAC_HANDLER_BEACON_LOST;
866             BeaconParams.Info.Time.Seconds = 0;
867             BeaconParams.Info.GwSpecific.InfoDesc = 0;
868             memset1( BeaconParams.Info.GwSpecific.Info, 0, 6 );
869 
870             LmHandlerCallbacks->OnClassChange( CLASS_A );
871             LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams );
872 
873             LmHandlerDeviceTimeReq( );
874         }
875         break;
876     case MLME_BEACON:
877     {
878         if( mlmeIndication->Status == LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED )
879         {
880             BeaconParams.State = LORAMAC_HANDLER_BEACON_RX;
881             BeaconParams.Info = mlmeIndication->BeaconInfo;
882 
883             LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams );
884         }
885         else
886         {
887             BeaconParams.State = LORAMAC_HANDLER_BEACON_NRX;
888             BeaconParams.Info = mlmeIndication->BeaconInfo;
889 
890             LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams );
891         }
892         break;
893     }
894     default:
895         break;
896     }
897 }
898 
899 /*
900  *=============================================================================
901  * PACKAGES HANDLING
902  *=============================================================================
903  */
904 
LmHandlerPackageRegister(uint8_t id,void * params)905 LmHandlerErrorStatus_t LmHandlerPackageRegister( uint8_t id, void *params )
906 {
907     LmhPackage_t *package = NULL;
908     switch( id )
909     {
910         case PACKAGE_ID_COMPLIANCE:
911         {
912             package = LmphCompliancePackageFactory( );
913             break;
914         }
915         case PACKAGE_ID_CLOCK_SYNC:
916         {
917             package = LmphClockSyncPackageFactory( );
918             break;
919         }
920         case PACKAGE_ID_REMOTE_MCAST_SETUP:
921         {
922             package = LmhpRemoteMcastSetupPackageFactory( );
923             break;
924         }
925         case PACKAGE_ID_FRAGMENTATION:
926         {
927             package = LmhpFragmentationPackageFactory( );
928             break;
929         }
930     }
931     if( package != NULL )
932     {
933         LmHandlerPackages[id] = package;
934         LmHandlerPackages[id]->OnMacMcpsRequest = LmHandlerCallbacks->OnMacMcpsRequest;
935         LmHandlerPackages[id]->OnMacMlmeRequest = LmHandlerCallbacks->OnMacMlmeRequest;
936         LmHandlerPackages[id]->OnJoinRequest = LmHandlerJoinRequest;
937         LmHandlerPackages[id]->OnDeviceTimeRequest = LmHandlerDeviceTimeReq;
938         LmHandlerPackages[id]->OnSysTimeUpdate = LmHandlerCallbacks->OnSysTimeUpdate;
939         LmHandlerPackages[id]->Init( params, LmHandlerParams->DataBuffer, LmHandlerParams->DataBufferMaxSize );
940 
941         return LORAMAC_HANDLER_SUCCESS;
942     }
943     else
944     {
945         return LORAMAC_HANDLER_ERROR;
946     }
947 }
948 
LmHandlerPackageIsInitialized(uint8_t id)949 bool LmHandlerPackageIsInitialized( uint8_t id )
950 {
951     if( LmHandlerPackages[id]->IsInitialized != NULL )
952     {
953         return LmHandlerPackages[id]->IsInitialized( );
954     }
955     else
956     {
957         return false;
958     }
959 }
960 
LmHandlerPackagesNotify(PackageNotifyTypes_t notifyType,void * params)961 static void LmHandlerPackagesNotify( PackageNotifyTypes_t notifyType, void *params )
962 {
963     for( int8_t i = 0; i < PKG_MAX_NUMBER; i++ )
964     {
965         if( LmHandlerPackages[i] != NULL )
966         {
967             switch( notifyType )
968             {
969                 case PACKAGE_MCPS_CONFIRM:
970                 {
971                     if( LmHandlerPackages[i]->OnMcpsConfirmProcess != NULL )
972                     {
973                         LmHandlerPackages[i]->OnMcpsConfirmProcess( ( McpsConfirm_t* ) params );
974                     }
975                     break;
976                 }
977                 case PACKAGE_MCPS_INDICATION:
978                 {
979                     if( LmHandlerPackages[i]->OnMcpsIndicationProcess != NULL )
980                     {
981                         LmHandlerPackages[i]->OnMcpsIndicationProcess( ( McpsIndication_t* )params );
982                     }
983                     break;
984                 }
985                 case PACKAGE_MLME_CONFIRM:
986                 {
987                     if( LmHandlerPackages[i]->OnMlmeConfirmProcess != NULL )
988                     {
989                         LmHandlerPackages[i]->OnMlmeConfirmProcess( ( MlmeConfirm_t* )params );
990                     }
991                     break;
992                 }
993                 case PACKAGE_MLME_INDICATION:
994                 {
995                     if( LmHandlerPackages[i]->OnMlmeIndicationProcess != NULL )
996                     {
997                         LmHandlerPackages[i]->OnMlmeIndicationProcess( params );
998                     }
999                     break;
1000                 }
1001             }
1002         }
1003     }
1004 }
1005 
LmHandlerPackageIsTxPending(void)1006 static bool LmHandlerPackageIsTxPending( void )
1007 {
1008     for( int8_t i = 0; i < PKG_MAX_NUMBER; i++ )
1009     {
1010         if( LmHandlerPackages[i] != NULL )
1011         {
1012             if( LmHandlerPackages[i]->IsTxPending( ) == true )
1013             {
1014                 return true;
1015             }
1016         }
1017     }
1018     return false;
1019 }
1020 
LmHandlerPackagesProcess(void)1021 static void LmHandlerPackagesProcess( void )
1022 {
1023     for( int8_t i = 0; i < PKG_MAX_NUMBER; i++ )
1024     {
1025         if( ( LmHandlerPackages[i] != NULL ) &&
1026             ( LmHandlerPackages[i]->Process != NULL ) &&
1027             ( LmHandlerPackageIsInitialized( i ) != false ) )
1028         {
1029             LmHandlerPackages[i]->Process( );
1030         }
1031     }
1032 }
1033