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