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  * Requests network server time update
191  *
192  * \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET
193  */
194 static LmHandlerErrorStatus_t LmHandlerDeviceTimeReq( void );
195 
196 /*!
197  * Starts the beacon search
198  *
199  * \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET
200  */
201 static LmHandlerErrorStatus_t LmHandlerBeaconReq( void );
202 
203 /*
204  *=============================================================================
205  * PACKAGES HANDLING
206  *=============================================================================
207  */
208 typedef enum PackageNotifyTypes_e
209 {
210     PACKAGE_MCPS_CONFIRM,
211     PACKAGE_MCPS_INDICATION,
212     PACKAGE_MLME_CONFIRM,
213     PACKAGE_MLME_INDICATION,
214 }PackageNotifyTypes_t;
215 
216 /*!
217  * Notifies the package to process the LoRaMac callbacks.
218  *
219  * \param [IN] notifyType MAC notification type [PACKAGE_MCPS_CONFIRM,
220  *                                               PACKAGE_MCPS_INDICATION,
221  *                                               PACKAGE_MLME_CONFIRM,
222  *                                               PACKAGE_MLME_INDICATION]
223  * \param[IN] params      Notification parameters. The params type can be
224  *                        [McpsConfirm_t, McpsIndication_t, MlmeConfirm_t, MlmeIndication_t]
225  */
226 static void LmHandlerPackagesNotify( PackageNotifyTypes_t notifyType, void *params );
227 
228 static bool LmHandlerPackageIsTxPending( void );
229 
230 static void LmHandlerPackagesProcess( void );
231 
LmHandlerInit(LmHandlerCallbacks_t * handlerCallbacks,LmHandlerParams_t * handlerParams)232 LmHandlerErrorStatus_t LmHandlerInit( LmHandlerCallbacks_t *handlerCallbacks,
233                                       LmHandlerParams_t *handlerParams )
234 {
235     //
236     uint16_t nbNvmData = 0;
237     MibRequestConfirm_t mibReq;
238     LmHandlerParams = handlerParams;
239     LmHandlerCallbacks = handlerCallbacks;
240 
241     LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
242     LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
243     LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
244     LoRaMacPrimitives.MacMlmeIndication = MlmeIndication;
245     LoRaMacCallbacks.GetBatteryLevel = LmHandlerCallbacks->GetBatteryLevel;
246     LoRaMacCallbacks.GetTemperatureLevel = LmHandlerCallbacks->GetTemperature;
247     LoRaMacCallbacks.NvmDataChange  = NvmDataMgmtEvent;
248     LoRaMacCallbacks.MacProcessNotify = LmHandlerCallbacks->OnMacProcess;
249 
250     IsClassBSwitchPending = false;
251     IsUplinkTxPending = false;
252 
253     if( LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LmHandlerParams->Region ) != LORAMAC_STATUS_OK )
254     {
255         return LORAMAC_HANDLER_ERROR;
256     }
257 
258     // Restore data if required
259     nbNvmData = NvmDataMgmtRestore( );
260 
261     // Try to restore from NVM and query the mac if possible.
262     if( nbNvmData > 0 )
263     {
264         LmHandlerCallbacks->OnNvmDataChange( LORAMAC_HANDLER_NVM_RESTORE, nbNvmData );
265     }
266     else
267     {
268         // Configure the default datarate
269         mibReq.Type = MIB_CHANNELS_DEFAULT_DATARATE;
270         mibReq.Param.ChannelsDefaultDatarate = LmHandlerParams->TxDatarate;
271         LoRaMacMibSetRequestConfirm( &mibReq );
272 
273         mibReq.Type = MIB_CHANNELS_DATARATE;
274         mibReq.Param.ChannelsDatarate = LmHandlerParams->TxDatarate;
275         LoRaMacMibSetRequestConfirm( &mibReq );
276 
277 #if( OVER_THE_AIR_ACTIVATION == 0 )
278         // Tell the MAC layer which network server version are we connecting too.
279         mibReq.Type = MIB_ABP_LORAWAN_VERSION;
280         mibReq.Param.AbpLrWanVersion.Value = ABP_ACTIVATION_LRWAN_VERSION;
281         LoRaMacMibSetRequestConfirm( &mibReq );
282 
283         mibReq.Type = MIB_NET_ID;
284         mibReq.Param.NetID = LORAWAN_NETWORK_ID;
285         LoRaMacMibSetRequestConfirm( &mibReq );
286 
287 #if( STATIC_DEVICE_ADDRESS != 1 )
288         // Random seed initialization
289         srand1( LmHandlerCallbacks->GetRandomSeed( ) );
290         // Choose a random device address
291         CommissioningParams.DevAddr = randr( 0, 0x01FFFFFF );
292 #endif
293 
294         mibReq.Type = MIB_DEV_ADDR;
295         mibReq.Param.DevAddr = CommissioningParams.DevAddr;
296         LoRaMacMibSetRequestConfirm( &mibReq );
297 #endif // #if( OVER_THE_AIR_ACTIVATION == 0 )
298     }
299 
300     // Read secure-element DEV_EUI, JOI_EUI and SE_PIN values.
301     mibReq.Type = MIB_DEV_EUI;
302     LoRaMacMibGetRequestConfirm( &mibReq );
303     memcpy1( CommissioningParams.DevEui, mibReq.Param.DevEui, 8 );
304 
305     mibReq.Type = MIB_JOIN_EUI;
306     LoRaMacMibGetRequestConfirm( &mibReq );
307     memcpy1( CommissioningParams.JoinEui, mibReq.Param.JoinEui, 8 );
308 
309     mibReq.Type = MIB_SE_PIN;
310     LoRaMacMibGetRequestConfirm( &mibReq );
311     memcpy1( CommissioningParams.SePin, mibReq.Param.SePin, 4 );
312 
313     mibReq.Type = MIB_PUBLIC_NETWORK;
314     mibReq.Param.EnablePublicNetwork = LmHandlerParams->PublicNetworkEnable;
315     LoRaMacMibSetRequestConfirm( &mibReq );
316 
317     mibReq.Type = MIB_ADR;
318     mibReq.Param.AdrEnable = LmHandlerParams->AdrEnable;
319     LoRaMacMibSetRequestConfirm( &mibReq );
320 
321     LoRaMacTestSetDutyCycleOn( LmHandlerParams->DutyCycleEnabled );
322 
323     LoRaMacStart( );
324 
325     mibReq.Type = MIB_NETWORK_ACTIVATION;
326     if( LoRaMacMibGetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
327     {
328         if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE )
329         {
330             LmHandlerCallbacks->OnNetworkParametersChange( &CommissioningParams );
331         }
332     }
333     return LORAMAC_HANDLER_SUCCESS;
334 }
335 
LmHandlerIsBusy(void)336 bool LmHandlerIsBusy( void )
337 {
338     if( LoRaMacIsBusy( ) == true )
339     {
340         return true;
341     }
342     if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET )
343     {
344         // The network isn't yet joined, try again later.
345         LmHandlerJoin( );
346         return true;
347     }
348 
349     if( LmHandlerPackageIsTxPending( ) == true )
350     {
351         return true;
352     }
353 
354     return false;
355 }
356 
LmHandlerProcess(void)357 void LmHandlerProcess( void )
358 {
359     uint16_t size = 0;
360 
361     // Process Radio IRQ
362     if( Radio.IrqProcess != NULL )
363     {
364         Radio.IrqProcess( );
365     }
366 
367     // Processes the LoRaMac events
368     LoRaMacProcess( );
369 
370     // Store to NVM if required
371     size = NvmDataMgmtStore( );
372 
373     if( size > 0 )
374     {
375         LmHandlerCallbacks->OnNvmDataChange( LORAMAC_HANDLER_NVM_STORE, size );
376     }
377 
378     // Call all packages process functions
379     LmHandlerPackagesProcess( );
380 
381     // Check if a package transmission is pending.
382     // If it is the case exit function earlier
383     if( LmHandlerPackageIsTxPending( ) == true )
384     {
385         return;
386     }
387 
388     // If a MAC layer scheduled uplink is still pending try to send it.
389     if( IsUplinkTxPending == true )
390     {
391         // Send an empty message
392         LmHandlerAppData_t appData =
393         {
394             .Buffer = NULL,
395             .BufferSize = 0,
396             .Port = 0,
397         };
398 
399         if( LmHandlerSend( &appData, LmHandlerParams->IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS )
400         {
401             IsUplinkTxPending = false;
402         }
403     }
404 }
405 
LmHandlerGetDutyCycleWaitTime(void)406 TimerTime_t LmHandlerGetDutyCycleWaitTime( void )
407 {
408     return DutyCycleWaitTime;
409 }
410 
411 /*!
412  * Join a LoRa Network in classA
413  *
414  * \Note if the device is ABP, this is a pass through function
415  *
416  * \param [IN] isOtaa Indicates which activation mode must be used
417  */
LmHandlerJoinRequest(bool isOtaa)418 static void LmHandlerJoinRequest( bool isOtaa )
419 {
420     MlmeReq_t mlmeReq;
421 
422     mlmeReq.Type = MLME_JOIN;
423     mlmeReq.Req.Join.Datarate = LmHandlerParams->TxDatarate;
424 
425     if( isOtaa == true )
426     {
427         mlmeReq.Req.Join.NetworkActivation = ACTIVATION_TYPE_OTAA;
428         // Update commissioning parameters activation type variable.
429         CommissioningParams.IsOtaaActivation = true;
430     }
431     else
432     {
433         mlmeReq.Req.Join.NetworkActivation = ACTIVATION_TYPE_ABP;
434         // Update commissioning parameters activation type variable.
435         CommissioningParams.IsOtaaActivation = false;
436     }
437     // Starts the join procedure
438     LmHandlerCallbacks->OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime );
439     DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
440 }
441 
LmHandlerJoin(void)442 void LmHandlerJoin( void )
443 {
444     LmHandlerJoinRequest( CommissioningParams.IsOtaaActivation );
445 }
446 
LmHandlerJoinStatus(void)447 LmHandlerFlagStatus_t LmHandlerJoinStatus( void )
448 {
449     MibRequestConfirm_t mibReq;
450     LoRaMacStatus_t status;
451 
452     mibReq.Type = MIB_NETWORK_ACTIVATION;
453     status = LoRaMacMibGetRequestConfirm( &mibReq );
454 
455     if( status == LORAMAC_STATUS_OK )
456     {
457         if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE )
458         {
459             return LORAMAC_HANDLER_RESET;
460         }
461         else
462         {
463             return LORAMAC_HANDLER_SET;
464         }
465     }
466     else
467     {
468         return LORAMAC_HANDLER_RESET;
469     }
470 }
471 
LmHandlerSend(LmHandlerAppData_t * appData,LmHandlerMsgTypes_t isTxConfirmed)472 LmHandlerErrorStatus_t LmHandlerSend( LmHandlerAppData_t *appData, LmHandlerMsgTypes_t isTxConfirmed )
473 {
474     LoRaMacStatus_t status;
475     McpsReq_t mcpsReq;
476     LoRaMacTxInfo_t txInfo;
477 
478     if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET )
479     {
480         // The network isn't joined, try again.
481         LmHandlerJoinRequest( CommissioningParams.IsOtaaActivation );
482         return LORAMAC_HANDLER_ERROR;
483     }
484 
485     TxParams.MsgType = isTxConfirmed;
486     mcpsReq.Type = ( isTxConfirmed == LORAMAC_HANDLER_UNCONFIRMED_MSG ) ? MCPS_UNCONFIRMED : MCPS_CONFIRMED;
487     mcpsReq.Req.Unconfirmed.Datarate = LmHandlerParams->TxDatarate;
488     if( LoRaMacQueryTxPossible( appData->BufferSize, &txInfo ) != LORAMAC_STATUS_OK )
489     {
490         // Send empty frame in order to flush MAC commands
491         mcpsReq.Type = MCPS_UNCONFIRMED;
492         mcpsReq.Req.Unconfirmed.fBuffer = NULL;
493         mcpsReq.Req.Unconfirmed.fBufferSize = 0;
494     }
495     else
496     {
497         mcpsReq.Req.Unconfirmed.fPort = appData->Port;
498         mcpsReq.Req.Unconfirmed.fBufferSize = appData->BufferSize;
499         mcpsReq.Req.Unconfirmed.fBuffer = appData->Buffer;
500     }
501 
502     TxParams.AppData = *appData;
503     TxParams.Datarate = LmHandlerParams->TxDatarate;
504 
505     status = LoRaMacMcpsRequest( &mcpsReq );
506     LmHandlerCallbacks->OnMacMcpsRequest( status, &mcpsReq, mcpsReq.ReqReturn.DutyCycleWaitTime );
507     DutyCycleWaitTime = mcpsReq.ReqReturn.DutyCycleWaitTime;
508 
509     if( status == LORAMAC_STATUS_OK )
510     {
511         IsUplinkTxPending = false;
512         return LORAMAC_HANDLER_SUCCESS;
513     }
514     else
515     {
516         return LORAMAC_HANDLER_ERROR;
517     }
518 }
519 
LmHandlerDeviceTimeReq(void)520 static LmHandlerErrorStatus_t LmHandlerDeviceTimeReq( void )
521 {
522     LoRaMacStatus_t status;
523     MlmeReq_t mlmeReq;
524 
525     mlmeReq.Type = MLME_DEVICE_TIME;
526 
527     status = LoRaMacMlmeRequest( &mlmeReq );
528     LmHandlerCallbacks->OnMacMlmeRequest( status, &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime );
529     DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
530 
531     if( status == LORAMAC_STATUS_OK )
532     {
533         return LORAMAC_HANDLER_SUCCESS;
534     }
535     else
536     {
537         return LORAMAC_HANDLER_ERROR;
538     }
539 }
540 
LmHandlerBeaconReq(void)541 static LmHandlerErrorStatus_t LmHandlerBeaconReq( void )
542 {
543     LoRaMacStatus_t status;
544     MlmeReq_t mlmeReq;
545 
546     mlmeReq.Type = MLME_BEACON_ACQUISITION;
547 
548     status = LoRaMacMlmeRequest( &mlmeReq );
549     LmHandlerCallbacks->OnMacMlmeRequest( status, &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime );
550     DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
551 
552     if( status == LORAMAC_STATUS_OK )
553     {
554         return LORAMAC_HANDLER_SUCCESS;
555     }
556     else
557     {
558         return LORAMAC_HANDLER_ERROR;
559     }
560 }
561 
LmHandlerPingSlotReq(uint8_t periodicity)562 LmHandlerErrorStatus_t LmHandlerPingSlotReq( uint8_t periodicity )
563 {
564     LoRaMacStatus_t status;
565     MlmeReq_t mlmeReq;
566 
567     mlmeReq.Type = MLME_PING_SLOT_INFO;
568     mlmeReq.Req.PingSlotInfo.PingSlot.Fields.Periodicity = periodicity;
569     mlmeReq.Req.PingSlotInfo.PingSlot.Fields.RFU = 0;
570 
571     status = LoRaMacMlmeRequest( &mlmeReq );
572     LmHandlerCallbacks->OnMacMlmeRequest( status, &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime );
573     DutyCycleWaitTime = mlmeReq.ReqReturn.DutyCycleWaitTime;
574 
575     if( status == LORAMAC_STATUS_OK )
576     {
577         // Send an empty message
578         LmHandlerAppData_t appData =
579         {
580             .Buffer = NULL,
581             .BufferSize = 0,
582             .Port = 0,
583         };
584         return LmHandlerSend( &appData, LmHandlerParams->IsTxConfirmed );
585     }
586     else
587     {
588         return LORAMAC_HANDLER_ERROR;
589     }
590 }
591 
LmHandlerRequestClass(DeviceClass_t newClass)592 LmHandlerErrorStatus_t LmHandlerRequestClass( DeviceClass_t newClass )
593 {
594     MibRequestConfirm_t mibReq;
595     DeviceClass_t currentClass;
596     LmHandlerErrorStatus_t errorStatus = LORAMAC_HANDLER_SUCCESS;
597 
598     mibReq.Type = MIB_DEVICE_CLASS;
599     LoRaMacMibGetRequestConfirm( &mibReq );
600     currentClass = mibReq.Param.Class;
601 
602     // Attempt to switch only if class update
603     if( currentClass != newClass )
604     {
605         switch( newClass )
606         {
607         case CLASS_A:
608             {
609                 if( currentClass != CLASS_A )
610                 {
611                     mibReq.Param.Class = CLASS_A;
612                     if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
613                     {
614                         // Switch is instantaneous
615                         LmHandlerCallbacks->OnClassChange( CLASS_A );
616                     }
617                     else
618                     {
619                         errorStatus = LORAMAC_HANDLER_ERROR;
620                     }
621                 }
622             }
623             break;
624         case CLASS_B:
625             {
626                 if( currentClass != CLASS_A )
627                 {
628                     errorStatus = LORAMAC_HANDLER_ERROR;
629                 }
630                 // Beacon must first be acquired
631                 errorStatus = LmHandlerDeviceTimeReq( );
632                 IsClassBSwitchPending = true;
633             }
634             break;
635         case CLASS_C:
636             {
637                 if( currentClass != CLASS_A )
638                 {
639                     errorStatus = LORAMAC_HANDLER_ERROR;
640                 }
641                 // Switch is instantaneous
642                 mibReq.Param.Class = CLASS_C;
643                 if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
644                 {
645                     LmHandlerCallbacks->OnClassChange( CLASS_C );
646                 }
647                 else
648                 {
649                     errorStatus = LORAMAC_HANDLER_ERROR;
650                 }
651             }
652             break;
653         default:
654             break;
655         }
656     }
657     return errorStatus;
658 }
659 
LmHandlerGetCurrentClass(void)660 DeviceClass_t LmHandlerGetCurrentClass( void )
661 {
662     MibRequestConfirm_t mibReq;
663 
664     mibReq.Type = MIB_DEVICE_CLASS;
665     LoRaMacMibGetRequestConfirm( &mibReq );
666 
667     return mibReq.Param.Class;
668 }
669 
LmHandlerGetCurrentDatarate(void)670 int8_t LmHandlerGetCurrentDatarate( void )
671 {
672     MibRequestConfirm_t mibGet;
673 
674     mibGet.Type = MIB_CHANNELS_DATARATE;
675     LoRaMacMibGetRequestConfirm( &mibGet );
676 
677     return mibGet.Param.ChannelsDatarate;
678 }
679 
LmHandlerGetActiveRegion(void)680 LoRaMacRegion_t LmHandlerGetActiveRegion( void )
681 {
682     return LmHandlerParams->Region;
683 }
684 
LmHandlerSetSystemMaxRxError(uint32_t maxErrorInMs)685 LmHandlerErrorStatus_t LmHandlerSetSystemMaxRxError( uint32_t maxErrorInMs )
686 {
687     MibRequestConfirm_t mibReq;
688 
689     mibReq.Type = MIB_SYSTEM_MAX_RX_ERROR;
690     mibReq.Param.SystemMaxRxError = maxErrorInMs;
691     if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK )
692     {
693         return LORAMAC_HANDLER_ERROR;
694     }
695     return LORAMAC_HANDLER_SUCCESS;
696 }
697 
698 /*
699  *=============================================================================
700  * LORAMAC NOTIFICATIONS HANDLING
701  *=============================================================================
702  */
703 
McpsConfirm(McpsConfirm_t * mcpsConfirm)704 static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
705 {
706     TxParams.IsMcpsConfirm = 1;
707     TxParams.Status = mcpsConfirm->Status;
708     TxParams.Datarate = mcpsConfirm->Datarate;
709     TxParams.UplinkCounter = mcpsConfirm->UpLinkCounter;
710     TxParams.TxPower = mcpsConfirm->TxPower;
711     TxParams.Channel = mcpsConfirm->Channel;
712     TxParams.AckReceived = mcpsConfirm->AckReceived;
713 
714     LmHandlerCallbacks->OnTxData( &TxParams );
715 
716     LmHandlerPackagesNotify( PACKAGE_MCPS_CONFIRM, mcpsConfirm );
717 }
718 
McpsIndication(McpsIndication_t * mcpsIndication)719 static void McpsIndication( McpsIndication_t *mcpsIndication )
720 {
721     LmHandlerAppData_t appData;
722 
723     RxParams.IsMcpsIndication = 1;
724     RxParams.Status = mcpsIndication->Status;
725 
726     if( RxParams.Status != LORAMAC_EVENT_INFO_STATUS_OK )
727     {
728         return;
729     }
730 
731     RxParams.Datarate = mcpsIndication->RxDatarate;
732     RxParams.Rssi = mcpsIndication->Rssi;
733     RxParams.Snr = mcpsIndication->Snr;
734     RxParams.DownlinkCounter = mcpsIndication->DownLinkCounter;
735     RxParams.RxSlot = mcpsIndication->RxSlot;
736 
737     appData.Port = mcpsIndication->Port;
738     appData.BufferSize = mcpsIndication->BufferSize;
739     appData.Buffer = mcpsIndication->Buffer;
740 
741     LmHandlerCallbacks->OnRxData( &appData, &RxParams );
742 
743     if( mcpsIndication->DeviceTimeAnsReceived == true )
744     {
745 #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 )
746         // Provide fix values. DeviceTimeAns is accurate
747         LmHandlerCallbacks->OnSysTimeUpdate( true, 0 );
748 #else
749         LmHandlerCallbacks->OnSysTimeUpdate( );
750 #endif
751     }
752     // Call packages RxProcess function
753     LmHandlerPackagesNotify( PACKAGE_MCPS_INDICATION, mcpsIndication );
754 
755     if( ( ( mcpsIndication->FramePending == true ) && ( LmHandlerGetCurrentClass( ) == CLASS_A ) ) ||
756         ( mcpsIndication->ResponseTimeout > 0 ) )
757     {
758         // The server signals that it has pending data to be sent.
759         // We schedule an uplink as soon as possible to flush the server.
760         IsUplinkTxPending = true;
761     }
762 }
763 
MlmeConfirm(MlmeConfirm_t * mlmeConfirm)764 static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm )
765 {
766     TxParams.IsMcpsConfirm = 0;
767     TxParams.Status = mlmeConfirm->Status;
768     LmHandlerCallbacks->OnTxData( &TxParams );
769 
770     LmHandlerPackagesNotify( PACKAGE_MLME_CONFIRM, mlmeConfirm );
771 
772     switch( mlmeConfirm->MlmeRequest )
773     {
774     case MLME_JOIN:
775         {
776             MibRequestConfirm_t mibReq;
777             mibReq.Type = MIB_DEV_ADDR;
778             LoRaMacMibGetRequestConfirm( &mibReq );
779             JoinParams.CommissioningParams->DevAddr = mibReq.Param.DevAddr;
780             JoinParams.Datarate = LmHandlerGetCurrentDatarate( );
781 
782             if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
783             {
784                 // Status is OK, node has joined the network
785                 JoinParams.Status = LORAMAC_HANDLER_SUCCESS;
786             }
787             else
788             {
789                 // Join was not successful. Try to join again
790                 JoinParams.Status = LORAMAC_HANDLER_ERROR;
791             }
792             // Notify upper layer
793             LmHandlerCallbacks->OnJoinRequest( &JoinParams );
794         }
795         break;
796     case MLME_LINK_CHECK:
797         {
798             // Check DemodMargin
799             // Check NbGateways
800         }
801         break;
802     case MLME_DEVICE_TIME:
803         {
804             if( IsClassBSwitchPending == true )
805             {
806                 LmHandlerBeaconReq( );
807             }
808         }
809         break;
810     case MLME_BEACON_ACQUISITION:
811         {
812             if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
813             {
814                 // Beacon has been acquired
815                 // Request server for ping slot
816                 LmHandlerPingSlotReq( LmHandlerParams->PingSlotPeriodicity );
817             }
818             else
819             {
820                 // Beacon not acquired
821                 // Request Device Time again.
822                 LmHandlerDeviceTimeReq( );
823             }
824         }
825         break;
826     case MLME_PING_SLOT_INFO:
827         {
828             if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
829             {
830                 MibRequestConfirm_t mibReq;
831 
832                 // Class B is now activated
833                 mibReq.Type = MIB_DEVICE_CLASS;
834                 mibReq.Param.Class = CLASS_B;
835                 LoRaMacMibSetRequestConfirm( &mibReq );
836                 // Notify upper layer
837                 LmHandlerCallbacks->OnClassChange( CLASS_B );
838                 IsClassBSwitchPending = false;
839             }
840             else
841             {
842                 LmHandlerPingSlotReq( LmHandlerParams->PingSlotPeriodicity );
843             }
844         }
845         break;
846     default:
847         break;
848     }
849 }
850 
MlmeIndication(MlmeIndication_t * mlmeIndication)851 static void MlmeIndication( MlmeIndication_t *mlmeIndication )
852 {
853     RxParams.IsMcpsIndication = 0;
854     RxParams.Status = mlmeIndication->Status;
855     if( RxParams.Status != LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED )
856     {
857         LmHandlerCallbacks->OnRxData( NULL, &RxParams );
858     }
859 
860     // Call packages RxProcess function
861     LmHandlerPackagesNotify( PACKAGE_MLME_INDICATION, mlmeIndication );
862 
863     switch( mlmeIndication->MlmeIndication )
864     {
865     case MLME_SCHEDULE_UPLINK:
866         {
867             // The MAC layer signals that we shall provide an uplink as soon as possible
868             IsUplinkTxPending = true;
869         }
870         break;
871     case MLME_BEACON_LOST:
872         {
873             MibRequestConfirm_t mibReq;
874             // Switch to class A again
875             mibReq.Type = MIB_DEVICE_CLASS;
876             mibReq.Param.Class = CLASS_A;
877             LoRaMacMibSetRequestConfirm( &mibReq );
878 
879             BeaconParams.State = LORAMAC_HANDLER_BEACON_LOST;
880             BeaconParams.Info.Time.Seconds = 0;
881             BeaconParams.Info.GwSpecific.InfoDesc = 0;
882             memset1( BeaconParams.Info.GwSpecific.Info, 0, 6 );
883 
884             LmHandlerCallbacks->OnClassChange( CLASS_A );
885             LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams );
886 
887             LmHandlerDeviceTimeReq( );
888         }
889         break;
890     case MLME_BEACON:
891     {
892         if( mlmeIndication->Status == LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED )
893         {
894             BeaconParams.State = LORAMAC_HANDLER_BEACON_RX;
895             BeaconParams.Info = mlmeIndication->BeaconInfo;
896 
897             LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams );
898         }
899         else
900         {
901             BeaconParams.State = LORAMAC_HANDLER_BEACON_NRX;
902             BeaconParams.Info = mlmeIndication->BeaconInfo;
903 
904             LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams );
905         }
906         break;
907     }
908     default:
909         break;
910     }
911 }
912 
913 /*
914  *=============================================================================
915  * PACKAGES HANDLING
916  *=============================================================================
917  */
918 
LmHandlerPackageRegister(uint8_t id,void * params)919 LmHandlerErrorStatus_t LmHandlerPackageRegister( uint8_t id, void *params )
920 {
921     LmhPackage_t *package = NULL;
922     switch( id )
923     {
924         case PACKAGE_ID_COMPLIANCE:
925         {
926             package = LmphCompliancePackageFactory( );
927             break;
928         }
929         case PACKAGE_ID_CLOCK_SYNC:
930         {
931             package = LmphClockSyncPackageFactory( );
932             break;
933         }
934         case PACKAGE_ID_REMOTE_MCAST_SETUP:
935         {
936             package = LmhpRemoteMcastSetupPackageFactory( );
937             break;
938         }
939         case PACKAGE_ID_FRAGMENTATION:
940         {
941             package = LmhpFragmentationPackageFactory( );
942             break;
943         }
944     }
945     if( package != NULL )
946     {
947         LmHandlerPackages[id] = package;
948         LmHandlerPackages[id]->OnMacMcpsRequest = LmHandlerCallbacks->OnMacMcpsRequest;
949         LmHandlerPackages[id]->OnMacMlmeRequest = LmHandlerCallbacks->OnMacMlmeRequest;
950         LmHandlerPackages[id]->OnJoinRequest = LmHandlerJoinRequest;
951         LmHandlerPackages[id]->OnDeviceTimeRequest = LmHandlerDeviceTimeReq;
952         LmHandlerPackages[id]->OnSysTimeUpdate = LmHandlerCallbacks->OnSysTimeUpdate;
953         LmHandlerPackages[id]->Init( params, LmHandlerParams->DataBuffer, LmHandlerParams->DataBufferMaxSize );
954 
955         return LORAMAC_HANDLER_SUCCESS;
956     }
957     else
958     {
959         return LORAMAC_HANDLER_ERROR;
960     }
961 }
962 
LmHandlerPackageIsInitialized(uint8_t id)963 bool LmHandlerPackageIsInitialized( uint8_t id )
964 {
965     if( LmHandlerPackages[id]->IsInitialized != NULL )
966     {
967         return LmHandlerPackages[id]->IsInitialized( );
968     }
969     else
970     {
971         return false;
972     }
973 }
974 
LmHandlerPackagesNotify(PackageNotifyTypes_t notifyType,void * params)975 static void LmHandlerPackagesNotify( PackageNotifyTypes_t notifyType, void *params )
976 {
977     for( int8_t i = 0; i < PKG_MAX_NUMBER; i++ )
978     {
979         if( LmHandlerPackages[i] != NULL )
980         {
981             switch( notifyType )
982             {
983                 case PACKAGE_MCPS_CONFIRM:
984                 {
985                     if( LmHandlerPackages[i]->OnMcpsConfirmProcess != NULL )
986                     {
987                         LmHandlerPackages[i]->OnMcpsConfirmProcess( ( McpsConfirm_t* ) params );
988                     }
989                     break;
990                 }
991                 case PACKAGE_MCPS_INDICATION:
992                 {
993                     if( LmHandlerPackages[i]->OnMcpsIndicationProcess != NULL )
994                     {
995                         LmHandlerPackages[i]->OnMcpsIndicationProcess( ( McpsIndication_t* )params );
996                     }
997                     break;
998                 }
999                 case PACKAGE_MLME_CONFIRM:
1000                 {
1001                     if( LmHandlerPackages[i]->OnMlmeConfirmProcess != NULL )
1002                     {
1003                         LmHandlerPackages[i]->OnMlmeConfirmProcess( ( MlmeConfirm_t* )params );
1004                     }
1005                     break;
1006                 }
1007                 case PACKAGE_MLME_INDICATION:
1008                 {
1009                     if( LmHandlerPackages[i]->OnMlmeIndicationProcess != NULL )
1010                     {
1011                         LmHandlerPackages[i]->OnMlmeIndicationProcess( params );
1012                     }
1013                     break;
1014                 }
1015             }
1016         }
1017     }
1018 }
1019 
LmHandlerPackageIsTxPending(void)1020 static bool LmHandlerPackageIsTxPending( void )
1021 {
1022     for( int8_t i = 0; i < PKG_MAX_NUMBER; i++ )
1023     {
1024         if( LmHandlerPackages[i] != NULL )
1025         {
1026             if( LmHandlerPackages[i]->IsTxPending( ) == true )
1027             {
1028                 return true;
1029             }
1030         }
1031     }
1032     return false;
1033 }
1034 
LmHandlerPackagesProcess(void)1035 static void LmHandlerPackagesProcess( void )
1036 {
1037     for( int8_t i = 0; i < PKG_MAX_NUMBER; i++ )
1038     {
1039         if( ( LmHandlerPackages[i] != NULL ) &&
1040             ( LmHandlerPackages[i]->Process != NULL ) &&
1041             ( LmHandlerPackageIsInitialized( i ) != false ) )
1042         {
1043             LmHandlerPackages[i]->Process( );
1044         }
1045     }
1046 }
1047