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