2018-11-25 22:11:22 +02:00
|
|
|
// Tracker for LoRA APRS
|
2021-01-20 20:50:03 +02:00
|
|
|
// from OE1ACM and OE3CJB redesigned by SQ9MDD
|
2021-02-14 02:09:11 +02:00
|
|
|
// KISS ans Bluetooth by SQ5RWU
|
2021-01-20 20:50:03 +02:00
|
|
|
// TTGO T-Beam v1.0 only
|
2018-11-25 22:07:34 +02:00
|
|
|
//
|
|
|
|
// licensed under CC BY-NC-SA
|
|
|
|
|
2018-12-01 13:27:58 +02:00
|
|
|
// Includes
|
2018-12-01 22:31:34 +02:00
|
|
|
#include <TTGO_T-Beam_LoRa_APRS_config.h> // to config user parameters
|
2018-12-01 13:27:58 +02:00
|
|
|
#include <Arduino.h>
|
|
|
|
#include <SPI.h>
|
2018-12-01 22:31:34 +02:00
|
|
|
#include <BG_RF95.h> // library from OE1ACM
|
2018-12-01 13:27:58 +02:00
|
|
|
#include <math.h>
|
|
|
|
#include <driver/adc.h>
|
|
|
|
#include <Wire.h>
|
2020-12-13 11:35:40 +02:00
|
|
|
#include <Adafruit_I2CDevice.h>
|
2018-12-01 13:27:58 +02:00
|
|
|
#include <Adafruit_SSD1306.h>
|
|
|
|
#include <splash.h>
|
|
|
|
#include <Adafruit_GFX.h>
|
|
|
|
#include <Adafruit_SPITFT.h>
|
|
|
|
#include <Adafruit_SPITFT_Macros.h>
|
|
|
|
#include <gfxfont.h>
|
2019-11-29 19:44:22 +02:00
|
|
|
#include <axp20x.h>
|
2021-02-11 17:09:24 +02:00
|
|
|
#include <KISS_TO_TNC2.h>
|
2021-02-13 18:42:51 +02:00
|
|
|
#include "taskGPS.h"
|
2019-11-22 15:22:31 +02:00
|
|
|
|
2021-02-12 17:25:14 +02:00
|
|
|
#ifdef ENABLE_BLUETOOTH
|
2021-02-13 21:58:41 +02:00
|
|
|
#include "BluetoothSerial.h"
|
2021-02-12 17:25:14 +02:00
|
|
|
#endif
|
|
|
|
|
2020-01-02 21:13:30 +02:00
|
|
|
// I2C LINES
|
|
|
|
#define I2C_SDA 21
|
|
|
|
#define I2C_SCL 22
|
|
|
|
|
|
|
|
// DISPLAY address
|
|
|
|
#define SSD1306_ADDRESS 0x3C
|
|
|
|
|
2018-11-25 22:07:34 +02:00
|
|
|
//other global Variables
|
2021-02-12 15:26:01 +02:00
|
|
|
String Textzeile1, Textzeile2;
|
|
|
|
|
2021-02-13 00:00:36 +02:00
|
|
|
#ifdef KISS_PROTOCOL
|
2021-02-12 15:26:01 +02:00
|
|
|
String inTNCData = "";
|
|
|
|
#endif
|
2021-02-15 13:41:46 +02:00
|
|
|
//int button=0;
|
|
|
|
//int button_ctr=0;
|
2018-11-25 22:07:34 +02:00
|
|
|
|
|
|
|
|
2019-11-22 15:22:31 +02:00
|
|
|
// LED for signalling
|
2021-02-13 12:15:25 +02:00
|
|
|
#ifdef T_BEAM_V1_0
|
|
|
|
const byte TXLED = 4; //pin number for LED on TX Tracker
|
|
|
|
#else
|
|
|
|
const byte TXLED = 14; //pin number for LED on TX Tracker
|
|
|
|
#endif
|
2019-11-22 15:22:31 +02:00
|
|
|
|
|
|
|
// Button of TTGO T-Beam
|
2021-02-13 12:15:25 +02:00
|
|
|
#ifdef T_BEAM_V1_0
|
|
|
|
// const byte BUTTON = 38; //pin number for Button on TTGO T-Beam
|
|
|
|
#define BUTTON 38 //pin number for Button on TTGO T-Beam
|
|
|
|
#else
|
|
|
|
#define BUTTON 39 //pin number for Button on TTGO T-Beam
|
|
|
|
#endif
|
2018-11-25 22:07:34 +02:00
|
|
|
|
|
|
|
// Pins for LoRa module
|
2021-01-20 20:50:03 +02:00
|
|
|
const byte lora_PReset = 23; //pin where LoRa device reset line is connected
|
|
|
|
const byte lora_PNSS = 18; //pin number where the NSS line for the LoRa device is connected.
|
2020-12-13 11:35:40 +02:00
|
|
|
|
2019-11-22 15:22:31 +02:00
|
|
|
// Variables for APRS packaging
|
|
|
|
String Tcall; //your Call Sign for normal position reports
|
|
|
|
String sTable="/"; //Primer
|
2021-02-12 09:08:36 +02:00
|
|
|
String relay_path;
|
2021-02-14 01:34:38 +02:00
|
|
|
boolean gps_state = true;
|
2021-02-15 13:41:46 +02:00
|
|
|
boolean key_up = true;
|
2018-11-25 22:07:34 +02:00
|
|
|
|
|
|
|
// Variables and Constants
|
2021-02-12 19:51:49 +02:00
|
|
|
String loraReceivedFrameString = ""; //data on buff is copied to this string
|
2018-11-25 22:07:34 +02:00
|
|
|
String Outputstring = "";
|
|
|
|
String outString=""; //The new Output String with GPS Conversion RAW
|
2018-12-09 23:23:20 +02:00
|
|
|
String LongShown="";
|
|
|
|
String LatShown="";
|
2018-12-24 16:29:36 +02:00
|
|
|
String LongFixed="";
|
|
|
|
String LatFixed="";
|
|
|
|
|
2018-11-25 22:07:34 +02:00
|
|
|
//byte arrays
|
2021-02-12 19:51:49 +02:00
|
|
|
byte lora_TXBUFF[BG_RF95_MAX_MESSAGE_LEN]; //buffer for packet to send
|
|
|
|
byte lora_RXBUFF[BG_RF95_MAX_MESSAGE_LEN]; //buffer for packet to send
|
2021-01-20 20:50:03 +02:00
|
|
|
|
2018-11-25 22:07:34 +02:00
|
|
|
//byte Variables
|
|
|
|
byte lora_TXStart; //start of packet data in TXbuff
|
|
|
|
byte lora_TXEnd; //end of packet data in TXbuff
|
|
|
|
byte lora_FTXOK; //flag, set to 1 if TX OK
|
|
|
|
byte lora_TXPacketType; //type number of packet to send
|
|
|
|
byte lora_TXDestination; //destination address of packet to send
|
|
|
|
byte lora_TXSource; //source address of packet received
|
|
|
|
byte lora_FDeviceError; //flag, set to 1 if RFM98 device error
|
|
|
|
byte lora_TXPacketL; //length of packet to send, includes source, destination and packet type.
|
|
|
|
|
|
|
|
unsigned long lastTX = 0L;
|
2018-12-01 13:27:58 +02:00
|
|
|
float BattVolts;
|
2018-11-25 22:07:34 +02:00
|
|
|
|
2019-11-22 15:22:31 +02:00
|
|
|
// variables for smart beaconing
|
2020-01-02 21:13:30 +02:00
|
|
|
float average_speed[5] = {0,0,0,0,0}, average_speed_final=0, max_speed=30, min_speed=0;
|
|
|
|
float old_course = 0, new_course = 0;
|
2020-01-05 19:12:52 +02:00
|
|
|
int point_avg_speed = 0, point_avg_course = 0;
|
2019-11-22 15:22:31 +02:00
|
|
|
ulong min_time_to_nextTX=60000L; // minimum time period between TX = 60000ms = 60secs = 1min
|
2021-02-13 19:08:37 +02:00
|
|
|
ulong max_time_to_nextTX= MAX_TIME_TO_NEXT_TX;
|
2021-01-20 20:50:03 +02:00
|
|
|
ulong nextTX=60000L; // preset time period between TX = 60000ms = 60secs = 1min
|
2021-02-13 21:58:41 +02:00
|
|
|
ulong time_to_refresh = 0;
|
2021-02-15 14:01:52 +02:00
|
|
|
ulong next_fixed_beacon = 0;
|
2021-02-15 14:27:59 +02:00
|
|
|
ulong fix_beacon_interval = FIX_BEACON_INTERVAL;
|
2021-01-20 20:50:03 +02:00
|
|
|
#define ANGLE 60 // angle to send packet at smart beaconing
|
|
|
|
#define ANGLE_AVGS 3 // angle averaging - x times
|
2020-04-19 18:52:27 +03:00
|
|
|
float average_course[ANGLE_AVGS];
|
|
|
|
float avg_c_y, avg_c_x;
|
|
|
|
|
2018-12-01 13:27:58 +02:00
|
|
|
static const adc_atten_t atten = ADC_ATTEN_DB_6;
|
|
|
|
static const adc_unit_t unit = ADC_UNIT_1;
|
2018-11-25 22:07:34 +02:00
|
|
|
|
|
|
|
void recalcGPS(void);
|
|
|
|
void sendpacket(void);
|
|
|
|
void loraSend(byte, byte, byte, byte, byte, long, byte, float);
|
|
|
|
void batt_read(void);
|
2018-12-06 08:47:42 +02:00
|
|
|
void writedisplaytext(String, String, String, String, String, String, int);
|
2018-12-09 23:23:20 +02:00
|
|
|
void setup_data(void);
|
2018-11-25 22:07:34 +02:00
|
|
|
|
2021-02-12 16:43:10 +02:00
|
|
|
void displayInvalidGPS();
|
|
|
|
|
2021-02-12 17:25:14 +02:00
|
|
|
void handleKISSData(char character);
|
|
|
|
|
2021-02-13 12:15:25 +02:00
|
|
|
#ifdef T_BEAM_V1_0
|
2021-01-20 20:50:03 +02:00
|
|
|
AXP20X_Class axp;
|
2021-02-13 12:15:25 +02:00
|
|
|
#endif
|
2018-11-25 22:07:34 +02:00
|
|
|
|
|
|
|
// checkRX
|
2021-02-12 19:51:49 +02:00
|
|
|
uint8_t loraReceivedLength = sizeof(lora_RXBUFF);
|
2018-11-25 22:07:34 +02:00
|
|
|
|
|
|
|
// Singleton instance of the radio driver
|
|
|
|
BG_RF95 rf95(18, 26); // TTGO T-Beam has NSS @ Pin 18 and Interrupt IO @ Pin26
|
|
|
|
|
|
|
|
// initialize OLED display
|
2021-02-13 22:41:56 +02:00
|
|
|
#define OLED_RESET 16 // not used
|
2018-11-25 22:07:34 +02:00
|
|
|
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
|
|
|
|
|
2021-02-12 17:25:14 +02:00
|
|
|
#ifdef ENABLE_BLUETOOTH
|
2021-02-13 22:41:56 +02:00
|
|
|
BluetoothSerial SerialBT;
|
2021-02-12 17:25:14 +02:00
|
|
|
#endif
|
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
// + FUNCTIONS-----------------------------------------------------------+//
|
2020-01-02 21:13:30 +02:00
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
char *ax25_base91enc(char *s, uint8_t n, uint32_t v){
|
2020-08-27 22:41:54 +03:00
|
|
|
/* Creates a Base-91 representation of the value in v in the string */
|
|
|
|
/* pointed to by s, n-characters long. String length should be n+1. */
|
|
|
|
for(s += n, *s = '\0'; n; n--)
|
|
|
|
{
|
|
|
|
*(--s) = v % 91 + 33;
|
|
|
|
v /= 91;
|
|
|
|
}
|
|
|
|
return(s);
|
|
|
|
}
|
2018-11-25 22:07:34 +02:00
|
|
|
|
|
|
|
void recalcGPS(){
|
|
|
|
String Ns, Ew, helper;
|
2020-08-27 22:41:54 +03:00
|
|
|
char helper_base91[] = {"0000\0"};
|
2021-01-20 20:50:03 +02:00
|
|
|
float Tlat=52.0000, Tlon=20.0000;
|
2019-10-24 22:54:33 +03:00
|
|
|
int i, Talt, lenalt;
|
2020-08-27 22:41:54 +03:00
|
|
|
uint32_t aprs_lat, aprs_lon;
|
2020-02-02 17:58:19 +02:00
|
|
|
float Tspeed=0, Tcourse=0;
|
2019-10-24 22:54:33 +03:00
|
|
|
String Speedx, Coursex, Altx;
|
2018-11-25 22:07:34 +02:00
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
Tlat=gps.location.lat();
|
|
|
|
Tlon=gps.location.lng();
|
|
|
|
Talt=gps.altitude.meters() * 3.28;
|
|
|
|
Altx = Talt;
|
|
|
|
lenalt = Altx.length();
|
|
|
|
Altx = "";
|
|
|
|
for (i = 0; i < (6-lenalt); i++) {
|
|
|
|
Altx += "0";
|
2018-12-06 08:47:42 +02:00
|
|
|
}
|
2021-01-20 20:50:03 +02:00
|
|
|
Altx += Talt;
|
|
|
|
Tcourse=gps.course.deg();
|
|
|
|
Tspeed=gps.speed.knots();
|
|
|
|
if(Tlat<0) { Ns = "S"; } else { Ns = "N"; }
|
|
|
|
if(Tlon<0) { Ew = "W"; } else { Ew = "E"; }
|
|
|
|
if(Tlat < 0) { Tlat= -Tlat; }
|
|
|
|
|
|
|
|
if(Tlon < 0) { Tlon= -Tlon; }
|
2021-02-15 13:41:46 +02:00
|
|
|
aprs_lat = 900000000 - Tlat * 10000000;
|
|
|
|
aprs_lat = aprs_lat / 26 - aprs_lat / 2710 + aprs_lat / 15384615;
|
|
|
|
aprs_lon = 900000000 + Tlon * 10000000 / 2;
|
|
|
|
aprs_lon = aprs_lon / 26 - aprs_lon / 2710 + aprs_lon / 15384615;
|
2021-01-20 20:50:03 +02:00
|
|
|
//}
|
2018-11-25 22:07:34 +02:00
|
|
|
|
2021-02-12 01:03:15 +02:00
|
|
|
outString = "";
|
|
|
|
for (i=0; i<Tcall.length();++i){ // remove unneeded "spaces" from callsign field
|
|
|
|
if (Tcall.charAt(i) != ' ') {
|
|
|
|
outString += Tcall.charAt(i);
|
|
|
|
}
|
2021-01-20 20:50:03 +02:00
|
|
|
}
|
2021-02-12 01:03:15 +02:00
|
|
|
// outString = (Tcall);
|
2021-02-12 09:08:36 +02:00
|
|
|
#ifdef DIGI_PATH
|
2021-02-12 14:26:06 +02:00
|
|
|
outString += ">APLM0," + relay_path + ":!";
|
2021-02-12 09:08:36 +02:00
|
|
|
#elif
|
2021-02-12 14:26:06 +02:00
|
|
|
outString += ">APLM0:!";
|
2021-02-12 09:08:36 +02:00
|
|
|
#endif
|
2021-02-13 19:15:02 +02:00
|
|
|
|
2021-02-15 13:41:46 +02:00
|
|
|
if(gps_state==true && gps.location.isValid()){
|
|
|
|
outString += APRS_SYMBOL_TABLE;
|
|
|
|
ax25_base91enc(helper_base91, 4, aprs_lat);
|
|
|
|
for (i=0; i<4; i++) {
|
|
|
|
outString += helper_base91[i];
|
|
|
|
}
|
|
|
|
ax25_base91enc(helper_base91, 4, aprs_lon);
|
|
|
|
for (i=0; i<4; i++) {
|
|
|
|
outString += helper_base91[i];
|
|
|
|
}
|
|
|
|
outString += APRS_SYMBOL;
|
|
|
|
ax25_base91enc(helper_base91, 1, (uint32_t) Tcourse/4 );
|
|
|
|
outString += helper_base91[0];
|
|
|
|
ax25_base91enc(helper_base91, 1, (uint32_t) (log1p(Tspeed)/0.07696));
|
|
|
|
outString += helper_base91[0];
|
|
|
|
outString += "\x48";
|
2021-02-15 14:15:38 +02:00
|
|
|
#ifdef SHOW_ALT
|
|
|
|
outString += "/A=";
|
|
|
|
outString += Altx;
|
|
|
|
#endif
|
2021-02-15 13:41:46 +02:00
|
|
|
}else{
|
|
|
|
outString += LATIDUDE_PRESET;
|
|
|
|
outString += APRS_SYMBOL_TABLE;
|
|
|
|
outString += LONGITUDE_PRESET;
|
|
|
|
outString += APRS_SYMBOL;
|
2021-02-12 01:03:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
outString += MY_COMMENT;
|
|
|
|
|
|
|
|
#ifdef SHOW_BATT // battery is not frame part move after comment
|
|
|
|
outString += " Batt=";
|
2021-02-13 19:15:02 +02:00
|
|
|
outString += String(BattVolts, 2);
|
2021-02-12 01:03:15 +02:00
|
|
|
outString += ("V");
|
|
|
|
#endif
|
2021-02-13 19:15:02 +02:00
|
|
|
|
2021-02-13 00:00:36 +02:00
|
|
|
#ifdef KISS_PROTOCOL
|
2021-02-12 15:26:01 +02:00
|
|
|
Serial.print(encode_kiss(outString));
|
2021-02-12 17:25:14 +02:00
|
|
|
#ifdef ENABLE_BLUETOOTH
|
2021-02-13 19:15:02 +02:00
|
|
|
if (SerialBT.connected()) {
|
|
|
|
SerialBT.print(encode_kiss(outString));
|
|
|
|
}
|
2021-02-12 17:25:14 +02:00
|
|
|
#endif
|
2021-02-13 19:15:02 +02:00
|
|
|
#else
|
2021-02-12 15:26:01 +02:00
|
|
|
Serial.println(outString);
|
|
|
|
#endif
|
2018-11-25 22:07:34 +02:00
|
|
|
}
|
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
void sendpacket(){
|
|
|
|
String message;
|
2018-11-25 22:07:34 +02:00
|
|
|
batt_read();
|
|
|
|
Outputstring = "";
|
|
|
|
|
2021-02-15 13:41:46 +02:00
|
|
|
//if ( gps.location.isValid() || gps.location.isUpdated() ) {
|
2018-11-25 22:07:34 +02:00
|
|
|
recalcGPS(); //
|
|
|
|
Outputstring =outString;
|
2021-01-20 20:50:03 +02:00
|
|
|
message = Outputstring;
|
|
|
|
loraSend(lora_TXStart, lora_TXEnd, 60, 255, 1, 10, TXdbmW, TXFREQ, message); //send the packet, data is in TXbuff from lora_TXStart to lora_TXEnd
|
2021-02-15 13:41:46 +02:00
|
|
|
//}
|
2018-11-25 22:07:34 +02:00
|
|
|
}
|
|
|
|
|
2021-02-12 15:26:01 +02:00
|
|
|
void loraSend(byte lora_LTXStart, byte lora_LTXEnd, byte lora_LTXPacketType, byte lora_LTXDestination, byte lora_LTXSource, long lora_LTXTimeout, byte lora_LTXPower, float lora_FREQ, const String& message){
|
2021-02-14 01:06:07 +02:00
|
|
|
digitalWrite(TXLED, LOW);
|
2018-11-25 22:07:34 +02:00
|
|
|
byte i;
|
|
|
|
byte ltemp;
|
|
|
|
|
2018-12-06 08:47:42 +02:00
|
|
|
lastTX = millis();
|
2018-11-25 22:07:34 +02:00
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
ltemp = message.length();
|
2021-01-20 21:09:03 +02:00
|
|
|
for (i = 0; i <= ltemp; i++){
|
2021-01-20 20:50:03 +02:00
|
|
|
lora_TXBUFF[i] = message.charAt(i);
|
2018-12-06 08:47:42 +02:00
|
|
|
}
|
2018-11-25 22:07:34 +02:00
|
|
|
|
2018-12-06 08:47:42 +02:00
|
|
|
i--;
|
|
|
|
lora_TXEnd = i;
|
|
|
|
lora_TXBUFF[i] ='\0';
|
2018-11-25 22:07:34 +02:00
|
|
|
rf95.setModemConfig(BG_RF95::Bw125Cr45Sf4096);
|
|
|
|
rf95.setFrequency(lora_FREQ);
|
|
|
|
rf95.setTxPower(lora_LTXPower);
|
2021-01-20 20:50:03 +02:00
|
|
|
rf95.sendAPRS(lora_TXBUFF, message.length());
|
2018-11-25 22:07:34 +02:00
|
|
|
rf95.waitPacketSent();
|
2021-02-14 01:06:07 +02:00
|
|
|
digitalWrite(TXLED, HIGH);
|
2018-11-25 22:07:34 +02:00
|
|
|
}
|
2021-01-20 20:50:03 +02:00
|
|
|
|
|
|
|
void batt_read(){
|
2021-02-13 19:05:18 +02:00
|
|
|
#ifdef T_BEAM_V1_0
|
2019-11-29 19:44:22 +02:00
|
|
|
BattVolts = axp.getBattVoltage()/1000;
|
2021-02-13 19:05:18 +02:00
|
|
|
#else
|
|
|
|
BattVolts = analogRead(35)*7.221/4096;
|
|
|
|
#endif
|
2018-11-25 22:07:34 +02:00
|
|
|
}
|
|
|
|
|
2018-12-09 23:23:20 +02:00
|
|
|
void writedisplaytext(String HeaderTxt, String Line1, String Line2, String Line3, String Line4, String Line5, int warten) {
|
2021-02-13 22:41:56 +02:00
|
|
|
batt_read();
|
2021-02-14 01:06:07 +02:00
|
|
|
if (BattVolts < 3.5){
|
2021-02-15 14:35:51 +02:00
|
|
|
#ifdef T_BEAM_V1_0
|
|
|
|
axp.setChgLEDMode(AXP20X_LED_BLINK_4HZ);
|
|
|
|
#endif
|
2021-02-14 01:06:07 +02:00
|
|
|
}
|
2021-02-15 14:13:59 +02:00
|
|
|
|
2018-11-25 22:07:34 +02:00
|
|
|
display.clearDisplay();
|
|
|
|
display.setTextColor(WHITE);
|
|
|
|
display.setTextSize(2);
|
|
|
|
display.setCursor(0,0);
|
2018-12-06 08:47:42 +02:00
|
|
|
display.println(HeaderTxt);
|
2018-11-25 22:07:34 +02:00
|
|
|
display.setTextSize(1);
|
2018-12-01 13:27:58 +02:00
|
|
|
display.setCursor(0,16);
|
2018-11-25 22:07:34 +02:00
|
|
|
display.println(Line1);
|
2018-12-01 13:27:58 +02:00
|
|
|
display.setCursor(0,26);
|
2018-11-25 22:07:34 +02:00
|
|
|
display.println(Line2);
|
2018-12-01 13:27:58 +02:00
|
|
|
display.setCursor(0,36);
|
2018-11-25 22:07:34 +02:00
|
|
|
display.println(Line3);
|
2018-12-01 13:27:58 +02:00
|
|
|
display.setCursor(0,46);
|
|
|
|
display.println(Line4);
|
|
|
|
display.setCursor(0,56);
|
|
|
|
display.println(Line5);
|
2018-11-25 22:07:34 +02:00
|
|
|
display.display();
|
2021-02-13 23:16:45 +02:00
|
|
|
time_to_refresh = millis() + SHOW_RX_TIME;
|
2018-11-25 22:07:34 +02:00
|
|
|
}
|
2021-02-14 02:09:11 +02:00
|
|
|
|
2021-02-15 14:27:59 +02:00
|
|
|
/**
|
|
|
|
* Handle incoming TNC KISS data character
|
|
|
|
* @param character
|
|
|
|
*/
|
2021-02-14 02:09:11 +02:00
|
|
|
void handleKISSData(char character) {
|
|
|
|
inTNCData.concat(character);
|
|
|
|
if (character == (char)FEND && inTNCData.length() > 3){
|
|
|
|
writedisplaytext("((KISSTX))","","","","","",1);
|
|
|
|
time_to_refresh = millis() + SHOW_RX_TIME;
|
2021-02-15 14:27:59 +02:00
|
|
|
#ifdef KISS_PROTOCOL
|
2021-02-14 02:09:11 +02:00
|
|
|
const String &TNC2DataFrame = decode_kiss(inTNCData);
|
|
|
|
|
2021-02-15 00:08:00 +02:00
|
|
|
#ifdef LOCAL_KISS_ECHO
|
|
|
|
Serial.print(inTNCData);
|
|
|
|
#endif
|
2021-02-14 02:09:11 +02:00
|
|
|
#ifdef ENABLE_BLUETOOTH
|
|
|
|
if (SerialBT.connected()) {
|
2021-02-15 00:08:00 +02:00
|
|
|
#ifdef LOCAL_KISS_ECHO
|
|
|
|
SerialBT.print(inTNCData);
|
|
|
|
#endif
|
2021-02-14 02:09:11 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
loraSend(lora_TXStart, lora_TXEnd, 60, 255, 1, 10, TXdbmW, TXFREQ, TNC2DataFrame);
|
|
|
|
inTNCData = "";
|
|
|
|
}
|
2018-11-25 22:07:34 +02:00
|
|
|
}
|
2021-02-14 02:09:11 +02:00
|
|
|
|
|
|
|
String getSatAndBatInfo() {
|
|
|
|
String line5;
|
|
|
|
if(gps_state == true){
|
|
|
|
line5 = "SAT: " + String(gps.satellites.value()) + " BAT: " + String(BattVolts, 1) + "V";
|
|
|
|
}else{
|
|
|
|
line5 = "SAT: X BAT: " + String(BattVolts, 1) + "V";
|
2021-02-15 14:13:59 +02:00
|
|
|
}
|
2021-02-14 02:09:11 +02:00
|
|
|
#ifdef ENABLE_BLUETOOTH
|
|
|
|
if (SerialBT.connected()){
|
|
|
|
line5 += "BT";
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return line5;
|
|
|
|
}
|
|
|
|
|
|
|
|
void displayInvalidGPS() {
|
|
|
|
writedisplaytext(" " + Tcall, "(TX) at valid GPS", "LAT: not valid", "LON: not valid", "SPD: --- CRS: ---", getSatAndBatInfo(), 1);
|
|
|
|
#ifdef SHOW_GPS_DATA
|
|
|
|
Serial.print("(TX) at valid GPS / LAT: not valid / Lon: not valid / SPD: --- / CRS: ---");
|
|
|
|
Serial.print(" / SAT: ");
|
|
|
|
Serial.print(String(gps.satellites.value()));
|
|
|
|
Serial.print(" / BAT: ");
|
|
|
|
Serial.println(String(BattVolts,1));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
// + SETUP --------------------------------------------------------------+//
|
|
|
|
|
|
|
|
void setup(){
|
|
|
|
for (int i=0;i<ANGLE_AVGS;i++) { // set average_course to "0"
|
|
|
|
average_course[i]=0;
|
2018-12-24 16:29:36 +02:00
|
|
|
}
|
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
pinMode(TXLED, OUTPUT);
|
|
|
|
pinMode(BUTTON, INPUT);
|
|
|
|
digitalWrite(TXLED, LOW); // turn blue LED off
|
|
|
|
Serial.begin(115200);
|
|
|
|
Wire.begin(I2C_SDA, I2C_SCL);
|
2018-12-09 23:23:20 +02:00
|
|
|
|
2021-02-13 19:15:02 +02:00
|
|
|
#ifdef T_BEAM_V1_0
|
2021-02-13 12:15:25 +02:00
|
|
|
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
|
2021-02-13 19:01:37 +02:00
|
|
|
}
|
2021-02-13 19:15:02 +02:00
|
|
|
axp.setPowerOutPut(AXP192_LDO2, AXP202_ON);
|
|
|
|
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // switch on GPS
|
|
|
|
axp.setPowerOutPut(AXP192_DCDC2, AXP202_ON);
|
|
|
|
axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON);
|
|
|
|
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON);
|
|
|
|
axp.setDCDC1Voltage(3300);
|
2021-02-15 14:27:59 +02:00
|
|
|
// Enable ADC to measure battery current, USB voltage etc.
|
2021-02-13 19:15:02 +02:00
|
|
|
axp.adc1Enable(0xfe, true);
|
|
|
|
axp.adc2Enable(0x80, true);
|
2021-02-13 19:01:37 +02:00
|
|
|
#endif
|
2021-02-13 19:15:02 +02:00
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
if(!display.begin(SSD1306_SWITCHCAPVCC, SSD1306_ADDRESS)) {
|
|
|
|
for(;;); // Don't proceed, loop forever
|
|
|
|
}
|
2021-02-13 19:15:02 +02:00
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
writedisplaytext("LoRa-APRS","","Init:","Display OK!","","",1000);
|
|
|
|
Tcall = CALLSIGN;
|
2021-02-12 09:08:36 +02:00
|
|
|
relay_path = DIGI_PATH;
|
2021-02-13 19:15:02 +02:00
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
if (!rf95.init()) {
|
|
|
|
writedisplaytext("LoRa-APRS","","Init:","RF95 FAILED!",":-(","",250);
|
|
|
|
for(;;); // Don't proceed, loop forever
|
|
|
|
}
|
|
|
|
|
|
|
|
if (max_time_to_nextTX < nextTX){
|
|
|
|
max_time_to_nextTX=nextTX;
|
2021-02-12 01:03:15 +02:00
|
|
|
}
|
2021-01-20 20:50:03 +02:00
|
|
|
writedisplaytext("LoRa-APRS","","Init:","RF95 OK!","","",250);
|
|
|
|
writedisplaytext(" "+Tcall,"","Init:","Waiting for GPS","","",250);
|
2021-02-15 14:27:59 +02:00
|
|
|
xTaskCreate(taskGPS, "taskGPS", 10000, nullptr, 1, nullptr);
|
2021-02-13 18:42:51 +02:00
|
|
|
writedisplaytext(" "+Tcall,"","Init:","GPS Task Created!","","",250);
|
2021-02-13 19:05:18 +02:00
|
|
|
#ifndef T_BEAM_V1_0
|
|
|
|
adc1_config_width(ADC_WIDTH_BIT_12);
|
|
|
|
adc1_config_channel_atten(ADC1_CHANNEL_7,ADC_ATTEN_DB_6);
|
|
|
|
#endif
|
|
|
|
batt_read();
|
|
|
|
writedisplaytext("LoRa-APRS","","Init:","ADC OK!","BAT: "+String(BattVolts,1),"",250);
|
2021-01-20 20:50:03 +02:00
|
|
|
rf95.setFrequency(433.775);
|
|
|
|
rf95.setModemConfig(BG_RF95::Bw125Cr45Sf4096); // hard coded because of double definition
|
2021-02-15 14:27:59 +02:00
|
|
|
rf95.setTxPower(TXdbmW);
|
2021-01-20 20:50:03 +02:00
|
|
|
delay(250);
|
2021-02-13 19:15:02 +02:00
|
|
|
#ifdef ENABLE_BLUETOOTH
|
|
|
|
#ifdef BLUETOOTH_PIN
|
|
|
|
SerialBT.setPin(BLUETOOTH_PIN);
|
|
|
|
#endif
|
|
|
|
SerialBT.begin(String("TTGO LORA APRS ") + CALLSIGN);
|
|
|
|
writedisplaytext("LoRa-APRS","","Init:","BT OK!","","",250);
|
2021-02-12 20:01:50 +02:00
|
|
|
#endif
|
2021-01-20 20:50:03 +02:00
|
|
|
writedisplaytext("LoRa-APRS","","Init:","FINISHED OK!"," =:-) ","",250);
|
|
|
|
writedisplaytext("","","","","","",0);
|
2021-02-13 21:58:41 +02:00
|
|
|
time_to_refresh = millis() + SHOW_RX_TIME;
|
2021-02-13 23:16:45 +02:00
|
|
|
displayInvalidGPS();
|
2021-02-14 01:06:07 +02:00
|
|
|
digitalWrite(TXLED, HIGH);
|
2021-02-15 14:35:51 +02:00
|
|
|
#ifdef T_BEAM_V1_0
|
|
|
|
axp.setChgLEDMode(AXP20X_LED_OFF);
|
|
|
|
#endif
|
2021-01-20 20:50:03 +02:00
|
|
|
}
|
2020-01-02 21:13:30 +02:00
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
// +---------------------------------------------------------------------+//
|
|
|
|
// + MAINLOOP -----------------------------------------------------------+//
|
|
|
|
// +---------------------------------------------------------------------+//
|
|
|
|
|
|
|
|
void loop() {
|
2021-02-15 13:41:46 +02:00
|
|
|
if(digitalRead(BUTTON)==LOW && key_up == true){
|
|
|
|
key_up = false;
|
|
|
|
delay(100);
|
|
|
|
if(digitalRead(BUTTON)==LOW){
|
|
|
|
delay(300);
|
|
|
|
if(digitalRead(BUTTON)==HIGH){
|
|
|
|
if(gps_state == true && gps.location.isValid()){
|
|
|
|
writedisplaytext("((MAN TX))","","","","","",1);
|
|
|
|
sendpacket();
|
|
|
|
}else{
|
|
|
|
writedisplaytext("((FIX TX))","","","","","",1);
|
|
|
|
sendpacket();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delay(1500);
|
2021-02-14 01:34:38 +02:00
|
|
|
if(digitalRead(BUTTON)==LOW){
|
|
|
|
if(gps_state == true){
|
|
|
|
gps_state = false;
|
2021-02-15 14:35:51 +02:00
|
|
|
#ifdef T_BEAM_V1_0
|
|
|
|
axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); // GPS OFF
|
|
|
|
#endif
|
2021-02-14 01:34:38 +02:00
|
|
|
writedisplaytext("((GPSOFF))","","","","","",1);
|
2021-02-15 14:01:52 +02:00
|
|
|
next_fixed_beacon = millis() + fix_beacon_interval;
|
2021-02-14 01:34:38 +02:00
|
|
|
|
|
|
|
}else{
|
|
|
|
gps_state = true;
|
2021-02-15 14:35:51 +02:00
|
|
|
#ifdef T_BEAM_V1_0
|
|
|
|
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON);
|
|
|
|
#endif
|
2021-02-14 02:09:11 +02:00
|
|
|
writedisplaytext("((GPS ON))","","","","","",1); // GPS ON
|
2021-02-14 01:34:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-15 14:13:59 +02:00
|
|
|
if(digitalRead(BUTTON)==HIGH && key_up == false){
|
2021-02-15 13:41:46 +02:00
|
|
|
key_up = true;
|
|
|
|
}
|
2021-02-15 14:13:59 +02:00
|
|
|
|
2021-02-15 14:01:52 +02:00
|
|
|
#ifdef FIXED_BEACON_EN
|
|
|
|
if(millis() >= next_fixed_beacon && gps_state == false){
|
|
|
|
next_fixed_beacon = millis() + fix_beacon_interval;
|
|
|
|
writedisplaytext("((AUT TX))","","","","","",1);
|
|
|
|
sendpacket();
|
|
|
|
}
|
|
|
|
#endif
|
2021-02-14 01:34:38 +02:00
|
|
|
|
2021-02-13 00:00:36 +02:00
|
|
|
#ifdef KISS_PROTOCOL
|
2021-02-12 01:03:15 +02:00
|
|
|
while (Serial.available() > 0 ){
|
|
|
|
char character = Serial.read();
|
2021-02-12 17:25:14 +02:00
|
|
|
handleKISSData(character);
|
2021-02-12 01:03:15 +02:00
|
|
|
}
|
2021-02-12 17:25:14 +02:00
|
|
|
#ifdef ENABLE_BLUETOOTH
|
|
|
|
if (SerialBT.connected()) {
|
|
|
|
while (SerialBT.available() > 0 ){
|
|
|
|
char character = SerialBT.read();
|
|
|
|
handleKISSData(character);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2021-02-12 01:03:15 +02:00
|
|
|
#endif
|
2021-01-20 20:50:03 +02:00
|
|
|
|
|
|
|
if (rf95.waitAvailableTimeout(100)) {
|
2021-02-15 14:35:51 +02:00
|
|
|
#ifdef T_BEAM_V1_0
|
|
|
|
axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL);
|
|
|
|
#endif
|
2021-01-20 20:50:03 +02:00
|
|
|
#ifdef SHOW_RX_PACKET // only show RX packets when activitated in config
|
2021-02-13 22:41:56 +02:00
|
|
|
loraReceivedLength = sizeof(lora_RXBUFF); // reset max length before receiving!
|
2021-02-12 19:51:49 +02:00
|
|
|
if (rf95.recvAPRS(lora_RXBUFF, &loraReceivedLength)) {
|
|
|
|
loraReceivedFrameString = "";
|
|
|
|
for (int i=0 ; i < loraReceivedLength ; i++) {
|
|
|
|
loraReceivedFrameString += (char) lora_RXBUFF[i];
|
|
|
|
}
|
2021-02-13 00:00:36 +02:00
|
|
|
#ifdef KISS_PROTOCOL
|
2021-02-12 19:51:49 +02:00
|
|
|
Serial.print(encode_kiss(loraReceivedFrameString));
|
2021-02-12 18:14:19 +02:00
|
|
|
#ifdef ENABLE_BLUETOOTH
|
|
|
|
if (SerialBT.connected()){
|
2021-02-12 19:51:49 +02:00
|
|
|
SerialBT.print(encode_kiss(loraReceivedFrameString));
|
2021-02-12 18:14:19 +02:00
|
|
|
}
|
|
|
|
#endif
|
2021-01-22 13:40:48 +02:00
|
|
|
#endif
|
2021-02-12 19:51:49 +02:00
|
|
|
writedisplaytext(" ((RX))", "", loraReceivedFrameString, "", "", "", SHOW_RX_TIME);
|
2018-12-24 16:29:36 +02:00
|
|
|
}
|
2021-01-20 20:50:03 +02:00
|
|
|
#endif
|
2021-02-15 14:35:51 +02:00
|
|
|
#ifdef T_BEAM_V1_0
|
|
|
|
axp.setChgLEDMode(AXP20X_LED_OFF);
|
|
|
|
#endif
|
2021-01-20 20:50:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
LatShown = String(gps.location.lat(),5);
|
|
|
|
LongShown = String(gps.location.lng(),5);
|
|
|
|
average_speed[point_avg_speed] = gps.speed.kmph(); // calculate smart beaconing
|
|
|
|
++point_avg_speed;
|
2021-02-12 01:03:15 +02:00
|
|
|
if (point_avg_speed>4) {
|
|
|
|
point_avg_speed=0;
|
|
|
|
}
|
2021-01-20 20:50:03 +02:00
|
|
|
average_speed_final = (average_speed[0]+average_speed[1]+average_speed[2]+average_speed[3]+average_speed[4])/5;
|
|
|
|
nextTX = (max_time_to_nextTX-min_time_to_nextTX)/(max_speed-min_speed)*(max_speed-average_speed_final)+min_time_to_nextTX;
|
|
|
|
|
|
|
|
if (nextTX < min_time_to_nextTX) {nextTX=min_time_to_nextTX;}
|
|
|
|
if (nextTX > max_time_to_nextTX) {nextTX=max_time_to_nextTX;}
|
|
|
|
|
|
|
|
average_course[point_avg_course] = gps.course.deg(); // calculate smart beaconing course
|
|
|
|
|
|
|
|
++point_avg_course;
|
|
|
|
if (point_avg_course>(ANGLE_AVGS-1)) {
|
|
|
|
point_avg_course=0;
|
|
|
|
avg_c_y = 0;
|
|
|
|
avg_c_x = 0;
|
|
|
|
|
|
|
|
for (int i=0;i<ANGLE_AVGS;i++) {
|
|
|
|
avg_c_y += sin(average_course[i]/180*3.1415);
|
|
|
|
avg_c_x += cos(average_course[i]/180*3.1415);
|
2018-12-24 16:29:36 +02:00
|
|
|
}
|
2020-01-02 21:13:30 +02:00
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
new_course = atan2f(avg_c_y,avg_c_x)*180/3.1415;
|
|
|
|
if (new_course < 0) {
|
|
|
|
new_course=360+new_course;
|
|
|
|
}
|
2021-02-13 19:15:02 +02:00
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
if ((old_course < ANGLE) && (new_course > (360-ANGLE))) {
|
|
|
|
if (abs(new_course-old_course-360)>=ANGLE) {
|
|
|
|
nextTX = 0;
|
|
|
|
// lastTX = min_time_to_nextTX
|
2020-01-02 21:13:30 +02:00
|
|
|
}
|
2021-01-20 20:50:03 +02:00
|
|
|
} else {
|
|
|
|
if ((old_course > (360-ANGLE)) && (new_course < ANGLE)) {
|
|
|
|
if (abs(new_course-old_course+360)>=ANGLE) {
|
|
|
|
nextTX = 0;
|
2020-01-02 21:13:30 +02:00
|
|
|
}
|
2021-01-20 20:50:03 +02:00
|
|
|
} else {
|
|
|
|
if (abs(new_course-old_course)>=ANGLE) {
|
|
|
|
nextTX = 0;
|
2020-01-02 21:13:30 +02:00
|
|
|
}
|
|
|
|
}
|
2018-12-24 16:29:36 +02:00
|
|
|
}
|
2021-01-20 20:50:03 +02:00
|
|
|
old_course = new_course;
|
|
|
|
}
|
2018-12-24 16:29:36 +02:00
|
|
|
|
2021-01-20 20:50:03 +02:00
|
|
|
if ((millis()<max_time_to_nextTX)&&(lastTX == 0)) {
|
|
|
|
nextTX = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (lastTX+nextTX) <= millis() ) {
|
|
|
|
if (gps.location.age() < 2000) {
|
2021-02-12 18:14:19 +02:00
|
|
|
writedisplaytext(" ((TX))","","LAT: "+LatShown,"LON: "+LongShown,"SPD: "+String(gps.speed.kmph(),1)+" CRS: "+String(gps.course.deg(),1),getSatAndBatInfo(),1);
|
2021-01-20 20:50:03 +02:00
|
|
|
sendpacket();
|
|
|
|
#ifdef SHOW_GPS_DATA
|
|
|
|
Serial.print("((TX)) / LAT: ");
|
|
|
|
Serial.print(LatShown);
|
|
|
|
Serial.print(" / LON: ");
|
|
|
|
Serial.print(LongShown);
|
|
|
|
Serial.print(" / SPD: ");
|
|
|
|
Serial.print(String(gps.speed.kmph(),1));
|
|
|
|
Serial.print(" / CRS: ");
|
|
|
|
Serial.print(String(gps.course.deg(),1));
|
|
|
|
Serial.print(" / SAT: ");
|
|
|
|
Serial.print(String(gps.satellites.value()));
|
|
|
|
Serial.print(" / BAT: ");
|
|
|
|
Serial.print(String(BattVolts,1));
|
2021-02-14 01:06:07 +02:00
|
|
|
//digitalWrite(TXLED, LOW);
|
2021-01-20 20:50:03 +02:00
|
|
|
#endif
|
2021-02-13 23:16:45 +02:00
|
|
|
} else {
|
|
|
|
if (millis() > time_to_refresh){
|
|
|
|
displayInvalidGPS();
|
|
|
|
}
|
|
|
|
}
|
2021-01-20 20:50:03 +02:00
|
|
|
}else{
|
2021-02-15 00:08:00 +02:00
|
|
|
if (millis() > time_to_refresh){
|
2021-01-20 20:50:03 +02:00
|
|
|
if (gps.location.age() < 2000) {
|
2021-02-12 18:14:19 +02:00
|
|
|
writedisplaytext(" "+Tcall,"Time to TX: "+String(((lastTX+nextTX)-millis())/1000)+"sec","LAT: "+LatShown,"LON: "+LongShown,"SPD: "+String(gps.speed.kmph(),1)+" CRS: "+String(gps.course.deg(),1),getSatAndBatInfo() ,1);
|
2021-02-12 16:43:10 +02:00
|
|
|
} else {
|
|
|
|
displayInvalidGPS();
|
|
|
|
}
|
2021-02-15 00:08:00 +02:00
|
|
|
}
|
2021-01-20 20:50:03 +02:00
|
|
|
}
|
2021-02-13 00:00:36 +02:00
|
|
|
#ifdef KISS_PROTOCOL
|
2021-02-13 19:15:02 +02:00
|
|
|
#ifdef KISS_DEBUG
|
|
|
|
static auto last_debug_send_time = millis();
|
|
|
|
if (millis() - last_debug_send_time > 1000*5) {
|
|
|
|
last_debug_send_time = millis();
|
|
|
|
String debug_message = "";
|
2021-02-15 14:35:51 +02:00
|
|
|
#ifdef T_BEAM_V1_0
|
|
|
|
debug_message += "Bat V: " + String(axp.getBattVoltage());
|
|
|
|
debug_message += ", ";
|
|
|
|
debug_message += "Bat IN A: " + String(axp.getBattChargeCurrent());
|
|
|
|
debug_message += ", ";
|
|
|
|
debug_message += "Bat OUT A: " + String(axp.getBattDischargeCurrent());
|
|
|
|
debug_message += ", ";
|
|
|
|
debug_message += "USB Plugged: " + String(axp.isVBUSPlug());
|
|
|
|
debug_message += ", ";
|
|
|
|
debug_message += "USB V: " + String(axp.getVbusVoltage());
|
|
|
|
debug_message += ", ";
|
|
|
|
debug_message += "USB A: " + String(axp.getVbusCurrent());
|
|
|
|
debug_message += ", ";
|
|
|
|
debug_message += "Temp C: " + String(axp.getTemp());
|
|
|
|
#else
|
|
|
|
debug_message += "Bat V: " + String(BattVolts);
|
|
|
|
#endif
|
2021-02-13 19:15:02 +02:00
|
|
|
|
|
|
|
Serial.print(encapsulateKISS(debug_message, CMD_HARDWARE));
|
|
|
|
#ifdef ENABLE_BLUETOOTH
|
|
|
|
SerialBT.print(encapsulateKISS(debug_message, CMD_HARDWARE));
|
|
|
|
#endif
|
|
|
|
}
|
2021-02-12 23:56:59 +02:00
|
|
|
#endif
|
2021-02-12 22:44:06 +02:00
|
|
|
#endif
|
2021-02-13 18:42:51 +02:00
|
|
|
vTaskDelay(1);
|
2018-12-09 23:23:20 +02:00
|
|
|
}
|
2021-02-13 09:48:32 +02:00
|
|
|
// end of main loop
|