Lora Node
Architecture
Project
Source Project
WORKSPACE_B-L072Z-LRWAN1_ENIB.zip
main.c
#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 ) ;
}
//===============================================================================
On startup, note the Device ID printed on the serial Terminal ( gtkterm or minicom, configured /dev/ttyACM0 115200-8-N-1 ) :
DevEui= 34-31-37-32-5E-36-7E-0D
AppEui= 70-B3-D5-7E-D0-00-AE-BD
AppKey= FD 5E 2B A6 84 49 26 DA EA 33 6C 59 E0 C0 ED DD
VERSION: 44101150
txDone
rxTimeOut
rxDone
JOINED
txDone
rxTimeOut
…