#include "hw.h" #include "low_power_manager.h" #include "lora.h" #include "bsp.h" #include "timeServer.h" #include "vcom.h" #include "version.h" #include "hts221.h" #include "lps25hb.h" // CAYENNE_LPP is myDevices Application server. #define CAYENNE_LPP #define LPP_DATATYPE_DIGITAL_INPUT 0x0 #define LPP_DATATYPE_DIGITAL_OUTPUT 0x1 #define LPP_DATATYPE_HUMIDITY 0x68 #define LPP_DATATYPE_TEMPERATURE 0x67 #define LPP_DATATYPE_BAROMETER 0x73 #define LPP_APP_PORT 99 // Defines the application data transmission duty cycle. 5s, value in [ms]. #define APP_TX_DUTYCYCLE 2000 // LoRaWAN Adaptive Data Rate // @note Please note that when ADR is enabled the end-device should be static #define LORAWAN_ADR_STATE LORAWAN_ADR_ON /*! * LoRaWAN Default data Rate Data Rate * @note Please note that LORAWAN_DEFAULT_DATA_RATE is used only when ADR is disabled */ #define LORAWAN_DEFAULT_DATA_RATE DR_0 // LoRaWAN application port // @note do not use 224. It is reserved for certification #define LORAWAN_APP_PORT 2 #define LORAWAN_DEFAULT_CLASS CLASS_A #define LORAWAN_DEFAULT_CONFIRM_MSG_STATE LORAWAN_UNCONFIRMED_MSG #define LORAWAN_APP_DATA_BUFF_SIZE 64 static uint8_t AppDataBuff[LORAWAN_APP_DATA_BUFF_SIZE]; static lora_AppData_t AppData={ AppDataBuff, 0 ,0 }; static void LORA_RxData( lora_AppData_t *AppData); /* call back when LoRa endNode has received a frame*/ static void LORA_HasJoined( void ); /* call back when LoRa endNode has just joined*/ static void LORA_ConfirmClass ( DeviceClass_t Class ); /* call back when LoRa endNode has just switch the class*/ static void LORA_TxNeeded ( void ); /* call back when server needs endNode to send a frame*/ static void Send( void ); /* LoRa endNode send request*/ static void LoraStartTx(TxEventType_t EventType); /* start the tx process*/ static void OnTxTimerEvent( void ); /* tx timer callback function*/ static LoRaMainCallback_t LoRaMainCallbacks = { HW_GetBatteryLevel, HW_GetTemperatureLevel, HW_GetUniqueId, HW_GetRandomSeed, LORA_RxData, LORA_HasJoined, LORA_ConfirmClass, LORA_TxNeeded}; static uint8_t AppLedStateOn = RESET; static TimerEvent_t TxTimer; static TimerEvent_t TxLedTimer; static void OnTimerLedEvent( void ); static LoRaParam_t LoRaParamInit= {LORAWAN_ADR_STATE, LORAWAN_DEFAULT_DATA_RATE, LORAWAN_PUBLIC_NETWORK}; //############################################################################### // MAIN //############################################################################### int main( void ) { HAL_Init(); SystemClock_Config(); DBG_Init(); HW_Init(); i2c1_Init(); LPM_SetOffMode(LPM_APPLI_Id , LPM_Disable ); /*Disbale Stand-by mode*/ LORA_Init( &LoRaMainCallbacks, &LoRaParamInit); /* Configure the Lora Stack*/ PRINTF("VERSION: %X\n\r", VERSION); LORA_Join(); LoraStartTx( TX_ON_TIMER) ; //------------------------------------------------ // INIT SENSORS //------------------------------------------------ hts221_activate(); hts221_storeCalibration(); lps25hb_setup(); //------------------------------------------------ while( 1 ) { DISABLE_IRQ( ); /* if an interrupt has occurred after DISABLE_IRQ, it is kept pending * and cortex will not enter low power anyway */ #ifndef LOW_POWER_DISABLE LPM_EnterLowPower( ); #endif ENABLE_IRQ(); } } //############################################################################### //############################################################################### static void LORA_HasJoined( void ) { #if( OVER_THE_AIR_ACTIVATION != 0 ) PRINTF("JOINED\n\r"); #endif LORA_RequestClass( LORAWAN_DEFAULT_CLASS ); } //=============================================================================== static void Send( void ) { uint16_t pressure = 0; int16_t temperature = 0; uint16_t humidity = 0; uint8_t batteryLevel; if ( LORA_JoinStatus () != LORA_SET) { // Not joined, try again later LORA_Join(); return; } DBG_PRINTF("SEND REQUEST\n\r"); TimerInit( &TxLedTimer, OnTimerLedEvent ); TimerSetValue( &TxLedTimer, 200); LED_On( LED_RED1 ) ; TimerStart( &TxLedTimer ); uint8_t cchannel=0; temperature = ( int16_t )( hts221_getTemperature() * 10 ); /* in °C * 10 */ pressure = ( uint16_t )( lps25hb_getPressure() * 100 / 10 ); /* in hPa / 10 */ humidity = ( uint16_t )( hts221_getHumidity() ); /* in %*2 */ uint32_t i = 0; batteryLevel = HW_GetBatteryLevel( ); /* 1 (very low) to 254 (fully charged) */ AppData.Port = LPP_APP_PORT; AppData.Buff[i++] = cchannel++; AppData.Buff[i++] = LPP_DATATYPE_BAROMETER; AppData.Buff[i++] = ( pressure >> 8 ) & 0xFF; AppData.Buff[i++] = pressure & 0xFF; AppData.Buff[i++] = cchannel++; AppData.Buff[i++] = LPP_DATATYPE_TEMPERATURE; AppData.Buff[i++] = ( temperature >> 8 ) & 0xFF; AppData.Buff[i++] = temperature & 0xFF; AppData.Buff[i++] = cchannel++; AppData.Buff[i++] = LPP_DATATYPE_HUMIDITY; AppData.Buff[i++] = humidity & 0xFF; AppData.Buff[i++] = cchannel++; AppData.Buff[i++] = LPP_DATATYPE_DIGITAL_INPUT; AppData.Buff[i++] = batteryLevel*100/254; AppData.Buff[i++] = cchannel++; AppData.Buff[i++] = LPP_DATATYPE_DIGITAL_OUTPUT; AppData.Buff[i++] = AppLedStateOn; AppData.BuffSize = i; LORA_send( &AppData, LORAWAN_DEFAULT_CONFIRM_MSG_STATE); } //=============================================================================== static void LORA_RxData( lora_AppData_t *AppData ) { DBG_PRINTF("PACKET RECEIVED ON PORT %d\n\r", AppData->Port); switch (AppData->Port) { case 3: // this port switches the class if( AppData->BuffSize == 1 ) { switch ( AppData->Buff[0] ) { case 0: { LORA_RequestClass(CLASS_A); break; } case 1: { LORA_RequestClass(CLASS_B); break; } case 2: { LORA_RequestClass(CLASS_C); break; } default: break; } } break; case LORAWAN_APP_PORT: if( AppData->BuffSize == 1 ) { AppLedStateOn = AppData->Buff[0] & 0x01; if ( AppLedStateOn == RESET ) { PRINTF("LED OFF\n\r"); LED_Off( LED_BLUE ) ; } else { PRINTF("LED ON\n\r"); LED_On( LED_BLUE ) ; } } break; case LPP_APP_PORT: { AppLedStateOn= (AppData->Buff[2] == 100) ? 0x01 : 0x00; if ( AppLedStateOn == RESET ) { PRINTF("LED OFF\n\r"); LED_Off( LED_BLUE ) ; } else { PRINTF("LED ON\n\r"); LED_On( LED_BLUE ) ; } break; } default: break; } } //=============================================================================== static void OnTxTimerEvent( void ) { Send( ); TimerStart( &TxTimer); // Wait for next tx slot } //=============================================================================== static void LoraStartTx(TxEventType_t EventType) { if (EventType == TX_ON_TIMER) { // send everytime timer elapses TimerInit( &TxTimer, OnTxTimerEvent ); TimerSetValue( &TxTimer, APP_TX_DUTYCYCLE); OnTxTimerEvent(); } else { // send everytime button is pushed GPIO_InitTypeDef initStruct={0}; initStruct.Mode =GPIO_MODE_IT_RISING; initStruct.Pull = GPIO_PULLUP; initStruct.Speed = GPIO_SPEED_HIGH; //USER_BUTTON_GPIO_PORT HW_GPIO_Init( GPIOB, GPIO_PIN_2, &initStruct ); HW_GPIO_SetIrq( GPIOB, GPIO_PIN_2, 0, Send ); } } //=============================================================================== static void LORA_ConfirmClass ( DeviceClass_t Class ) { PRINTF("switch to class %c done\n\r","ABC"[Class] ); /*Optionnal*/ /*informs the server that switch has occurred ASAP*/ AppData.BuffSize = 0; AppData.Port = LORAWAN_APP_PORT; LORA_send( &AppData, LORAWAN_UNCONFIRMED_MSG); } //=============================================================================== static void LORA_TxNeeded ( void ) { AppData.BuffSize = 0; AppData.Port = LORAWAN_APP_PORT; LORA_send( &AppData, LORAWAN_UNCONFIRMED_MSG); } //=============================================================================== static void OnTimerLedEvent( void ) { LED_Off( LED_RED1 ) ; } //===============================================================================