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