attmapper/src/main.cpp

313 lines
7.2 KiB
C++

#include <Arduino.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <SPI.h>
#include <Wire.h>
#include <EEPROM.h>
#include <LoRaWAN.h>
// OLED
#include <U8x8lib.h>
U8X8_SSD1306_128X64_NONAME_HW_I2C oled(U8X8_PIN_NONE, PIN_PB0, PIN_PB1);
// GPS
#include <gps.h>
Gps gps;
bool hasFix = false;
bool oldFix = false;
// Button Handling
#include <Button2.h>
Button2 btn = Button2(PIN_PC2);
bool adhocsend = false;
// Modes for Display Menus and Navigation
enum Modes {
M_NORMAL,
M_SETUP
};
enum Settings {
S_NONE,
S_INTERVAL,
S_KEYSET,
S_BRIGHT,
S_EXIT
};
Modes amode = M_NORMAL; // Active Mode
Modes omode = M_NORMAL; // Previous Mode
Settings cset = S_INTERVAL; // Current Setting
Settings aset = S_NONE; // Selected Setting
#define EEPROM_KEYSET_ADR 0
#define EEPROM_INTERVAL_ADR 1
#define EEPROM_BRIGHTNESS_ADR 2
// LoRa
#include "config.h" // Contains LoRa ABP Keys
#define DIO0 PIN_PA4
#define NSS PIN_PA5
RFM95 rfm(DIO0, NSS);
LoRaWAN lora = LoRaWAN(rfm);
uint16_t Frame_Counter_Tx = 0x0001;
// Some Status Variables
uint8_t interval = 20; // Sending Interval in Settings
uint8_t packets = 0; // Sent LoRa Packets
uint8_t keyset = 1; // LoRa KeySet
uint8_t bright = 128; // Brightness
String statusmsg = "";
uint8_t loraBuffer[9]; // Lora Data Packet
uint32_t lastmillis;
// Supply Voltage
uint16_t readSupplyVoltage() {
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;
}
void loraKeySetup(uint8_t keyset) {
if (keyset == 1)
lora.setKeys(NwkSkey_1, AppSkey_1, DevAddr_1);
if (keyset == 2)
lora.setKeys(NwkSkey_2, AppSkey_2, DevAddr_2);
}
void fillLine() {
for (uint8_t i = oled.tx; i<15; i++)
oled.print(" ");
oled.println("");
}
// Button Handler Function
void handler(Button2& btn) {
switch (btn.getClickType()) {
case SINGLE_CLICK:
if (amode == M_SETUP) {
if (aset == S_INTERVAL) {
interval = interval += 10;
if (interval > 30)
interval = 10;
} else if (aset == S_KEYSET) {
keyset = keyset + 1;
if (keyset > 2)
keyset = 1;
loraKeySetup(keyset);
} else if (aset == S_BRIGHT) {
bright += 32;
if (bright > 255)
bright = 32;
oled.setContrast(bright);
} else {
switch (cset) {
case S_INTERVAL:
cset = S_KEYSET;
break;
case S_KEYSET:
cset = S_BRIGHT;
break;
case S_BRIGHT:
cset = S_EXIT;
break;
case S_EXIT:
cset = S_INTERVAL;
break;
}
}
} else if (amode == M_NORMAL) {
statusmsg = "Adhoc Request";
adhocsend = true;
}
break;
case LONG_CLICK:
switch (amode) {
case M_NORMAL:
amode = M_SETUP;
cset = S_INTERVAL;
break;
case M_SETUP:
if (cset == S_EXIT) {
aset = S_NONE;
amode = M_NORMAL;
EEPROM.update(EEPROM_KEYSET_ADR, keyset);
EEPROM.update(EEPROM_INTERVAL_ADR, interval);
EEPROM.update(EEPROM_BRIGHTNESS_ADR, bright);
} else if (aset == S_NONE) {
aset = cset;
} else {
aset = S_NONE;
}
break;
}
break;
}
}
// Draw the Display
void updateDisplay() {
uint16_t buffer[6];
gps.gdisplay(buffer);
oled.home();
oled.setFont(u8x8_font_victoriabold8_r);
if (amode != omode) {
oled.clear();
omode = amode;
}
if (amode == M_SETUP) {
oled.println ("**** SETUP ****");
oled.println ("");
char tmp = ' ';
tmp = (cset == S_INTERVAL) ? '>' : ' ';
oled.print(tmp);
tmp = (aset == S_INTERVAL) ? '>' : ' ';
oled.print(tmp);
oled.print("Interval: ");
oled.println(interval);
tmp = (cset == S_KEYSET) ? '>' : ' ';
oled.print(tmp);
tmp = (aset == S_KEYSET) ? '>' : ' ';
oled.print(tmp);
oled.print("ABP Keys: ");
oled.println(keyset);
tmp = (cset == S_BRIGHT) ? '>' : ' ';
oled.print(tmp);
tmp = (aset == S_BRIGHT) ? '>' : ' ';
oled.print(tmp);
oled.print("Brightn.: ");
oled.println(bright);
oled.println("");
tmp = (cset == S_EXIT) ? '>' : ' ';
oled.print(tmp);
oled.println(" Exit Setup");
} else if (amode == M_NORMAL) {
if (hasFix) {
if (hasFix != oldFix){
oled.clear();
oldFix = hasFix;
}
oled.print("HDOP: ");
oled.print(buffer[0]);
fillLine();
oled.print("Sats: ");
oled.print(buffer[1]);
oled.print("/");
oled.print(buffer[2]);
fillLine();
oled.print("Int: ");
oled.print(interval);
fillLine();
oled.print("Packet: ");
oled.print(packets);
fillLine();
oled.print("Alt: ");
oled.print(buffer[3]);
fillLine();
oled.print("Speed: ");
oled.print(buffer[4]);
fillLine();
oled.print("Bat: ");
oled.print((float)readSupplyVoltage()/1000);
fillLine();
} else {
if (hasFix != oldFix){
oled.clear();
oldFix = hasFix;
}
oled.print("NO GPS FIX");
fillLine();
oled.print("Sats: ");
oled.print(buffer[1]);
oled.print("/");
oled.print(buffer[2]);
fillLine();
oled.print("Int: ");
oled.print(interval);
fillLine();
oled.print("Packet: ");
oled.print(packets);
fillLine();
oled.print("Bat: ");
oled.print((float)readSupplyVoltage()/1000);
fillLine();
}
oled.print(statusmsg);
oled.println(" ");
}
}
// Setup
void setup() {
// GPS Setup
Serial.begin(9600);
// Button
btn.setLongClickTime(1000);
btn.setClickHandler(handler);
btn.setLongClickHandler(handler);
// OLED Setup
Wire.begin();
Wire.setClock(400000L);
oled.begin();
oled.setPowerSave(0);
oled.setFlipMode(1);
oled.clear();
// Get Settings from EEPROM
EEPROM.get(EEPROM_KEYSET_ADR, keyset);
if (keyset < 1 || keyset > 2) keyset = 1;
EEPROM.get(EEPROM_INTERVAL_ADR, interval);
if (interval < 10 || interval > 30) interval = 20;
EEPROM.get(EEPROM_BRIGHTNESS_ADR, bright);
if (bright < 0 || bright > 255) bright = 128;
oled.setContrast(bright);
// Lora Initialization
rfm.init();
loraKeySetup(keyset);
}
// Main Loop
void loop() {
hasFix = gps.checkGpsFix();
uint32_t curmillis = millis();
if (hasFix && (((uint32_t)(curmillis - lastmillis) >= interval*1000) || adhocsend)) {
if (adhocsend) {
statusmsg = "Sending (Adhoc)";
} else {
statusmsg = "Sending";
}
updateDisplay();
adhocsend = false;
gps.buildPacket(loraBuffer);
lora.Send_Data((unsigned char *)&loraBuffer, sizeof(loraBuffer), Frame_Counter_Tx, SF7BW125, 0x01);
packets++;
Frame_Counter_Tx++;
lastmillis = millis();
} else {
updateDisplay();
}
statusmsg = "";
btn.loop();
}