#include #include #include #include #include #include #include // OLED #include U8X8_SSD1306_128X64_NONAME_HW_I2C oled(U8X8_PIN_NONE, PIN_PB0, PIN_PB1); // GPS #include Gps gps; bool hasFix = false; bool oldFix = false; // Button Handling #include 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(); }