269 lines
7.1 KiB
C++
269 lines
7.1 KiB
C++
#include "LoRaWan_APP.h"
|
|
#include "Arduino.h"
|
|
#include <Wire.h>
|
|
#include "Adafruit_SHT31.h"
|
|
#include <BMP280.h>
|
|
|
|
#define USE_TTN_NETWORK 1
|
|
/*
|
|
set LoraWan_RGB to Active,the RGB active in loraWan
|
|
RGB red means sending;
|
|
RGB purple means joined done;
|
|
RGB blue means RxWindow1;
|
|
RGB yellow means RxWindow2;
|
|
RGB green means received done;
|
|
*/
|
|
Adafruit_SHT31 sht31 = Adafruit_SHT31();
|
|
BMP280 bmp;
|
|
|
|
/*LoraWan Class*/
|
|
//DeviceClass_t CLASS = LORAWAN_CLASS;
|
|
DeviceClass_t CLASS = CLASS_A;
|
|
|
|
bool OVER_THE_AIR_ACTIVATION = true;
|
|
//bool OVER_THE_AIR_ACTIVATION = LORAWAN_NETMODE;
|
|
|
|
bool LORAWAN_ADR_ON = true;
|
|
//bool LORAWAN_ADR_ON = LORAWAN_ADR;
|
|
|
|
bool KeepNet = true; //save network info to flash
|
|
//bool KeepNet = LORAWAN_Net_Reserve;
|
|
|
|
//#define ACTIVE_REGION LORAMAC_REGION_EU868
|
|
/*LoraWan REGION*/
|
|
LoRaMacRegion_t REGION = ACTIVE_REGION;
|
|
//LoRaMacRegion_t REGION = REGION_EU868;
|
|
|
|
bool IsTxConfirmed = false; //send confirm message
|
|
/*!
|
|
Number of trials to transmit the frame, if the LoRaMAC layer did not
|
|
receive an acknowledgment. The MAC performs a datarate adaptation,
|
|
according to the LoRaWAN Specification V1.0.2, chapter 18.4, according
|
|
to the following table:
|
|
|
|
Transmission nb | Data Rate
|
|
----------------|-----------
|
|
1 (first) | DR
|
|
2 | DR
|
|
3 | max(DR-1,0)
|
|
4 | max(DR-1,0)
|
|
5 | max(DR-2,0)
|
|
6 | max(DR-2,0)
|
|
7 | max(DR-3,0)
|
|
8 | max(DR-3,0)
|
|
|
|
Note, that if NbTrials is set to 1 or 2, the MAC will not decrease
|
|
the datarate, in case the LoRaMAC layer did not receive an acknowledgment
|
|
*/
|
|
uint8_t ConfirmedNbTrials = 8;
|
|
|
|
/* Application port */
|
|
uint8_t AppPort = 2;
|
|
|
|
/*the application data transmission duty cycle. value in [ms].*/
|
|
uint32_t APP_TX_DUTYCYCLE = 300000; //5min
|
|
|
|
union {
|
|
uint8_t val;
|
|
struct {
|
|
uint8_t r1 : 1; // bit position 0
|
|
uint8_t r2 : 1; // bit positions 1
|
|
uint8_t r3 : 1; // bit positions 2
|
|
uint8_t r4 : 1; // bit positions 3
|
|
uint8_t r5 : 1; // bit positions 3
|
|
//uint8_t r5 : 2; // bit positions 4 5
|
|
// total # of bits just needs to add up to the uint8_t size
|
|
} bits;
|
|
} inputState;
|
|
|
|
|
|
const char myDevEui[] = { 0xA8, 0xD6, 0x52, 0xB5, 0x90, 0x24, 0xAD, 0xBC };
|
|
const char myAppEui[] = { 0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x02, 0x34, 0xB8 };
|
|
const char myAppKey[] = { 0xE9, 0x64, 0x28, 0x39, 0x10, 0x47, 0x4B, 0x65, 0x35, 0xF3, 0x51, 0x59, 0xC8, 0xDF, 0x9A, 0x22 };
|
|
extern uint8_t DevEui[];
|
|
extern uint8_t AppEui[];
|
|
extern uint8_t AppKey[];
|
|
//bool IsLoRaMacNetworkJoined;
|
|
|
|
volatile bool isr_flag = false;
|
|
|
|
//------------- Interrupts -----------------------------
|
|
|
|
void gpioInterruptRoutine() {
|
|
isr_flag = true;
|
|
}
|
|
|
|
//------------- Functions -----------------------------
|
|
|
|
void intToBytes(byte *buf, int32_t i, uint8_t byteSize) {
|
|
for (uint8_t x = 0; x < byteSize; x++) {
|
|
buf[x] = (byte) (i >> (x * 8));
|
|
}
|
|
}
|
|
|
|
/* Prepares the payload of the frame */
|
|
static bool PrepareTxFrame( uint8_t port )
|
|
{
|
|
ReadInputs();
|
|
AppDataSize = 9;//AppDataSize max value is 64
|
|
AppData[0] = inputState.val;
|
|
|
|
uint16_t BatteryVoltage = GetBatteryVoltage();
|
|
AppData[1] = (uint8_t)(BatteryVoltage >> 8);
|
|
AppData[2] = (uint8_t)BatteryVoltage;
|
|
|
|
|
|
if (!sht31.begin(0x44)) { // Set to 0x45 for alternate i2c addr
|
|
Serial.println("Couldn't find SHT31");
|
|
} else {
|
|
float temp = sht31.readTemperature();
|
|
float hum = sht31.readHumidity();
|
|
Wire.end();
|
|
int16_t t = (int16_t) (temp * 100);
|
|
if (temp < 0) {
|
|
t = ~ -t;
|
|
t = t + 1;
|
|
}
|
|
AppData[3] = (byte) ((t >> 8) & 0xFF);
|
|
AppData[4] = (byte) t & 0xFF;
|
|
|
|
int16_t h = (int16_t) (hum * 100);
|
|
intToBytes(&AppData[5], h, 2);
|
|
}
|
|
|
|
if (!bmp.begin()) {
|
|
Serial.println("Couldn't find BMP280");
|
|
} else {
|
|
bmp.setSampling(BMP280::MODE_NORMAL, /* Operating Mode. */
|
|
BMP280::SAMPLING_X2, /* Temp. oversampling */
|
|
BMP280::SAMPLING_X16, /* Pressure oversampling */
|
|
BMP280::FILTER_X16, /* Filtering. */
|
|
BMP280::STANDBY_MS_500); /* Standby time. */
|
|
float temp = bmp.readTemperature();
|
|
float Pressure = (float)bmp.readPressure() / 100.0;
|
|
Wire.end();
|
|
|
|
if (! isnan(Pressure)) { // check if 'is not a number'
|
|
int16_t val = Pressure * 10;
|
|
AppData[7] = val >> 8;
|
|
AppData[8] = val;
|
|
} else {
|
|
Serial.println("BMP280 Failed to read pressure");
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ReadInputs() {
|
|
inputState.bits.r1 = !digitalRead(GPIO0);
|
|
inputState.bits.r2 = !digitalRead(GPIO1);
|
|
inputState.bits.r3 = !digitalRead(GPIO2);
|
|
inputState.bits.r4 = !digitalRead(GPIO3);
|
|
inputState.bits.r5 = !digitalRead(GPIO5);
|
|
}
|
|
|
|
|
|
//------------- Main code -----------------------------
|
|
void setup() {
|
|
BoardInitMcu();
|
|
Serial.begin(115200);
|
|
|
|
memcpy(DevEui, myDevEui, sizeof(myDevEui));
|
|
memcpy(AppEui, myAppEui, sizeof(myAppEui));
|
|
memcpy(AppKey, myAppKey, sizeof(myAppKey));
|
|
|
|
pinMode(GPIO0, INPUT);
|
|
pinMode(GPIO1, INPUT);
|
|
pinMode(GPIO2, INPUT);
|
|
pinMode(GPIO3, INPUT);
|
|
pinMode(GPIO5, INPUT);
|
|
|
|
|
|
Enable_AT();
|
|
DeviceState = DEVICE_STATE_INIT;
|
|
LoRaWAN.Ifskipjoin();
|
|
|
|
attachInterrupt(GPIO0, gpioInterruptRoutine, BOTH);
|
|
attachInterrupt(GPIO1, gpioInterruptRoutine, BOTH);
|
|
attachInterrupt(GPIO2, gpioInterruptRoutine, BOTH);
|
|
attachInterrupt(GPIO3, gpioInterruptRoutine, BOTH);
|
|
attachInterrupt(GPIO5, gpioInterruptRoutine, BOTH);
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
//LoRaWAN.Tick();
|
|
|
|
switch ( DeviceState )
|
|
{
|
|
//case DEVICE_STATE_RESTORE: {
|
|
// LoRaWAN.Restore();
|
|
// break;
|
|
// }
|
|
//case DEVICE_STATE_START: {
|
|
// LoRaWAN.Start();
|
|
// break;
|
|
// }
|
|
case DEVICE_STATE_INIT:
|
|
{
|
|
Serial.println("DEVICE_STATE_INIT");
|
|
getDevParam();
|
|
printDevParam();
|
|
LoRaWAN.Init(CLASS, REGION);
|
|
DeviceState = DEVICE_STATE_JOIN;
|
|
break;
|
|
}
|
|
case DEVICE_STATE_JOIN:
|
|
{
|
|
Serial.println("DEVICE_STATE_JOIN");
|
|
LoRaWAN.Join();
|
|
break;
|
|
}
|
|
case DEVICE_STATE_SEND:
|
|
{
|
|
Serial.println("DEVICE_STATE_SEND");
|
|
AppPort = 2; //send timer
|
|
PrepareTxFrame(AppPort);
|
|
LoRaWAN.Send();
|
|
DeviceState = DEVICE_STATE_CYCLE;
|
|
break;
|
|
}
|
|
case DEVICE_STATE_CYCLE:
|
|
{
|
|
Serial.println("DEVICE_STATE_CYCLE");
|
|
// Schedule next packet transmission
|
|
TxDutyCycleTime = APP_TX_DUTYCYCLE + randr( 0, APP_TX_DUTYCYCLE_RND );
|
|
LoRaWAN.Cycle(TxDutyCycleTime);
|
|
DeviceState = DEVICE_STATE_SLEEP;
|
|
break;
|
|
}
|
|
case DEVICE_STATE_SLEEP:
|
|
{
|
|
//Serial.println("DEVICE_STATE_SLEEP");
|
|
//if (isr_flag == true) {
|
|
// if (IsLoRaMacNetworkJoined) {
|
|
// AppPort = 3; //send interrupt
|
|
// if (PrepareTxFrame(AppPort)) {
|
|
// LoRaWAN.Send();
|
|
// }
|
|
// }
|
|
// isr_flag = false;
|
|
|
|
// Schedule next packet transmission
|
|
// TxDutyCycleTime = APP_TX_DUTYCYCLE + randr( 0, APP_TX_DUTYCYCLE_RND );
|
|
// LoRaWAN.Cycle(TxDutyCycleTime);
|
|
//}
|
|
|
|
LoRaWAN.Sleep();
|
|
//Serial.println("LoRaWAN.Sleep() finished");
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
DeviceState = DEVICE_STATE_INIT;
|
|
break;
|
|
}
|
|
}
|
|
}
|