Implement a secure ICS protocol targeting LoRa Node151 microcontroller for controlling irrigation.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

587 lines
14 KiB

  1. /*!
  2. * \file main.c
  3. *
  4. * \brief Performs a periodic uplink
  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. /*! \file periodic-uplink/SKiM980A/main.c */
  22. #include <stdio.h>
  23. #include "../firmwareVersion.h"
  24. #include "../../common/githubVersion.h"
  25. #include "utilities.h"
  26. #include "board.h"
  27. #include "gpio.h"
  28. #include "uart.h"
  29. #include "RegionCommon.h"
  30. #include "cli.h"
  31. #include "Commissioning.h"
  32. #include "LmHandler.h"
  33. #include "LmhpCompliance.h"
  34. #include "CayenneLpp.h"
  35. #include "LmHandlerMsgDisplay.h"
  36. #ifndef ACTIVE_REGION
  37. #warning "No active region defined, LORAMAC_REGION_EU868 will be used as default."
  38. #define ACTIVE_REGION LORAMAC_REGION_EU868
  39. #endif
  40. /*!
  41. * LoRaWAN default end-device class
  42. */
  43. #define LORAWAN_DEFAULT_CLASS CLASS_A
  44. /*!
  45. * Defines the application data transmission duty cycle. 5s, value in [ms].
  46. */
  47. #define APP_TX_DUTYCYCLE 5000
  48. /*!
  49. * Defines a random delay for application data transmission duty cycle. 1s,
  50. * value in [ms].
  51. */
  52. #define APP_TX_DUTYCYCLE_RND 1000
  53. /*!
  54. * LoRaWAN Adaptive Data Rate
  55. *
  56. * \remark Please note that when ADR is enabled the end-device should be static
  57. */
  58. #define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_ON
  59. /*!
  60. * Default datarate
  61. *
  62. * \remark Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled
  63. */
  64. #define LORAWAN_DEFAULT_DATARATE DR_0
  65. /*!
  66. * LoRaWAN confirmed messages
  67. */
  68. #define LORAWAN_DEFAULT_CONFIRMED_MSG_STATE LORAMAC_HANDLER_UNCONFIRMED_MSG
  69. /*!
  70. * User application data buffer size
  71. */
  72. #define LORAWAN_APP_DATA_BUFFER_MAX_SIZE 242
  73. /*!
  74. * LoRaWAN ETSI duty cycle control enable/disable
  75. *
  76. * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes
  77. */
  78. #define LORAWAN_DUTYCYCLE_ON true
  79. /*!
  80. * LoRaWAN application port
  81. * @remark The allowed port range is from 1 up to 223. Other values are reserved.
  82. */
  83. #define LORAWAN_APP_PORT 3
  84. /*!
  85. *
  86. */
  87. typedef enum
  88. {
  89. LORAMAC_HANDLER_TX_ON_TIMER,
  90. LORAMAC_HANDLER_TX_ON_EVENT,
  91. }LmHandlerTxEvents_t;
  92. /*!
  93. * User application data
  94. */
  95. static uint8_t AppDataBuffer[LORAWAN_APP_DATA_BUFFER_MAX_SIZE];
  96. /*!
  97. * User application data structure
  98. */
  99. static LmHandlerAppData_t AppData =
  100. {
  101. .Buffer = AppDataBuffer,
  102. .BufferSize = 0,
  103. .Port = 0,
  104. };
  105. /*!
  106. * Specifies the state of the application LED
  107. */
  108. static bool AppLedStateOn = false;
  109. /*!
  110. * Timer to handle the application data transmission duty cycle
  111. */
  112. static TimerEvent_t TxTimer;
  113. /*!
  114. * Timer to handle the state of LED4
  115. */
  116. static TimerEvent_t Led4Timer;
  117. /*!
  118. * Timer to handle the state of LED2
  119. */
  120. static TimerEvent_t Led2Timer;
  121. /*!
  122. * Timer to handle the state of LED beacon indicator
  123. */
  124. static TimerEvent_t LedBeaconTimer;
  125. static void OnMacProcessNotify( void );
  126. static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size );
  127. static void OnNetworkParametersChange( CommissioningParams_t* params );
  128. static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn );
  129. static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn );
  130. static void OnJoinRequest( LmHandlerJoinParams_t* params );
  131. static void OnTxData( LmHandlerTxParams_t* params );
  132. static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params );
  133. static void OnClassChange( DeviceClass_t deviceClass );
  134. static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params );
  135. #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 )
  136. static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection );
  137. #else
  138. static void OnSysTimeUpdate( void );
  139. #endif
  140. static void PrepareTxFrame( void );
  141. static void StartTxProcess( LmHandlerTxEvents_t txEvent );
  142. static void UplinkProcess( void );
  143. static void OnTxPeriodicityChanged( uint32_t periodicity );
  144. static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed );
  145. static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity );
  146. /*!
  147. * Function executed on TxTimer event
  148. */
  149. static void OnTxTimerEvent( void* context );
  150. /*!
  151. * Function executed on Led 4 Timeout event
  152. */
  153. static void OnLed4TimerEvent( void* context );
  154. /*!
  155. * Function executed on Led 2 Timeout event
  156. */
  157. static void OnLed2TimerEvent( void* context );
  158. /*!
  159. * \brief Function executed on Beacon timer Timeout event
  160. */
  161. static void OnLedBeaconTimerEvent( void* context );
  162. static LmHandlerCallbacks_t LmHandlerCallbacks =
  163. {
  164. .GetBatteryLevel = BoardGetBatteryLevel,
  165. .GetTemperature = NULL,
  166. .GetRandomSeed = BoardGetRandomSeed,
  167. .OnMacProcess = OnMacProcessNotify,
  168. .OnNvmDataChange = OnNvmDataChange,
  169. .OnNetworkParametersChange = OnNetworkParametersChange,
  170. .OnMacMcpsRequest = OnMacMcpsRequest,
  171. .OnMacMlmeRequest = OnMacMlmeRequest,
  172. .OnJoinRequest = OnJoinRequest,
  173. .OnTxData = OnTxData,
  174. .OnRxData = OnRxData,
  175. .OnClassChange= OnClassChange,
  176. .OnBeaconStatusChange = OnBeaconStatusChange,
  177. .OnSysTimeUpdate = OnSysTimeUpdate,
  178. };
  179. static LmHandlerParams_t LmHandlerParams =
  180. {
  181. .Region = ACTIVE_REGION,
  182. .AdrEnable = LORAWAN_ADR_STATE,
  183. .IsTxConfirmed = LORAWAN_DEFAULT_CONFIRMED_MSG_STATE,
  184. .TxDatarate = LORAWAN_DEFAULT_DATARATE,
  185. .PublicNetworkEnable = LORAWAN_PUBLIC_NETWORK,
  186. .DutyCycleEnabled = LORAWAN_DUTYCYCLE_ON,
  187. .DataBufferMaxSize = LORAWAN_APP_DATA_BUFFER_MAX_SIZE,
  188. .DataBuffer = AppDataBuffer,
  189. .PingSlotPeriodicity = REGION_COMMON_DEFAULT_PING_SLOT_PERIODICITY,
  190. };
  191. static LmhpComplianceParams_t LmhpComplianceParams =
  192. {
  193. .FwVersion.Value = FIRMWARE_VERSION,
  194. .OnTxPeriodicityChanged = OnTxPeriodicityChanged,
  195. .OnTxFrameCtrlChanged = OnTxFrameCtrlChanged,
  196. .OnPingSlotPeriodicityChanged = OnPingSlotPeriodicityChanged,
  197. };
  198. /*!
  199. * Indicates if LoRaMacProcess call is pending.
  200. *
  201. * \warning If variable is equal to 0 then the MCU can be set in low power mode
  202. */
  203. static volatile uint8_t IsMacProcessPending = 0;
  204. static volatile uint8_t IsTxFramePending = 0;
  205. static volatile uint32_t TxPeriodicity = 0;
  206. /*!
  207. * LED GPIO pins objects
  208. */
  209. extern Gpio_t Led4; // Tx
  210. extern Gpio_t Led2; // Rx and blinks every 5 seconds when beacon is acquired
  211. extern Gpio_t Led3; // App
  212. /*!
  213. * UART object used for command line interface handling
  214. */
  215. extern Uart_t Uart1;
  216. /*!
  217. * Main application entry point.
  218. */
  219. int main( void )
  220. {
  221. BoardInitMcu( );
  222. BoardInitPeriph( );
  223. TimerInit( &Led4Timer, OnLed4TimerEvent );
  224. TimerSetValue( &Led4Timer, 25 );
  225. TimerInit( &Led2Timer, OnLed2TimerEvent );
  226. TimerSetValue( &Led2Timer, 25 );
  227. TimerInit( &LedBeaconTimer, OnLedBeaconTimerEvent );
  228. TimerSetValue( &LedBeaconTimer, 5000 );
  229. // Initialize transmission periodicity variable
  230. TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );
  231. const Version_t appVersion = { .Value = FIRMWARE_VERSION };
  232. const Version_t gitHubVersion = { .Value = GITHUB_VERSION };
  233. DisplayAppInfo( "periodic-uplink-lpp",
  234. &appVersion,
  235. &gitHubVersion );
  236. if ( LmHandlerInit( &LmHandlerCallbacks, &LmHandlerParams ) != LORAMAC_HANDLER_SUCCESS )
  237. {
  238. printf( "LoRaMac wasn't properly initialized\n" );
  239. // Fatal error, endless loop.
  240. while ( 1 )
  241. {
  242. }
  243. }
  244. // Set system maximum tolerated rx error in milliseconds
  245. LmHandlerSetSystemMaxRxError( 20 );
  246. // The LoRa-Alliance Compliance protocol package should always be
  247. // initialized and activated.
  248. LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, &LmhpComplianceParams );
  249. LmHandlerJoin( );
  250. StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER );
  251. while( 1 )
  252. {
  253. // Process characters sent over the command line interface
  254. CliProcess( &Uart1 );
  255. // Processes the LoRaMac events
  256. LmHandlerProcess( );
  257. // Process application uplinks management
  258. UplinkProcess( );
  259. CRITICAL_SECTION_BEGIN( );
  260. if( IsMacProcessPending == 1 )
  261. {
  262. // Clear flag and prevent MCU to go into low power modes.
  263. IsMacProcessPending = 0;
  264. }
  265. else
  266. {
  267. // The MCU wakes up through events
  268. BoardLowPowerHandler( );
  269. }
  270. CRITICAL_SECTION_END( );
  271. }
  272. }
  273. static void OnMacProcessNotify( void )
  274. {
  275. IsMacProcessPending = 1;
  276. }
  277. static void OnNvmDataChange( LmHandlerNvmContextStates_t state, uint16_t size )
  278. {
  279. DisplayNvmDataChange( state, size );
  280. }
  281. static void OnNetworkParametersChange( CommissioningParams_t* params )
  282. {
  283. DisplayNetworkParametersUpdate( params );
  284. }
  285. static void OnMacMcpsRequest( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn )
  286. {
  287. DisplayMacMcpsRequestUpdate( status, mcpsReq, nextTxIn );
  288. }
  289. static void OnMacMlmeRequest( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn )
  290. {
  291. DisplayMacMlmeRequestUpdate( status, mlmeReq, nextTxIn );
  292. }
  293. static void OnJoinRequest( LmHandlerJoinParams_t* params )
  294. {
  295. DisplayJoinRequestUpdate( params );
  296. if( params->Status == LORAMAC_HANDLER_ERROR )
  297. {
  298. LmHandlerJoin( );
  299. }
  300. else
  301. {
  302. LmHandlerRequestClass( LORAWAN_DEFAULT_CLASS );
  303. }
  304. }
  305. static void OnTxData( LmHandlerTxParams_t* params )
  306. {
  307. DisplayTxUpdate( params );
  308. }
  309. static void OnRxData( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params )
  310. {
  311. DisplayRxUpdate( appData, params );
  312. switch( appData->Port )
  313. {
  314. case 1: // The application LED can be controlled on port 1 or 2
  315. case LORAWAN_APP_PORT:
  316. {
  317. AppLedStateOn = appData->Buffer[0] & 0x01;
  318. GpioWrite( &Led3, ( ( AppLedStateOn & 0x01 ) != 0 ) ? 1 : 0 );
  319. }
  320. break;
  321. default:
  322. break;
  323. }
  324. // Switch LED 2 ON for each received downlink
  325. GpioWrite( &Led2, 1 );
  326. TimerStart( &Led2Timer );
  327. }
  328. static void OnClassChange( DeviceClass_t deviceClass )
  329. {
  330. DisplayClassUpdate( deviceClass );
  331. // Inform the server as soon as possible that the end-device has switched to ClassB
  332. LmHandlerAppData_t appData =
  333. {
  334. .Buffer = NULL,
  335. .BufferSize = 0,
  336. .Port = 0,
  337. };
  338. LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG );
  339. }
  340. static void OnBeaconStatusChange( LoRaMacHandlerBeaconParams_t* params )
  341. {
  342. switch( params->State )
  343. {
  344. case LORAMAC_HANDLER_BEACON_RX:
  345. {
  346. TimerStart( &LedBeaconTimer );
  347. break;
  348. }
  349. case LORAMAC_HANDLER_BEACON_LOST:
  350. case LORAMAC_HANDLER_BEACON_NRX:
  351. {
  352. TimerStop( &LedBeaconTimer );
  353. break;
  354. }
  355. default:
  356. {
  357. break;
  358. }
  359. }
  360. DisplayBeaconUpdate( params );
  361. }
  362. #if( LMH_SYS_TIME_UPDATE_NEW_API == 1 )
  363. static void OnSysTimeUpdate( bool isSynchronized, int32_t timeCorrection )
  364. {
  365. }
  366. #else
  367. static void OnSysTimeUpdate( void )
  368. {
  369. }
  370. #endif
  371. /*!
  372. * Prepares the payload of the frame and transmits it.
  373. */
  374. static void PrepareTxFrame( void )
  375. {
  376. if( LmHandlerIsBusy( ) == true )
  377. {
  378. return;
  379. }
  380. uint8_t channel = 0;
  381. AppData.Port = LORAWAN_APP_PORT;
  382. CayenneLppReset( );
  383. uint8_t potiPercentage = 0;
  384. uint16_t vdd = 0;
  385. // Read the current potentiometer setting in percent
  386. potiPercentage = BoardGetPotiLevel( );
  387. // Read the current voltage level
  388. BoardGetBatteryLevel( ); // Updates the value returned by BoardGetBatteryVoltage( ) function.
  389. vdd = BoardGetBatteryVoltage( );
  390. CayenneLppAddDigitalInput( channel++, AppLedStateOn );
  391. CayenneLppAddAnalogInput( channel++, BoardGetBatteryLevel( ) * 100 / 254 );
  392. CayenneLppAddAnalogInput( channel++, potiPercentage );
  393. CayenneLppAddAnalogInput( channel++, vdd );
  394. CayenneLppCopy( AppData.Buffer );
  395. AppData.BufferSize = CayenneLppGetSize( );
  396. if( LmHandlerSend( &AppData, LmHandlerParams.IsTxConfirmed ) == LORAMAC_HANDLER_SUCCESS )
  397. {
  398. // Switch LED 4 ON
  399. GpioWrite( &Led4, 1 );
  400. TimerStart( &Led4Timer );
  401. }
  402. }
  403. static void StartTxProcess( LmHandlerTxEvents_t txEvent )
  404. {
  405. switch( txEvent )
  406. {
  407. default:
  408. // Intentional fall through
  409. case LORAMAC_HANDLER_TX_ON_TIMER:
  410. {
  411. // Schedule 1st packet transmission
  412. TimerInit( &TxTimer, OnTxTimerEvent );
  413. TimerSetValue( &TxTimer, TxPeriodicity );
  414. OnTxTimerEvent( NULL );
  415. }
  416. break;
  417. case LORAMAC_HANDLER_TX_ON_EVENT:
  418. {
  419. }
  420. break;
  421. }
  422. }
  423. static void UplinkProcess( void )
  424. {
  425. uint8_t isPending = 0;
  426. CRITICAL_SECTION_BEGIN( );
  427. isPending = IsTxFramePending;
  428. IsTxFramePending = 0;
  429. CRITICAL_SECTION_END( );
  430. if( isPending == 1 )
  431. {
  432. PrepareTxFrame( );
  433. }
  434. }
  435. static void OnTxPeriodicityChanged( uint32_t periodicity )
  436. {
  437. TxPeriodicity = periodicity;
  438. if( TxPeriodicity == 0 )
  439. { // Revert to application default periodicity
  440. TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );
  441. }
  442. // Update timer periodicity
  443. TimerStop( &TxTimer );
  444. TimerSetValue( &TxTimer, TxPeriodicity );
  445. TimerStart( &TxTimer );
  446. }
  447. static void OnTxFrameCtrlChanged( LmHandlerMsgTypes_t isTxConfirmed )
  448. {
  449. LmHandlerParams.IsTxConfirmed = isTxConfirmed;
  450. }
  451. static void OnPingSlotPeriodicityChanged( uint8_t pingSlotPeriodicity )
  452. {
  453. LmHandlerParams.PingSlotPeriodicity = pingSlotPeriodicity;
  454. }
  455. /*!
  456. * Function executed on TxTimer event
  457. */
  458. static void OnTxTimerEvent( void* context )
  459. {
  460. TimerStop( &TxTimer );
  461. IsTxFramePending = 1;
  462. // Schedule next transmission
  463. TimerSetValue( &TxTimer, TxPeriodicity );
  464. TimerStart( &TxTimer );
  465. }
  466. /*!
  467. * Function executed on Led 4 Timeout event
  468. */
  469. static void OnLed4TimerEvent( void* context )
  470. {
  471. TimerStop( &Led4Timer );
  472. // Switch LED 4 OFF
  473. GpioWrite( &Led4, 0 );
  474. }
  475. /*!
  476. * Function executed on Led 2 Timeout event
  477. */
  478. static void OnLed2TimerEvent( void* context )
  479. {
  480. TimerStop( &Led2Timer );
  481. // Switch LED 2 OFF
  482. GpioWrite( &Led2, 0 );
  483. }
  484. /*!
  485. * \brief Function executed on Beacon timer Timeout event
  486. */
  487. static void OnLedBeaconTimerEvent( void* context )
  488. {
  489. GpioWrite( &Led2, 1 );
  490. TimerStart( &Led2Timer );
  491. TimerStart( &LedBeaconTimer );
  492. }