1 /*!
2  * \file      main.c
3  *
4  * \brief     FUOTA interop tests - test 01
5  *
6  * \copyright Revised BSD License, see section \ref LICENSE.
7  *
8  * \code
9  *                ______                              _
10  *               / _____)             _              | |
11  *              ( (____  _____ ____ _| |_ _____  ____| |__
12  *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
13  *               _____) ) ____| | | || |_| ____( (___| | | |
14  *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
15  *              (C)2013-2018 Semtech
16  *
17  * \endcode
18  *
19  * \author    Miguel Luis ( Semtech )
20  */
21 
22 /*! \file fuota-test-01/NAMote72/main.c */
23 
24 #include <stdio.h>
25 #include "../firmwareVersion.h"
26 #include "../../common/githubVersion.h"
27 #include "utilities.h"
28 #include "board-config.h"
29 #include "board.h"
30 #include "gpio.h"
31 #include "uart.h"
32 #include "RegionCommon.h"
33 #include "gps.h"
34 #include "mpl3115.h"
35 
36 #include "cli.h"
37 #include "Commissioning.h"
38 #include "LmHandler.h"
39 #include "LmhpCompliance.h"
40 #include "LmhpClockSync.h"
41 #include "LmhpRemoteMcastSetup.h"
42 #include "LmhpFragmentation.h"
43 #include "LmHandlerMsgDisplay.h"
44 
45 #ifndef ACTIVE_REGION
46 
47 #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default."
48 
49 #define ACTIVE_REGION LORAMAC_REGION_EU868
50 
51 #endif
52 
53 /*!
54  * LoRaWAN default end-device class
55  */
56 #define LORAWAN_DEFAULT_CLASS                       CLASS_A
57 
58 /*!
59  * Defines the application data transmission duty cycle. 40s, value in [ms].
60  */
61 #define APP_TX_DUTYCYCLE                            40000
62 
63 /*!
64  * Defines a random delay for application data transmission duty cycle. 5s,
65  * value in [ms].
66  */
67 #define APP_TX_DUTYCYCLE_RND                        5000
68 
69 /*!
70  * LoRaWAN Adaptive Data Rate
71  *
72  * \remark Please note that when ADR is enabled the end-device should be static
73  */
74 #define LORAWAN_ADR_STATE                           LORAMAC_HANDLER_ADR_ON
75 
76 /*!
77  * Default datarate
78  *
79  * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled
80  */
81 #define LORAWAN_DEFAULT_DATARATE                    DR_3
82 
83 /*!
84  * LoRaWAN confirmed messages
85  */
86 #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE         LORAMAC_HANDLER_UNCONFIRMED_MSG
87 
88 /*!
89  * User application data buffer size
90  */
91 #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE            242
92 
93 /*!
94  * LoRaWAN ETSI duty cycle control enable/disable
95  *
96  * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes
97  */
98 #define LORAWAN_DUTYCYCLE_ON                        true
99 
100 /*!
101  *
102  */
103 typedef enum
104 {
105     LORAMAC_HANDLER_TX_ON_TIMER,
106     LORAMAC_HANDLER_TX_ON_EVENT,
107 }LmHandlerTxEvents_t;
108 
109 /*!
110  * User application data
111  */
112 static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE];
113 
114 /*!
115  * Timer to handle the application data transmission duty cycle
116  */
117 static TimerEvent_t TxTimer;
118 
119 /*!
120  * Timer to handle the state of LED1
121  */
122 static TimerEvent_t Led1Timer;
123 
124 /*!
125  * Timer to handle the state of LED2
126  */
127 static TimerEvent_t Led2Timer;
128 
129 /*!
130  * Timer to handle the state of LED beacon indicator
131  */
132 static TimerEvent_t LedBeaconTimer;
133 
134 static void OnMacProcessNotify( void );
135 static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size );
136 static void OnNetworkParametersChange( CommissioningParams_t* params );
137 static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn );
138 static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn );
139 static void OnJoinRequest( LmHandlerJoinParams_t* params );
140 static void OnTxData( LmHandlerTxParams_t* params );
141 static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params );
142 static void OnClassChange( DeviceClass_t deviceClass );
143 static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params );
144 #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 )
145 static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection );
146 #else
147 static void OnSysTimeUpdate( void );
148 #endif
149 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
150 static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size );
151 static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size );
152 #endif
153 static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost );
154 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
155 static void OnFragDone( int32_t status, uint32_t size );
156 #else
157 static void OnFragDone( int32_t status, uint8_t *file, uint32_t size );
158 #endif
159 static void StartTxProcess( LmHandlerTxEvents_t txEvent );
160 static void UplinkProcess( void );
161 
162 static void OnTxPeriodicityChanged( uint32_t periodicity );
163 static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed );
164 static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity );
165 
166 /*!
167  * Function executed on TxTimer event
168  */
169 static void OnTxTimerEvent( void* context );
170 
171 /*!
172  * Function executed on Led 1 Timeout event
173  */
174 static void OnLed1TimerEvent( void* context );
175 
176 /*!
177  * Function executed on Led 2 Timeout event
178  */
179 static void OnLed2TimerEvent( void* context );
180 
181 /*!
182  * \brief Function executed on Beacon timer Timeout event
183  */
184 static void OnLedBeaconTimerEvent( void* context );
185 
186 static LmHandlerCallbacks_t LmHandlerCallbacks =
187 {
188     .GetBatteryLevel = BoardGetBatteryLevel,
189     .GetTemperature = MPL3115ReadTemperature,
190     .GetRandomSeed = BoardGetRandomSeed,
191     .OnMacProcess = OnMacProcessNotify,
192     .OnNvmDataChange = OnNvmDataChange,
193     .OnNetworkParametersChange = OnNetworkParametersChange,
194     .OnMacMcpsRequest = OnMacMcpsRequest,
195     .OnMacMlmeRequest = OnMacMlmeRequest,
196     .OnJoinRequest = OnJoinRequest,
197     .OnTxData = OnTxData,
198     .OnRxData = OnRxData,
199     .OnClassChange= OnClassChange,
200     .OnBeaconStatusChange = OnBeaconStatusChange,
201     .OnSysTimeUpdate = OnSysTimeUpdate,
202 };
203 
204 static LmHandlerParams_t LmHandlerParams =
205 {
206     .Region = ACTIVE_REGION,
207     .AdrEnable = LORAWAN_ADR_STATE,
208     .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE,
209     .TxDatarate = LORAWAN_DEFAULT_DATARATE,
210     .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK,
211     .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON,
212     .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE,
213     .DataBuffer = AppDataBuffer,
214     .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY,
215 };
216 
217 static LmhpComplianceParams_t LmhpComplianceParams =
218 {
219     .FwVersion.Value = FIRMWARE_VERSION,
220     .OnTxPeriodicityChanged = OnTxPeriodicityChanged,
221     .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged,
222     .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged,
223 };
224 
225 /*!
226  * Defines the maximum size for the buffer receiving the fragmentation result.
227  *
228  * \remark By default FragDecoder.h defines:
229  *         \ref FRAG_MAX_NB   21
230  *         \ref FRAG_MAX_SIZE 50
231  *
232  *         FileSize = FRAG_MAX_NB * FRAG_MAX_SIZE
233  *
234  *         If bigger file size is to be received or is fragmented differently
235  *         one must update those parameters.
236  */
237 #define UNFRAGMENTED_DATA_SIZE                     ( 21 * 50 )
238 
239 /*
240  * Un-fragmented data storage.
241  */
242 static uint8_t UnfragmentedData[UNFRAGMENTED_DATA_SIZE];
243 
244 static LmhpFragmentationParams_t FragmentationParams =
245 {
246 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
247     .DecoderCallbacks =
248     {
249         .FragDecoderWrite = FragDecoderWrite,
250         .FragDecoderRead = FragDecoderRead,
251     },
252 #else
253     .Buffer = UnfragmentedData,
254     .BufferSize = UNFRAGMENTED_DATA_SIZE,
255 #endif
256     .OnProgress = OnFragProgress,
257     .OnDone = OnFragDone
258 };
259 
260 /*!
261  * Indicates if LoRaMacProcess call is pending.
262  *
263  * \warning If variable is equal to 0 then the MCU can be set in low power mode
264  */
265 static volatile uint8_t IsMacProcessPending = 0;
266 
267 static volatile uint8_t IsTxFramePending = 0;
268 
269 static volatile uint32_t TxPeriodicity = 0;
270 
271 /*
272  * Indicates if the system time has been synchronized
273  */
274 static volatile bool IsClockSynched = false;
275 
276 /*
277  * MC Session Started
278  */
279 static volatile bool IsMcSessionStarted = false;
280 
281 /*
282  * Indicates if the file transfer is done
283  */
284 static volatile bool IsFileTransferDone = false;
285 
286 /*
287  *  Received file computed CRC32
288  */
289 static volatile uint32_t FileRxCrc = 0;
290 
291 /*!
292  * LED GPIO pins objects
293  */
294 extern Gpio_t Led1; // Tx
295 extern Gpio_t Led2; // Rx
296 extern Gpio_t Led3; // App
297 
298 /*!
299  * UART object used for command line interface handling
300  */
301 extern Uart_t Uart2;
302 
303 /*!
304  * Main application entry point.
305  */
main(void)306 int main( void )
307 {
308     BoardInitMcu( );
309     BoardInitPeriph( );
310 
311     TimerInit( &Led1Timer, OnLed1TimerEvent );
312     TimerSetValue( &Led1Timer, 25 );
313 
314     TimerInit( &Led2Timer, OnLed2TimerEvent );
315     TimerSetValue( &Led2Timer, 100 );
316 
317     TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent );
318     TimerSetValue( &LedBeaconTimer, 5000 );
319 
320     // Initialize transmission periodicity variable
321     TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );
322 
323     const Version_t appVersion = { .Value = FIRMWARE_VERSION };
324     const Version_t gitHubVersion = { .Value = GITHUB_VERSION };
325     DisplayAppInfo( "fuota-test-01",
326                     &appVersion,
327                     &gitHubVersion );
328 
329     if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS )
330     {
331         printf( "LoRaMac wasn't properly initialized\n" );
332         // Fatal error, endless loop.
333         while ( 1 )
334         {
335         }
336     }
337 
338     // Set system maximum tolerated rx error in milliseconds
339     LmHandlerSetSystemMaxRxError( 20 );
340 
341     // The LoRa-Alliance Compliance protocol package should always be
342     // initialized and activated.
343     LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams );
344     LmHandlerPackageRegister( PACKAGE_ID_CLOCK_SYNC, NULL );
345     LmHandlerPackageRegister( PACKAGE_ID_REMOTE_MCAST_SETUP, NULL );
346     LmHandlerPackageRegister( PACKAGE_ID_FRAGMENTATION, &FragmentationParams );
347 
348     IsClockSynched = false;
349     IsFileTransferDone = false;
350 
351     LmHandlerJoin( );
352 
353     StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER );
354 
355     while( 1 )
356     {
357         // Process characters sent over the command line interface
358         CliProcess( &Uart2 );
359 
360         // Processes the LoRaMac events
361         LmHandlerProcess( );
362 
363         // Process application uplinks management
364         UplinkProcess( );
365 
366         CRITICAL_SECTION_BEGIN( );
367         if( IsMacProcessPending == 1 )
368         {
369             // Clear flag and prevent MCU to go into low power modes.
370             IsMacProcessPending = 0;
371         }
372         else
373         {
374             // The MCU wakes up through events
375             BoardLowPowerHandler( );
376         }
377         CRITICAL_SECTION_END( );
378     }
379 }
380 
OnMacProcessNotify(void)381 static void OnMacProcessNotify( void )
382 {
383     IsMacProcessPending = 1;
384 }
385 
OnNvmDataChange(LmHandlerNvmContextStates_t state,uint16_t size)386 static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size )
387 {
388     DisplayNvmDataChange( state, size );
389 }
390 
OnNetworkParametersChange(CommissioningParams_t * params)391 static void OnNetworkParametersChange( CommissioningParams_t* params )
392 {
393     DisplayNetworkParametersUpdate( params );
394 }
395 
OnMacMcpsRequest(LoRaMacStatus_t status,McpsReq_t * mcpsReq,TimerTime_t nextTxIn)396 static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn )
397 {
398     DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn );
399 }
400 
OnMacMlmeRequest(LoRaMacStatus_t status,MlmeReq_t * mlmeReq,TimerTime_t nextTxIn)401 static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn )
402 {
403     DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn );
404 }
405 
OnJoinRequest(LmHandlerJoinParams_t * params)406 static void OnJoinRequest( LmHandlerJoinParams_t* params )
407 {
408     DisplayJoinRequestUpdate( params );
409     if( params->Status == LORAMAC_HANDLER_ERROR )
410     {
411         LmHandlerJoin( );
412     }
413     else
414     {
415         LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS );
416     }
417 }
418 
OnTxData(LmHandlerTxParams_t * params)419 static void OnTxData( LmHandlerTxParams_t* params )
420 {
421     DisplayTxUpdate( params );
422 }
423 
OnRxData(LmHandlerAppData_t * appData,LmHandlerRxParams_t * params)424 static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params )
425 {
426     DisplayRxUpdate( appData, params );
427 }
428 
OnClassChange(DeviceClass_t deviceClass)429 static void OnClassChange( DeviceClass_t deviceClass )
430 {
431     DisplayClassUpdate( deviceClass );
432 
433     switch( deviceClass )
434     {
435         default:
436         case CLASS_A:
437         {
438             IsMcSessionStarted = false;
439             break;
440         }
441         case CLASS_B:
442         {
443             // Inform the server as soon as possible that the end-device has switched to ClassB
444             LmHandlerAppData_t appData =
445             {
446                 .Buffer = NULL,
447                 .BufferSize = 0,
448                 .Port = 0,
449             };
450             LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG );
451             IsMcSessionStarted = true;
452             break;
453         }
454         case CLASS_C:
455         {
456             IsMcSessionStarted = true;
457             // Switch LED 2 ON
458             GpioWrite( &Led2, 0 );
459             break;
460         }
461     }
462 }
463 
OnBeaconStatusChange(LoRaMacHandlerBeaconParams_t * params)464 static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params )
465 {
466     switch( params->State )
467     {
468         case LORAMAC_HANDLER_BEACON_RX:
469         {
470             TimerStart( &LedBeaconTimer );
471             break;
472         }
473         case LORAMAC_HANDLER_BEACON_LOST:
474         case LORAMAC_HANDLER_BEACON_NRX:
475         {
476             TimerStop( &LedBeaconTimer );
477             break;
478         }
479         default:
480         {
481             break;
482         }
483     }
484 
485     DisplayBeaconUpdate( params );
486 }
487 
488 #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 )
OnSysTimeUpdate(bool isSynchronized,int32_t timeCorrection)489 static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection )
490 {
491     IsClockSynched = isSynchronized;
492 }
493 #else
OnSysTimeUpdate(void)494 static void OnSysTimeUpdate( void )
495 {
496     IsClockSynched = true;
497 }
498 #endif
499 
500 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
FragDecoderWrite(uint32_t addr,uint8_t * data,uint32_t size)501 static int8_t FragDecoderWrite( uint32_t addr, uint8_t *data, uint32_t size )
502 {
503     if( size >= UNFRAGMENTED_DATA_SIZE )
504     {
505         return -1; // Fail
506     }
507     for(uint32_t i = 0; i < size; i++ )
508     {
509         UnfragmentedData[addr + i] = data[i];
510     }
511     return 0; // Success
512 }
513 
FragDecoderRead(uint32_t addr,uint8_t * data,uint32_t size)514 static int8_t FragDecoderRead( uint32_t addr, uint8_t *data, uint32_t size )
515 {
516     if( size >= UNFRAGMENTED_DATA_SIZE )
517     {
518         return -1; // Fail
519     }
520     for(uint32_t i = 0; i < size; i++ )
521     {
522         data[i] = UnfragmentedData[addr + i];
523     }
524     return 0; // Success
525 }
526 #endif
527 
OnFragProgress(uint16_t fragCounter,uint16_t fragNb,uint8_t fragSize,uint16_t fragNbLost)528 static void OnFragProgress( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost )
529 {
530     // Switch LED 2 OFF for each received downlink
531     GpioWrite( &Led2, 1 );
532     TimerStart( &Led2Timer );
533 
534     printf( "\n###### =========== FRAG_DECODER ============ ######\n" );
535     printf( "######               PROGRESS                ######\n");
536     printf( "###### ===================================== ######\n");
537     printf( "RECEIVED    : %5d / %5d Fragments\n", fragCounter, fragNb );
538     printf( "              %5d / %5d Bytes\n", fragCounter * fragSize, fragNb * fragSize );
539     printf( "LOST        :       %7d Fragments\n\n", fragNbLost );
540 }
541 
542 #if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 )
OnFragDone(int32_t status,uint32_t size)543 static void OnFragDone( int32_t status, uint32_t size )
544 {
545     FileRxCrc = Crc32( UnfragmentedData, size );
546     IsFileTransferDone = true;
547     // Switch LED 2 OFF
548     GpioWrite( &Led2, 1 );
549 
550     printf( "\n###### =========== FRAG_DECODER ============ ######\n" );
551     printf( "######               FINISHED                ######\n");
552     printf( "###### ===================================== ######\n");
553     printf( "STATUS      : %ld\n", status );
554     printf( "CRC         : %08lX\n\n", FileRxCrc );
555 }
556 #else
OnFragDone(int32_t status,uint8_t * file,uint32_t size)557 static void OnFragDone( int32_t status, uint8_t *file, uint32_t size )
558 {
559     FileRxCrc = Crc32( file, size );
560     IsFileTransferDone = true;
561     // Switch LED 2 OFF
562     GpioWrite( &Led2, 1 );
563 
564     printf( "\n###### =========== FRAG_DECODER ============ ######\n" );
565     printf( "######               FINISHED                ######\n");
566     printf( "###### ===================================== ######\n");
567     printf( "STATUS      : %ld\n", status );
568     printf( "CRC         : %08lX\n\n", FileRxCrc );
569 }
570 #endif
571 
StartTxProcess(LmHandlerTxEvents_t txEvent)572 static void StartTxProcess( LmHandlerTxEvents_t txEvent )
573 {
574     switch( txEvent )
575     {
576     default:
577         // Intentional fall through
578     case LORAMAC_HANDLER_TX_ON_TIMER:
579         {
580             // Schedule 1st packet transmission
581             TimerInit( &TxTimer, OnTxTimerEvent );
582             TimerSetValue( &TxTimer, TxPeriodicity );
583             OnTxTimerEvent( NULL );
584         }
585         break;
586     case LORAMAC_HANDLER_TX_ON_EVENT:
587         {
588         }
589         break;
590     }
591 }
592 
UplinkProcess(void)593 static void UplinkProcess( void )
594 {
595     LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR;
596 
597     if( LmHandlerIsBusy( ) == true )
598     {
599         return;
600     }
601 
602     uint8_t isPending = 0;
603     CRITICAL_SECTION_BEGIN( );
604     isPending = IsTxFramePending;
605     IsTxFramePending = 0;
606     CRITICAL_SECTION_END( );
607     if( isPending == 1 )
608     {
609         if( IsMcSessionStarted == false )
610         {
611             if( IsFileTransferDone == false )
612             {
613                 if( IsClockSynched == false )
614                 {
615                     status = LmhpClockSyncAppTimeReq( );
616                 }
617                 else
618                 {
619                     AppDataBuffer[0] = randr( 0, 255 );
620                     // Send random packet
621                     LmHandlerAppData_t appData =
622                     {
623                         .Buffer = AppDataBuffer,
624                         .BufferSize = 1,
625                         .Port = 1,
626                     };
627                     status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed );
628                 }
629             }
630             else
631             {
632                 AppDataBuffer[0] = 0x05; // FragDataBlockAuthReq
633                 AppDataBuffer[1] = FileRxCrc & 0x000000FF;
634                 AppDataBuffer[2] = ( FileRxCrc >> 8 ) & 0x000000FF;
635                 AppDataBuffer[3] = ( FileRxCrc >> 16 ) & 0x000000FF;
636                 AppDataBuffer[4] = ( FileRxCrc >> 24 ) & 0x000000FF;
637 
638                 // Send FragAuthReq
639                 LmHandlerAppData_t appData =
640                 {
641                     .Buffer = AppDataBuffer,
642                     .BufferSize = 5,
643                     .Port = 201,
644                 };
645                 status = LmHandlerSend( &appData, LmHandlerParams.IsTxConfirmed );
646             }
647             if( status == LORAMAC_HANDLER_SUCCESS )
648             {
649                 // Switch LED 1 ON
650                 GpioWrite( &Led1, 0 );
651                 TimerStart( &Led1Timer );
652             }
653         }
654     }
655 }
656 
OnTxPeriodicityChanged(uint32_t periodicity)657 static void OnTxPeriodicityChanged( uint32_t periodicity )
658 {
659     TxPeriodicity = periodicity;
660 
661     if( TxPeriodicity == 0 )
662     { // Revert to application default periodicity
663         TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );
664     }
665 
666     // Update timer periodicity
667     TimerStop( &TxTimer );
668     TimerSetValue( &TxTimer, TxPeriodicity );
669     TimerStart( &TxTimer );
670 }
671 
OnTxFrameCtrlChanged(LmHandlerMsgTypes_t isTxConfirmed)672 static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed )
673 {
674     LmHandlerParams.IsTxConfirmed = isTxConfirmed;
675 }
676 
OnPingSlotPeriodicityChanged(uint8_t pingSlotPeriodicity)677 static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity )
678 {
679     LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity;
680 }
681 
682 /*!
683  * Function executed on TxTimer event
684  */
OnTxTimerEvent(void * context)685 static void OnTxTimerEvent( void* context )
686 {
687     TimerStop( &TxTimer );
688 
689     IsTxFramePending = 1;
690 
691     // Schedule next transmission
692     TimerSetValue( &TxTimer, TxPeriodicity );
693     TimerStart( &TxTimer );
694 }
695 
696 /*!
697  * Function executed on Led 1 Timeout event
698  */
OnLed1TimerEvent(void * context)699 static void OnLed1TimerEvent( void* context )
700 {
701     TimerStop( &Led1Timer );
702     // Switch LED 1 OFF
703     GpioWrite( &Led1, 1 );
704 }
705 
706 /*!
707  * Function executed on Led 2 Timeout event
708  */
OnLed2TimerEvent(void * context)709 static void OnLed2TimerEvent( void* context )
710 {
711     TimerStop( &Led2Timer );
712     // Switch LED 2 ON
713     GpioWrite( &Led2, 0 );
714 }
715 
716 /*!
717  * \brief Function executed on Beacon timer Timeout event
718  */
OnLedBeaconTimerEvent(void * context)719 static void OnLedBeaconTimerEvent( void* context )
720 {
721     GpioWrite( &Led2, 0 );
722     TimerStart( &Led2Timer );
723 
724     TimerStart( &LedBeaconTimer );
725 }
726