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