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