2018-11-25 20:11:22 +00:00
// Tracker for LoRA APRS
2021-01-20 18:50:03 +00:00
// from OE1ACM and OE3CJB redesigned by SQ9MDD
// TTGO T-Beam v1.0 only
2018-11-25 20:07:34 +00:00
//
// licensed under CC BY-NC-SA
2018-12-01 11:27:58 +00:00
// Includes
2018-12-01 20:31:34 +00:00
# include <TTGO_T-Beam_LoRa_APRS_config.h> // to config user parameters
2018-12-01 11:27:58 +00:00
# include <Arduino.h>
# include <SPI.h>
2018-12-01 20:31:34 +00:00
# include <BG_RF95.h> // library from OE1ACM
2018-12-01 11:27:58 +00:00
# include <TinyGPS++.h>
# include <math.h>
# include <driver/adc.h>
# include <Wire.h>
2020-12-13 09:35:40 +00:00
# include <Adafruit_I2CDevice.h>
2018-12-01 11:27:58 +00: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 17:44:22 +00:00
# include <axp20x.h>
2021-02-11 15:09:24 +00:00
# include <KISS_TO_TNC2.h>
2019-11-22 13:22:31 +00:00
2020-01-02 19:13:30 +00:00
// I2C LINES
# define I2C_SDA 21
# define I2C_SCL 22
// DISPLAY address
# define SSD1306_ADDRESS 0x3C
2018-11-25 20:07:34 +00:00
//other global Variables
2021-02-12 13:26:01 +00:00
String Textzeile1 , Textzeile2 ;
# ifdef KISS_PROTOCOLL
String inTNCData = " " ;
# endif
2018-12-06 06:47:42 +00:00
int button = 0 ;
int button_ctr = 0 ;
2018-11-25 20:07:34 +00:00
// Pins for GPS
2021-01-20 18:50:03 +00:00
static const int RXPin = 12 , TXPin = 34 ; // changed BG A3 A2
2018-11-25 20:07:34 +00:00
static const uint32_t GPSBaud = 9600 ; //GPS
2019-11-22 13:22:31 +00:00
// LED for signalling
2021-01-20 18:50:03 +00:00
const byte TXLED = 33 ; //pin number for LED on TX Tracker
2019-11-22 13:22:31 +00:00
// Button of TTGO T-Beam
2021-01-20 18:50:03 +00:00
# define BUTTON 38 //pin number for Button on TTGO T-Beam
2018-11-25 20:07:34 +00:00
// Pins for LoRa module
2021-01-20 18:50:03 +00: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 09:35:40 +00:00
2019-11-22 13:22:31 +00:00
// Variables for APRS packaging
String Tcall ; //your Call Sign for normal position reports
String sTable = " / " ; //Primer
2021-02-12 07:08:36 +00:00
String relay_path ;
2018-11-25 20:07:34 +00:00
// Variables and Constants
String InputString = " " ; //data on buff is copied to this string
String Outputstring = " " ;
String outString = " " ; //The new Output String with GPS Conversion RAW
2018-12-09 21:23:20 +00:00
String LongShown = " " ;
String LatShown = " " ;
2018-12-24 14:29:36 +00:00
String LongFixed = " " ;
String LatFixed = " " ;
2018-11-25 20:07:34 +00:00
//byte arrays
byte lora_TXBUFF [ 128 ] ; //buffer for packet to send
2020-02-02 20:40:08 +00:00
byte lora_RXBUFF [ 128 ] ; //buffer for packet to send
2021-01-20 18:50:03 +00:00
2018-11-25 20:07:34 +00: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 11:27:58 +00:00
float BattVolts ;
2018-11-25 20:07:34 +00:00
2019-11-22 13:22:31 +00:00
// variables for smart beaconing
2020-01-02 19:13:30 +00: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 17:12:52 +00:00
int point_avg_speed = 0 , point_avg_course = 0 ;
2019-11-22 13:22:31 +00:00
ulong min_time_to_nextTX = 60000L ; // minimum time period between TX = 60000ms = 60secs = 1min
2021-01-20 18:50:03 +00:00
ulong nextTX = 60000L ; // preset time period between TX = 60000ms = 60secs = 1min
# define ANGLE 60 // angle to send packet at smart beaconing
# define ANGLE_AVGS 3 // angle averaging - x times
2020-04-19 15:52:27 +00:00
float average_course [ ANGLE_AVGS ] ;
float avg_c_y , avg_c_x ;
2018-12-01 11:27:58 +00:00
static const adc_atten_t atten = ADC_ATTEN_DB_6 ;
static const adc_unit_t unit = ADC_UNIT_1 ;
2018-11-25 20:07:34 +00:00
static void smartDelay ( unsigned long ) ;
void recalcGPS ( void ) ;
void sendpacket ( void ) ;
void loraSend ( byte , byte , byte , byte , byte , long , byte , float ) ;
void batt_read ( void ) ;
2018-12-06 06:47:42 +00:00
void writedisplaytext ( String , String , String , String , String , String , int ) ;
2018-12-09 21:23:20 +00:00
void setup_data ( void ) ;
2018-11-25 20:07:34 +00:00
// SoftwareSerial ss(RXPin, TXPin); // The serial connection to the GPS device
2021-02-12 13:26:01 +00:00
HardwareSerial gpsSerial ( 1 ) ; // TTGO has HW serial
2018-11-25 20:07:34 +00:00
TinyGPSPlus gps ; // The TinyGPS++ object
2021-01-20 18:50:03 +00:00
AXP20X_Class axp ;
2018-11-25 20:07:34 +00:00
// checkRX
uint8_t buf [ BG_RF95_MAX_MESSAGE_LEN ] ;
uint8_t len = sizeof ( buf ) ;
// 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
# define OLED_RESET 4 // not used
Adafruit_SSD1306 display ( 128 , 64 , & Wire , OLED_RESET ) ;
2021-01-20 18:50:03 +00:00
// + FUNCTIONS-----------------------------------------------------------+//
2020-01-02 19:13:30 +00:00
2018-11-25 20:07:34 +00:00
// This custom version of delay() ensures that the gps object
// is being "fed".
2021-01-20 18:50:03 +00:00
static void smartDelay ( unsigned long ms ) {
2021-02-11 23:03:15 +00:00
# ifdef KISS_PROTOCOLL
2021-02-12 12:27:52 +00:00
delay ( 10 ) ;
2021-02-11 23:03:15 +00:00
return ;
# endif
2018-11-25 20:07:34 +00:00
unsigned long start = millis ( ) ;
2021-01-20 18:50:03 +00:00
do {
2021-02-12 13:26:01 +00:00
while ( gpsSerial . available ( ) )
gps . encode ( gpsSerial . read ( ) ) ;
2018-11-25 20:07:34 +00:00
} while ( millis ( ) - start < ms ) ;
}
2021-01-20 18:50:03 +00:00
char * ax25_base91enc ( char * s , uint8_t n , uint32_t v ) {
2020-08-27 19:41:54 +00: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 20:07:34 +00:00
void recalcGPS ( ) {
String Ns , Ew , helper ;
2020-08-27 19:41:54 +00:00
char helper_base91 [ ] = { " 0000 \0 " } ;
2021-01-20 18:50:03 +00:00
float Tlat = 52.0000 , Tlon = 20.0000 ;
2019-10-24 19:54:33 +00:00
int i , Talt , lenalt ;
2020-08-27 19:41:54 +00:00
uint32_t aprs_lat , aprs_lon ;
2020-02-02 15:58:19 +00:00
float Tspeed = 0 , Tcourse = 0 ;
2019-10-24 19:54:33 +00:00
String Speedx , Coursex , Altx ;
2018-11-25 20:07:34 +00:00
2021-01-20 18:50:03 +00: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 06:47:42 +00:00
}
2021-01-20 18:50:03 +00: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 ; }
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 ;
//}
2018-11-25 20:07:34 +00:00
2021-02-11 23:03:15 +00: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 18:50:03 +00:00
}
2021-02-11 23:03:15 +00:00
// outString = (Tcall);
2021-02-12 07:08:36 +00:00
# ifdef DIGI_PATH
2021-02-12 12:26:06 +00:00
outString + = " >APLM0, " + relay_path + " :! " ;
2021-02-12 07:08:36 +00:00
# elif
2021-02-12 12:26:06 +00:00
outString + = " >APLM0:! " ;
2021-02-12 07:08:36 +00:00
# endif
2021-02-12 12:26:06 +00:00
outString + = APRS_SYMBOL_TABLE ;
2021-02-12 07:08:36 +00:00
2021-02-11 23:03:15 +00:00
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 ] ;
}
2021-02-12 12:26:06 +00:00
outString + = APRS_SYMBOL ;
2021-02-11 23:03:15 +00:00
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 " ;
# ifdef SHOW_ALT
outString + = " /A= " ;
outString + = Altx ;
# endif
outString + = MY_COMMENT ;
# ifdef SHOW_BATT // battery is not frame part move after comment
outString + = " Batt= " ;
outString + = String ( BattVolts , 2 ) ;
outString + = ( " V " ) ;
# endif
2021-02-12 13:26:01 +00:00
# ifdef KISS_PROTOCOLL
Serial . print ( encode_kiss ( outString ) ) ;
# else
Serial . println ( outString ) ;
# endif
2018-11-25 20:07:34 +00:00
}
2021-01-20 18:50:03 +00:00
void sendpacket ( ) {
String message ;
2018-11-25 20:07:34 +00:00
batt_read ( ) ;
Outputstring = " " ;
2021-01-20 18:50:03 +00:00
if ( gps . location . isValid ( ) | | gps . location . isUpdated ( ) ) {
2018-11-25 20:07:34 +00:00
recalcGPS ( ) ; //
Outputstring = outString ;
2021-01-20 18:50:03 +00: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
} else {
Outputstring = ( Tcall ) ;
Outputstring + = " No GPS-Fix " ;
Outputstring + = " Batt= " ;
Outputstring + = String ( BattVolts , 2 ) ;
Outputstring + = ( " V " ) ;
message = Outputstring ;
loraSend ( lora_TXStart , lora_TXEnd , 60 , 255 , 1 , 10 , 5 , TXFREQ , message ) ; //send the packet, data is in TXbuff from lora_TXStart to lora_TXEnd
2018-11-25 20:07:34 +00:00
}
}
2021-02-12 13:26:01 +00: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 ) {
2018-11-25 20:07:34 +00:00
byte i ;
byte ltemp ;
2018-12-06 06:47:42 +00:00
if ( rf95 . waitAvailableTimeout ( 100 ) ) {
if ( rf95 . recvAPRS ( buf , & len ) ) {
}
2018-11-25 20:07:34 +00:00
}
2018-12-06 06:47:42 +00:00
lastTX = millis ( ) ;
2018-11-25 20:07:34 +00:00
2021-01-20 18:50:03 +00:00
ltemp = message . length ( ) ;
2021-01-20 19:09:03 +00:00
for ( i = 0 ; i < = ltemp ; i + + ) {
2021-01-20 18:50:03 +00:00
lora_TXBUFF [ i ] = message . charAt ( i ) ;
2018-12-06 06:47:42 +00:00
}
2018-11-25 20:07:34 +00:00
2018-12-06 06:47:42 +00:00
i - - ;
lora_TXEnd = i ;
lora_TXBUFF [ i ] = ' \0 ' ;
2018-11-25 20:07:34 +00:00
rf95 . setModemConfig ( BG_RF95 : : Bw125Cr45Sf4096 ) ;
rf95 . setFrequency ( lora_FREQ ) ;
rf95 . setTxPower ( lora_LTXPower ) ;
2021-01-20 18:50:03 +00:00
rf95 . sendAPRS ( lora_TXBUFF , message . length ( ) ) ;
2018-11-25 20:07:34 +00:00
rf95 . waitPacketSent ( ) ;
}
2021-01-20 18:50:03 +00:00
void batt_read ( ) {
2019-11-29 17:44:22 +00:00
BattVolts = axp . getBattVoltage ( ) / 1000 ;
2018-11-25 20:07:34 +00:00
}
2018-12-09 21:23:20 +00:00
void writedisplaytext ( String HeaderTxt , String Line1 , String Line2 , String Line3 , String Line4 , String Line5 , int warten ) {
2018-11-25 20:07:34 +00:00
display . clearDisplay ( ) ;
display . setTextColor ( WHITE ) ;
display . setTextSize ( 2 ) ;
display . setCursor ( 0 , 0 ) ;
2018-12-06 06:47:42 +00:00
display . println ( HeaderTxt ) ;
2018-11-25 20:07:34 +00:00
display . setTextSize ( 1 ) ;
2018-12-01 11:27:58 +00:00
display . setCursor ( 0 , 16 ) ;
2018-11-25 20:07:34 +00:00
display . println ( Line1 ) ;
2018-12-01 11:27:58 +00:00
display . setCursor ( 0 , 26 ) ;
2018-11-25 20:07:34 +00:00
display . println ( Line2 ) ;
2018-12-01 11:27:58 +00:00
display . setCursor ( 0 , 36 ) ;
2018-11-25 20:07:34 +00:00
display . println ( Line3 ) ;
2018-12-01 11:27:58 +00:00
display . setCursor ( 0 , 46 ) ;
display . println ( Line4 ) ;
display . setCursor ( 0 , 56 ) ;
display . println ( Line5 ) ;
2018-11-25 20:07:34 +00:00
display . display ( ) ;
smartDelay ( warten ) ;
}
2021-01-20 18:50:03 +00:00
// + SETUP --------------------------------------------------------------+//
void setup ( ) {
for ( int i = 0 ; i < ANGLE_AVGS ; i + + ) { // set average_course to "0"
average_course [ i ] = 0 ;
2018-12-24 14:29:36 +00:00
}
2021-01-20 18:50:03 +00: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 21:23:20 +00:00
2021-01-20 18:50:03 +00:00
if ( ! axp . begin ( Wire , AXP192_SLAVE_ADDRESS ) ) {
2021-01-22 16:31:22 +00:00
}
2020-01-02 19:13:30 +00:00
2021-01-20 18:50:03 +00: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 ) ;
2020-01-02 19:13:30 +00:00
2021-01-20 18:50:03 +00:00
if ( ! display . begin ( SSD1306_SWITCHCAPVCC , SSD1306_ADDRESS ) ) {
for ( ; ; ) ; // Don't proceed, loop forever
}
writedisplaytext ( " LoRa-APRS " , " " , " Init: " , " Display OK! " , " " , " " , 1000 ) ;
Tcall = CALLSIGN ;
2021-02-12 07:08:36 +00:00
relay_path = DIGI_PATH ;
2021-01-20 18:50:03 +00: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-11 23:03:15 +00:00
}
2021-01-20 18:50:03 +00:00
writedisplaytext ( " LoRa-APRS " , " " , " Init: " , " RF95 OK! " , " " , " " , 250 ) ;
2021-02-12 13:26:01 +00:00
gpsSerial . begin ( GPSBaud , SERIAL_8N1 , TXPin , RXPin ) ; //Startup HW serial for GPS
2021-01-20 18:50:03 +00:00
writedisplaytext ( " LoRa-APRS " , " " , " Init: " , " GPS Serial OK! " , " " , " " , 250 ) ;
writedisplaytext ( " " + Tcall , " " , " Init: " , " Waiting for GPS " , " " , " " , 250 ) ;
while ( millis ( ) < 5000 & & gps . charsProcessed ( ) < 10 ) { }
if ( millis ( ) > 5000 & & gps . charsProcessed ( ) < 10 ) {
writedisplaytext ( " " + Tcall , " " , " Init: " , " ERROR! " , " No GPS data! " , " Please restart TTGO " , 0 ) ;
2021-02-11 23:03:15 +00:00
while ( true ) { }
2021-01-20 18:50:03 +00:00
}
writedisplaytext ( " " + Tcall , " " , " Init: " , " Data from GPS OK! " , " " , " " , 250 ) ;
writedisplaytext ( " LoRa-APRS " , " " , " Init: " , " ADC OK! " , " BAT: " + String ( axp . getBattVoltage ( ) / 1000 , 1 ) , " " , 250 ) ;
rf95 . setFrequency ( 433.775 ) ;
rf95 . setModemConfig ( BG_RF95 : : Bw125Cr45Sf4096 ) ; // hard coded because of double definition
2021-01-22 11:40:48 +00:00
rf95 . setTxPower ( 20 ) ; // was 5
2021-01-20 18:50:03 +00:00
delay ( 250 ) ;
writedisplaytext ( " LoRa-APRS " , " " , " Init: " , " FINISHED OK! " , " =:-) " , " " , 250 ) ;
writedisplaytext ( " " , " " , " " , " " , " " , " " , 0 ) ;
}
2020-01-02 19:13:30 +00:00
2021-01-20 18:50:03 +00:00
// +---------------------------------------------------------------------+//
// + MAINLOOP -----------------------------------------------------------+//
// +---------------------------------------------------------------------+//
void loop ( ) {
2021-02-12 13:26:01 +00:00
while ( gpsSerial . available ( ) > 0 ) {
gps . encode ( gpsSerial . read ( ) ) ;
2021-01-20 18:50:03 +00:00
}
2021-02-11 23:03:15 +00:00
# ifdef KISS_PROTOCOLL
while ( Serial . available ( ) > 0 ) {
char character = Serial . read ( ) ;
2021-02-12 13:26:01 +00:00
inTNCData . concat ( character ) ;
if ( character = = ( char ) FEND & & inTNCData . length ( ) > 3 ) {
2021-02-11 23:03:15 +00:00
writedisplaytext ( " (KISSTX)) " , " " , " " , " " , " " , " " , 1 ) ;
2021-02-12 13:26:01 +00:00
loraSend ( lora_TXStart , lora_TXEnd , 60 , 255 , 1 , 10 , TXdbmW , TXFREQ , decode_kiss ( inTNCData ) ) ;
inTNCData = " " ;
2021-02-11 23:03:15 +00:00
}
}
# endif
2021-01-20 18:50:03 +00:00
if ( rf95 . waitAvailableTimeout ( 100 ) ) {
# ifdef SHOW_RX_PACKET // only show RX packets when activitated in config
if ( rf95 . recvAPRS ( lora_RXBUFF , & len ) ) {
InputString = " " ;
for ( int i = 0 ; i < len ; i + + ) {
InputString + = ( char ) lora_RXBUFF [ i ] ;
2021-01-22 11:40:48 +00:00
}
# ifdef KISS_PROTOCOLL
2021-02-11 19:17:18 +00:00
Serial . print ( encode_kiss ( InputString ) ) ;
2021-01-22 11:40:48 +00:00
# endif
2021-01-20 18:50:03 +00:00
writedisplaytext ( " ((RX)) " , " " , InputString , " " , " " , " " , SHOW_RX_TIME ) ;
2018-12-24 14:29:36 +00:00
}
2021-01-20 18:50:03 +00:00
# endif
}
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-11 23:03:15 +00:00
if ( point_avg_speed > 4 ) {
point_avg_speed = 0 ;
}
2021-01-20 18:50:03 +00: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 14:29:36 +00:00
}
2020-01-02 19:13:30 +00:00
2021-01-20 18:50:03 +00:00
new_course = atan2f ( avg_c_y , avg_c_x ) * 180 / 3.1415 ;
if ( new_course < 0 ) {
new_course = 360 + new_course ;
}
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 19:13:30 +00:00
}
2021-01-20 18:50:03 +00:00
} else {
if ( ( old_course > ( 360 - ANGLE ) ) & & ( new_course < ANGLE ) ) {
if ( abs ( new_course - old_course + 360 ) > = ANGLE ) {
nextTX = 0 ;
2020-01-02 19:13:30 +00:00
}
2021-01-20 18:50:03 +00:00
} else {
if ( abs ( new_course - old_course ) > = ANGLE ) {
nextTX = 0 ;
2020-01-02 19:13:30 +00:00
}
}
2018-12-24 14:29:36 +00:00
}
2021-01-20 18:50:03 +00:00
old_course = new_course ;
}
2018-12-24 14:29:36 +00:00
2021-01-20 18:50:03 +00:00
batt_read ( ) ;
2020-01-02 19:13:30 +00:00
2021-01-20 18:50:03 +00:00
if ( button_ctr = = 2 ) {
nextTX = 0 ;
2020-01-02 19:13:30 +00:00
}
2021-01-20 18:50:03 +00:00
if ( ( millis ( ) < max_time_to_nextTX ) & & ( lastTX = = 0 ) ) {
nextTX = 0 ;
}
if ( ( lastTX + nextTX ) < = millis ( ) ) {
if ( gps . location . age ( ) < 2000 ) {
digitalWrite ( TXLED , HIGH ) ;
writedisplaytext ( " ((TX)) " , " " , " LAT: " + LatShown , " LON: " + LongShown , " SPD: " + String ( gps . speed . kmph ( ) , 1 ) + " CRS: " + String ( gps . course . deg ( ) , 1 ) , " SAT: " + String ( gps . satellites . value ( ) ) , 1 ) ;
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 ) ) ;
digitalWrite ( TXLED , LOW ) ;
# endif
} else {
writedisplaytext ( " " + Tcall , " (TX) at valid GPS " , " LAT: not valid " , " LON: not valid " , " SPD: --- CRS: --- " , " SAT: " + String ( gps . satellites . value ( ) ) + " BAT: " + String ( BattVolts , 1 ) + " V " , 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
}
} else {
if ( gps . location . age ( ) < 2000 ) {
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 ) , " SAT: " + String ( gps . satellites . value ( ) ) + " BAT: " + String ( BattVolts , 1 ) + " V " , 1 ) ;
}
}
2018-12-09 21:23:20 +00:00
}
2021-01-20 18:50:03 +00:00
// end of main loop