181 lines
4.2 KiB
C++
181 lines
4.2 KiB
C++
|
|
#include <Arduino.h>
|
|
#include <avr/sleep.h>
|
|
#include <avr/interrupt.h>
|
|
#include <SPI.h>
|
|
#include <Wire.h>
|
|
|
|
// Use the local config.h for LMIC Configuration
|
|
#define ARDUINO_LMIC_PROJECT_CONFIG_H config.h
|
|
#include <lmic.h>
|
|
#include <hal/hal.h>
|
|
#include "config.h"
|
|
|
|
#ifdef HAS_BME280
|
|
#include "BME280.h"
|
|
BME280 sensor;
|
|
#endif
|
|
|
|
// Define some LMIC Callbacks and Variables
|
|
void os_getArtEui (u1_t* buf) {
|
|
memcpy_P(buf, APPEUI, 8);
|
|
}
|
|
void os_getDevEui (u1_t* buf) {
|
|
memcpy_P(buf, DEVEUI, 8);
|
|
}
|
|
void os_getDevKey (u1_t* buf) {
|
|
memcpy_P(buf, APPKEY, 16);
|
|
}
|
|
static osjob_t sendjob;
|
|
|
|
// Pin-Mapping for ATTNode v3
|
|
const lmic_pinmap lmic_pins = {
|
|
.nss = PIN_PA5,
|
|
.rxtx = LMIC_UNUSED_PIN,
|
|
.rst = LMIC_UNUSED_PIN,
|
|
.dio = {PIN_PA4, PIN_PA6, LMIC_UNUSED_PIN},
|
|
};
|
|
|
|
// List of unused Pins - will be disabled for Power Saving
|
|
const int disabledPins[] = {PIN_PB5, PIN_PB4, PIN_PB3, PIN_PB2, PIN_PB1, PIN_PB0, PIN_PC3, PIN_PC2, PIN_PC1, PIN_PC0};
|
|
|
|
// ISR Routine for Sleep
|
|
ISR(RTC_PIT_vect)
|
|
{
|
|
/* Clear interrupt flag by writing '1' (required) */
|
|
RTC.PITINTFLAGS = RTC_PI_bm;
|
|
}
|
|
|
|
// Sleep Routine
|
|
void sleep_32s() {
|
|
cli();
|
|
while (RTC.PITSTATUS > 0) {}
|
|
RTC.PITINTCTRL = RTC_PI_bm;
|
|
// 32 Sekunden
|
|
RTC.PITCTRLA = RTC_PERIOD_CYC32768_gc | RTC_PITEN_bm;
|
|
while (RTC.PITSTATUS & RTC_CTRLBUSY_bm) {}
|
|
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
|
sleep_enable();
|
|
sei();
|
|
sleep_cpu();
|
|
sleep_disable();
|
|
sei();
|
|
}
|
|
|
|
// LMIC Callback Handling
|
|
void onEvent(ev_t ev) {
|
|
switch (ev) {
|
|
case EV_JOINED:
|
|
// Disable LinkCheck
|
|
LMIC_setLinkCheckMode(0);
|
|
break;
|
|
case EV_TXCOMPLETE:
|
|
// Schedule Next Transmit
|
|
do_send(&sendjob);
|
|
// Got to sleep for specified Time
|
|
for (int i = 0; i < int(SLEEP_TIME*2); i++)
|
|
sleep_32s();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Get Battery Voltage
|
|
uint16_t readSupplyVoltage() { //returns value in millivolts to avoid floating point
|
|
uint16_t temp = 0;
|
|
analogReference(VDD);
|
|
VREF.CTRLA = VREF_ADC0REFSEL_1V5_gc;
|
|
ADC0.CTRLD = ADC_INITDLY_DLY256_gc;
|
|
ADC0_CTRLB = ADC_SAMPNUM_ACC64_gc;
|
|
uint16_t reading = analogRead(ADC_INTREF);
|
|
temp = reading / 64;
|
|
uint32_t intermediate = 1534500;
|
|
reading = 0;
|
|
reading = intermediate / temp;
|
|
return reading;
|
|
}
|
|
|
|
// Blink x times
|
|
#ifdef LED_PIN
|
|
void blink(uint8_t num) {
|
|
pinMode(LED_PIN, OUTPUT);
|
|
digitalWrite(LED_PIN, 0);
|
|
for (uint8_t i = 0; i < num * 2; i++) {
|
|
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
|
|
delay(5);
|
|
}
|
|
digitalWrite(LED_PIN, 0);
|
|
}
|
|
#endif
|
|
|
|
// Read Sensors and Send Data
|
|
// All Sensor Code and Data Preparation goes here
|
|
void do_send(osjob_t* j) {
|
|
// Prepare LoRa Data Packet
|
|
#ifdef HAS_BME280
|
|
struct lora_data {
|
|
uint8_t bat;
|
|
int32_t temperature;
|
|
int32_t humidity;
|
|
int32_t pressure;
|
|
} __attribute__ ((packed)) data;
|
|
#endif
|
|
|
|
if (LMIC.opmode & OP_TXRXPEND) {
|
|
delay(10);
|
|
} else {
|
|
// Add Battery Voltage (0.2V Accuracy stored in 1 byte)
|
|
uint32_t batv = readSupplyVoltage();
|
|
data.bat = (uint8_t)(batv / 20);
|
|
if (batv % 20 > 9)
|
|
data.bat += 1;
|
|
|
|
#ifdef HAS_BME280
|
|
sensor.getData(&data.temperature, &data.pressure, &data.humidity);
|
|
#endif
|
|
|
|
// Queue Paket for Sending
|
|
LMIC_setTxData2(1, (unsigned char *)&data, sizeof(data), 0);
|
|
}
|
|
}
|
|
|
|
void setup()
|
|
{
|
|
// Initialize SPI and I2C
|
|
Wire.begin();
|
|
SPI.begin();
|
|
|
|
// Disable unused Pins (for power saving)
|
|
for (int i = 0; i < (sizeof(disabledPins) / sizeof(disabledPins[0])) - 1; i++)
|
|
pinMode(disabledPins[i], INPUT_PULLUP);
|
|
|
|
// Set RTC
|
|
while (RTC.STATUS > 0) {}
|
|
RTC.CLKSEL = RTC_CLKSEL_INT1K_gc;
|
|
while (RTC.PITSTATUS > 0) {}
|
|
|
|
// Initialize Sensor(s)
|
|
#ifdef HAS_BME280
|
|
sensor.getCalData();
|
|
#endif
|
|
|
|
// Setup LMIC
|
|
os_init();
|
|
LMIC_reset(); // Reset LMIC state and cancel all queued transmissions
|
|
LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100); // Compensate for Clock Skew
|
|
LMIC.dn2Dr = DR_SF9; // Downlink Band
|
|
LMIC_setDrTxpow(DR_SF7, 14); // Default to SF7
|
|
|
|
// Schedule First Send (Triggers OTAA Join as well)
|
|
do_send(&sendjob);
|
|
|
|
#ifdef LED_PIN
|
|
pinMode(LED_PIN, OUTPUT);
|
|
blink(1);
|
|
#endif
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
// Only Run the LMIC loop here. Actual Sending Code is in do_send()
|
|
os_runloop_once();
|
|
}
|